diff options
| author | 2021-02-24 14:45:16 -0500 | |
|---|---|---|
| committer | 2021-02-26 10:10:05 -0500 | |
| commit | 7c9fbcc6787df792275dd871a7f0781e2befce8f (patch) | |
| tree | 01078cc7647562bef6e7ef7f8c32a7c0ce2e2861 | |
| parent | 2409543ce829d9cb1e899ac5e0f138976d7e8451 (diff) | |
Adds an NLS api for telling the OS what notifs types they bridge
If an app doesn't bridge a particular type of notification
we will disabled in Settings so users understand why they aren't
seeing those types of notifications on paired devices.
Test: CTS, Settings unit
Bug: 181125165
Change-Id: I6e702898c3e682f732e91c4a4e02b96ff16b7077
4 files changed, 108 insertions, 19 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 160ad7a4d555..e8d13f9ced61 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -38534,6 +38534,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 diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 73e66d0212fa..7aa5bbc930fb 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -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 @@ -123,6 +127,19 @@ public abstract class NotificationListenerService extends Service { = "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. */ diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 8b4c6392fec0..4463da8c2f4a 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -73,6 +73,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; @@ -9859,33 +9861,54 @@ public class NotificationManagerService extends SystemService { Pair listener = Pair.create(si.getComponentName(), userId); NotificationListenerFilter existingNlf = mRequestedNotificationListeners.get(listener); - 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 (typeList != null) { - int types = 0; - String[] typeStrings = typeList.split(XML_SEPARATOR); - for (int i = 0; i < typeStrings.length; i++) { - if (TextUtils.isEmpty(typeStrings[i])) { - continue; - } - try { - types |= Integer.parseInt(typeStrings[i]); - } catch (NumberFormatException e) { - // skip - } + if (si.metaData != null) { + if (existingNlf == null) { + // no stored filters for this listener; see if they provided a default + 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); } + } + } - NotificationListenerFilter nlf = - new NotificationListenerFilter(types, new ArraySet<>()); + // 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])) { + continue; + } + try { + types |= Integer.parseInt(typeStrings[i]); + } catch (NumberFormatException e) { + // skip + } + } + } + return types; + } + @GuardedBy("mNotificationLock") public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { if (trim == TRIM_LIGHT) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index 80a046a1e8bb..9ac755f78a06 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -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; @@ -205,6 +207,52 @@ public class NotificationListenersTest extends UiServiceTestCase { } @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(); si.packageName = "new"; |