Loading services/core/java/com/android/server/notification/GroupHelper.java +36 −1 Original line number Diff line number Diff line Loading @@ -788,6 +788,20 @@ public class GroupHelper { return; } // Check if summary & child notifications are not part of the same section/bundle // Needs a check here if notification was bundled while enqueued if (notificationRegroupOnClassification() && android.service.notification.Flags.notificationClassification()) { if (isGroupChildBundled(record, summaryByGroupKey)) { if (DEBUG) { Slog.v(TAG, "isGroupChildInDifferentBundleThanSummary: " + record); } moveNotificationsToNewSection(record.getUserId(), pkgName, List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey))); return; } } // scenario 3: sparse/singleton groups if (Flags.notificationForceGroupSingletons()) { try { Loading @@ -800,6 +814,27 @@ public class GroupHelper { } } private static boolean isGroupChildBundled(final NotificationRecord record, final Map<String, NotificationRecord> summaryByGroupKey) { final StatusBarNotification sbn = record.getSbn(); final String groupKey = record.getSbn().getGroupKey(); if (!sbn.isAppGroup()) { return false; } if (record.getNotification().isGroupSummary()) { return false; } final NotificationRecord summary = summaryByGroupKey.get(groupKey); if (summary == null) { return false; } return NotificationChannel.SYSTEM_RESERVED_IDS.contains(record.getChannel().getId()); } /** * Called when a notification is removed, so that this helper can adjust the aggregate groups: * - Removes the autogroup summary of the notification's section Loading Loading @@ -1598,7 +1633,7 @@ public class GroupHelper { final int mSummaryId; private final Predicate<NotificationRecord> mSectionChecker; public NotificationSectioner(String name, int summaryId, private NotificationSectioner(String name, int summaryId, Predicate<NotificationRecord> sectionChecker) { mName = name; mSummaryId = summaryId; Loading services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +66 −3 Original line number Diff line number Diff line Loading @@ -2410,11 +2410,13 @@ public class GroupHelperTest extends UiServiceTestCase { NotificationChannel.NEWS_ID); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild() && record.getSbn().getId() % 2 == 0) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild() && record.getSbn().getId() % 2 != 0) { record.updateNotificationChannel(newsChannel); mGroupHelper.onChannelUpdated(record); Loading Loading @@ -2474,7 +2476,8 @@ public class GroupHelperTest extends UiServiceTestCase { NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, IMPORTANCE_DEFAULT); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading Loading @@ -2532,7 +2535,8 @@ public class GroupHelperTest extends UiServiceTestCase { BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp")) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading Loading @@ -2631,7 +2635,8 @@ public class GroupHelperTest extends UiServiceTestCase { BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp")) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading @@ -2649,6 +2654,64 @@ public class GroupHelperTest extends UiServiceTestCase { anyString(), anyString(), any()); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, FLAG_NOTIFICATION_CLASSIFICATION}) public void testValidGroupsRegrouped_notificationBundledWhileEnqueued() { // Check that valid group notifications are regrouped if classification is done // before onNotificationPostedWithDelay (within DELAY_FOR_ASSISTANT_TIME) final List<NotificationRecord> notificationList = new ArrayList<>(); final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); final String pkg = "package"; final int summaryId = 0; final int numChildren = 3; // Post a regular/valid group: summary + notifications NotificationRecord summary = getNotificationRecord(pkg, summaryId, String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true); notificationList.add(summary); summaryByGroup.put(summary.getGroupKey(), summary); for (int i = 0; i < numChildren; i++) { NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp", false); notificationList.add(child); } // Classify/bundle child notifications. Don't call onChannelUpdated, // adjustments applied while enqueued will use NotificationAdjustmentExtractor. final NotificationChannel socialChannel = new NotificationChannel( NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, IMPORTANCE_DEFAULT); final String expectedGroupKey_social = GroupHelper.getFullAggregateGroupKey(pkg, AGGREGATE_GROUP_KEY + "SocialSection", UserHandle.SYSTEM.getIdentifier()); final NotificationAttributes expectedSummaryAttr_social = new NotificationAttributes( BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); } } // Check that notifications are forced grouped and app-provided summaries are canceled for (NotificationRecord record: notificationList) { mGroupHelper.onNotificationPostedWithDelay(record, notificationList, summaryByGroup); } verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social)); verify(mCallback, times(numChildren)).addAutoGroup(anyString(), eq(expectedGroupKey_social), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); verify(mCallback, times(numChildren - 1)).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(anyString(), anyString()); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void testMoveAggregateGroups_updateChannel_groupsUngrouped() { Loading Loading
services/core/java/com/android/server/notification/GroupHelper.java +36 −1 Original line number Diff line number Diff line Loading @@ -788,6 +788,20 @@ public class GroupHelper { return; } // Check if summary & child notifications are not part of the same section/bundle // Needs a check here if notification was bundled while enqueued if (notificationRegroupOnClassification() && android.service.notification.Flags.notificationClassification()) { if (isGroupChildBundled(record, summaryByGroupKey)) { if (DEBUG) { Slog.v(TAG, "isGroupChildInDifferentBundleThanSummary: " + record); } moveNotificationsToNewSection(record.getUserId(), pkgName, List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey))); return; } } // scenario 3: sparse/singleton groups if (Flags.notificationForceGroupSingletons()) { try { Loading @@ -800,6 +814,27 @@ public class GroupHelper { } } private static boolean isGroupChildBundled(final NotificationRecord record, final Map<String, NotificationRecord> summaryByGroupKey) { final StatusBarNotification sbn = record.getSbn(); final String groupKey = record.getSbn().getGroupKey(); if (!sbn.isAppGroup()) { return false; } if (record.getNotification().isGroupSummary()) { return false; } final NotificationRecord summary = summaryByGroupKey.get(groupKey); if (summary == null) { return false; } return NotificationChannel.SYSTEM_RESERVED_IDS.contains(record.getChannel().getId()); } /** * Called when a notification is removed, so that this helper can adjust the aggregate groups: * - Removes the autogroup summary of the notification's section Loading Loading @@ -1598,7 +1633,7 @@ public class GroupHelper { final int mSummaryId; private final Predicate<NotificationRecord> mSectionChecker; public NotificationSectioner(String name, int summaryId, private NotificationSectioner(String name, int summaryId, Predicate<NotificationRecord> sectionChecker) { mName = name; mSummaryId = summaryId; Loading
services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +66 −3 Original line number Diff line number Diff line Loading @@ -2410,11 +2410,13 @@ public class GroupHelperTest extends UiServiceTestCase { NotificationChannel.NEWS_ID); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild() && record.getSbn().getId() % 2 == 0) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild() && record.getSbn().getId() % 2 != 0) { record.updateNotificationChannel(newsChannel); mGroupHelper.onChannelUpdated(record); Loading Loading @@ -2474,7 +2476,8 @@ public class GroupHelperTest extends UiServiceTestCase { NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, IMPORTANCE_DEFAULT); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { if (record.getChannel().getId().equals(channel1.getId()) && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading Loading @@ -2532,7 +2535,8 @@ public class GroupHelperTest extends UiServiceTestCase { BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp")) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading Loading @@ -2631,7 +2635,8 @@ public class GroupHelperTest extends UiServiceTestCase { BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp")) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); mGroupHelper.onChannelUpdated(record); } Loading @@ -2649,6 +2654,64 @@ public class GroupHelperTest extends UiServiceTestCase { anyString(), anyString(), any()); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, FLAG_NOTIFICATION_CLASSIFICATION}) public void testValidGroupsRegrouped_notificationBundledWhileEnqueued() { // Check that valid group notifications are regrouped if classification is done // before onNotificationPostedWithDelay (within DELAY_FOR_ASSISTANT_TIME) final List<NotificationRecord> notificationList = new ArrayList<>(); final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); final String pkg = "package"; final int summaryId = 0; final int numChildren = 3; // Post a regular/valid group: summary + notifications NotificationRecord summary = getNotificationRecord(pkg, summaryId, String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true); notificationList.add(summary); summaryByGroup.put(summary.getGroupKey(), summary); for (int i = 0; i < numChildren; i++) { NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp", false); notificationList.add(child); } // Classify/bundle child notifications. Don't call onChannelUpdated, // adjustments applied while enqueued will use NotificationAdjustmentExtractor. final NotificationChannel socialChannel = new NotificationChannel( NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, IMPORTANCE_DEFAULT); final String expectedGroupKey_social = GroupHelper.getFullAggregateGroupKey(pkg, AGGREGATE_GROUP_KEY + "SocialSection", UserHandle.SYSTEM.getIdentifier()); final NotificationAttributes expectedSummaryAttr_social = new NotificationAttributes( BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, NotificationChannel.SOCIAL_MEDIA_ID); for (NotificationRecord record: notificationList) { if (record.getOriginalGroupKey().contains("testGrp") && record.getNotification().isGroupChild()) { record.updateNotificationChannel(socialChannel); } } // Check that notifications are forced grouped and app-provided summaries are canceled for (NotificationRecord record: notificationList) { mGroupHelper.onNotificationPostedWithDelay(record, notificationList, summaryByGroup); } verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social)); verify(mCallback, times(numChildren)).addAutoGroup(anyString(), eq(expectedGroupKey_social), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); verify(mCallback, times(numChildren - 1)).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(anyString(), anyString()); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void testMoveAggregateGroups_updateChannel_groupsUngrouped() { Loading