Loading core/api/current.txt +2 −0 Original line number Original line Diff line number Diff line Loading @@ -40779,6 +40779,7 @@ package android.service.notification { method public final void requestInterruptionFilter(int); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public final void requestListenerHints(int); method public static void requestRebind(android.content.ComponentName); method public static void requestRebind(android.content.ComponentName); method public static void requestUnbind(@NonNull android.content.ComponentName); method public final void requestUnbind(); method public final void requestUnbind(); method public final void setNotificationsShown(String[]); method public final void setNotificationsShown(String[]); method public final void snoozeNotification(String, long); method public final void snoozeNotification(String, long); Loading @@ -40796,6 +40797,7 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final String META_DATA_DEFAULT_AUTOBIND = "android.service.notification.default_autobind_listenerservice"; field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1 core/java/android/app/INotificationManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -147,6 +147,7 @@ interface INotificationManager void requestBindListener(in ComponentName component); void requestBindListener(in ComponentName component); void requestUnbindListener(in INotificationListener token); void requestUnbindListener(in INotificationListener token); void requestUnbindListenerComponent(in ComponentName component); void requestBindProvider(in ComponentName component); void requestBindProvider(in ComponentName component); void requestUnbindProvider(in IConditionProvider token); void requestUnbindProvider(in IConditionProvider token); Loading core/java/android/service/notification/NotificationListenerService.java +25 −0 Original line number Original line Diff line number Diff line Loading @@ -140,6 +140,16 @@ public abstract class NotificationListenerService extends Service { public static final String META_DATA_DISABLED_FILTER_TYPES public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; = "android.service.notification.disabled_filter_types"; /** * The name of the {@code meta-data} tag containing a boolean value that is used to decide if * this listener should be automatically bound by default. * If the value is 'false', the listener can be bound on demand using {@link #requestRebind} * <p>An absent value means that the default is 'true'</p> * */ public static final String META_DATA_DEFAULT_AUTOBIND = "android.service.notification.default_autobind_listenerservice"; /** /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. * Normal interruption filter. Loading Loading @@ -1323,6 +1333,21 @@ public abstract class NotificationListenerService extends Service { } } } } /** * Request that the service be unbound. * * <p>This method will fail for components that are not part of the calling app. */ public static void requestUnbind(@NonNull ComponentName componentName) { INotificationManager noMan = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); try { noMan.requestUnbindListenerComponent(componentName); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } /** /** * Request that the service be unbound. * Request that the service be unbound. * * Loading services/core/java/com/android/server/notification/ManagedServices.java +62 −27 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_SYSTEM; import static android.os.UserHandle.USER_SYSTEM; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND; import android.annotation.NonNull; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager; Loading Loading @@ -60,6 +61,7 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseSetArray; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -390,14 +392,18 @@ abstract public class ManagedServices { } } } } final SparseSetArray<ComponentName> snoozingComponents; synchronized (mSnoozing) { synchronized (mSnoozing) { pw.println(" Snoozed " + getCaption() + "s (" snoozingComponents = new SparseSetArray<>(mSnoozing); + mSnoozing.size() + "):"); for (int i = 0; i < mSnoozing.size(); i++) { pw.println(" User: " + mSnoozing.keyAt(i)); for (ComponentName name : mSnoozing.valuesAt(i)) { pw.println(" " + name.flattenToShortString()); } } pw.println(" Snoozed " + getCaption() + "s (" + snoozingComponents.size() + "):"); for (int i = 0; i < snoozingComponents.size(); i++) { pw.println(" User: " + snoozingComponents.keyAt(i)); for (ComponentName name : snoozingComponents.valuesAt(i)) { final ServiceInfo info = getServiceInfo(name, snoozingComponents.keyAt(i)); pw.println(" " + name.flattenToShortString() + (isAutobindAllowed(info) ? "" : " (META_DATA_DEFAULT_AUTOBIND=false)")); } } } } } } Loading Loading @@ -1432,12 +1438,7 @@ abstract public class ManagedServices { final int userId = componentsToBind.keyAt(i); final int userId = componentsToBind.keyAt(i); final Set<ComponentName> add = componentsToBind.get(userId); final Set<ComponentName> add = componentsToBind.get(userId); for (ComponentName component : add) { for (ComponentName component : add) { try { ServiceInfo info = getServiceInfo(component, userId); ServiceInfo info = mPm.getServiceInfo(component, PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); if (info == null) { if (info == null) { Slog.w(TAG, "Not binding " + getCaption() + " service " + component Slog.w(TAG, "Not binding " + getCaption() + " service " + component + ": service not found"); + ": service not found"); Loading @@ -1448,12 +1449,19 @@ abstract public class ManagedServices { + ": it does not require the permission " + mConfig.bindPermission); + ": it does not require the permission " + mConfig.bindPermission); continue; continue; } } // Do not (auto)bind if service has meta-data to explicitly disallow it if (!isAutobindAllowed(info) && !isBoundOrRebinding(component, userId)) { synchronized (mSnoozing) { Slog.d(TAG, "Not binding " + getCaption() + " service " + component + ": has META_DATA_DEFAULT_AUTOBIND = false"); mSnoozing.add(userId, component); } continue; } Slog.v(TAG, Slog.v(TAG, "enabling " + getCaption() + " for " + userId + ": " + component); "enabling " + getCaption() + " for " + userId + ": " + component); registerService(info, userId); registerService(info, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } } } } } Loading Loading @@ -1620,6 +1628,12 @@ abstract public class ManagedServices { return mServicesBound.contains(servicesBindingTag); return mServicesBound.contains(servicesBindingTag); } } protected boolean isBoundOrRebinding(final ComponentName cn, final int userId) { synchronized (mMutex) { return isBound(cn, userId) || mServicesRebinding.contains(Pair.create(cn, userId)); } } /** /** * Remove a service for the given user by ComponentName * Remove a service for the given user by ComponentName */ */ Loading Loading @@ -1718,6 +1732,27 @@ abstract public class ManagedServices { } } } } private ServiceInfo getServiceInfo(ComponentName component, int userId) { try { return mPm.getServiceInfo(component, PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return null; } private boolean isAutobindAllowed(ServiceInfo serviceInfo) { if (serviceInfo != null && serviceInfo.metaData != null && serviceInfo.metaData.containsKey( META_DATA_DEFAULT_AUTOBIND)) { return serviceInfo.metaData.getBoolean(META_DATA_DEFAULT_AUTOBIND, true); } return true; } public class ManagedServiceInfo implements IBinder.DeathRecipient { public class ManagedServiceInfo implements IBinder.DeathRecipient { public IInterface service; public IInterface service; public ComponentName component; public ComponentName component; Loading services/core/java/com/android/server/notification/NotificationManagerService.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -4546,6 +4546,27 @@ public class NotificationManagerService extends SystemService { } } } } @Override public void requestUnbindListenerComponent(ComponentName component) { checkCallerIsSameApp(component.getPackageName()); int uid = Binder.getCallingUid(); final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { ManagedServices manager = mAssistants.isComponentEnabledForCurrentProfiles(component) ? mAssistants : mListeners; if (manager.isPackageOrComponentAllowed(component.flattenToString(), UserHandle.getUserId(uid))) { manager.setComponentState(component, UserHandle.getUserId(uid), false); } } } finally { Binder.restoreCallingIdentity(identity); } } @Override @Override public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity(); Loading Loading
core/api/current.txt +2 −0 Original line number Original line Diff line number Diff line Loading @@ -40779,6 +40779,7 @@ package android.service.notification { method public final void requestInterruptionFilter(int); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public final void requestListenerHints(int); method public static void requestRebind(android.content.ComponentName); method public static void requestRebind(android.content.ComponentName); method public static void requestUnbind(@NonNull android.content.ComponentName); method public final void requestUnbind(); method public final void requestUnbind(); method public final void setNotificationsShown(String[]); method public final void setNotificationsShown(String[]); method public final void snoozeNotification(String, long); method public final void snoozeNotification(String, long); Loading @@ -40796,6 +40797,7 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final String META_DATA_DEFAULT_AUTOBIND = "android.service.notification.default_autobind_listenerservice"; field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
core/java/android/app/INotificationManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -147,6 +147,7 @@ interface INotificationManager void requestBindListener(in ComponentName component); void requestBindListener(in ComponentName component); void requestUnbindListener(in INotificationListener token); void requestUnbindListener(in INotificationListener token); void requestUnbindListenerComponent(in ComponentName component); void requestBindProvider(in ComponentName component); void requestBindProvider(in ComponentName component); void requestUnbindProvider(in IConditionProvider token); void requestUnbindProvider(in IConditionProvider token); Loading
core/java/android/service/notification/NotificationListenerService.java +25 −0 Original line number Original line Diff line number Diff line Loading @@ -140,6 +140,16 @@ public abstract class NotificationListenerService extends Service { public static final String META_DATA_DISABLED_FILTER_TYPES public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; = "android.service.notification.disabled_filter_types"; /** * The name of the {@code meta-data} tag containing a boolean value that is used to decide if * this listener should be automatically bound by default. * If the value is 'false', the listener can be bound on demand using {@link #requestRebind} * <p>An absent value means that the default is 'true'</p> * */ public static final String META_DATA_DEFAULT_AUTOBIND = "android.service.notification.default_autobind_listenerservice"; /** /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. * Normal interruption filter. Loading Loading @@ -1323,6 +1333,21 @@ public abstract class NotificationListenerService extends Service { } } } } /** * Request that the service be unbound. * * <p>This method will fail for components that are not part of the calling app. */ public static void requestUnbind(@NonNull ComponentName componentName) { INotificationManager noMan = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); try { noMan.requestUnbindListenerComponent(componentName); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } /** /** * Request that the service be unbound. * Request that the service be unbound. * * Loading
services/core/java/com/android/server/notification/ManagedServices.java +62 −27 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_SYSTEM; import static android.os.UserHandle.USER_SYSTEM; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND; import android.annotation.NonNull; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager; Loading Loading @@ -60,6 +61,7 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseSetArray; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -390,14 +392,18 @@ abstract public class ManagedServices { } } } } final SparseSetArray<ComponentName> snoozingComponents; synchronized (mSnoozing) { synchronized (mSnoozing) { pw.println(" Snoozed " + getCaption() + "s (" snoozingComponents = new SparseSetArray<>(mSnoozing); + mSnoozing.size() + "):"); for (int i = 0; i < mSnoozing.size(); i++) { pw.println(" User: " + mSnoozing.keyAt(i)); for (ComponentName name : mSnoozing.valuesAt(i)) { pw.println(" " + name.flattenToShortString()); } } pw.println(" Snoozed " + getCaption() + "s (" + snoozingComponents.size() + "):"); for (int i = 0; i < snoozingComponents.size(); i++) { pw.println(" User: " + snoozingComponents.keyAt(i)); for (ComponentName name : snoozingComponents.valuesAt(i)) { final ServiceInfo info = getServiceInfo(name, snoozingComponents.keyAt(i)); pw.println(" " + name.flattenToShortString() + (isAutobindAllowed(info) ? "" : " (META_DATA_DEFAULT_AUTOBIND=false)")); } } } } } } Loading Loading @@ -1432,12 +1438,7 @@ abstract public class ManagedServices { final int userId = componentsToBind.keyAt(i); final int userId = componentsToBind.keyAt(i); final Set<ComponentName> add = componentsToBind.get(userId); final Set<ComponentName> add = componentsToBind.get(userId); for (ComponentName component : add) { for (ComponentName component : add) { try { ServiceInfo info = getServiceInfo(component, userId); ServiceInfo info = mPm.getServiceInfo(component, PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); if (info == null) { if (info == null) { Slog.w(TAG, "Not binding " + getCaption() + " service " + component Slog.w(TAG, "Not binding " + getCaption() + " service " + component + ": service not found"); + ": service not found"); Loading @@ -1448,12 +1449,19 @@ abstract public class ManagedServices { + ": it does not require the permission " + mConfig.bindPermission); + ": it does not require the permission " + mConfig.bindPermission); continue; continue; } } // Do not (auto)bind if service has meta-data to explicitly disallow it if (!isAutobindAllowed(info) && !isBoundOrRebinding(component, userId)) { synchronized (mSnoozing) { Slog.d(TAG, "Not binding " + getCaption() + " service " + component + ": has META_DATA_DEFAULT_AUTOBIND = false"); mSnoozing.add(userId, component); } continue; } Slog.v(TAG, Slog.v(TAG, "enabling " + getCaption() + " for " + userId + ": " + component); "enabling " + getCaption() + " for " + userId + ": " + component); registerService(info, userId); registerService(info, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } } } } } Loading Loading @@ -1620,6 +1628,12 @@ abstract public class ManagedServices { return mServicesBound.contains(servicesBindingTag); return mServicesBound.contains(servicesBindingTag); } } protected boolean isBoundOrRebinding(final ComponentName cn, final int userId) { synchronized (mMutex) { return isBound(cn, userId) || mServicesRebinding.contains(Pair.create(cn, userId)); } } /** /** * Remove a service for the given user by ComponentName * Remove a service for the given user by ComponentName */ */ Loading Loading @@ -1718,6 +1732,27 @@ abstract public class ManagedServices { } } } } private ServiceInfo getServiceInfo(ComponentName component, int userId) { try { return mPm.getServiceInfo(component, PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return null; } private boolean isAutobindAllowed(ServiceInfo serviceInfo) { if (serviceInfo != null && serviceInfo.metaData != null && serviceInfo.metaData.containsKey( META_DATA_DEFAULT_AUTOBIND)) { return serviceInfo.metaData.getBoolean(META_DATA_DEFAULT_AUTOBIND, true); } return true; } public class ManagedServiceInfo implements IBinder.DeathRecipient { public class ManagedServiceInfo implements IBinder.DeathRecipient { public IInterface service; public IInterface service; public ComponentName component; public ComponentName component; Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -4546,6 +4546,27 @@ public class NotificationManagerService extends SystemService { } } } } @Override public void requestUnbindListenerComponent(ComponentName component) { checkCallerIsSameApp(component.getPackageName()); int uid = Binder.getCallingUid(); final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { ManagedServices manager = mAssistants.isComponentEnabledForCurrentProfiles(component) ? mAssistants : mListeners; if (manager.isPackageOrComponentAllowed(component.flattenToString(), UserHandle.getUserId(uid))) { manager.setComponentState(component, UserHandle.getUserId(uid), false); } } } finally { Binder.restoreCallingIdentity(identity); } } @Override @Override public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity(); Loading