Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -135,11 +135,30 @@ class ConversationNotificationProcessorTest : SysuiTestCase() { .isNotNull() } @Test @EnableFlags(Flags.FLAG_NM_SUMMARIZATION) fun processNotification_messagingStyleUpdateSummarizationToNull() { val nb = getMessagingNotification() val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build()) newRow.entry.setRanking( RankingBuilder(newRow.entry.ranking).setSummarization("hello").build() ) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() newRow.entry.setRanking(RankingBuilder(newRow.entry.ranking).setSummarization(null).build()) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull() } @Test @EnableFlags(Flags.FLAG_NM_SUMMARIZATION) fun processNotification_messagingStyleWithoutSummarization() { val nb = getMessagingNotification() val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build()) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull() Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +35 −32 Original line number Diff line number Diff line Loading @@ -71,14 +71,14 @@ constructor( Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT else if (entry.ranking.isConversation) Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL else Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY else Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY entry.ranking.conversationShortcutInfo?.let { shortcutInfo -> logger.logAsyncTaskProgress(entry.logKey, "getting shortcut icon") messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo) shortcutInfo.label?.let { label -> messagingStyle.conversationTitle = label } } if (NmSummarizationUiFlag.isEnabled && !TextUtils.isEmpty(entry.ranking.summarization)) { if (NmSummarizationUiFlag.isEnabled) { if (!TextUtils.isEmpty(entry.ranking.summarization)) { val icon = context.getDrawable(R.drawable.ic_notification_summarization)?.mutate() val imageSpan = icon?.let { Loading Loading @@ -111,6 +111,9 @@ constructor( EXTRA_SUMMARIZED_CONTENT, decoratedSummary, ) } else { entry.sbn.notification.extras.putCharSequence(EXTRA_SUMMARIZED_CONTENT, null) } } messagingStyle.unreadMessageCount = Loading services/core/java/com/android/server/notification/NotificationManagerService.java +100 −107 Original line number Diff line number Diff line Loading @@ -1877,73 +1877,35 @@ public class NotificationManagerService extends SystemService { } }; private void unclassifyNotificationsForUser(final int userId) { if (DBG) { Slog.v(TAG, "unclassifyForUser: " + userId); } unclassifyNotificationsFiltered((r) -> r.getUserId() == userId); private void applyNotificationUpdateForUser(final int userId, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId, notificationUpdate); } private void unclassifyNotificationsForUid(final int userId, @NonNull final String pkg) { if (DBG) { Slog.v(TAG, "unclassifyForUid userId: " + userId + " pkg: " + pkg); } unclassifyNotificationsFiltered((r) -> private void applyNotificationUpdateForUid(final int userId, @NonNull final String pkg, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg)); && Objects.equals(r.getSbn().getPackageName(), pkg), notificationUpdate); } private void unclassifyNotificationsForUserAndType(final int userId, final @Types int bundleType) { if (DBG) { Slog.v(TAG, "unclassifyForUserAndType userId: " + userId + " bundleType: " + bundleType); } private void applyNotificationUpdateForUserAndChannelType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate) { final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType); unclassifyNotificationsFiltered((r) -> applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId && r.getChannel() != null && Objects.equals(bundleChannelId, r.getChannel().getId())); } private void unclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { return; } synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { unclassifyNotificationLocked(r); } && Objects.equals(bundleChannelId, r.getChannel().getId()), notificationUpdate); } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { unclassifyNotificationLocked(r); } } } } @GuardedBy("mNotificationLock") private void unclassifyNotificationLocked(@NonNull final NotificationRecord r) { if (DBG) { Slog.v(TAG, "unclassifyNotification: " + r); } // Only NotificationRecord's mChannel is updated when bundled, the Notification // mChannelId will always be the original channel. String origChannelId = r.getNotification().getChannelId(); NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( r.getSbn().getPackageName(), r.getUid(), origChannelId, false); String currChannelId = r.getChannel().getId(); boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) { r.updateNotificationChannel(originalChannel); mGroupHelper.onNotificationUnbundled(r, GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey)); } private void applyNotificationUpdateForUserAndType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered( (r) -> r.getUserId() == userId && r.getBundleType() == bundleType, notificationUpdate); } @VisibleForTesting Loading @@ -1956,7 +1918,7 @@ public class NotificationManagerService extends SystemService { if (r == null) { return; } unclassifyNotificationLocked(r); unclassifyNotificationLocked(r, true); } } Loading @@ -1974,50 +1936,36 @@ public class NotificationManagerService extends SystemService { } } private void reclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { return; } synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { reclassifyNotificationLocked(r, false); } } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { reclassifyNotificationLocked(r, true); } } } } private void reclassifyNotificationsForUserAndType(final int userId, final @Types int bundleType) { @GuardedBy("mNotificationLock") private void unclassifyNotificationLocked(@NonNull final NotificationRecord r, boolean isPosted) { if (DBG) { Slog.v(TAG, "reclassifyNotificationsForUserAndType userId: " + userId + " bundleType: " + bundleType); } reclassifyNotificationsFiltered( (r) -> r.getUserId() == userId && r.getBundleType() == bundleType); Slog.v(TAG, "unclassifyNotification: " + r); } private void reclassifyNotificationsForUid(final int userId, final String pkg) { if (DBG) { Slog.v(TAG, "reclassifyNotificationsForUid userId: " + userId + " pkg: " + pkg); // Only NotificationRecord's mChannel is updated when bundled, the Notification // mChannelId will always be the original channel. String origChannelId = r.getNotification().getChannelId(); NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( r.getSbn().getPackageName(), r.getUid(), origChannelId, false); String currChannelId = r.getChannel().getId(); boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) { r.updateNotificationChannel(originalChannel); mGroupHelper.onNotificationUnbundled(r, GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey)); } reclassifyNotificationsFiltered((r) -> r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg)); } private void reclassifyNotificationsForUser(final int userId) { if (DBG) { Slog.v(TAG, "reclassifyAllNotificationsForUser: " + userId); } reclassifyNotificationsFiltered((r) -> r.getUserId() == userId); @GuardedBy("mNotificationLock") private void unsummarizeNotificationLocked(@NonNull final NotificationRecord r, boolean isPosted) { Bundle signals = new Bundle(); signals.putString(KEY_SUMMARIZATION, null); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getSbn().getUserId()); r.addAdjustment(adjustment); mRankingHandler.requestSort(); } @GuardedBy("mNotificationLock") Loading @@ -2043,6 +1991,33 @@ public class NotificationManagerService extends SystemService { } } /** * Given a filter and a function to update a notification record, runs that function on all * enqueued and posted notifications that match the filter */ private void applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter, NotificationUpdate notificationUpdate) { synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { notificationUpdate.apply(r, false); } } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { notificationUpdate.apply(r, true); } } } } private interface NotificationUpdate { void apply(NotificationRecord r, boolean isPosted); } NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { @Nullable @Override Loading Loading @@ -4475,9 +4450,11 @@ public class NotificationManagerService extends SystemService { public void allowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.allowAdjustmentType(adjustmentType); int userId = UserHandle.getUserId(Binder.getCallingUid()); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (KEY_TYPE.equals(adjustmentType)) { reclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); applyNotificationUpdateForUser(userId, NotificationManagerService.this::reclassifyNotificationLocked); } } handleSavePolicyFile(); Loading @@ -4488,9 +4465,17 @@ public class NotificationManagerService extends SystemService { public void disallowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.disallowAdjustmentType(adjustmentType); int userId = UserHandle.getUserId(Binder.getCallingUid()); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (KEY_TYPE.equals(adjustmentType)) { unclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); applyNotificationUpdateForUser(userId, NotificationManagerService.this::unclassifyNotificationLocked); } } if (nmSummarizationUi() || nmSummarization()) { if (KEY_SUMMARIZATION.equals(adjustmentType)) { applyNotificationUpdateForUser(userId, NotificationManagerService.this::unsummarizeNotificationLocked); } } handleSavePolicyFile(); Loading Loading @@ -4539,11 +4524,13 @@ public class NotificationManagerService extends SystemService { mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (enabled) { reclassifyNotificationsForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type); applyNotificationUpdateForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type, NotificationManagerService.this::reclassifyNotificationLocked); } else { unclassifyNotificationsForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type); applyNotificationUpdateForUserAndChannelType( UserHandle.getUserId(Binder.getCallingUid()), type, NotificationManagerService.this::unclassifyNotificationLocked); } } handleSavePolicyFile(); Loading @@ -4569,11 +4556,17 @@ public class NotificationManagerService extends SystemService { if (notificationClassificationUi() && notificationRegroupOnClassification() && key.equals(KEY_TYPE)) { if (enabled) { reclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg); applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::reclassifyNotificationLocked); } else { unclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg); applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::unclassifyNotificationLocked); } } if (nmSummarization() || nmSummarizationUi()) { if (KEY_SUMMARIZATION.equals(key) && !enabled) { applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::unsummarizeNotificationLocked); } } handleSavePolicyFile(); Loading services/core/java/com/android/server/notification/NotificationRecord.java +1 −1 Original line number Diff line number Diff line Loading @@ -999,7 +999,7 @@ public final class NotificationRecord { return null; } public String getSummarization() { public @Nullable String getSummarization() { if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())) { return mSummarization; } Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +68 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; import static android.app.Flags.FLAG_NM_SUMMARIZATION; import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; import static android.app.Notification.EXTRA_PICTURE; Loading Loading @@ -105,6 +106,7 @@ import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS; import static android.service.notification.Adjustment.KEY_IMPORTANCE; import static android.service.notification.Adjustment.KEY_SUMMARIZATION; import static android.service.notification.Adjustment.KEY_TEXT_REPLIES; import static android.service.notification.Adjustment.KEY_TYPE; import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; Loading Loading @@ -18308,9 +18310,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Post some notifications and classify in different bundles final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); final int numNewsNotifications = 1; List<String> postedNotificationKeys = new ArrayList(); for (int i = 0; i < numNotifications; i++) { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); mService.addNotification(r); postedNotificationKeys.add(r.getKey()); Bundle signals = new Bundle(); final int adjustmentType = i + 1; signals.putInt(Adjustment.KEY_TYPE, adjustmentType); Loading @@ -18330,7 +18334,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); //Check that all notifications classified as TYPE_NEWS have been unbundled for (NotificationRecord record : mService.mNotificationList) { for (String key : postedNotificationKeys) { NotificationRecord record= mService.mNotificationsByKey.get(key); // Check that the original channel was restored // for notifications classified as TYPE_NEWS if (record.getBundleType() == TYPE_NEWS) { Loading @@ -18355,7 +18360,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Check that the bundle channel was restored verify(mRankingHandler, times(numNewsNotifications)).requestSort(); for (NotificationRecord record : mService.mNotificationList) { for (String key : postedNotificationKeys) { NotificationRecord record= mService.mNotificationsByKey.get(key); assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); } } Loading Loading @@ -18424,6 +18430,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags({FLAG_NM_SUMMARIZATION}) public void testDisableBundleAdjustmentByPkg_unsummarizesNotifications() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); mService.addNotification(r); Bundle signals = new Bundle(); signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); mBinderService.applyAdjustmentFromAssistant(null, adjustment); waitForIdle(); r.applyAdjustments(); Mockito.clearInvocations(mRankingHandler); // Disable summarization for package mBinderService.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, mPkg, false); verify(mRankingHandler).requestSort(); mService.handleRankingSort(); assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); } @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING, Loading Loading @@ -18626,6 +18662,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags({FLAG_NM_SUMMARIZATION}) public void testDisableBundleAdjustment_unsummarizesNotifications() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); mService.addNotification(r); Bundle signals = new Bundle(); signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); mBinderService.applyAdjustmentFromAssistant(null, adjustment); waitForIdle(); r.applyAdjustments(); Mockito.clearInvocations(mRankingHandler); // Disable summarization for package mBinderService.disallowAssistantAdjustment(KEY_SUMMARIZATION); verify(mRankingHandler).requestSort(); mService.handleRankingSort(); assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void clearAll_fromUser_willSendDeleteIntentForCachedSummaries() throws Exception { Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -135,11 +135,30 @@ class ConversationNotificationProcessorTest : SysuiTestCase() { .isNotNull() } @Test @EnableFlags(Flags.FLAG_NM_SUMMARIZATION) fun processNotification_messagingStyleUpdateSummarizationToNull() { val nb = getMessagingNotification() val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build()) newRow.entry.setRanking( RankingBuilder(newRow.entry.ranking).setSummarization("hello").build() ) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() newRow.entry.setRanking(RankingBuilder(newRow.entry.ranking).setSummarization(null).build()) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull() } @Test @EnableFlags(Flags.FLAG_NM_SUMMARIZATION) fun processNotification_messagingStyleWithoutSummarization() { val nb = getMessagingNotification() val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build()) assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger)) .isNotNull() assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull() Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +35 −32 Original line number Diff line number Diff line Loading @@ -71,14 +71,14 @@ constructor( Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT else if (entry.ranking.isConversation) Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL else Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY else Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY entry.ranking.conversationShortcutInfo?.let { shortcutInfo -> logger.logAsyncTaskProgress(entry.logKey, "getting shortcut icon") messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo) shortcutInfo.label?.let { label -> messagingStyle.conversationTitle = label } } if (NmSummarizationUiFlag.isEnabled && !TextUtils.isEmpty(entry.ranking.summarization)) { if (NmSummarizationUiFlag.isEnabled) { if (!TextUtils.isEmpty(entry.ranking.summarization)) { val icon = context.getDrawable(R.drawable.ic_notification_summarization)?.mutate() val imageSpan = icon?.let { Loading Loading @@ -111,6 +111,9 @@ constructor( EXTRA_SUMMARIZED_CONTENT, decoratedSummary, ) } else { entry.sbn.notification.extras.putCharSequence(EXTRA_SUMMARIZED_CONTENT, null) } } messagingStyle.unreadMessageCount = Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +100 −107 Original line number Diff line number Diff line Loading @@ -1877,73 +1877,35 @@ public class NotificationManagerService extends SystemService { } }; private void unclassifyNotificationsForUser(final int userId) { if (DBG) { Slog.v(TAG, "unclassifyForUser: " + userId); } unclassifyNotificationsFiltered((r) -> r.getUserId() == userId); private void applyNotificationUpdateForUser(final int userId, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId, notificationUpdate); } private void unclassifyNotificationsForUid(final int userId, @NonNull final String pkg) { if (DBG) { Slog.v(TAG, "unclassifyForUid userId: " + userId + " pkg: " + pkg); } unclassifyNotificationsFiltered((r) -> private void applyNotificationUpdateForUid(final int userId, @NonNull final String pkg, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg)); && Objects.equals(r.getSbn().getPackageName(), pkg), notificationUpdate); } private void unclassifyNotificationsForUserAndType(final int userId, final @Types int bundleType) { if (DBG) { Slog.v(TAG, "unclassifyForUserAndType userId: " + userId + " bundleType: " + bundleType); } private void applyNotificationUpdateForUserAndChannelType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate) { final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType); unclassifyNotificationsFiltered((r) -> applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId && r.getChannel() != null && Objects.equals(bundleChannelId, r.getChannel().getId())); } private void unclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { return; } synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { unclassifyNotificationLocked(r); } && Objects.equals(bundleChannelId, r.getChannel().getId()), notificationUpdate); } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { unclassifyNotificationLocked(r); } } } } @GuardedBy("mNotificationLock") private void unclassifyNotificationLocked(@NonNull final NotificationRecord r) { if (DBG) { Slog.v(TAG, "unclassifyNotification: " + r); } // Only NotificationRecord's mChannel is updated when bundled, the Notification // mChannelId will always be the original channel. String origChannelId = r.getNotification().getChannelId(); NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( r.getSbn().getPackageName(), r.getUid(), origChannelId, false); String currChannelId = r.getChannel().getId(); boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) { r.updateNotificationChannel(originalChannel); mGroupHelper.onNotificationUnbundled(r, GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey)); } private void applyNotificationUpdateForUserAndType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate) { applyUpdateForNotificationsFiltered( (r) -> r.getUserId() == userId && r.getBundleType() == bundleType, notificationUpdate); } @VisibleForTesting Loading @@ -1956,7 +1918,7 @@ public class NotificationManagerService extends SystemService { if (r == null) { return; } unclassifyNotificationLocked(r); unclassifyNotificationLocked(r, true); } } Loading @@ -1974,50 +1936,36 @@ public class NotificationManagerService extends SystemService { } } private void reclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { return; } synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { reclassifyNotificationLocked(r, false); } } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { reclassifyNotificationLocked(r, true); } } } } private void reclassifyNotificationsForUserAndType(final int userId, final @Types int bundleType) { @GuardedBy("mNotificationLock") private void unclassifyNotificationLocked(@NonNull final NotificationRecord r, boolean isPosted) { if (DBG) { Slog.v(TAG, "reclassifyNotificationsForUserAndType userId: " + userId + " bundleType: " + bundleType); } reclassifyNotificationsFiltered( (r) -> r.getUserId() == userId && r.getBundleType() == bundleType); Slog.v(TAG, "unclassifyNotification: " + r); } private void reclassifyNotificationsForUid(final int userId, final String pkg) { if (DBG) { Slog.v(TAG, "reclassifyNotificationsForUid userId: " + userId + " pkg: " + pkg); // Only NotificationRecord's mChannel is updated when bundled, the Notification // mChannelId will always be the original channel. String origChannelId = r.getNotification().getChannelId(); NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( r.getSbn().getPackageName(), r.getUid(), origChannelId, false); String currChannelId = r.getChannel().getId(); boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) { r.updateNotificationChannel(originalChannel); mGroupHelper.onNotificationUnbundled(r, GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey)); } reclassifyNotificationsFiltered((r) -> r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg)); } private void reclassifyNotificationsForUser(final int userId) { if (DBG) { Slog.v(TAG, "reclassifyAllNotificationsForUser: " + userId); } reclassifyNotificationsFiltered((r) -> r.getUserId() == userId); @GuardedBy("mNotificationLock") private void unsummarizeNotificationLocked(@NonNull final NotificationRecord r, boolean isPosted) { Bundle signals = new Bundle(); signals.putString(KEY_SUMMARIZATION, null); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getSbn().getUserId()); r.addAdjustment(adjustment); mRankingHandler.requestSort(); } @GuardedBy("mNotificationLock") Loading @@ -2043,6 +1991,33 @@ public class NotificationManagerService extends SystemService { } } /** * Given a filter and a function to update a notification record, runs that function on all * enqueued and posted notifications that match the filter */ private void applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter, NotificationUpdate notificationUpdate) { synchronized (mNotificationLock) { for (int i = 0; i < mEnqueuedNotifications.size(); i++) { final NotificationRecord r = mEnqueuedNotifications.get(i); if (filter.test(r)) { notificationUpdate.apply(r, false); } } for (int i = 0; i < mNotificationList.size(); i++) { final NotificationRecord r = mNotificationList.get(i); if (filter.test(r)) { notificationUpdate.apply(r, true); } } } } private interface NotificationUpdate { void apply(NotificationRecord r, boolean isPosted); } NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { @Nullable @Override Loading Loading @@ -4475,9 +4450,11 @@ public class NotificationManagerService extends SystemService { public void allowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.allowAdjustmentType(adjustmentType); int userId = UserHandle.getUserId(Binder.getCallingUid()); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (KEY_TYPE.equals(adjustmentType)) { reclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); applyNotificationUpdateForUser(userId, NotificationManagerService.this::reclassifyNotificationLocked); } } handleSavePolicyFile(); Loading @@ -4488,9 +4465,17 @@ public class NotificationManagerService extends SystemService { public void disallowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.disallowAdjustmentType(adjustmentType); int userId = UserHandle.getUserId(Binder.getCallingUid()); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (KEY_TYPE.equals(adjustmentType)) { unclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); applyNotificationUpdateForUser(userId, NotificationManagerService.this::unclassifyNotificationLocked); } } if (nmSummarizationUi() || nmSummarization()) { if (KEY_SUMMARIZATION.equals(adjustmentType)) { applyNotificationUpdateForUser(userId, NotificationManagerService.this::unsummarizeNotificationLocked); } } handleSavePolicyFile(); Loading Loading @@ -4539,11 +4524,13 @@ public class NotificationManagerService extends SystemService { mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled); if ((notificationClassificationUi() && notificationRegroupOnClassification())) { if (enabled) { reclassifyNotificationsForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type); applyNotificationUpdateForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type, NotificationManagerService.this::reclassifyNotificationLocked); } else { unclassifyNotificationsForUserAndType( UserHandle.getUserId(Binder.getCallingUid()), type); applyNotificationUpdateForUserAndChannelType( UserHandle.getUserId(Binder.getCallingUid()), type, NotificationManagerService.this::unclassifyNotificationLocked); } } handleSavePolicyFile(); Loading @@ -4569,11 +4556,17 @@ public class NotificationManagerService extends SystemService { if (notificationClassificationUi() && notificationRegroupOnClassification() && key.equals(KEY_TYPE)) { if (enabled) { reclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg); applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::reclassifyNotificationLocked); } else { unclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg); applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::unclassifyNotificationLocked); } } if (nmSummarization() || nmSummarizationUi()) { if (KEY_SUMMARIZATION.equals(key) && !enabled) { applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), pkg, NotificationManagerService.this::unsummarizeNotificationLocked); } } handleSavePolicyFile(); Loading
services/core/java/com/android/server/notification/NotificationRecord.java +1 −1 Original line number Diff line number Diff line Loading @@ -999,7 +999,7 @@ public final class NotificationRecord { return null; } public String getSummarization() { public @Nullable String getSummarization() { if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())) { return mSummarization; } Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +68 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; import static android.app.Flags.FLAG_NM_SUMMARIZATION; import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; import static android.app.Notification.EXTRA_PICTURE; Loading Loading @@ -105,6 +106,7 @@ import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS; import static android.service.notification.Adjustment.KEY_IMPORTANCE; import static android.service.notification.Adjustment.KEY_SUMMARIZATION; import static android.service.notification.Adjustment.KEY_TEXT_REPLIES; import static android.service.notification.Adjustment.KEY_TYPE; import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; Loading Loading @@ -18308,9 +18310,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Post some notifications and classify in different bundles final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); final int numNewsNotifications = 1; List<String> postedNotificationKeys = new ArrayList(); for (int i = 0; i < numNotifications; i++) { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); mService.addNotification(r); postedNotificationKeys.add(r.getKey()); Bundle signals = new Bundle(); final int adjustmentType = i + 1; signals.putInt(Adjustment.KEY_TYPE, adjustmentType); Loading @@ -18330,7 +18334,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); //Check that all notifications classified as TYPE_NEWS have been unbundled for (NotificationRecord record : mService.mNotificationList) { for (String key : postedNotificationKeys) { NotificationRecord record= mService.mNotificationsByKey.get(key); // Check that the original channel was restored // for notifications classified as TYPE_NEWS if (record.getBundleType() == TYPE_NEWS) { Loading @@ -18355,7 +18360,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Check that the bundle channel was restored verify(mRankingHandler, times(numNewsNotifications)).requestSort(); for (NotificationRecord record : mService.mNotificationList) { for (String key : postedNotificationKeys) { NotificationRecord record= mService.mNotificationsByKey.get(key); assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); } } Loading Loading @@ -18424,6 +18430,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags({FLAG_NM_SUMMARIZATION}) public void testDisableBundleAdjustmentByPkg_unsummarizesNotifications() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); mService.addNotification(r); Bundle signals = new Bundle(); signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); mBinderService.applyAdjustmentFromAssistant(null, adjustment); waitForIdle(); r.applyAdjustments(); Mockito.clearInvocations(mRankingHandler); // Disable summarization for package mBinderService.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, mPkg, false); verify(mRankingHandler).requestSort(); mService.handleRankingSort(); assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); } @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING, Loading Loading @@ -18626,6 +18662,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags({FLAG_NM_SUMMARIZATION}) public void testDisableBundleAdjustment_unsummarizesNotifications() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); mService.addNotification(r); Bundle signals = new Bundle(); signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); mBinderService.applyAdjustmentFromAssistant(null, adjustment); waitForIdle(); r.applyAdjustments(); Mockito.clearInvocations(mRankingHandler); // Disable summarization for package mBinderService.disallowAssistantAdjustment(KEY_SUMMARIZATION); verify(mRankingHandler).requestSort(); mService.handleRankingSort(); assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); } @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void clearAll_fromUser_willSendDeleteIntentForCachedSummaries() throws Exception {