Loading services/core/java/com/android/server/notification/GroupHelper.java +33 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -651,11 +660,34 @@ public class GroupHelper { maybeUngroupWithSections(record, getPreviousValidSectionKey(record)); } /** * 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); } /** Loading services/core/java/com/android/server/notification/NotificationManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -9537,7 +9537,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() ? Loading services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +128 −0 Original line number Diff line number Diff line Loading @@ -2508,6 +2508,134 @@ public class GroupHelperTest extends UiServiceTestCase { 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_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() { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -6340,6 +6340,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); } @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, Loading Loading
services/core/java/com/android/server/notification/GroupHelper.java +33 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -651,11 +660,34 @@ public class GroupHelper { maybeUngroupWithSections(record, getPreviousValidSectionKey(record)); } /** * 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); } /** Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -9537,7 +9537,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() ? Loading
services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +128 −0 Original line number Diff line number Diff line Loading @@ -2508,6 +2508,134 @@ public class GroupHelperTest extends UiServiceTestCase { 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_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() { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -6340,6 +6340,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); } @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, Loading