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

Commit 31f0c479 authored by Yuri Lin's avatar Yuri Lin
Browse files

Re-sort notifications when their bundle classification is removed

The channel reassignment for unclassifying notifications needs to happen as part of signal extraction in order to trigger a re-sorting of the notification list. Otherwise, the notification list reordering would only happen after another notification comes in.

Flag: android.app.notification_classification_ui
Bug: 406491771
Test: NotificationManagerServiceTest, NotificationAdjustmentExtractorTest
Change-Id: Id313bdc0109255bbbbfd65217314eb33cac1d4c5
parent 5ba7eda2
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Notification;
import android.app.Notification;
import android.os.Build;
import android.os.Build;
import android.os.Bundle;
import android.os.Bundle;
@@ -67,6 +66,7 @@ public final class Adjustment implements Parcelable {
            KEY_RANKING_SCORE,
            KEY_RANKING_SCORE,
            KEY_NOT_CONVERSATION,
            KEY_NOT_CONVERSATION,
            KEY_TYPE,
            KEY_TYPE,
            KEY_UNCLASSIFY,
            KEY_SUMMARIZATION
            KEY_SUMMARIZATION
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
@@ -224,6 +224,14 @@ public final class Adjustment implements Parcelable {
    @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
    @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
    public static final int TYPE_CONTENT_RECOMMENDATION = 4;
    public static final int TYPE_CONTENT_RECOMMENDATION = 4;


    /**
     * Data type: NotificationChannel; the presence of this key indicates that the notification
     * classification should be removed and the channel reverted to its original channel (provided).
     * @hide
     */
    @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
    public static final String KEY_UNCLASSIFY = "key_unclassify";

    /**
    /**
     * Data type: CharSequence, a summarization of the text of the notification, or, if provided for
     * Data type: CharSequence, a summarization of the text of the notification, or, if provided for
     * a group summary, a summarization of the text of all of the notificatrions in the group.
     * a group summary, a summarization of the text of all of the notificatrions in the group.
+13 −2
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.server.notification;
package com.android.server.notification;


import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_UNCLASSIFY;
import static android.service.notification.Flags.notificationForceGrouping;
import static android.service.notification.Flags.notificationForceGrouping;


import android.content.Context;
import android.content.Context;
@@ -41,12 +42,13 @@ public class NotificationAdjustmentExtractor implements NotificationSignalExtrac
        }
        }


        final boolean hasAdjustedClassification = record.hasAdjustment(KEY_TYPE);
        final boolean hasAdjustedClassification = record.hasAdjustment(KEY_TYPE);
        final boolean removedClassification = record.hasAdjustment(KEY_UNCLASSIFY);
        record.applyAdjustments();
        record.applyAdjustments();


        if (notificationForceGrouping()
        if (notificationForceGrouping()
                && android.service.notification.Flags.notificationClassification()) {
                && android.service.notification.Flags.notificationClassification()) {
            // Classification adjustments trigger regrouping
            // Classification adjustments trigger regrouping
            if (mGroupHelper != null && hasAdjustedClassification) {
            if (mGroupHelper != null && (hasAdjustedClassification || removedClassification)) {
                return new RankingReconsideration(record.getKey(), 0) {
                return new RankingReconsideration(record.getKey(), 0) {
                    @Override
                    @Override
                    public void work() {
                    public void work() {
@@ -54,8 +56,17 @@ public class NotificationAdjustmentExtractor implements NotificationSignalExtrac


                    @Override
                    @Override
                    public void applyChangesLocked(NotificationRecord record) {
                    public void applyChangesLocked(NotificationRecord record) {
                        if (hasAdjustedClassification) {
                            mGroupHelper.onChannelUpdated(record);
                            mGroupHelper.onChannelUpdated(record);
                        }
                        }
                        if (removedClassification) {
                            mGroupHelper.onNotificationUnbundled(record,
                                    record.hadGroupSummaryWhenUnclassified());

                            // clear this bit now that we're done reading it
                            record.setHadGroupSummaryWhenUnclassified(false);
                        }
                    }
                };
                };
            }
            }
        }
        }
+8 −2
Original line number Original line Diff line number Diff line
@@ -109,6 +109,7 @@ import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_UNCLASSIFY;
import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
import static android.service.notification.Adjustment.TYPE_NEWS;
import static android.service.notification.Adjustment.TYPE_NEWS;
import static android.service.notification.Adjustment.TYPE_PROMOTION;
import static android.service.notification.Adjustment.TYPE_PROMOTION;
@@ -1950,9 +1951,14 @@ public class NotificationManagerService extends SystemService {
        String currChannelId = r.getChannel().getId();
        String currChannelId = r.getChannel().getId();
        boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
        boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
        if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) {
        if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) {
            r.updateNotificationChannel(originalChannel);
            final Bundle signals = new Bundle();
            mGroupHelper.onNotificationUnbundled(r,
            signals.putParcelable(KEY_UNCLASSIFY, originalChannel);
            Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
                    "unclassify", r.getSbn().getUserId());
            r.addAdjustment(adjustment);
            r.setHadGroupSummaryWhenUnclassified(
                    GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey));
                    GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey));
            mRankingHandler.requestSort();
        }
        }
    }
    }
+26 −7
Original line number Original line Diff line number Diff line
@@ -232,6 +232,10 @@ public final class NotificationRecord {


    private String mSummarization = null;
    private String mSummarization = null;


    // If this notification was unclassified, whether the notification's original group summary
    // was present at the time of unclassification.
    private boolean mHadGroupSummaryWhenUnclassified = false;

    public NotificationRecord(Context context, StatusBarNotification sbn,
    public NotificationRecord(Context context, StatusBarNotification sbn,
            NotificationChannel channel) {
            NotificationChannel channel) {
        this.sbn = sbn;
        this.sbn = sbn;
@@ -807,14 +811,21 @@ public final class NotificationRecord {
                            Adjustment.KEY_SENSITIVE_CONTENT,
                            Adjustment.KEY_SENSITIVE_CONTENT,
                            Boolean.toString(mSensitiveContent));
                            Boolean.toString(mSensitiveContent));
                }
                }
                if (android.service.notification.Flags.notificationClassification()
                if (android.service.notification.Flags.notificationClassification()) {
                        && signals.containsKey(Adjustment.KEY_TYPE)) {
                    if (signals.containsKey(Adjustment.KEY_TYPE)) {
                        updateNotificationChannel(signals.getParcelable(Adjustment.KEY_TYPE,
                        updateNotificationChannel(signals.getParcelable(Adjustment.KEY_TYPE,
                                NotificationChannel.class));
                                NotificationChannel.class));
                        EventLogTags.writeNotificationAdjusted(getKey(),
                        EventLogTags.writeNotificationAdjusted(getKey(),
                                Adjustment.KEY_TYPE,
                                Adjustment.KEY_TYPE,
                                mChannel.getId());
                                mChannel.getId());
                    }
                    }
                    if (signals.containsKey(Adjustment.KEY_UNCLASSIFY)) {
                        updateNotificationChannel(signals.getParcelable(Adjustment.KEY_UNCLASSIFY,
                                NotificationChannel.class));
                        EventLogTags.writeNotificationAdjusted(getKey(),
                                Adjustment.KEY_UNCLASSIFY, mChannel.getId());
                    }
                }
                if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())
                if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())
                        && signals.containsKey(KEY_SUMMARIZATION)) {
                        && signals.containsKey(KEY_SUMMARIZATION)) {
                    CharSequence summary = signals.getCharSequence(KEY_SUMMARIZATION,
                    CharSequence summary = signals.getCharSequence(KEY_SUMMARIZATION,
@@ -1675,6 +1686,14 @@ public final class NotificationRecord {
        mBundleType = bundleType;
        mBundleType = bundleType;
    }
    }


    public boolean hadGroupSummaryWhenUnclassified() {
        return mHadGroupSummaryWhenUnclassified;
    }

    public void setHadGroupSummaryWhenUnclassified(boolean exists) {
        mHadGroupSummaryWhenUnclassified = exists;
    }

    /**
    /**
     * Whether this notification is a conversation notification.
     * Whether this notification is a conversation notification.
     */
     */
+29 −1
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.server.notification;
package com.android.server.notification;


import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_LOW;

import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
@@ -148,6 +147,35 @@ public class NotificationAdjustmentExtractorTest extends UiServiceTestCase {
        verify(groupHelper, times(1)).onChannelUpdated(r);
        verify(groupHelper, times(1)).onChannelUpdated(r);
    }
    }


    @Test
    @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING})
    public void testClassificationAdjustments_unclassifyTriggersUnbundling() {
        GroupHelper groupHelper = mock(GroupHelper.class);
        NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor();
        extractor.setGroupHelper(groupHelper);

        NotificationRecord r = generateRecord();
        r.setHadGroupSummaryWhenUnclassified(true);

        Bundle classificationAdj = new Bundle();
        classificationAdj.putParcelable(Adjustment.KEY_UNCLASSIFY, mock(NotificationChannel.class));
        Adjustment adjustment = new Adjustment("pkg", r.getKey(), classificationAdj, "", 0);
        r.addAdjustment(adjustment);

        RankingReconsideration regroupingTask = extractor.process(r);
        assertThat(regroupingTask).isNotNull();
        regroupingTask.applyChangesLocked(r);
        verify(groupHelper, times(1)).onNotificationUnbundled(r, true);

        // make sure that the group summary boolean is passed through correctly
        r.setHadGroupSummaryWhenUnclassified(false);
        r.addAdjustment(adjustment);
        RankingReconsideration regroupingTask2 = extractor.process(r);
        assertThat(regroupingTask2).isNotNull();
        regroupingTask2.applyChangesLocked(r);
        verify(groupHelper, times(1)).onNotificationUnbundled(r, false);
    }

    @Test
    @Test
    @DisableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING})
    @DisableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING})
    public void testClassificationAdjustments_notTriggerRegrouping_flagsDisabled() {
    public void testClassificationAdjustments_notTriggerRegrouping_flagsDisabled() {
Loading