Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7842a51 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Unsummarize notifications when feature is turned off" into main

parents aea36dea 3d898423
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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()
+35 −32
Original line number Diff line number Diff line
@@ -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 {
@@ -111,6 +111,9 @@ constructor(
                    EXTRA_SUMMARIZED_CONTENT,
                    decoratedSummary,
                )
            } else {
                entry.sbn.notification.extras.putCharSequence(EXTRA_SUMMARIZED_CONTENT, null)
            }
        }

        messagingStyle.unreadMessageCount =
+100 −107
Original line number Diff line number Diff line
@@ -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
@@ -1956,7 +1918,7 @@ public class NotificationManagerService extends SystemService {
            if (r == null) {
                return;
            }
            unclassifyNotificationLocked(r);
            unclassifyNotificationLocked(r, true);
        }
    }
@@ -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")
@@ -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
@@ -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();
@@ -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();
@@ -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();
@@ -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();
+1 −1
Original line number Diff line number Diff line
@@ -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;
        }
+68 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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) {
@@ -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);
        }
    }
@@ -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,
@@ -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 {