Loading services/core/java/com/android/server/notification/GroupHelper.java +122 −62 Original line number Diff line number Diff line Loading @@ -830,10 +830,34 @@ public class GroupHelper { } } // The list of notification operations required after the channel update final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); // Check any already auto-grouped notifications that may need to be re-grouped // after the channel update notificationsToMove.addAll( getAutogroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); // Check any ungrouped notifications that may need to be auto-grouped // after the channel update notificationsToMove.addAll( getUngroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); // Batch move to new section if (!notificationsToMove.isEmpty()) { moveNotificationsToNewSection(userId, pkgName, notificationsToMove); } } } @GuardedBy("mAggregatedNotifications") private List<NotificationMoveOp> getAutogroupedNotificationsMoveOps(int userId, String pkgName, ArrayMap<String, NotificationRecord> notificationsToCheck) { final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); final Set<FullyQualifiedGroupKey> oldGroups = new HashSet<>(mAggregatedNotifications.keySet()); // Move auto-grouped updated notifications from the old groups to the new groups (section) for (FullyQualifiedGroupKey oldFullAggKey : oldGroups) { // Only check aggregate groups that match the same userId & packageName if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { Loading @@ -847,8 +871,7 @@ public class GroupHelper { for (String key : notificationsInAggGroup.keySet()) { if (notificationsToCheck.get(key) != null) { // check if section changes NotificationSectioner sectioner = getSection( notificationsToCheck.get(key)); NotificationSectioner sectioner = getSection(notificationsToCheck.get(key)); if (sectioner == null) { continue; } Loading @@ -861,36 +884,63 @@ public class GroupHelper { notificationsToMove.add( new NotificationMoveOp(notificationsToCheck.get(key), oldFullAggKey, newFullAggregateGroupKey)); notificationsToCheck.remove(key); } } } } } return notificationsToMove; } if (newFullAggregateGroupKey != null) { // Add any notifications left ungrouped to the new section ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.get(newFullAggregateGroupKey); if (ungrouped != null) { for (NotificationRecord r : notificationList) { if (ungrouped.containsKey(r.getKey())) { if (DEBUG) { Log.i(TAG, "Add previously ungrouped: " + r); @GuardedBy("mAggregatedNotifications") private List<NotificationMoveOp> getUngroupedNotificationsMoveOps(int userId, String pkgName, final ArrayMap<String, NotificationRecord> notificationsToCheck) { final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); // Move any remaining ungrouped updated notifications from the old ungrouped list // to the new ungrouped section list, if necessary if (!notificationsToCheck.isEmpty()) { final Set<FullyQualifiedGroupKey> oldUngroupedSectionKeys = new HashSet<>(mUngroupedAbuseNotifications.keySet()); for (FullyQualifiedGroupKey oldFullAggKey : oldUngroupedSectionKeys) { // Only check aggregate groups that match the same userId & packageName if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { final ArrayMap<String, NotificationAttributes> ungroupedOld = mUngroupedAbuseNotifications.get(oldFullAggKey); if (ungroupedOld == null) { continue; } notificationsToMove.add( new NotificationMoveOp(r, null, newFullAggregateGroupKey)); FullyQualifiedGroupKey newFullAggregateGroupKey = null; final Set<String> ungroupedKeys = new HashSet<>(ungroupedOld.keySet()); for (String key : ungroupedKeys) { NotificationRecord record = notificationsToCheck.get(key); if (record != null) { // check if section changes NotificationSectioner sectioner = getSection(record); if (sectioner == null) { continue; } newFullAggregateGroupKey = new FullyQualifiedGroupKey(userId, pkgName, sectioner); if (!oldFullAggKey.equals(newFullAggregateGroupKey)) { if (DEBUG) { Log.i(TAG, "Change ungrouped section: " + key); } //Cleanup mUngroupedAbuseNotifications mUngroupedAbuseNotifications.remove(newFullAggregateGroupKey); notificationsToMove.add( new NotificationMoveOp(record, oldFullAggKey, newFullAggregateGroupKey)); notificationsToCheck.remove(key); //Remove from previous ungrouped list ungroupedOld.remove(key); } } } mUngroupedAbuseNotifications.put(oldFullAggKey, ungroupedOld); } // Batch move to new section if (!notificationsToMove.isEmpty()) { moveNotificationsToNewSection(userId, pkgName, notificationsToMove); } } return notificationsToMove; } @GuardedBy("mAggregatedNotifications") Loading @@ -898,6 +948,7 @@ public class GroupHelper { final List<NotificationMoveOp> notificationsToMove) { record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record, boolean hasSummary) { } // Bundled operations to apply to groups affected by the channel update ArrayMap<FullyQualifiedGroupKey, GroupUpdateOp> groupsToUpdate = new ArrayMap<>(); for (NotificationMoveOp moveOp: notificationsToMove) { Loading Loading @@ -927,31 +978,32 @@ public class GroupHelper { } } // Add/update aggregate summary for new group // Add moved notifications to the ungrouped list for new group and do grouping // after all notifications have been handled if (newFullAggregateGroupKey != null) { final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); boolean newGroupExists = !newAggregatedNotificationsAttrs.isEmpty(); newAggregatedNotificationsAttrs.put(record.getKey(), new NotificationAttributes(record.getFlags(), boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty(); ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); ungrouped.put(record.getKey(), new NotificationAttributes( record.getFlags(), record.getNotification().getSmallIcon(), record.getNotification().color, record.getNotification().visibility, record.getNotification().getGroupAlertBehavior(), record.getChannel().getId())); mAggregatedNotifications.put(newFullAggregateGroupKey, newAggregatedNotificationsAttrs); mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped); record.setOverrideGroupKey(null); // Only add once, for triggering notification if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) { groupsToUpdate.put(newFullAggregateGroupKey, new GroupUpdateOp(newFullAggregateGroupKey, record, newGroupExists)); new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary)); } // Add notification to new group. do not request resort record.setOverrideGroupKey(null); mCallback.addAutoGroup(record.getKey(), newFullAggregateGroupKey.toString(), false); } } Loading @@ -959,18 +1011,26 @@ public class GroupHelper { for (FullyQualifiedGroupKey groupKey : groupsToUpdate.keySet()) { final ArrayMap<String, NotificationAttributes> aggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(groupKey, new ArrayMap<>()); if (aggregatedNotificationsAttrs.isEmpty()) { mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); mAggregatedNotifications.remove(groupKey); } else { final ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.getOrDefault(groupKey, new ArrayMap<>()); NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record; boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary; //Group needs to be created/updated if (ungrouped.size() >= mAutoGroupAtCount || (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) { NotificationSectioner sectioner = getSection(triggeringNotification); if (sectioner == null) { continue; } updateAggregateAppGroup(groupKey, triggeringNotification.getKey(), hasSummary, sectioner.mSummaryId); aggregateUngroupedNotifications(groupKey, triggeringNotification.getKey(), ungrouped, hasSummary, sectioner.mSummaryId); } else { // Remove empty groups if (aggregatedNotificationsAttrs.isEmpty() && hasSummary) { mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); mAggregatedNotifications.remove(groupKey); } } } } Loading services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +65 −9 Original line number Diff line number Diff line Loading @@ -2204,7 +2204,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), Loading Loading @@ -2264,13 +2264,15 @@ public class GroupHelperTest extends UiServiceTestCase { notificationList); // Check that channel1's notifications are moved to the silent section group expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, "TEST_CHANNEL_ID1"); verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); verify(mCallback, times(AUTOGROUP_AT_COUNT/2 + 1)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); // But not enough to auto-group => remove override group key verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), anyString(), anyInt(), any()); verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { assertThat(record.getSbn().getOverrideGroupKey()).isNull(); } } // Check that the alerting section group is not removed, only updated expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, Loading Loading @@ -2343,7 +2345,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(numSilentGroupNotifications)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), Loading @@ -2352,6 +2354,60 @@ public class GroupHelperTest extends UiServiceTestCase { any()); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void testAutogroup_updateChannel_reachedMinAutogroupCount() { final String pkg = "package"; final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1", "TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT); final NotificationChannel channel2 = new NotificationChannel("TEST_CHANNEL_ID2", "TEST_CHANNEL_ID2", IMPORTANCE_LOW); final List<NotificationRecord> notificationList = new ArrayList<>(); // Post notifications with different channels that would autogroup in different sections NotificationRecord r; // Not enough notifications to autogroup initially for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { if (i % 2 == 0) { r = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null, false, channel1); } else { r = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null, false, channel2); } notificationList.add(r); mGroupHelper.onNotificationPosted(r, false); } verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), anyString(), anyInt(), any()); verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); Mockito.reset(mCallback); // Update channel1's importance final String expectedGroupKey_silent = GroupHelper.getFullAggregateGroupKey(pkg, AGGREGATE_GROUP_KEY + "SilentSection", UserHandle.SYSTEM.getIdentifier()); channel1.setImportance(IMPORTANCE_LOW); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { record.updateNotificationChannel(channel1); } } mGroupHelper.onChannelUpdated(UserHandle.SYSTEM.getIdentifier(), pkg, channel1, notificationList); // Check that channel1's notifications are moved to the silent section & autogroup all NotificationAttributes expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, "TEST_CHANNEL_ID1"); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(true)); verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) Loading Loading
services/core/java/com/android/server/notification/GroupHelper.java +122 −62 Original line number Diff line number Diff line Loading @@ -830,10 +830,34 @@ public class GroupHelper { } } // The list of notification operations required after the channel update final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); // Check any already auto-grouped notifications that may need to be re-grouped // after the channel update notificationsToMove.addAll( getAutogroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); // Check any ungrouped notifications that may need to be auto-grouped // after the channel update notificationsToMove.addAll( getUngroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); // Batch move to new section if (!notificationsToMove.isEmpty()) { moveNotificationsToNewSection(userId, pkgName, notificationsToMove); } } } @GuardedBy("mAggregatedNotifications") private List<NotificationMoveOp> getAutogroupedNotificationsMoveOps(int userId, String pkgName, ArrayMap<String, NotificationRecord> notificationsToCheck) { final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); final Set<FullyQualifiedGroupKey> oldGroups = new HashSet<>(mAggregatedNotifications.keySet()); // Move auto-grouped updated notifications from the old groups to the new groups (section) for (FullyQualifiedGroupKey oldFullAggKey : oldGroups) { // Only check aggregate groups that match the same userId & packageName if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { Loading @@ -847,8 +871,7 @@ public class GroupHelper { for (String key : notificationsInAggGroup.keySet()) { if (notificationsToCheck.get(key) != null) { // check if section changes NotificationSectioner sectioner = getSection( notificationsToCheck.get(key)); NotificationSectioner sectioner = getSection(notificationsToCheck.get(key)); if (sectioner == null) { continue; } Loading @@ -861,36 +884,63 @@ public class GroupHelper { notificationsToMove.add( new NotificationMoveOp(notificationsToCheck.get(key), oldFullAggKey, newFullAggregateGroupKey)); notificationsToCheck.remove(key); } } } } } return notificationsToMove; } if (newFullAggregateGroupKey != null) { // Add any notifications left ungrouped to the new section ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.get(newFullAggregateGroupKey); if (ungrouped != null) { for (NotificationRecord r : notificationList) { if (ungrouped.containsKey(r.getKey())) { if (DEBUG) { Log.i(TAG, "Add previously ungrouped: " + r); @GuardedBy("mAggregatedNotifications") private List<NotificationMoveOp> getUngroupedNotificationsMoveOps(int userId, String pkgName, final ArrayMap<String, NotificationRecord> notificationsToCheck) { final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); // Move any remaining ungrouped updated notifications from the old ungrouped list // to the new ungrouped section list, if necessary if (!notificationsToCheck.isEmpty()) { final Set<FullyQualifiedGroupKey> oldUngroupedSectionKeys = new HashSet<>(mUngroupedAbuseNotifications.keySet()); for (FullyQualifiedGroupKey oldFullAggKey : oldUngroupedSectionKeys) { // Only check aggregate groups that match the same userId & packageName if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { final ArrayMap<String, NotificationAttributes> ungroupedOld = mUngroupedAbuseNotifications.get(oldFullAggKey); if (ungroupedOld == null) { continue; } notificationsToMove.add( new NotificationMoveOp(r, null, newFullAggregateGroupKey)); FullyQualifiedGroupKey newFullAggregateGroupKey = null; final Set<String> ungroupedKeys = new HashSet<>(ungroupedOld.keySet()); for (String key : ungroupedKeys) { NotificationRecord record = notificationsToCheck.get(key); if (record != null) { // check if section changes NotificationSectioner sectioner = getSection(record); if (sectioner == null) { continue; } newFullAggregateGroupKey = new FullyQualifiedGroupKey(userId, pkgName, sectioner); if (!oldFullAggKey.equals(newFullAggregateGroupKey)) { if (DEBUG) { Log.i(TAG, "Change ungrouped section: " + key); } //Cleanup mUngroupedAbuseNotifications mUngroupedAbuseNotifications.remove(newFullAggregateGroupKey); notificationsToMove.add( new NotificationMoveOp(record, oldFullAggKey, newFullAggregateGroupKey)); notificationsToCheck.remove(key); //Remove from previous ungrouped list ungroupedOld.remove(key); } } } mUngroupedAbuseNotifications.put(oldFullAggKey, ungroupedOld); } // Batch move to new section if (!notificationsToMove.isEmpty()) { moveNotificationsToNewSection(userId, pkgName, notificationsToMove); } } return notificationsToMove; } @GuardedBy("mAggregatedNotifications") Loading @@ -898,6 +948,7 @@ public class GroupHelper { final List<NotificationMoveOp> notificationsToMove) { record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record, boolean hasSummary) { } // Bundled operations to apply to groups affected by the channel update ArrayMap<FullyQualifiedGroupKey, GroupUpdateOp> groupsToUpdate = new ArrayMap<>(); for (NotificationMoveOp moveOp: notificationsToMove) { Loading Loading @@ -927,31 +978,32 @@ public class GroupHelper { } } // Add/update aggregate summary for new group // Add moved notifications to the ungrouped list for new group and do grouping // after all notifications have been handled if (newFullAggregateGroupKey != null) { final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); boolean newGroupExists = !newAggregatedNotificationsAttrs.isEmpty(); newAggregatedNotificationsAttrs.put(record.getKey(), new NotificationAttributes(record.getFlags(), boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty(); ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); ungrouped.put(record.getKey(), new NotificationAttributes( record.getFlags(), record.getNotification().getSmallIcon(), record.getNotification().color, record.getNotification().visibility, record.getNotification().getGroupAlertBehavior(), record.getChannel().getId())); mAggregatedNotifications.put(newFullAggregateGroupKey, newAggregatedNotificationsAttrs); mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped); record.setOverrideGroupKey(null); // Only add once, for triggering notification if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) { groupsToUpdate.put(newFullAggregateGroupKey, new GroupUpdateOp(newFullAggregateGroupKey, record, newGroupExists)); new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary)); } // Add notification to new group. do not request resort record.setOverrideGroupKey(null); mCallback.addAutoGroup(record.getKey(), newFullAggregateGroupKey.toString(), false); } } Loading @@ -959,18 +1011,26 @@ public class GroupHelper { for (FullyQualifiedGroupKey groupKey : groupsToUpdate.keySet()) { final ArrayMap<String, NotificationAttributes> aggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(groupKey, new ArrayMap<>()); if (aggregatedNotificationsAttrs.isEmpty()) { mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); mAggregatedNotifications.remove(groupKey); } else { final ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.getOrDefault(groupKey, new ArrayMap<>()); NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record; boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary; //Group needs to be created/updated if (ungrouped.size() >= mAutoGroupAtCount || (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) { NotificationSectioner sectioner = getSection(triggeringNotification); if (sectioner == null) { continue; } updateAggregateAppGroup(groupKey, triggeringNotification.getKey(), hasSummary, sectioner.mSummaryId); aggregateUngroupedNotifications(groupKey, triggeringNotification.getKey(), ungrouped, hasSummary, sectioner.mSummaryId); } else { // Remove empty groups if (aggregatedNotificationsAttrs.isEmpty() && hasSummary) { mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); mAggregatedNotifications.remove(groupKey); } } } } Loading
services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +65 −9 Original line number Diff line number Diff line Loading @@ -2204,7 +2204,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), Loading Loading @@ -2264,13 +2264,15 @@ public class GroupHelperTest extends UiServiceTestCase { notificationList); // Check that channel1's notifications are moved to the silent section group expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, "TEST_CHANNEL_ID1"); verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); verify(mCallback, times(AUTOGROUP_AT_COUNT/2 + 1)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); // But not enough to auto-group => remove override group key verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), anyString(), anyInt(), any()); verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { assertThat(record.getSbn().getOverrideGroupKey()).isNull(); } } // Check that the alerting section group is not removed, only updated expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, Loading Loading @@ -2343,7 +2345,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(numSilentGroupNotifications)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(false)); eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), Loading @@ -2352,6 +2354,60 @@ public class GroupHelperTest extends UiServiceTestCase { any()); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void testAutogroup_updateChannel_reachedMinAutogroupCount() { final String pkg = "package"; final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1", "TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT); final NotificationChannel channel2 = new NotificationChannel("TEST_CHANNEL_ID2", "TEST_CHANNEL_ID2", IMPORTANCE_LOW); final List<NotificationRecord> notificationList = new ArrayList<>(); // Post notifications with different channels that would autogroup in different sections NotificationRecord r; // Not enough notifications to autogroup initially for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { if (i % 2 == 0) { r = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null, false, channel1); } else { r = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null, false, channel2); } notificationList.add(r); mGroupHelper.onNotificationPosted(r, false); } verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), anyString(), anyInt(), any()); verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); Mockito.reset(mCallback); // Update channel1's importance final String expectedGroupKey_silent = GroupHelper.getFullAggregateGroupKey(pkg, AGGREGATE_GROUP_KEY + "SilentSection", UserHandle.SYSTEM.getIdentifier()); channel1.setImportance(IMPORTANCE_LOW); for (NotificationRecord record: notificationList) { if (record.getChannel().getId().equals(channel1.getId())) { record.updateNotificationChannel(channel1); } } mGroupHelper.onChannelUpdated(UserHandle.SYSTEM.getIdentifier(), pkg, channel1, notificationList); // Check that channel1's notifications are moved to the silent section & autogroup all NotificationAttributes expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, "TEST_CHANNEL_ID1"); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), eq(expectedGroupKey_silent), eq(true)); verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) Loading