diff --git a/Android.mk b/Android.mk index d3e1cf5b4db83..aff6cf2a1e910 100644 --- a/Android.mk +++ b/Android.mk @@ -226,7 +226,6 @@ LOCAL_SRC_FILES += \ core/java/android/service/carrier/ICarrierMessagingService.aidl \ core/java/android/service/gatekeeper/IGateKeeperService.aidl \ core/java/android/service/notification/INotificationListener.aidl \ - core/java/android/service/notification/INotificationAssistant.aidl \ core/java/android/service/notification/IStatusBarNotificationHolder.aidl \ core/java/android/service/notification/IConditionListener.aidl \ core/java/android/service/notification/IConditionProvider.aidl \ diff --git a/api/current.txt b/api/current.txt index 3854b7aebca16..b3e4a36c0c45c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -33491,20 +33491,13 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } - public class NotificationAdjustment implements android.os.Parcelable { - ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri); - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - } - public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { ctor public NotificationAssistantService(); - method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment); + method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment); method public final void clearAnnotation(java.lang.String); method public void onNotificationActionClick(java.lang.String, long, int); method public void onNotificationClick(java.lang.String, long); - method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); method public void onNotificationRemoved(java.lang.String, long, int); method public void onNotificationVisibilityChanged(java.lang.String, long, boolean); method public final void setAnnotation(java.lang.String, android.app.Notification); @@ -33524,6 +33517,10 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } + public class NotificationAssistantService.Adjustment { + ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri); + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); diff --git a/api/system-current.txt b/api/system-current.txt index 29905169b0da2..c9f45d28ce24c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -35633,20 +35633,13 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } - public class NotificationAdjustment implements android.os.Parcelable { - ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri); - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - } - public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { ctor public NotificationAssistantService(); - method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment); + method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment); method public final void clearAnnotation(java.lang.String); method public void onNotificationActionClick(java.lang.String, long, int); method public void onNotificationClick(java.lang.String, long); - method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); method public void onNotificationRemoved(java.lang.String, long, int); method public void onNotificationVisibilityChanged(java.lang.String, long, boolean); method public final void setAnnotation(java.lang.String, android.app.Notification); @@ -35666,6 +35659,10 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } + public class NotificationAssistantService.Adjustment { + ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri); + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); diff --git a/api/test-current.txt b/api/test-current.txt index 83d12fcf1ee33..d3acce7a9f851 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -33494,20 +33494,13 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } - public class NotificationAdjustment implements android.os.Parcelable { - ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri); - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - } - public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { ctor public NotificationAssistantService(); - method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment); + method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment); method public final void clearAnnotation(java.lang.String); method public void onNotificationActionClick(java.lang.String, long, int); method public void onNotificationClick(java.lang.String, long); - method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); method public void onNotificationRemoved(java.lang.String, long, int); method public void onNotificationVisibilityChanged(java.lang.String, long, boolean); method public final void setAnnotation(java.lang.String, android.app.Notification); @@ -33527,6 +33520,10 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } + public class NotificationAssistantService.Adjustment { + ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri); + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index abe9822e972f9..e60cb0377e962 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -78,6 +78,8 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); + void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation); + ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); boolean isSystemConditionProviderEnabled(String path); diff --git a/core/java/android/service/notification/INotificationAssistant.aidl b/core/java/android/service/notification/INotificationAssistant.aidl deleted file mode 100644 index 5c5f358b99b9e..0000000000000 --- a/core/java/android/service/notification/INotificationAssistant.aidl +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.notification; - -import android.service.notification.NotificationAdjustment; -import android.service.notification.IStatusBarNotificationHolder; -import android.service.notification.NotificationRankingUpdate; - -/** @hide */ -interface INotificationAssistant -{ - void onListenerConnected(in NotificationRankingUpdate update); - void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder, - in NotificationRankingUpdate update); - void onNotificationRankingUpdate(in NotificationRankingUpdate update); - void onListenerHintsChanged(int hints); - void onInterruptionFilterChanged(int interruptionFilter); - NotificationAdjustment onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user); - void onNotificationVisibilityChanged(String key, long time, boolean visible); - void onNotificationClick(String key, long time); - void onNotificationActionClick(String key, long time, int actionIndex); - void onNotificationRemoved(String key, long time, int reason); -} \ No newline at end of file diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index e6bf6ba974921..a0de17f4b7cfa 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -23,6 +23,7 @@ import android.service.notification.NotificationRankingUpdate; /** @hide */ oneway interface INotificationListener { + // listeners and assistants void onListenerConnected(in NotificationRankingUpdate update); void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder, in NotificationRankingUpdate update); @@ -31,4 +32,11 @@ oneway interface INotificationListener void onNotificationRankingUpdate(in NotificationRankingUpdate update); void onListenerHintsChanged(int hints); void onInterruptionFilterChanged(int interruptionFilter); + + // assistants only + void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user); + void onNotificationVisibilityChanged(String key, long time, boolean visible); + void onNotificationClick(String key, long time); + void onNotificationActionClick(String key, long time, int actionIndex); + void onNotificationRemovedReason(String key, long time, int reason); } diff --git a/core/java/android/service/notification/NotificationAdjustment.java b/core/java/android/service/notification/NotificationAdjustment.java deleted file mode 100644 index c5f0db9bf5f1d..0000000000000 --- a/core/java/android/service/notification/NotificationAdjustment.java +++ /dev/null @@ -1,57 +0,0 @@ -package android.service.notification; - -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; - -public class NotificationAdjustment implements Parcelable { - int mImportance; - CharSequence mExplanation; - Uri mReference; - - /** - * Create a notification importance adjustment. - * - * @param importance The final importance of the notification. - * @param explanation A human-readable justification for the adjustment. - * @param reference A reference to an external object that augments the - * explanation, such as a - * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, - * or null. - */ - public NotificationAdjustment(int importance, CharSequence explanation, Uri reference) { - mImportance = importance; - mExplanation = explanation; - mReference = reference; - } - - private NotificationAdjustment(Parcel source) { - this(source.readInt(), source.readCharSequence(), - (Uri) source.readParcelable(NotificationAdjustment.class.getClassLoader())); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mImportance); - dest.writeCharSequence(mExplanation); - dest.writeParcelable(mReference, 0); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public NotificationAdjustment createFromParcel(Parcel source) { - return new NotificationAdjustment(source); - } - - @Override - public NotificationAdjustment[] newArray(int size) { - return new NotificationAdjustment[size]; - } - }; -} diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 7ce5e1f9da9cf..3a8956ec15d9f 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -20,8 +20,11 @@ import android.annotation.SdkConstant; import android.app.Notification; import android.content.Intent; import android.net.Uri; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Log; /** * A service that helps the user manage notifications by modifying the @@ -39,6 +42,8 @@ import android.os.Parcelable; * </service> */ public abstract class NotificationAssistantService extends NotificationListenerService { + private static final String TAG = "NotificationAssistant"; + /** * The {@link Intent} that must be declared as handled by the service. */ @@ -85,6 +90,36 @@ public abstract class NotificationAssistantService extends NotificationListenerS /** Notification was canceled because it was an invisible member of a group. */ public static final int REASON_GROUP_OPTIMIZATION = 13; + public class Adjustment { + int mImportance; + CharSequence mExplanation; + Uri mReference; + + /** + * Create a notification importance adjustment. + * + * @param importance The final importance of the notification. + * @param explanation A human-readable justification for the adjustment. + * @param reference A reference to an external object that augments the + * explanation, such as a + * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, + * or null. + */ + public Adjustment(int importance, CharSequence explanation, Uri reference) { + mImportance = importance; + mExplanation = explanation; + mReference = reference; + } + } + + @Override + public IBinder onBind(Intent intent) { + if (mWrapper == null) { + mWrapper = new NotificationAssistantWrapper(); + } + return mWrapper; + } + /** * A notification was posted by an app. Called before alert. * @@ -93,7 +128,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param user true if the initial importance reflects an explicit user preference. * @return an adjustment or null to take no action, within 100ms. */ - abstract public NotificationAdjustment onNotificationEnqueued(StatusBarNotification sbn, + abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance, boolean user); /** @@ -150,9 +185,15 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param key the notification key * @param adjustment the new importance with an explanation */ - public final void adjustImportance(String key, NotificationAdjustment adjustment) + public final void adjustImportance(String key, Adjustment adjustment) { - // TODO: pack up the adjustment and send it to the NotificationManager. + if (!isBound()) return; + try { + getNotificationInterface().setImportanceFromAssistant(mWrapper, key, + adjustment.mImportance, adjustment.mExplanation); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + } } /** @@ -160,7 +201,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS * be fired when the host notification is deleted, or when this annotation * is removed or replaced. * - * @param key the notification key + * @param key the key of the notification to be annotated * @param annotation the new annotation object */ public final void setAnnotation(String key, Notification annotation) @@ -171,10 +212,74 @@ public abstract class NotificationAssistantService extends NotificationListenerS /** * Remove the annotation from a notification. * - * @param key the notification key + * @param key the key of the notification to be cleansed of annotatons */ public final void clearAnnotation(String key) { // TODO: ask the NotificationManager to clear the annotation. } + + private class NotificationAssistantWrapper extends NotificationListenerWrapper { + @Override + public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder, + int importance, boolean user) throws RemoteException { + StatusBarNotification sbn; + try { + sbn = sbnHolder.get(); + } catch (RemoteException e) { + Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e); + return; + } + + try { + Adjustment adjustment = + NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user); + if (adjustment != null) { + adjustImportance(sbn.getKey(), adjustment); + } + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationEnqueued", t); + } + } + + @Override + public void onNotificationVisibilityChanged(String key, long time, boolean visible) + throws RemoteException { + try { + NotificationAssistantService.this.onNotificationVisibilityChanged(key, time, + visible); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationVisibilityChanged", t); + } + } + + @Override + public void onNotificationClick(String key, long time) throws RemoteException { + try { + NotificationAssistantService.this.onNotificationClick(key, time); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationClick", t); + } + } + + @Override + public void onNotificationActionClick(String key, long time, int actionIndex) + throws RemoteException { + try { + NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationActionClick", t); + } + } + + @Override + public void onNotificationRemovedReason(String key, long time, int reason) + throws RemoteException { + try { + NotificationAssistantService.this.onNotificationRemoved(key, time, reason); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationRemoved", t); + } + } + } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 1e62edc6634fd..6c99489d77090 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -15,6 +15,7 @@ */ package android.service.notification; +import android.service.notification.IStatusBarNotificationHolder; import android.annotation.SystemApi; import android.annotation.SdkConstant; @@ -151,7 +152,8 @@ public abstract class NotificationListenerService extends Service { @SystemApi public static final int TRIM_LIGHT = 1; - private INotificationListenerWrapper mWrapper = null; + /** @hide */ + protected NotificationListenerWrapper mWrapper = null; private RankingMap mRankingMap; private INotificationManager mNoMan; @@ -291,7 +293,8 @@ public abstract class NotificationListenerService extends Service { // optional } - private final INotificationManager getNotificationInterface() { + /** @hide */ + protected final INotificationManager getNotificationInterface() { if (mNoMan == null) { mNoMan = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); @@ -634,12 +637,13 @@ public abstract class NotificationListenerService extends Service { @Override public IBinder onBind(Intent intent) { if (mWrapper == null) { - mWrapper = new INotificationListenerWrapper(); + mWrapper = new NotificationListenerWrapper(); } return mWrapper; } - private boolean isBound() { + /** @hide */ + protected boolean isBound() { if (mWrapper == null) { Log.w(TAG, "Notification listener service not yet bound."); return false; @@ -664,7 +668,7 @@ public abstract class NotificationListenerService extends Service { int currentUser) throws RemoteException { mSystemContext = context; if (mWrapper == null) { - mWrapper = new INotificationListenerWrapper(); + mWrapper = new NotificationListenerWrapper(); } INotificationManager noMan = getNotificationInterface(); noMan.registerListener(mWrapper, componentName, currentUser); @@ -716,7 +720,8 @@ public abstract class NotificationListenerService extends Service { } } - private class INotificationListenerWrapper extends INotificationListener.Stub { + /** @hide */ + protected class NotificationListenerWrapper extends INotificationListener.Stub { @Override public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder, NotificationRankingUpdate update) { @@ -817,6 +822,35 @@ public abstract class NotificationListenerService extends Service { Log.w(TAG, "Error running onInterruptionFilterChanged", t); } } + + @Override + public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder, + int importance, boolean user) throws RemoteException { + // no-op in the listener + } + + @Override + public void onNotificationVisibilityChanged(String key, long time, boolean visible) + throws RemoteException { + // no-op in the listener + } + + @Override + public void onNotificationClick(String key, long time) throws RemoteException { + // no-op in the listener + } + + @Override + public void onNotificationActionClick(String key, long time, int actionIndex) + throws RemoteException { + // no-op in the listener + } + + @Override + public void onNotificationRemovedReason(String key, long time, int reason) + throws RemoteException { + // no-op in the listener + } } private void applyUpdate(NotificationRankingUpdate update) { diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 19872144bfe3c..ce18818c1fba4 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -120,6 +120,11 @@ public class ConditionProviders extends ManagedServices { return IConditionProvider.Stub.asInterface(binder); } + @Override + protected boolean checkType(IInterface service) { + return service instanceof IConditionProvider; + } + @Override public void onBootPhaseAppsCanStart() { super.onBootPhaseAppsCanStart(); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index b7662daffec4e..09e66475c1be0 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -141,6 +141,8 @@ abstract public class ManagedServices { abstract protected IInterface asInterface(IBinder binder); + abstract protected boolean checkType(IInterface service); + abstract protected void onServiceAdded(ManagedServiceInfo info); protected void onServiceRemovedLocked(ManagedServiceInfo removed) { } @@ -169,7 +171,8 @@ abstract public class ManagedServices { if (filter != null && !filter.matches(info.component)) continue; pw.println(" " + info.component + " (user " + info.userid + "): " + info.service - + (info.isSystem?" SYSTEM":"")); + + (info.isSystem?" SYSTEM":"") + + (info.isGuest(this)?" GUEST":"")); } } @@ -266,6 +269,18 @@ abstract public class ManagedServices { } } + /** + * Add a service to our callbacks. The lifecycle of this service is managed externally, + * but unlike a system service, it should not be considered privledged. + * */ + public void registerGuestService(ManagedServiceInfo guest) { + checkNotNull(guest.service); + checkType(guest.service); + if (registerServiceImpl(guest) != null) { + onServiceAdded(guest); + } + } + public void setCategoryState(String category, boolean enabled) { synchronized (mMutex) { final Boolean previous = mCategoryEnabled.put(category, enabled); @@ -484,7 +499,7 @@ abstract public class ManagedServices { synchronized (mMutex) { // Unbind automatically bound services, retain system services. for (ManagedServiceInfo service : mServices) { - if (!service.isSystem) { + if (!service.isSystem && !service.isGuest(this)) { toRemove.add(service); } } @@ -709,11 +724,15 @@ abstract public class ManagedServices { private ManagedServiceInfo registerServiceImpl(final IInterface service, final ComponentName component, final int userid) { + ManagedServiceInfo info = newServiceInfo(service, component, userid, + true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP); + return registerServiceImpl(info); + } + + private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) { synchronized (mMutex) { try { - ManagedServiceInfo info = newServiceInfo(service, component, userid, - true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP); - service.asBinder().linkToDeath(info, 0); + info.service.asBinder().linkToDeath(info, 0); mServices.add(info); return info; } catch (RemoteException e) { @@ -728,7 +747,7 @@ abstract public class ManagedServices { */ private void unregisterServiceImpl(IInterface service, int userid) { ManagedServiceInfo info = removeServiceImpl(service, userid); - if (info != null && info.connection != null) { + if (info != null && info.connection != null && !info.isGuest(this)) { mContext.unbindService(info.connection); } } @@ -780,6 +799,10 @@ abstract public class ManagedServices { this.targetSdkVersion = targetSdkVersion; } + public boolean isGuest(ManagedServices host) { + return ManagedServices.this != host; + } + @Override public String toString() { return new StringBuilder("ManagedServiceInfo[") diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 49aa73efc3b29..82c38af677ced 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -39,6 +39,7 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; +import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppGlobals; @@ -96,6 +97,7 @@ import android.service.notification.Condition; import android.service.notification.IConditionProvider; import android.service.notification.INotificationListener; import android.service.notification.IStatusBarNotificationHolder; +import android.service.notification.NotificationAssistantService; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationRankingUpdate; import android.service.notification.StatusBarNotification; @@ -154,6 +156,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** {@hide} */ public class NotificationManagerService extends SystemService { @@ -167,11 +170,13 @@ public class NotificationManagerService extends SystemService { // message codes static final int MESSAGE_TIMEOUT = 2; static final int MESSAGE_SAVE_POLICY_FILE = 3; - static final int MESSAGE_RECONSIDER_RANKING = 4; - static final int MESSAGE_RANKING_CONFIG_CHANGE = 5; - static final int MESSAGE_SEND_RANKING_UPDATE = 6; - static final int MESSAGE_LISTENER_HINTS_CHANGED = 7; - static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8; + static final int MESSAGE_SEND_RANKING_UPDATE = 4; + static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; + static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; + + // ranking thread messages + private static final int MESSAGE_RECONSIDER_RANKING = 1000; + private static final int MESSAGE_RANKING_SORT = 1001; static final int LONG_DELAY = 3500; // 3.5 seconds static final int SHORT_DELAY = 2000; // 2 seconds @@ -281,11 +286,13 @@ public class NotificationManagerService extends SystemService { private final UserProfiles mUserProfiles = new UserProfiles(); private NotificationListeners mListeners; + private NotificationAssistant mAssistant; private ConditionProviders mConditionProviders; private NotificationUsageStats mUsageStats; private static final int MY_UID = Process.myUid(); private static final int MY_PID = Process.myPid(); + private RankingHandler mRankingHandler; private static class Archive { final int mBufferSize; @@ -738,6 +745,7 @@ public class NotificationManagerService extends SystemService { } } mListeners.onPackagesChanged(queryReplace, pkgList); + mAssistant.onPackagesChanged(queryReplace, pkgList); mConditionProviders.onPackagesChanged(queryReplace, pkgList); mRankingHelper.onPackagesChanged(queryReplace, pkgList); } @@ -779,6 +787,7 @@ public class NotificationManagerService extends SystemService { // Refresh managed services mConditionProviders.onUserSwitched(user); mListeners.onUserSwitched(user); + mAssistant.onUserSwitched(user); mZenModeHelper.onUserSwitched(user); } else if (action.equals(Intent.ACTION_USER_ADDED)) { mUserProfiles.updateCache(context); @@ -874,8 +883,9 @@ public class NotificationManagerService extends SystemService { extractorNames = new String[0]; } mUsageStats = new NotificationUsageStats(getContext()); + mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); mRankingHelper = new RankingHelper(getContext(), - new RankingWorkerHandler(mRankingThread.getLooper()), + mRankingHandler, mUsageStats, extractorNames); mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles); @@ -909,6 +919,7 @@ public class NotificationManagerService extends SystemService { importOldBlockDb(); mListeners = new NotificationListeners(); + mAssistant = new NotificationAssistant(); mStatusBar = getLocalService(StatusBarManagerInternal.class); mStatusBar.setNotificationDelegate(mNotificationDelegate); @@ -1025,6 +1036,7 @@ public class NotificationManagerService extends SystemService { // bind to listener services. mSettingsObserver.observe(); mListeners.onBootPhaseAppsCanStart(); + mAssistant.onBootPhaseAppsCanStart(); mConditionProviders.onBootPhaseAppsCanStart(); } } @@ -1896,6 +1908,22 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } } + + @Override + public void setImportanceFromAssistant(INotificationListener token, String key, + int importance, CharSequence explanation) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mNotificationList) { + mAssistant.checkServiceTokenLocked(token); + NotificationRecord n = mNotificationsByKey.get(key); + n.setImportance(importance, explanation); + mRankingHandler.requestSort(); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } }; private String disableNotificationEffects(NotificationRecord record) { @@ -2037,6 +2065,8 @@ public class NotificationManagerService extends SystemService { pw.print(listener.component); } pw.println(')'); + pw.println("\n Notification assistant:"); + mAssistant.dump(pw, filter); } pw.println("\n Policy access:"); pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); @@ -2686,7 +2716,7 @@ public class NotificationManagerService extends SystemService { } } - private void handleRankingConfigChange() { + private void handleRankingSort() { synchronized (mNotificationList) { final int N = mNotificationList.size(); ArrayList orderBefore = new ArrayList(N); @@ -2788,9 +2818,9 @@ public class NotificationManagerService extends SystemService { } - private final class RankingWorkerHandler extends Handler + private final class RankingHandlerWorker extends Handler implements RankingHandler { - public RankingWorkerHandler(Looper looper) { + public RankingHandlerWorker(Looper looper) { super(looper); } @@ -2800,11 +2830,23 @@ public class NotificationManagerService extends SystemService { case MESSAGE_RECONSIDER_RANKING: handleRankingReconsideration(msg); break; - case MESSAGE_RANKING_CONFIG_CHANGE: - handleRankingConfigChange(); + case MESSAGE_RANKING_SORT: + handleRankingSort(); break; } } + + public void requestSort() { + removeMessages(MESSAGE_RANKING_SORT); + sendEmptyMessage(MESSAGE_RANKING_SORT); + } + + public void requestReconsideration(RankingReconsideration recon) { + Message m = Message.obtain(this, + NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); + long delay = recon.getDelay(TimeUnit.MILLISECONDS); + sendMessageDelayed(m, delay); + } } // Notifications @@ -3305,6 +3347,45 @@ public class NotificationManagerService extends SystemService { return true; } + public class NotificationAssistant extends ManagedServices { + + public NotificationAssistant() { + super(getContext(), mHandler, mNotificationList, mUserProfiles); + } + + @Override + protected Config getConfig() { + Config c = new Config(); + c.caption = "notification assistant"; + c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; + c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; + c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; + c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; + c.clientLabel = R.string.notification_assistant_binding_label; + return c; + } + + @Override + protected IInterface asInterface(IBinder binder) { + return INotificationListener.Stub.asInterface(binder); + } + + @Override + protected boolean checkType(IInterface service) { + return service instanceof INotificationListener; + } + + @Override + protected void onServiceAdded(ManagedServiceInfo info) { + mListeners.registerGuestService(info); + } + + @Override + protected void onServiceRemovedLocked(ManagedServiceInfo removed) { + mListeners.unregisterService(removed.service, removed.userid); + } + } + public class NotificationListeners extends ManagedServices { private final ArraySet mLightTrimListeners = new ArraySet<>(); @@ -3331,6 +3412,11 @@ public class NotificationManagerService extends SystemService { return INotificationListener.Stub.asInterface(binder); } + @Override + protected boolean checkType(IInterface service) { + return service instanceof INotificationListener; + } + @Override public void onServiceAdded(ManagedServiceInfo info) { final INotificationListener listener = (INotificationListener) info.service; @@ -3366,7 +3452,6 @@ public class NotificationManagerService extends SystemService { public int getOnNotificationPostedTrim(ManagedServiceInfo info) { return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; - } /** diff --git a/core/java/android/service/notification/NotificationAdjustment.aidl b/services/core/java/com/android/server/notification/RankingHandler.java similarity index 77% rename from core/java/android/service/notification/NotificationAdjustment.aidl rename to services/core/java/com/android/server/notification/RankingHandler.java index 805fe2c67695b..80bb4f0896396 100644 --- a/core/java/android/service/notification/NotificationAdjustment.aidl +++ b/services/core/java/com/android/server/notification/RankingHandler.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.server.notification; -package android.service.notification; - -parcelable NotificationAdjustment; \ No newline at end of file +public interface RankingHandler { + public void requestSort(); + public void requestReconsideration(RankingReconsideration recon); +} diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 3287f67a6b863..0662e7a68ceaf 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -19,10 +19,7 @@ import android.app.Notification; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Handler; -import android.os.Message; import android.os.UserHandle; -import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.text.TextUtils; import android.util.ArrayMap; @@ -40,7 +37,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; public class RankingHelper implements RankingConfig { private static final String TAG = "RankingHelper"; @@ -73,10 +69,10 @@ public class RankingHelper implements RankingConfig { private final ArrayMap mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record private final Context mContext; - private final Handler mRankingHandler; + private final RankingHandler mRankingHandler; - public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats, - String[] extractorNames) { + public RankingHelper(Context context, RankingHandler rankingHandler, + NotificationUsageStats usageStats, String[] extractorNames) { mContext = context; mRankingHandler = rankingHandler; @@ -119,10 +115,7 @@ public class RankingHelper implements RankingConfig { try { RankingReconsideration recon = extractor.process(r); if (recon != null) { - Message m = Message.obtain(mRankingHandler, - NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); - long delay = recon.getDelay(TimeUnit.MILLISECONDS); - mRankingHandler.sendMessageDelayed(m, delay); + mRankingHandler.requestReconsideration(recon); } } catch (Throwable t) { Slog.w(TAG, "NotificationSignalExtractor failed.", t); @@ -287,7 +280,7 @@ public class RankingHelper implements RankingConfig { for (int i = 0; i < N; i++) { mSignalExtractors[i].setConfig(this); } - mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE); + mRankingHandler.requestSort(); } public void sort(ArrayList notificationList) { diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java index df7b412a27fee..264088903777c 100644 --- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java @@ -35,7 +35,7 @@ import java.util.ArrayList; public class RankingHelperTest extends AndroidTestCase { @Mock NotificationUsageStats mUsageStats; - @Mock Handler handler; + @Mock RankingHandler handler; private Notification mNotiGroupGSortA; private Notification mNotiGroupGSortB;