summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Julia Reynolds <juliacr@google.com> 2021-02-24 14:45:16 -0500
committer Julia Reynolds <juliacr@google.com> 2021-02-26 10:10:05 -0500
commit7c9fbcc6787df792275dd871a7f0781e2befce8f (patch)
tree01078cc7647562bef6e7ef7f8c32a7c0ce2e2861
parent2409543ce829d9cb1e899ac5e0f138976d7e8451 (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
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java17
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java61
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java48
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">
* &lt;/meta-data>
+ * &lt;meta-data
+ * android:name="android.service.notification.disabled_filter_types"
+ * android:value="2">
+ * &lt;/meta-data>
* &lt;/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";