summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Julia Reynolds <juliacr@google.com> 2021-02-10 13:06:43 -0500
committer Julia Reynolds <juliacr@google.com> 2021-02-12 12:55:02 -0500
commitb6c718c9b8ebfa19d9ee90973111e21353f94e5c (patch)
treeeddc39fbd0631936e8a7faeb7eb6c91ba8a8673d
parent98039ded901181b14c3b79edc79d1b9a71bbfbbb (diff)
Allow NLSes to supply a default notif type filter
Test: atest, cts verifier Bug: 173052211 Change-Id: I06a110679c1c9c1de8d0e3f45a2b69c040e538f6
-rw-r--r--core/api/current.txt5
-rw-r--r--core/java/android/service/notification/NotificationListenerFilter.java1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java23
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java6
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java20
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java63
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java5
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java87
8 files changed, 141 insertions, 69 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 1296dd19cc7e..dd57b6a9fd02 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -38076,6 +38076,10 @@ package android.service.notification {
method public final void setNotificationsShown(String[]);
method public final void snoozeNotification(String, long);
method public final void updateNotificationChannel(@NonNull String, @NonNull android.os.UserHandle, @NonNull android.app.NotificationChannel);
+ field public static final int FLAG_FILTER_TYPE_ALERTING = 2; // 0x2
+ field public static final int FLAG_FILTER_TYPE_CONVERSATIONS = 1; // 0x1
+ field public static final int FLAG_FILTER_TYPE_ONGOING = 8; // 0x8
+ field public static final int FLAG_FILTER_TYPE_SILENT = 4; // 0x4
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -38084,6 +38088,7 @@ package android.service.notification {
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_UNKNOWN = 0; // 0x0
+ field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_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/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java
index 053fb2b1b4eb..9de75cac159a 100644
--- a/core/java/android/service/notification/NotificationListenerFilter.java
+++ b/core/java/android/service/notification/NotificationListenerFilter.java
@@ -32,6 +32,7 @@ import android.util.ArraySet;
*/
public class NotificationListenerFilter implements Parcelable {
private int mAllowedNotificationTypes;
+ // VersionedPackage is holding the pkg name and pkg uid
private ArraySet<VersionedPackage> mDisallowedPackages;
public NotificationListenerFilter() {
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 64cddc35d2bb..f66f85b9e8cc 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -80,6 +80,10 @@ import java.util.Objects;
* &lt;intent-filter>
* &lt;action android:name="android.service.notification.NotificationListenerService" />
* &lt;/intent-filter>
+ * &lt;meta-data
+ * android:name="android.service.notification.default_filter_types"
+ * android:value="1,2">
+ * &lt;/meta-data>
* &lt;/service></pre>
*
* <p>The service should wait for the {@link #onListenerConnected()} event
@@ -103,6 +107,21 @@ public abstract class NotificationListenerService extends Service {
private final String TAG = getClass().getSimpleName();
/**
+ * The name of the {@code meta-data} tag containing a comma separated list of default
+ * integer notification types that should be provided to this listener. See
+ * {@link #FLAG_FILTER_TYPE_ONGOING},
+ * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING),
+ * and {@link #FLAG_FILTER_TYPE_SILENT}.
+ * <p>This value will only be read if the app has not previously specified a default type list,
+ * and if the user has not overridden the allowed types.</p>
+ * <p>An absent value means 'allow all types'.
+ * A present but empty value means 'allow no types'.</p>
+ *
+ */
+ public static final String META_DATA_DEFAULT_FILTER_TYPES
+ = "android.service.notification.default_filter_types";
+
+ /**
* {@link #getCurrentInterruptionFilter() Interruption filter} constant -
* Normal interruption filter.
*/
@@ -254,23 +273,19 @@ public abstract class NotificationListenerService extends Service {
/**
* A flag value indicating that this notification listener can see conversation type
* notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_CONVERSATIONS = 1;
/**
* A flag value indicating that this notification listener can see altering type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_ALERTING = 2;
/**
* A flag value indicating that this notification listener can see silent type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_SILENT = 4;
/**
* A flag value indicating that this notification listener can see important
* ( > {@link NotificationManager#IMPORTANCE_MIN}) ongoing type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_ONGOING = 8;
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 769b781b1ae9..78c1a95a891d 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -21,6 +21,7 @@ import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.IBinder;
import android.os.IInterface;
@@ -197,6 +198,11 @@ public class ConditionProviders extends ManagedServices {
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ // nothing to filter
+ }
+
+ @Override
protected void loadDefaultsFromConfig() {
String defaultDndAccess = mContext.getResources().getString(
R.string.config_defaultDndAccessPackages);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 21537e6aaa22..bbdcac28fb02 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -189,6 +189,8 @@ abstract public class ManagedServices {
abstract protected void onServiceAdded(ManagedServiceInfo info);
+ abstract protected void ensureFilters(ServiceInfo si, int userId);
+
protected List<ManagedServiceInfo> getServices() {
synchronized (mMutex) {
List<ManagedServiceInfo> services = new ArrayList<>(mServices);
@@ -1342,8 +1344,10 @@ abstract public class ManagedServices {
for (ComponentName component : add) {
try {
ServiceInfo info = mPm.getServiceInfo(component,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
if (info == null) {
Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ ": service not found");
@@ -1356,7 +1360,7 @@ abstract public class ManagedServices {
}
Slog.v(TAG,
"enabling " + getCaption() + " for " + userId + ": " + component);
- registerService(component, userId);
+ registerService(info, userId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -1368,9 +1372,15 @@ abstract public class ManagedServices {
* Version of registerService that takes the name of a service component to bind to.
*/
@VisibleForTesting
- void registerService(final ComponentName name, final int userid) {
+ void registerService(final ServiceInfo si, final int userId) {
+ ensureFilters(si, userId);
+ registerService(si.getComponentName(), userId);
+ }
+
+ @VisibleForTesting
+ void registerService(final ComponentName cn, final int userId) {
synchronized (mMutex) {
- registerServiceLocked(name, userid);
+ registerServiceLocked(cn, userId);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1591e999e893..917be29243ad 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -215,6 +215,7 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
@@ -9134,6 +9135,12 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ // nothing to filter; no user visible settings for types/packages like other
+ // listeners
+ }
+
+ @Override
@GuardedBy("mNotificationLock")
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
mListeners.unregisterService(removed.service, removed.userid);
@@ -9578,7 +9585,7 @@ public class NotificationManagerService extends SystemService {
public class NotificationListeners extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
- static final String TAG_REQUESTED_LISTENERS = "req_listeners";
+ static final String TAG_REQUESTED_LISTENERS = "request_listeners";
static final String TAG_REQUESTED_LISTENER = "listener";
static final String ATT_COMPONENT = "component";
static final String ATT_TYPES = "types";
@@ -9701,28 +9708,6 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void onUserUnlocked(int user) {
- int flags = PackageManager.GET_SERVICES | PackageManager.GET_META_DATA;
-
- final PackageManager pmWrapper = mContext.getPackageManager();
- List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
- new Intent(getConfig().serviceInterface), flags, user);
-
- for (ResolveInfo resolveInfo : installedServices) {
- ServiceInfo info = resolveInfo.serviceInfo;
-
- if (!getConfig().bindPermission.equals(info.permission)) {
- continue;
- }
- Pair key = Pair.create(info.getComponentName(), user);
- if (!mRequestedNotificationListeners.containsKey(key)) {
- mRequestedNotificationListeners.put(key, new NotificationListenerFilter());
- }
- }
- super.onUserUnlocked(user);
- }
-
- @Override
public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
super.onPackagesChanged(removingPackage, pkgList, uidList);
@@ -9842,6 +9827,38 @@ public class NotificationManagerService extends SystemService {
mRequestedNotificationListeners.put(pair, nlf);
}
+ @Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ 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
+ }
+ }
+
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(types, new ArraySet<>());
+ mRequestedNotificationListeners.put(listener, nlf);
+ }
+ }
+ }
+ }
+
@GuardedBy("mNotificationLock")
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
if (trim == TRIM_LIGHT) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index ec28baf53d3c..07475e955785 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1686,6 +1686,11 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+
+ }
+
+ @Override
protected void loadDefaultsFromConfig() {
mDefaultComponents.addAll(mDefaults);
}
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 b13f80b6f490..80a046a1e8bb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -15,6 +15,11 @@
*/
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 com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -25,14 +30,16 @@ import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.content.ComponentName;
-import android.content.pm.VersionedPackage;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.VersionedPackage;
+import android.os.Bundle;
import android.service.notification.NotificationListenerFilter;
+import android.service.notification.NotificationListenerService;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -48,8 +55,6 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -81,7 +86,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
@Test
public void testReadExtraTag() throws Exception {
- String xml = "<req_listeners>"
+ String xml = "<" + TAG_REQUESTED_LISTENERS+ ">"
+ "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
+ "<allowed types=\"7\" />"
+ "</listener>"
@@ -89,13 +94,13 @@ public class NotificationListenersTest extends UiServiceTestCase {
+ "<allowed types=\"4\" />"
+ "<disallowed pkg=\"pkg1\" uid=\"243\"/>"
+ "</listener>"
- + "</req_listeners>";
+ + "</" + TAG_REQUESTED_LISTENERS + ">";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
- mListeners.readExtraTag("req_listeners", parser);
+ mListeners.readExtraTag(TAG_REQUESTED_LISTENERS, parser);
validateListenersFromXml();
}
@@ -158,52 +163,60 @@ public class NotificationListenersTest extends UiServiceTestCase {
}
@Test
- public void testOnUserUnlocked() {
+ public void testEnsureFilters_newServiceNoMetadata() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new2";
+ si.name = "comp2";
+
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isNull();
+ }
+
+ @Test
+ public void testEnsureFilters_preExisting() {
// one exists already, say from xml
VersionedPackage a1 = new VersionedPackage("pkg1", 243);
NotificationListenerFilter nlf =
new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf);
+ ServiceInfo siOld = new ServiceInfo();
+ siOld.packageName = mCn2.getPackageName();
+ siOld.name = mCn2.getClassName();
+
+ mListeners.ensureFilters(siOld, 0);
- // new service exists or backfilling on upgrade to S
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isEqualTo(nlf);
+ }
+
+ @Test
+ public void testEnsureFilters_newServiceWithMetadata() {
ServiceInfo si = new ServiceInfo();
- si.permission = mListeners.getConfig().bindPermission;
si.packageName = "new";
si.name = "comp";
- ResolveInfo ri = new ResolveInfo();
- ri.serviceInfo = si;
-
- // incorrect service
- ServiceInfo si2 = new ServiceInfo();
- ResolveInfo ri2 = new ResolveInfo();
- ri2.serviceInfo = si2;
- si2.packageName = "new2";
- si2.name = "comp2";
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2");
- List<ResolveInfo> ris = new ArrayList<>();
- ris.add(ri);
- ris.add(ri2);
+ mListeners.ensureFilters(si, 0);
- when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(ris);
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING);
+ }
- mListeners.onUserUnlocked(0);
+ @Test
+ public void testEnsureFilters_newServiceWithEmptyMetadata() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new";
+ si.name = "comp";
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "");
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)).getTypes())
- .isEqualTo(4);
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))
- .getDisallowedPackages())
- .contains(a1);
+ mListeners.ensureFilters(si, 0);
assertThat(mListeners.getNotificationListenerFilter(
Pair.create(si.getComponentName(), 0)).getTypes())
- .isEqualTo(15);
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(si.getComponentName(), 0))
- .getDisallowedPackages())
- .isEmpty();
-
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(si2.getComponentName(), 0)))
- .isNull();
-
+ .isEqualTo(0);
}
@Test