Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -38076,6 +38076,7 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 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 int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2 core/java/android/service/notification/NotificationListenerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,10 @@ import java.util.Objects; * android:name="android.service.notification.default_filter_types" * android:value="1,2"> * </meta-data> * <meta-data * android:name="android.service.notification.disabled_filter_types" * android:value="2"> * </meta-data> * </service></pre> * * <p>The service should wait for the {@link #onListenerConnected()} event Loading Loading @@ -122,6 +126,19 @@ public abstract class NotificationListenerService extends Service { public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; /** * The name of the {@code meta-data} tag containing a comma separated list of default * integer notification types that this listener never wants to receive. See * {@link #FLAG_FILTER_TYPE_ONGOING}, * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING), * and {@link #FLAG_FILTER_TYPE_SILENT}. * <p>Types provided in this list will appear as 'off' and 'disabled' in the user interface, * so users don't enable a type that the listener will never bridge to their paired devices.</p> * */ public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. Loading services/core/java/com/android/server/notification/NotificationManagerService.java +42 −19 Original line number Diff line number Diff line Loading @@ -75,6 +75,8 @@ import static android.service.notification.NotificationListenerService.FLAG_FILT import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES; import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; Loading Loading @@ -9866,13 +9868,39 @@ public class NotificationManagerService extends SystemService { Pair listener = Pair.create(si.getComponentName(), userId); NotificationListenerFilter existingNlf = mRequestedNotificationListeners.get(listener); if (si.metaData != null) { if (existingNlf == null) { // no stored filters for this listener; see if they provided a default if (si.metaData != null) { String typeList = si.metaData.getString( NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES); if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { String typeList = si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); if (typeList != null) { int types = getTypesFromStringList(typeList); NotificationListenerFilter nlf = new NotificationListenerFilter(types, new ArraySet<>()); mRequestedNotificationListeners.put(listener, nlf); } } } // also check the types they never want bridged if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { int neverBridge = getTypesFromStringList(si.metaData.get( META_DATA_DISABLED_FILTER_TYPES).toString()); if (neverBridge != 0) { NotificationListenerFilter nlf = mRequestedNotificationListeners.getOrDefault( listener, new NotificationListenerFilter()); nlf.setTypes(nlf.getTypes() & ~neverBridge); mRequestedNotificationListeners.put(listener, nlf); } } } } private int getTypesFromStringList(String typeList) { int types = 0; if (typeList != null) { String[] typeStrings = typeList.split(XML_SEPARATOR); for (int i = 0; i < typeStrings.length; i++) { if (TextUtils.isEmpty(typeStrings[i])) { Loading @@ -9884,13 +9912,8 @@ public class NotificationManagerService extends SystemService { // skip } } NotificationListenerFilter nlf = new NotificationListenerFilter(types, new ArraySet<>()); mRequestedNotificationListeners.put(listener, nlf); } } } return types; } @GuardedBy("mNotificationLock") Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.notification; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS; Loading Loading @@ -204,6 +206,52 @@ public class NotificationListenersTest extends UiServiceTestCase { .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithMetadata_disabledTypes() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1,2"); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING); } @Test public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2"); si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithEmptyMetadata() { ServiceInfo si = new ServiceInfo(); Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -38076,6 +38076,7 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 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 int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3 field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
core/java/android/service/notification/NotificationListenerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,10 @@ import java.util.Objects; * android:name="android.service.notification.default_filter_types" * android:value="1,2"> * </meta-data> * <meta-data * android:name="android.service.notification.disabled_filter_types" * android:value="2"> * </meta-data> * </service></pre> * * <p>The service should wait for the {@link #onListenerConnected()} event Loading Loading @@ -122,6 +126,19 @@ public abstract class NotificationListenerService extends Service { public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types"; /** * The name of the {@code meta-data} tag containing a comma separated list of default * integer notification types that this listener never wants to receive. See * {@link #FLAG_FILTER_TYPE_ONGOING}, * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING), * and {@link #FLAG_FILTER_TYPE_SILENT}. * <p>Types provided in this list will appear as 'off' and 'disabled' in the user interface, * so users don't enable a type that the listener will never bridge to their paired devices.</p> * */ public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types"; /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +42 −19 Original line number Diff line number Diff line Loading @@ -75,6 +75,8 @@ import static android.service.notification.NotificationListenerService.FLAG_FILT import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES; import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; Loading Loading @@ -9866,13 +9868,39 @@ public class NotificationManagerService extends SystemService { Pair listener = Pair.create(si.getComponentName(), userId); NotificationListenerFilter existingNlf = mRequestedNotificationListeners.get(listener); if (si.metaData != null) { if (existingNlf == null) { // no stored filters for this listener; see if they provided a default if (si.metaData != null) { String typeList = si.metaData.getString( NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES); if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { String typeList = si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); if (typeList != null) { int types = getTypesFromStringList(typeList); NotificationListenerFilter nlf = new NotificationListenerFilter(types, new ArraySet<>()); mRequestedNotificationListeners.put(listener, nlf); } } } // also check the types they never want bridged if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { int neverBridge = getTypesFromStringList(si.metaData.get( META_DATA_DISABLED_FILTER_TYPES).toString()); if (neverBridge != 0) { NotificationListenerFilter nlf = mRequestedNotificationListeners.getOrDefault( listener, new NotificationListenerFilter()); nlf.setTypes(nlf.getTypes() & ~neverBridge); mRequestedNotificationListeners.put(listener, nlf); } } } } private int getTypesFromStringList(String typeList) { int types = 0; if (typeList != null) { String[] typeStrings = typeList.split(XML_SEPARATOR); for (int i = 0; i < typeStrings.length; i++) { if (TextUtils.isEmpty(typeStrings[i])) { Loading @@ -9884,13 +9912,8 @@ public class NotificationManagerService extends SystemService { // skip } } NotificationListenerFilter nlf = new NotificationListenerFilter(types, new ArraySet<>()); mRequestedNotificationListeners.put(listener, nlf); } } } return types; } @GuardedBy("mNotificationLock") Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.notification; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS; Loading Loading @@ -204,6 +206,52 @@ public class NotificationListenersTest extends UiServiceTestCase { .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithMetadata_disabledTypes() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1,2"); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING); } @Test public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() { ServiceInfo si = new ServiceInfo(); si.packageName = "new"; si.name = "comp"; si.metaData = new Bundle(); si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2"); si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1); mListeners.ensureFilters(si, 0); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) .isEqualTo(FLAG_FILTER_TYPE_ALERTING); } @Test public void testEnsureFilters_newServiceWithEmptyMetadata() { ServiceInfo si = new ServiceInfo(); Loading