summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Valentin Iftime <valiiftime@google.com> 2025-01-08 11:18:40 +0100
committer Valentin Iftime <valiiftime@google.com> 2025-01-08 11:20:11 +0100
commit65a8b6e935fd6f6ea1d76f004e3a2ef9fb0d449e (patch)
tree3c7376b85a3b9f56cd569fba3b47eeda3ce8116a
parent271ede58aa7cdc5e2f3968f6ef379be3f307df40 (diff)
Call GroupHelper when posting notification update with different channel
Call GH#onNotificationPosted when the updated notification has a different channel, as it may result in regrouping to a new section. Only trigger ungrouping/cleanup in onNotificationPosted, grouping/regrouping will be handled automatically as the notification is treated as new after cleanup. Flag: android.service.notification.notification_force_grouping Test: atest GroupHelperTest NotificationManagerServiceTest Bug: 382762909 Change-Id: Ia13fcfbabb9d1ed60095da9048d258f1f691fd94
-rw-r--r--services/core/java/com/android/server/notification/GroupHelper.java34
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java128
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java20
4 files changed, 183 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 4b41696a4390..e47f8ae9d3a5 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -583,6 +583,15 @@ public class GroupHelper {
final FullyQualifiedGroupKey fullAggregateGroupKey = new FullyQualifiedGroupKey(
record.getUserId(), pkgName, sectioner);
+ // The notification was part of a different section => trigger regrouping
+ final FullyQualifiedGroupKey prevSectionKey = getPreviousValidSectionKey(record);
+ if (prevSectionKey != null && !fullAggregateGroupKey.equals(prevSectionKey)) {
+ if (DEBUG) {
+ Slog.i(TAG, "Section changed for: " + record);
+ }
+ maybeUngroupOnSectionChanged(record, prevSectionKey);
+ }
+
// This notification is already aggregated
if (record.getGroupKey().equals(fullAggregateGroupKey.toString())) {
return false;
@@ -652,10 +661,33 @@ public class GroupHelper {
}
/**
+ * A notification was added that was previously part of a different section and needs to trigger
+ * GH state cleanup.
+ */
+ private void maybeUngroupOnSectionChanged(NotificationRecord record,
+ FullyQualifiedGroupKey prevSectionKey) {
+ maybeUngroupWithSections(record, prevSectionKey);
+ if (record.getGroupKey().equals(prevSectionKey.toString())) {
+ record.setOverrideGroupKey(null);
+ }
+ }
+
+ /**
* A notification was added that is app-grouped.
*/
private void maybeUngroupOnAppGrouped(NotificationRecord record) {
- maybeUngroupWithSections(record, getSectionGroupKeyWithFallback(record));
+ FullyQualifiedGroupKey currentSectionKey = getSectionGroupKeyWithFallback(record);
+
+ // The notification was part of a different section => trigger regrouping
+ final FullyQualifiedGroupKey prevSectionKey = getPreviousValidSectionKey(record);
+ if (prevSectionKey != null && !prevSectionKey.equals(currentSectionKey)) {
+ if (DEBUG) {
+ Slog.i(TAG, "Section changed for: " + record);
+ }
+ currentSectionKey = prevSectionKey;
+ }
+
+ maybeUngroupWithSections(record, currentSectionKey);
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f50e8aa7eb7b..c297ba7629b7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -9532,7 +9532,8 @@ public class NotificationManagerService extends SystemService {
|| !Objects.equals(oldSbn.getNotification().getGroup(),
n.getNotification().getGroup())
|| oldSbn.getNotification().flags
- != n.getNotification().flags) {
+ != n.getNotification().flags
+ || !old.getChannel().getId().equals(r.getChannel().getId())) {
synchronized (mNotificationLock) {
final String autogroupName =
notificationForceGrouping() ?
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 6cb24293a7d5..fa733e85c89c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -2509,6 +2509,134 @@ public class GroupHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+ public void testRepostWithNewChannel_afterAutogrouping_isRegrouped() {
+ final String pkg = "package";
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ // Post ungrouped notifications => will be autogrouped
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ NotificationRecord notification = getNotificationRecord(pkg, i + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, null, false);
+ notificationList.add(notification);
+ mGroupHelper.onNotificationPosted(notification, false);
+ }
+
+ final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey), anyInt(), any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).addAutoGroup(anyString(),
+ eq(expectedGroupKey), eq(true));
+
+ // Post ungrouped notifications to a different section, below autogroup limit
+ Mockito.reset(mCallback);
+ // Post ungrouped notifications => will be autogrouped
+ final NotificationChannel silentChannel = new NotificationChannel("TEST_CHANNEL_ID1",
+ "TEST_CHANNEL_ID1", IMPORTANCE_LOW);
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ NotificationRecord notification = getNotificationRecord(pkg, i + 4242,
+ String.valueOf(i + 4242), UserHandle.SYSTEM, null, false, silentChannel);
+ notificationList.add(notification);
+ mGroupHelper.onNotificationPosted(notification, false);
+ }
+
+ verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(),
+ anyString(), anyInt(), any());
+ verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean());
+
+ // Update a notification to a different channel that moves it to a different section
+ Mockito.reset(mCallback);
+ final NotificationRecord notifToInvalidate = notificationList.get(0);
+ final NotificationSectioner initialSection = GroupHelper.getSection(notifToInvalidate);
+ final NotificationChannel updatedChannel = new NotificationChannel("TEST_CHANNEL_ID2",
+ "TEST_CHANNEL_ID2", IMPORTANCE_LOW);
+ notifToInvalidate.updateNotificationChannel(updatedChannel);
+ assertThat(GroupHelper.getSection(notifToInvalidate)).isNotEqualTo(initialSection);
+ boolean needsAutogrouping = mGroupHelper.onNotificationPosted(notifToInvalidate, false);
+ assertThat(needsAutogrouping).isTrue();
+
+ // Check that the silent section was autogrouped
+ final String silentSectionGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "SilentSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(silentSectionGroupKey), anyInt(), any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).addAutoGroup(anyString(),
+ eq(silentSectionGroupKey), eq(true));
+ verify(mCallback, times(1)).removeAutoGroup(eq(notifToInvalidate.getKey()));
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(),
+ eq(expectedGroupKey), any());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+ public void testRepostWithNewChannel_afterForceGrouping_isRegrouped() {
+ final String pkg = "package";
+ final String groupName = "testGroup";
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ // Post valid section summary notifications without children => force group
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ NotificationRecord notification = getNotificationRecord(pkg, i + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, groupName, false);
+ notificationList.add(notification);
+ mGroupHelper.onNotificationPostedWithDelay(notification, notificationList,
+ summaryByGroup);
+ }
+
+ final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey), anyInt(), any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey), eq(true));
+
+ // Update a notification to a different channel that moves it to a different section
+ Mockito.reset(mCallback);
+ final NotificationRecord notifToInvalidate = notificationList.get(0);
+ final NotificationSectioner initialSection = GroupHelper.getSection(notifToInvalidate);
+ final NotificationChannel updatedChannel = new NotificationChannel("TEST_CHANNEL_ID2",
+ "TEST_CHANNEL_ID2", IMPORTANCE_LOW);
+ notifToInvalidate.updateNotificationChannel(updatedChannel);
+ assertThat(GroupHelper.getSection(notifToInvalidate)).isNotEqualTo(initialSection);
+ boolean needsAutogrouping = mGroupHelper.onNotificationPosted(notifToInvalidate, false);
+
+ mGroupHelper.onNotificationPostedWithDelay(notifToInvalidate, notificationList,
+ summaryByGroup);
+
+ // Check that the updated notification is removed from the autogroup
+ assertThat(needsAutogrouping).isFalse();
+ verify(mCallback, times(1)).removeAutoGroup(eq(notifToInvalidate.getKey()));
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(),
+ eq(expectedGroupKey), any());
+
+ // Post child notifications for the silent sectin => will be autogrouped
+ Mockito.reset(mCallback);
+ final NotificationChannel silentChannel = new NotificationChannel("TEST_CHANNEL_ID1",
+ "TEST_CHANNEL_ID1", IMPORTANCE_LOW);
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ NotificationRecord notification = getNotificationRecord(pkg, i + 4242,
+ String.valueOf(i + 4242), UserHandle.SYSTEM, "aGroup", false, silentChannel);
+ notificationList.add(notification);
+ needsAutogrouping = mGroupHelper.onNotificationPosted(notification, false);
+ assertThat(needsAutogrouping).isFalse();
+ mGroupHelper.onNotificationPostedWithDelay(notification, notificationList,
+ summaryByGroup);
+ }
+
+ // Check that the silent section was autogrouped
+ final String silentSectionGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "SilentSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(silentSectionGroupKey), anyInt(), any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ eq(silentSectionGroupKey), eq(true));
+ }
+
+ @Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
public void testMoveAggregateGroups_updateChannel() {
final String pkg = "package";
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 301165f8151d..7d576c678c90 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6341,6 +6341,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testOnlyAutogroupIfNeeded_channelChanged_ghUpdate() {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
+ "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false);
+ mService.addNotification(r);
+
+ NotificationRecord update = generateNotificationRecord(mSilentChannel, 0,
+ "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false);
+ mService.addEnqueuedNotification(update);
+
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(update.getKey(),
+ update.getSbn().getPackageName(), update.getUid(),
+ mPostNotificationTrackerFactory.newTracker(null));
+ runnable.run();
+ waitForIdle();
+
+ verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
+ }
+
+ @Test
public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
"testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);