Merge "Enable specific bundles to be enabled/disabled" into main
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 98d6f58..1173519 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -402,6 +402,7 @@
method @FlaggedApi("android.service.notification.notification_classification") @NonNull public java.util.Set<java.lang.String> getUnsupportedAdjustmentTypes();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
method @FlaggedApi("android.app.modes_api") public boolean removeAutomaticZenRule(@NonNull String, boolean);
+ method @FlaggedApi("android.service.notification.notification_classification") public void setAssistantAdjustmentKeyTypeState(int, boolean);
method @FlaggedApi("android.app.api_rich_ongoing") public void setCanPostPromotedNotifications(@NonNull String, int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index a97fa18..0654ac2 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -267,4 +267,7 @@
void setAdjustmentTypeSupportedState(in INotificationListener token, String key, boolean supported);
List<String> getUnsupportedAdjustmentTypes();
+
+ int[] getAllowedAdjustmentKeyTypes();
+ void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 768b70c..c49b022 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1848,6 +1848,20 @@
/**
* @hide
*/
+ @TestApi
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type, boolean enabled) {
+ INotificationManager service = getService();
+ try {
+ service.setAssistantAdjustmentKeyTypeState(type, 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 e966c15..b929d40 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -474,6 +474,10 @@
Adjustment.KEY_TYPE
};
+ static final Integer[] DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES = new Integer[] {
+ TYPE_PROMOTION
+ };
+
static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
RoleManager.ROLE_DIALER,
RoleManager.ROLE_EMERGENCY
@@ -4195,6 +4199,22 @@
}
@Override
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public @NonNull int[] getAllowedAdjustmentKeyTypes() {
+ checkCallerIsSystemOrSystemUiOrShell();
+ return mAssistants.getAllowedAdjustmentKeyTypes();
+ }
+
+ @Override
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) {
+ checkCallerIsSystemOrSystemUiOrShell();
+ mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled);
+
+ handleSavePolicyFile();
+ }
+
+ @Override
@FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public boolean appCanBePromoted(String pkg, int uid) {
checkCallerIsSystemOrSystemUiOrShell();
@@ -6983,12 +7003,16 @@
if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
toRemove.add(potentialKey);
}
+ if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
+ if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
+ toRemove.add(potentialKey);
+ }
+ }
}
for (String removeKey : toRemove) {
adjustments.remove(removeKey);
}
- if (android.service.notification.Flags.notificationClassification()
- && adjustments.containsKey(KEY_TYPE)) {
+ if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
final NotificationChannel newChannel = getClassificationChannelLocked(r,
adjustments);
if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) {
@@ -11565,11 +11589,15 @@
private static final String ATT_TYPES = "types";
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 final Object mLock = new Object();
@GuardedBy("mLock")
+ private Set<Integer> mAllowedAdjustmentKeyTypes = new ArraySet<>();
+
+ @GuardedBy("mLock")
private Set<String> mAllowedAdjustments = new ArraySet<>();
@GuardedBy("mLock")
@@ -11652,6 +11680,8 @@
for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
}
+ } else {
+ mAllowedAdjustmentKeyTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES));
}
}
@@ -11739,6 +11769,42 @@
}
}
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ protected @NonNull boolean isAdjustmentKeyTypeAllowed(@Adjustment.Types int type) {
+ synchronized (mLock) {
+ if (notificationClassification()) {
+ return mAllowedAdjustmentKeyTypes.contains(type);
+ }
+ }
+ return false;
+ }
+
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ protected @NonNull int[] getAllowedAdjustmentKeyTypes() {
+ synchronized (mLock) {
+ if (notificationClassification()) {
+ return mAllowedAdjustmentKeyTypes.stream()
+ .mapToInt(Integer::intValue).toArray();
+ }
+ }
+ return new int[]{};
+ }
+
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type,
+ boolean enabled) {
+ if (!android.service.notification.Flags.notificationClassification()) {
+ return;
+ }
+ synchronized (mLock) {
+ if (enabled) {
+ mAllowedAdjustmentKeyTypes.add(type);
+ } else {
+ mAllowedAdjustmentKeyTypes.remove(type);
+ }
+ }
+ }
+
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
@@ -12178,27 +12244,46 @@
@Override
protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
- if (!android.service.notification.Flags.notificationClassification()) {
+ if (!notificationClassification()) {
return;
}
synchronized (mLock) {
out.startTag(null, ATT_DENIED);
out.attribute(null, ATT_TYPES, TextUtils.join(",", mDeniedAdjustments));
out.endTag(null, ATT_DENIED);
+ out.startTag(null, ATT_ENABLED_TYPES);
+ out.attribute(null, ATT_TYPES,
+ TextUtils.join(",", mAllowedAdjustmentKeyTypes));
+ out.endTag(null, ATT_ENABLED_TYPES);
}
}
@Override
protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
- if (!android.service.notification.Flags.notificationClassification()) {
+ if (!notificationClassification()) {
return;
}
if (ATT_DENIED.equals(tag)) {
- final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+ final String keys = XmlUtils.readStringAttribute(parser, ATT_TYPES);
synchronized (mLock) {
mDeniedAdjustments.clear();
+ if (!TextUtils.isEmpty(keys)) {
+ mDeniedAdjustments.addAll(Arrays.asList(keys.split(",")));
+ }
+ }
+ } else if (ATT_ENABLED_TYPES.equals(tag)) {
+ final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+ synchronized (mLock) {
+ mAllowedAdjustmentKeyTypes.clear();
if (!TextUtils.isEmpty(types)) {
- mDeniedAdjustments.addAll(Arrays.asList(types.split(",")));
+ List<String> typeList = Arrays.asList(types.split(","));
+ for (String type : typeList) {
+ try {
+ mAllowedAdjustmentKeyTypes.add(Integer.parseInt(type));
+ } catch (NumberFormatException e) {
+ Slog.wtf(TAG, "Bad type specified", e);
+ }
+ }
}
}
}
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 0f7de7d..6eb2f71 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -17,6 +17,9 @@
import static android.os.UserHandle.USER_ALL;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
+import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
+import static android.service.notification.Adjustment.TYPE_NEWS;
+import static android.service.notification.Adjustment.TYPE_PROMOTION;
import static com.android.server.notification.NotificationManagerService.DEFAULT_ALLOWED_ADJUSTMENTS;
@@ -57,6 +60,8 @@
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;
@@ -680,4 +685,47 @@
assertThat(mAssistants.getAllowedAssistantAdjustments())
.containsExactlyElementsIn(DEFAULT_ALLOWED_ADJUSTMENTS);
}
+
+ @Test
+ @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testSetAssistantAdjustmentKeyTypeState_allow() {
+ assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
+ .containsExactly(TYPE_PROMOTION);
+
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true);
+
+ assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
+ .containsExactlyElementsIn(List.of(TYPE_PROMOTION, TYPE_CONTENT_RECOMMENDATION));
+ }
+
+ @Test
+ @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testSetAssistantAdjustmentKeyTypeState_disallow() {
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false);
+ assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testDisallowAdjustmentKeyType_readWriteXml() throws Exception {
+ mAssistants.loadDefaultsFromConfig(true);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true);
+
+ writeXmlAndReload(USER_ALL);
+
+ assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
+ .containsExactlyElementsIn(List.of(TYPE_NEWS, TYPE_CONTENT_RECOMMENDATION));
+ }
+
+ @Test
+ public void testDefaultAllowedKeyAdjustments_readWriteXml() throws Exception {
+ mAssistants.loadDefaultsFromConfig(true);
+
+ writeXmlAndReload(USER_ALL);
+
+ assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
+ .containsExactly(TYPE_PROMOTION);
+ }
}
\ 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 07fa70e..ea16ea2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -17156,6 +17156,7 @@
NotificationManagerService.WorkerHandler handler = mock(
NotificationManagerService.WorkerHandler.class);
mService.setHandler(handler);
+ when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
Bundle signals = new Bundle();
signals.putInt(KEY_TYPE, TYPE_NEWS);