Loading services/core/java/com/android/server/notification/GroupHelper.java +35 −14 Original line number Diff line number Diff line Loading @@ -122,8 +122,9 @@ public class GroupHelper { getNotificationShadeSections(); private static List<NotificationSectioner> getNotificationShadeSections() { ArrayList<NotificationSectioner> sectionsList = new ArrayList<>(); if (android.service.notification.Flags.notificationClassification()) { return List.of( sectionsList.addAll(List.of( new NotificationSectioner("PromotionsSection", 0, (record) -> NotificationChannel.PROMOTIONS_ID.equals(record.getChannel().getId())), new NotificationSectioner("SocialSection", 0, (record) -> Loading @@ -131,18 +132,36 @@ public class GroupHelper { new NotificationSectioner("NewsSection", 0, (record) -> NotificationChannel.NEWS_ID.equals(record.getChannel().getId())), new NotificationSectioner("RecsSection", 0, (record) -> NotificationChannel.RECS_ID.equals(record.getChannel().getId())), new NotificationSectioner("AlertingSection", 0, (record) -> record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT), new NotificationSectioner("SilentSection", 1, (record) -> record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); NotificationChannel.RECS_ID.equals(record.getChannel().getId())))); } if (Flags.notificationForceGroupConversations()) { // add priority people section sectionsList.add(new NotificationSectioner("PeopleSection(priority)", 1, (record) -> record.isConversation() && record.getChannel().isImportantConversation())); if (android.app.Flags.sortSectionByTime()) { // add single people (alerting) section sectionsList.add(new NotificationSectioner("PeopleSection", 0, NotificationRecord::isConversation)); } else { return List.of( // add people alerting section sectionsList.add(new NotificationSectioner("PeopleSection(alerting)", 1, (record) -> record.isConversation() && record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT)); // add people silent section sectionsList.add(new NotificationSectioner("PeopleSection(silent)", 1, (record) -> record.isConversation() && record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); } } sectionsList.addAll(List.of( new NotificationSectioner("AlertingSection", 0, (record) -> record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT), new NotificationSectioner("SilentSection", 1, (record) -> record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); } record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT))); return sectionsList; } public GroupHelper(Context context, PackageManager packageManager, int autoGroupAtCount, Loading Loading @@ -1387,9 +1406,11 @@ public class GroupHelper { } private boolean isNotificationGroupable(final NotificationRecord record) { if (!Flags.notificationForceGroupConversations()) { if (record.isConversation()) { return false; } } Notification notification = record.getSbn().getNotification(); boolean isColorizedFGS = notification.isForegroundService() Loading services/core/java/com/android/server/notification/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -149,3 +149,10 @@ flag { description: "This flag enables forced auto-grouping singleton groups" bug: "336488844" } flag { name: "notification_force_group_conversations" namespace: "systemui" description: "This flag enables forced auto-grouping conversations" bug: "336488844" } services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +86 −4 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.server.notification; import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; import static android.app.Notification.COLOR_DEFAULT; import static android.app.Notification.FLAG_AUTO_CANCEL; import static android.app.Notification.FLAG_BUBBLE; Loading @@ -36,6 +37,7 @@ import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPIN import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.server.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS; import static com.android.server.notification.GroupHelper.AGGREGATE_GROUP_KEY; import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; import static com.android.server.notification.GroupHelper.BASE_FLAGS; Loading Loading @@ -2575,7 +2577,11 @@ public class GroupHelperTest extends UiServiceTestCase { assertThat(cachedSummary).isNull(); } private void checkNonGroupableNotifications() { @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS) public void testNonGroupableNotifications() { // Check that there is no valid section for: conversations, calls, foreground services NotificationRecord notification_conversation = mock(NotificationRecord.class); when(notification_conversation.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation)).isNull(); Loading Loading @@ -2648,8 +2654,6 @@ public class GroupHelperTest extends UiServiceTestCase { "", false, recsChannel); assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo( "AlertingSection"); checkNonGroupableNotifications(); } @Test Loading Loading @@ -2694,8 +2698,86 @@ public class GroupHelperTest extends UiServiceTestCase { "", false, recsChannel); assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo( "RecsSection"); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS}) public void testNonGroupableNotifications_forceGroupConversations() { // Check that there is no valid section for: calls, foreground services NotificationRecord notification_call = spy(getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW)); Notification n = mock(Notification.class); StatusBarNotification sbn = spy(getSbn("package", 0, "0", UserHandle.SYSTEM)); when(notification_call.isConversation()).thenReturn(false); when(notification_call.getNotification()).thenReturn(n); when(notification_call.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(n); when(n.isStyle(Notification.CallStyle.class)).thenReturn(true); assertThat(GroupHelper.getSection(notification_call)).isNull(); NotificationRecord notification_colorFg = spy(getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW)); sbn = spy(getSbn("package", 0, "0", UserHandle.SYSTEM)); n = mock(Notification.class); when(notification_colorFg.isConversation()).thenReturn(false); when(notification_colorFg.getNotification()).thenReturn(n); when(notification_colorFg.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(n); when(n.isForegroundService()).thenReturn(true); when(n.isColorized()).thenReturn(true); when(n.isStyle(Notification.CallStyle.class)).thenReturn(false); assertThat(GroupHelper.getSection(notification_colorFg)).isNull(); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS}) @DisableFlags(FLAG_SORT_SECTION_BY_TIME) public void testConversationGroupSections_disableSortSectionByTime() { // Check that there are separate sections for conversations: alerting and silent NotificationRecord notification_conversation_silent = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW); notification_conversation_silent = spy(notification_conversation_silent); when(notification_conversation_silent.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_silent).mName).isEqualTo( "PeopleSection(silent)"); checkNonGroupableNotifications(); // Check that there is a correct section for conversations NotificationRecord notification_conversation_alerting = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_alerting = spy(notification_conversation_alerting); when(notification_conversation_alerting.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_alerting).mName).isEqualTo( "PeopleSection(alerting)"); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS, FLAG_SORT_SECTION_BY_TIME}) public void testConversationGroupSections() { // Check that there is a single section for silent/alerting conversations NotificationRecord notification_conversation_silent = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW); notification_conversation_silent = spy(notification_conversation_silent); when(notification_conversation_silent.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_silent).mName).isEqualTo( "PeopleSection"); NotificationRecord notification_conversation_alerting = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_alerting = spy(notification_conversation_alerting); when(notification_conversation_alerting.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_alerting).mName).isEqualTo( "PeopleSection"); // Check that there is a section for priority conversations NotificationRecord notification_conversation_prio = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_prio = spy(notification_conversation_prio); when(notification_conversation_prio.isConversation()).thenReturn(true); notification_conversation_prio.getChannel().setImportantConversation(true); assertThat(GroupHelper.getSection(notification_conversation_prio).mName).isEqualTo( "PeopleSection(priority)"); } } Loading
services/core/java/com/android/server/notification/GroupHelper.java +35 −14 Original line number Diff line number Diff line Loading @@ -122,8 +122,9 @@ public class GroupHelper { getNotificationShadeSections(); private static List<NotificationSectioner> getNotificationShadeSections() { ArrayList<NotificationSectioner> sectionsList = new ArrayList<>(); if (android.service.notification.Flags.notificationClassification()) { return List.of( sectionsList.addAll(List.of( new NotificationSectioner("PromotionsSection", 0, (record) -> NotificationChannel.PROMOTIONS_ID.equals(record.getChannel().getId())), new NotificationSectioner("SocialSection", 0, (record) -> Loading @@ -131,18 +132,36 @@ public class GroupHelper { new NotificationSectioner("NewsSection", 0, (record) -> NotificationChannel.NEWS_ID.equals(record.getChannel().getId())), new NotificationSectioner("RecsSection", 0, (record) -> NotificationChannel.RECS_ID.equals(record.getChannel().getId())), new NotificationSectioner("AlertingSection", 0, (record) -> record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT), new NotificationSectioner("SilentSection", 1, (record) -> record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); NotificationChannel.RECS_ID.equals(record.getChannel().getId())))); } if (Flags.notificationForceGroupConversations()) { // add priority people section sectionsList.add(new NotificationSectioner("PeopleSection(priority)", 1, (record) -> record.isConversation() && record.getChannel().isImportantConversation())); if (android.app.Flags.sortSectionByTime()) { // add single people (alerting) section sectionsList.add(new NotificationSectioner("PeopleSection", 0, NotificationRecord::isConversation)); } else { return List.of( // add people alerting section sectionsList.add(new NotificationSectioner("PeopleSection(alerting)", 1, (record) -> record.isConversation() && record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT)); // add people silent section sectionsList.add(new NotificationSectioner("PeopleSection(silent)", 1, (record) -> record.isConversation() && record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); } } sectionsList.addAll(List.of( new NotificationSectioner("AlertingSection", 0, (record) -> record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT), new NotificationSectioner("SilentSection", 1, (record) -> record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT)); } record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT))); return sectionsList; } public GroupHelper(Context context, PackageManager packageManager, int autoGroupAtCount, Loading Loading @@ -1387,9 +1406,11 @@ public class GroupHelper { } private boolean isNotificationGroupable(final NotificationRecord record) { if (!Flags.notificationForceGroupConversations()) { if (record.isConversation()) { return false; } } Notification notification = record.getSbn().getNotification(); boolean isColorizedFGS = notification.isForegroundService() Loading
services/core/java/com/android/server/notification/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -149,3 +149,10 @@ flag { description: "This flag enables forced auto-grouping singleton groups" bug: "336488844" } flag { name: "notification_force_group_conversations" namespace: "systemui" description: "This flag enables forced auto-grouping conversations" bug: "336488844" }
services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +86 −4 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.server.notification; import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; import static android.app.Notification.COLOR_DEFAULT; import static android.app.Notification.FLAG_AUTO_CANCEL; import static android.app.Notification.FLAG_BUBBLE; Loading @@ -36,6 +37,7 @@ import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPIN import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.server.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS; import static com.android.server.notification.GroupHelper.AGGREGATE_GROUP_KEY; import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; import static com.android.server.notification.GroupHelper.BASE_FLAGS; Loading Loading @@ -2575,7 +2577,11 @@ public class GroupHelperTest extends UiServiceTestCase { assertThat(cachedSummary).isNull(); } private void checkNonGroupableNotifications() { @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS) public void testNonGroupableNotifications() { // Check that there is no valid section for: conversations, calls, foreground services NotificationRecord notification_conversation = mock(NotificationRecord.class); when(notification_conversation.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation)).isNull(); Loading Loading @@ -2648,8 +2654,6 @@ public class GroupHelperTest extends UiServiceTestCase { "", false, recsChannel); assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo( "AlertingSection"); checkNonGroupableNotifications(); } @Test Loading Loading @@ -2694,8 +2698,86 @@ public class GroupHelperTest extends UiServiceTestCase { "", false, recsChannel); assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo( "RecsSection"); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS}) public void testNonGroupableNotifications_forceGroupConversations() { // Check that there is no valid section for: calls, foreground services NotificationRecord notification_call = spy(getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW)); Notification n = mock(Notification.class); StatusBarNotification sbn = spy(getSbn("package", 0, "0", UserHandle.SYSTEM)); when(notification_call.isConversation()).thenReturn(false); when(notification_call.getNotification()).thenReturn(n); when(notification_call.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(n); when(n.isStyle(Notification.CallStyle.class)).thenReturn(true); assertThat(GroupHelper.getSection(notification_call)).isNull(); NotificationRecord notification_colorFg = spy(getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW)); sbn = spy(getSbn("package", 0, "0", UserHandle.SYSTEM)); n = mock(Notification.class); when(notification_colorFg.isConversation()).thenReturn(false); when(notification_colorFg.getNotification()).thenReturn(n); when(notification_colorFg.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(n); when(n.isForegroundService()).thenReturn(true); when(n.isColorized()).thenReturn(true); when(n.isStyle(Notification.CallStyle.class)).thenReturn(false); assertThat(GroupHelper.getSection(notification_colorFg)).isNull(); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS}) @DisableFlags(FLAG_SORT_SECTION_BY_TIME) public void testConversationGroupSections_disableSortSectionByTime() { // Check that there are separate sections for conversations: alerting and silent NotificationRecord notification_conversation_silent = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW); notification_conversation_silent = spy(notification_conversation_silent); when(notification_conversation_silent.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_silent).mName).isEqualTo( "PeopleSection(silent)"); checkNonGroupableNotifications(); // Check that there is a correct section for conversations NotificationRecord notification_conversation_alerting = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_alerting = spy(notification_conversation_alerting); when(notification_conversation_alerting.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_alerting).mName).isEqualTo( "PeopleSection(alerting)"); } @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS, FLAG_SORT_SECTION_BY_TIME}) public void testConversationGroupSections() { // Check that there is a single section for silent/alerting conversations NotificationRecord notification_conversation_silent = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_LOW); notification_conversation_silent = spy(notification_conversation_silent); when(notification_conversation_silent.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_silent).mName).isEqualTo( "PeopleSection"); NotificationRecord notification_conversation_alerting = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_alerting = spy(notification_conversation_alerting); when(notification_conversation_alerting.isConversation()).thenReturn(true); assertThat(GroupHelper.getSection(notification_conversation_alerting).mName).isEqualTo( "PeopleSection"); // Check that there is a section for priority conversations NotificationRecord notification_conversation_prio = getNotificationRecord(mPkg, 0, "", mUser, "", false, IMPORTANCE_DEFAULT); notification_conversation_prio = spy(notification_conversation_prio); when(notification_conversation_prio.isConversation()).thenReturn(true); notification_conversation_prio.getChannel().setImportantConversation(true); assertThat(GroupHelper.getSection(notification_conversation_prio).mName).isEqualTo( "PeopleSection(priority)"); } }