diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 3a7f61a91a6d0..fe2168bc6d72f 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -18,14 +18,12 @@ package android.app; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.Notification.Builder; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.ParceledListSlice; import android.graphics.drawable.Icon; import android.net.Uri; @@ -33,7 +31,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -41,7 +38,6 @@ import android.os.ServiceManager; import android.os.StrictMode; import android.os.UserHandle; import android.provider.Settings.Global; -import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; import android.service.notification.ZenModeConfig; import android.util.ArraySet; @@ -419,12 +415,16 @@ public class NotificationManager { * Creates a notification channel that notifications can be posted to. * * This can also be used to restore a deleted channel and to update an existing channel's - * name and description. + * name, description, and/or importance. * *
The name and description should only be changed if the locale changes * or in response to the user renaming this channel. For example, if a user has a channel * named 'John Doe' that represents messages from a 'John Doe', and 'John Doe' changes his name * to 'John Smith,' the channel can be renamed to match. + * + *
The importance of an existing channel will only be changed if the new importance is lower
+ * than the current value and the user has not altered any settings on this channel.
+ *
* All other fields are ignored for channels that already exist.
*
* @param channel the channel to create. Note that the created channel may differ from this
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index d7b36aaa80088..8420c90ed76fa 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -567,6 +567,13 @@ public class RankingHelper implements RankingConfig {
existing.setDescription(channel.getDescription());
existing.setBlockableSystem(channel.isBlockableSystem());
+ // Apps are allowed to downgrade channel importance if the user has not changed any
+ // fields on this channel yet.
+ if (existing.getUserLockedFields() == 0 &&
+ channel.getImportance() < existing.getImportance()) {
+ existing.setImportance(channel.getImportance());
+ }
+
updateConfig();
return;
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 8b3fb18173045..bbec98ce583d0 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -81,7 +81,7 @@ import com.android.server.lights.LightsManager;
@RunWithLooper
public class NotificationManagerServiceTest extends NotificationTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
- private final int uid = Binder.getCallingUid();
+ private final int mUid = Binder.getCallingUid();
private NotificationManagerService mNotificationManagerService;
private INotificationManager mBinderService;
private NotificationManagerInternal mInternalService;
@@ -133,13 +133,13 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
// most tests assume badging is enabled
Secure.putIntForUser(getContext().getContentResolver(),
Secure.NOTIFICATION_BADGING, 1,
- UserHandle.getUserHandleForUid(uid).getIdentifier());
+ UserHandle.getUserHandleForUid(mUid).getIdentifier());
mNotificationManagerService = new TestableNotificationManagerService(mContext);
// MockPackageManager - default returns ApplicationInfo with matching calling UID
final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = uid;
+ applicationInfo.uid = mUid;
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
@@ -151,7 +151,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
mTestableLooper = TestableLooper.get(this);
mListener = mNotificationListeners.new ManagedServiceInfo(
- null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
+ null, new ComponentName(PKG, "test_class"), mUid, true, null, 0);
when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
try {
mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
@@ -183,8 +183,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
.setGroup(groupKey)
.setGroupSummary(isSummary);
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
- nb.build(), new UserHandle(uid), null, 0);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
@@ -202,8 +202,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
if (extender != null) {
nb.extend(extender);
}
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
- nb.build(), new UserHandle(uid), null, 0);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -211,17 +211,17 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel("test_pkg", "id");
+ mBinderService.getNotificationChannel(PKG, "id");
assertTrue(createdChannel != null);
}
@Test
public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
try {
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(null)));
fail("Exception should be thrown immediately.");
} catch (NullPointerException e) {
@@ -235,10 +235,10 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT);
final NotificationChannel channel2 =
new NotificationChannel("id2", "name", NotificationManager.IMPORTANCE_DEFAULT);
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
- assertTrue(mBinderService.getNotificationChannel("test_pkg", "id1") != null);
- assertTrue(mBinderService.getNotificationChannel("test_pkg", "id2") != null);
+ assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null);
+ assertTrue(mBinderService.getNotificationChannel(PKG, "id2") != null);
}
@Test
@@ -246,19 +246,60 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
// Recreating the channel doesn't throw, but ignores importance.
final NotificationChannel dupeChannel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel("test_pkg", "id");
+ mBinderService.getNotificationChannel(PKG, "id");
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
+ @Test
+ public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()
+ throws Exception {
+ final NotificationChannel channel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+ mBinderService.createNotificationChannels(PKG,
+ new ParceledListSlice(Arrays.asList(channel)));
+
+ // Recreating with a lower importance is allowed to modify the channel.
+ final NotificationChannel dupeChannel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
+ mBinderService.createNotificationChannels(PKG,
+ new ParceledListSlice(Arrays.asList(dupeChannel)));
+ final NotificationChannel createdChannel =
+ mBinderService.getNotificationChannel(PKG, "id");
+ assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
+ }
+
+ @Test
+ public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()
+ throws Exception {
+ final NotificationChannel channel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+ mBinderService.createNotificationChannels(PKG,
+ new ParceledListSlice(Arrays.asList(channel)));
+
+ // The user modifies importance directly, can no longer be changed by the app.
+ final NotificationChannel updatedChannel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+ mBinderService.updateNotificationChannelForPackage(PKG, mUid, updatedChannel);
+
+ // Recreating with a lower importance leaves channel unchanged.
+ final NotificationChannel dupeChannel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
+ mBinderService.createNotificationChannels(PKG,
+ new ParceledListSlice(Arrays.asList(dupeChannel)));
+ final NotificationChannel createdChannel =
+ mBinderService.getNotificationChannel(PKG, "id");
+ assertEquals(NotificationManager.IMPORTANCE_HIGH, createdChannel.getImportance());
+ }
+
@Test
public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
throws Exception {
@@ -266,10 +307,10 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
final NotificationChannel channel2 =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
- mBinderService.createNotificationChannels("test_pkg",
+ mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel("test_pkg", "id");
+ mBinderService.getNotificationChannel(PKG, "id");
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
@@ -300,7 +341,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
- mBinderService.setNotificationsEnabledForPackage(PKG, uid, false);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -381,7 +422,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId());
waitForIdle();
- mNotificationManagerService.mNotificationDelegate.onClearAll(uid, Binder.getCallingPid(),
+ mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
n.getUserId());
waitForIdle();
StatusBarNotification[] notifs =
@@ -607,7 +648,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
public void testCreateChannelNotifyListener() throws Exception {
List