summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/NotificationManager.java13
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java77
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java77
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java51
5 files changed, 211 insertions, 9 deletions
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9bb16ae7fa02..a6c1a57a8131 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -270,4 +270,6 @@ interface INotificationManager
int[] getAllowedAdjustmentKeyTypes();
void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
+ String[] getTypeAdjustmentDeniedPackages();
+ void setTypeAdjustmentForPackageState(String pkg, boolean enabled);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c310f95814dc..87c861912036 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1868,6 +1868,19 @@ public class NotificationManager {
/**
* @hide
*/
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) {
+ INotificationManager service = getService();
+ try {
+ service.setTypeAdjustmentForPackageState(pkg, enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
public List<String> getEnabledNotificationListenerPackages() {
INotificationManager service = getService();
try {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5182dfe60fcc..d2b2fad8aa35 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -26,6 +26,7 @@ import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
import static android.app.Flags.lifetimeExtensionRefactor;
+import static android.app.Flags.notificationClassificationUi;
import static android.app.Flags.sortSectionByTime;
import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -4225,6 +4226,22 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public @NonNull String[] getTypeAdjustmentDeniedPackages() {
+ checkCallerIsSystemOrSystemUiOrShell();
+ return mAssistants.getTypeAdjustmentDeniedPackages();
+ }
+
+ @Override
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+ checkCallerIsSystemOrSystemUiOrShell();
+ mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
+
+ handleSavePolicyFile();
+ }
+
+ @Override
@FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public boolean appCanBePromoted(String pkg, int uid) {
checkCallerIsSystemOrSystemUiOrShell();
@@ -7006,6 +7023,10 @@ public class NotificationManagerService extends SystemService {
if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
toRemove.add(potentialKey);
+ } else if (notificationClassificationUi()
+ && !mAssistants.isTypeAdjustmentAllowedForPackage(
+ r.getSbn().getPackageName())) {
+ toRemove.add(potentialKey);
}
}
}
@@ -11643,6 +11664,7 @@ public class NotificationManagerService extends SystemService {
private static final String ATT_DENIED = "denied_adjustments";
private static final String ATT_ENABLED_TYPES = "enabled_key_types";
private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
+ private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps";
private final Object mLock = new Object();
@@ -11658,6 +11680,9 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mLock")
private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>();
+
protected ComponentName mDefaultFromConfig = null;
@Override
@@ -11857,6 +11882,44 @@ public class NotificationManagerService extends SystemService {
}
}
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) {
+ synchronized (mLock) {
+ if (notificationClassificationUi()) {
+ return !mClassificationTypeDeniedPackages.contains(pkg);
+ }
+ }
+ return true;
+ }
+
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull String[] getTypeAdjustmentDeniedPackages() {
+ synchronized (mLock) {
+ if (notificationClassificationUi()) {
+ return mClassificationTypeDeniedPackages.toArray(new String[0]);
+ }
+ }
+ return new String[]{};
+ }
+
+ /**
+ * Set whether a particular package can have its notification channels adjusted to have a
+ * different type by NotificationAssistants.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+ if (!notificationClassificationUi()) {
+ return;
+ }
+ synchronized (mLock) {
+ if (enabled) {
+ mClassificationTypeDeniedPackages.remove(pkg);
+ } else {
+ mClassificationTypeDeniedPackages.add(pkg);
+ }
+ }
+ }
+
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
@@ -12315,6 +12378,12 @@ public class NotificationManagerService extends SystemService {
out.attribute(null, ATT_TYPES,
TextUtils.join(",", mAllowedAdjustmentKeyTypes));
out.endTag(null, ATT_ENABLED_TYPES);
+ if (notificationClassificationUi()) {
+ out.startTag(null, ATT_TYPES_DENIED_APPS);
+ out.attribute(null, ATT_TYPES,
+ TextUtils.join(",", mClassificationTypeDeniedPackages));
+ out.endTag(null, ATT_TYPES_DENIED_APPS);
+ }
}
}
@@ -12346,6 +12415,14 @@ public class NotificationManagerService extends SystemService {
}
}
}
+ } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) {
+ final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+ synchronized (mLock) {
+ mClassificationTypeDeniedPackages.clear();
+ if (!TextUtils.isEmpty(apps)) {
+ mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(",")));
+ }
+ }
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 9eddcc94e650..decbaacdcef9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -60,8 +60,6 @@ import android.testing.TestableContext;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.Log;
-import android.util.Slog;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -729,4 +727,79 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
.containsExactly(TYPE_PROMOTION);
}
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
+ // Given that a package is allowed to have its type adjusted,
+ String allowedPackage = "allowed.package";
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+ // Set type adjustment disallowed for this package
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false);
+
+ // Then the package is marked as denied
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactly(allowedPackage);
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+ // Set type adjustment allowed again
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+ // Then the package is marked as allowed again
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() {
+ // Given packages not allowed to have their type adjusted,
+ String deniedPkg1 = "denied.Pkg1";
+ String deniedPkg2 = "denied.Pkg2";
+ String deniedPkg3 = "denied.Pkg3";
+ // Set type adjustment disallowed for these packages
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+ // Then the packages are marked as denied
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+
+ // And when we re-allow one of them,
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true);
+
+ // Then the rest of the original packages are still marked as denied.
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception {
+ mAssistants.loadDefaultsFromConfig(true);
+ String deniedPkg1 = "denied.Pkg1";
+ String allowedPkg2 = "allowed.Pkg2";
+ String deniedPkg3 = "denied.Pkg3";
+ // Set type adjustment disallowed or allowed for these packages
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+ mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+ writeXmlAndReload(USER_ALL);
+
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+ }
} \ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e6b4bc98ea4c..9b37347e1161 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -232,7 +232,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -337,12 +336,12 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -361,9 +360,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -378,6 +374,9 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@RunWithLooper
@@ -7534,6 +7533,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
// Set up notifications that will be adjusted
final NotificationRecord r1 = spy(generateNotificationRecord(
@@ -17142,6 +17142,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationManagerService.WorkerHandler.class);
mService.setHandler(handler);
when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
Bundle signals = new Bundle();
signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17176,6 +17177,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
+ android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
+ public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+ when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+
+ Bundle signals = new Bundle();
+ signals.putInt(KEY_TYPE, TYPE_NEWS);
+ Adjustment adjustment = new Adjustment(
+ r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+
+ waitForIdle();
+
+ r.applyAdjustments();
+
+ assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+
+ // When we block adjustments for this package
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
+
+ signals.putInt(KEY_TYPE, TYPE_PROMOTION);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+ waitForIdle();
+ r.applyAdjustments();
+ // Then the adjustment is not applied.
+ assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+ }
+
+ @Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_granted() throws Exception {
// qualifying posted notification