diff options
| author | 2016-01-08 15:50:13 +0000 | |
|---|---|---|
| committer | 2016-01-08 15:50:13 +0000 | |
| commit | 2d20a4dcc60a4d87ddf536d40cf00a59fa2d9479 (patch) | |
| tree | eb3886f1bd5826ac8f3920bc91263e8a318ca5a6 | |
| parent | c03c596a537df81bcb0ab4629e56c2ce1be4c0ed (diff) | |
| parent | ab41eecf22352f54167ce9a272a397715ffd0015 (diff) | |
Merge "allow listeners to disable themselves"
8 files changed, 138 insertions, 3 deletions
diff --git a/api/current.txt b/api/current.txt index 6bcf19fc28d8..f6b4d6105c00 100644 --- a/api/current.txt +++ b/api/current.txt @@ -33591,6 +33591,8 @@ package android.service.notification { method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 diff --git a/api/system-current.txt b/api/system-current.txt index 9a302c5260e9..bf4fc5004b16 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -35730,6 +35730,8 @@ package android.service.notification { method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException; method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); method public final void setOnNotificationPostedTrim(int); method public void unregisterAsSystemService() throws android.os.RemoteException; diff --git a/api/test-current.txt b/api/test-current.txt index 4777ba86ccff..8ff46c2ef267 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -33605,6 +33605,8 @@ package android.service.notification { method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index e60cb0377e96..633f6995b986 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -68,6 +68,9 @@ interface INotificationManager void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id); void cancelNotificationsFromListener(in INotificationListener token, in String[] keys); + void requestBindListener(in ComponentName component); + void requestUnbindListener(in INotificationListener token); + void setNotificationsShownFromListener(in INotificationListener token, in String[] keys); ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim); diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 3a8956ec15d9..aba82fad0bfa 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -17,13 +17,18 @@ package android.service.notification; import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.app.INotificationManager; import android.app.Notification; +import android.content.ComponentName; +import android.content.Context; 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.os.ServiceManager; import android.util.Log; /** diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 1fd5f95ae9bf..ed90e795af00 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -692,6 +692,36 @@ public abstract class NotificationListenerService extends Service { } } + /** + * Request that the listener be rebound, after a previous call to (@link requestUnbind). + * + * <P>This method will fail for assistants that have + * not been granted the permission by the user. + * + * <P>The service should wait for the {@link #onListenerConnected()} event + * before performing any operations. + */ + public static final void requestRebind(ComponentName componentName) + throws RemoteException { + INotificationManager noMan = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + noMan.requestBindListener(componentName); + } + + /** + * Request that the service be unbound. + * + * <P>This will no longer receive updates until + * {@link #requestRebind(ComponentName)} is called. + * The service will likely be kiled by the system after this call. + */ + public final void requestUnbind() throws RemoteException { + if (mWrapper != null) { + INotificationManager noMan = getNotificationInterface(); + noMan.requestUnbindListener(mWrapper); + } + } + /** Convert new-style Icons to legacy representations for pre-M clients. */ private void createLegacyIconExtras(Notification n) { Icon smallIcon = n.getSmallIcon(); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 09e66475c1be..f360dc2c4283 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -86,7 +86,7 @@ abstract public class ManagedServices { protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>(); // things that will be put into mServices as soon as they're ready private final ArrayList<String> mServicesBinding = new ArrayList<String>(); - // lists the component names of all enabled (and therefore connected) + // lists the component names of all enabled (and therefore potentially connected) // app services for current profiles. private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles = new ArraySet<ComponentName>(); @@ -97,6 +97,8 @@ abstract public class ManagedServices { private ArraySet<String> mRestoredPackages = new ArraySet<>(); // State of current service categories private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>(); + // List of enabled packages that have nevertheless asked not to be run + private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>(); // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a @@ -174,6 +176,12 @@ abstract public class ManagedServices { + (info.isSystem?" SYSTEM":"") + (info.isGuest(this)?" GUEST":"")); } + + pw.println(" Snoozed " + getCaption() + "s (" + + mSnoozingForCurrentProfiles.size() + "):"); + for (ComponentName name : mSnoozingForCurrentProfiles) { + pw.println(" " + name.flattenToShortString()); + } } // By convention, restored settings are replicated to another settings @@ -242,14 +250,25 @@ abstract public class ManagedServices { rebindServices(); } - public ManagedServiceInfo checkServiceTokenLocked(IInterface service) { - checkNotNull(service); + public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) { + if (service == null) { + return null; + } final IBinder token = service.asBinder(); final int N = mServices.size(); for (int i = 0; i < N; i++) { final ManagedServiceInfo info = mServices.get(i); if (info.service.asBinder() == token) return info; } + return null; + } + + public ManagedServiceInfo checkServiceTokenLocked(IInterface service) { + checkNotNull(service); + ManagedServiceInfo info = getServiceFromTokenLocked(service); + if (info != null) { + return info; + } throw new SecurityException("Disallowed call from unknown " + getCaption() + ": " + service); } @@ -278,6 +297,35 @@ abstract public class ManagedServices { checkType(guest.service); if (registerServiceImpl(guest) != null) { onServiceAdded(guest); + onServiceAdded(guest); + } + } + + public void setComponentState(ComponentName component, boolean enabled) { + boolean previous = !mSnoozingForCurrentProfiles.contains(component); + if (previous == enabled) { + return; + } + + if (enabled) { + mSnoozingForCurrentProfiles.remove(component); + } else { + mSnoozingForCurrentProfiles.add(component); + } + + // State changed + if (DEBUG) { + Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " + + component.flattenToShortString()); + } + + final int[] userIds = mUserProfiles.getCurrentProfileIds(); + for (int userId : userIds) { + if (enabled) { + registerServiceLocked(component, userId); + } else { + unregisterServiceLocked(component, userId); + } } } @@ -324,6 +372,7 @@ abstract public class ManagedServices { private void rebuildRestoredPackages() { mRestoredPackages.clear(); + mSnoozingForCurrentProfiles.clear(); String settingName = restoredSettingName(mConfig); int[] userIds = mUserProfiles.getCurrentProfileIds(); final int N = userIds.length; @@ -525,6 +574,7 @@ abstract public class ManagedServices { add.removeAll(c); } } + add.removeAll(mSnoozingForCurrentProfiles); toAdd.put(userIds[i], add); @@ -803,6 +853,10 @@ abstract public class ManagedServices { return ManagedServices.this != host; } + public ManagedServices getOwner() { + return ManagedServices.this; + } + @Override public String toString() { return new StringBuilder("ManagedServiceInfo[") @@ -846,6 +900,11 @@ abstract public class ManagedServices { } } + /** convenience method for looking in mEnabledServicesForCurrentProfiles */ + public boolean isComponentEnabledForCurrentProfiles(ComponentName component) { + return mEnabledServicesForCurrentProfiles.contains(component); + } + public static class UserProfiles { // Profiles of the current user. private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6b0399bd31a1..e787eda171ea 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1446,6 +1446,37 @@ public class NotificationManagerService extends SystemService { } } + /** + * Handle request from an approved listener to re-enable itself. + * + * @param component The componenet to be re-enabled, caller must match package. + */ + @Override + public void requestBindListener(ComponentName component) { + checkCallerIsSystemOrSameApp(component.getPackageName()); + long identity = Binder.clearCallingIdentity(); + try { + ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component) + ? mAssistant + : mListeners; + manager.setComponentState(component, true); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void requestUnbindListener(INotificationListener token) { + long identity = Binder.clearCallingIdentity(); + try { + // allow bound services to disable themselves + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + info.getOwner().setComponentState(info.component, false); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { long identity = Binder.clearCallingIdentity(); @@ -3426,6 +3457,7 @@ public class NotificationManagerService extends SystemService { } } + @Override protected void onServiceRemovedLocked(ManagedServiceInfo removed) { if (mListenersDisablingEffects.remove(removed)) { |