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

Commit 405e0b70 authored by Lyn Han's avatar Lyn Han Committed by Julia Reynolds
Browse files

Dedup smart reply updates for bubble flyout

Smart reply updates are not visually interruptive and bubbles should not
show flyout for them, since flyout text remains the same.

1) Modify NoMan.isVisuallyInterruptive to skip evaluation of fields
irrelevant to bubbles

2) Modify NotificationComparator to rank interruptive notifs higher

3) Pipe bool (isInterruptive) from system_process to SysUI
	NoMan --- set bool on notif record and ranking
	Ranking --- parcel bool for cross-process transport
	SysUI notif entry --- get bool from ranking
	SysUI bubble data --- on notif entry update, suppress flyout if isInterruptive=false

	Considered adding "isInterruptive" bool to StatusBarNotification.
	Did not because "visually-interruptive" is additional information that the
	system figured out and SBNs should be limited to info from the app.

4) NoMan --- schedule ranking update if interruptive changes for bubble

Fixes: 138755533
Test: manual - send one sms => flyout appears once
Test: manual - send multiple sms in a row => flyout appears for each one
Test: atest FrameworksUiServicesTests
Test: atest NotificationComparatorTest
Test: atest SystemUITests
Change-Id: Id4b855054689ee73a109bb7cd18004531b41f28c
(cherry picked from commit 0dddc61824d091e48962e36939828cae3cde2aa9)
parent 1d35b3cd
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -1522,6 +1522,7 @@ public abstract class NotificationListenerService extends Service {
        private ArrayList<Notification.Action> mSmartActions;
        private ArrayList<CharSequence> mSmartReplies;
        private boolean mCanBubble;
        private boolean mVisuallyInterruptive;

        private static final int PARCEL_VERSION = 2;

@@ -1553,6 +1554,7 @@ public abstract class NotificationListenerService extends Service {
            out.writeTypedList(mSmartActions, flags);
            out.writeCharSequenceList(mSmartReplies);
            out.writeBoolean(mCanBubble);
            out.writeBoolean(mVisuallyInterruptive);
        }

        /** @hide */
@@ -1585,6 +1587,7 @@ public abstract class NotificationListenerService extends Service {
            mSmartActions = in.createTypedArrayList(Notification.Action.CREATOR);
            mSmartReplies = in.readCharSequenceList();
            mCanBubble = in.readBoolean();
            mVisuallyInterruptive = in.readBoolean();
        }


@@ -1771,6 +1774,11 @@ public abstract class NotificationListenerService extends Service {
            return mCanBubble;
        }

        /** @hide */
        public boolean visuallyInterruptive() {
            return mVisuallyInterruptive;
        }

        /** @hide */
        public boolean isNoisy() {
            return mNoisy;
@@ -1787,7 +1795,8 @@ public abstract class NotificationListenerService extends Service {
                ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
                int userSentiment, boolean hidden, long lastAudiblyAlertedMs,
                boolean noisy, ArrayList<Notification.Action> smartActions,
                ArrayList<CharSequence> smartReplies, boolean canBubble) {
                ArrayList<CharSequence> smartReplies, boolean canBubble,
                boolean visuallyInterruptive) {
            mKey = key;
            mRank = rank;
            mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1808,6 +1817,7 @@ public abstract class NotificationListenerService extends Service {
            mSmartActions = smartActions;
            mSmartReplies = smartReplies;
            mCanBubble = canBubble;
            mVisuallyInterruptive = visuallyInterruptive;
        }

        /**
@@ -1832,7 +1842,8 @@ public abstract class NotificationListenerService extends Service {
                    other.mNoisy,
                    other.mSmartActions,
                    other.mSmartReplies,
                    other.mCanBubble);
                    other.mCanBubble,
                    other.mVisuallyInterruptive);
        }

        /**
+4 −0
Original line number Diff line number Diff line
@@ -184,6 +184,8 @@ public class BubbleData {
            Log.d(TAG, "notificationEntryUpdated: " + entry);
        }
        Bubble bubble = getBubbleWithKey(entry.key);
        suppressFlyout = !entry.isVisuallyInterruptive || suppressFlyout;

        if (bubble == null) {
            // Create a new bubble
            bubble = new Bubble(mContext, entry);
@@ -193,8 +195,10 @@ public class BubbleData {
        } else {
            // Updates an existing bubble
            bubble.updateEntry(entry);
            bubble.setSuppressFlyout(suppressFlyout);
            doUpdate(bubble);
        }

        if (bubble.shouldAutoExpand()) {
            setSelectedBubbleInternal(bubble);
            if (!mExpanded) {
+8 −0
Original line number Diff line number Diff line
@@ -140,6 +140,12 @@ public final class NotificationEntry {
     */
    private boolean hasSentReply;

    /**
     * Whether this notification has changed in visual appearance since the previous post.
     * New notifications are interruptive by default.
     */
    public boolean isVisuallyInterruptive;

    /**
     * Whether this notification is shown to the user as a high priority notification: visible on
     * the lock screen/status bar and in the top section in the shade.
@@ -205,6 +211,7 @@ public final class NotificationEntry {
                    + " doesn't match existing key " + key);
        }
        mRanking = ranking;
        isVisuallyInterruptive = ranking.visuallyInterruptive();
    }

    public NotificationChannel getChannel() {
@@ -244,6 +251,7 @@ public final class NotificationEntry {
        return mRanking.canBubble();
    }


    public @NonNull List<Notification.Action> getSmartActions() {
        return mRanking.getSmartActions();
    }
+3 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ public class RankingBuilder {
    private ArrayList<Notification.Action> mSmartActions = new ArrayList<>();
    private ArrayList<CharSequence> mSmartReplies = new ArrayList<>();
    private boolean mCanBubble = false;
    private boolean mIsVisuallyInterruptive = false;

    public RankingBuilder() {
    }
@@ -98,7 +99,8 @@ public class RankingBuilder {
                mNoisy,
                mSmartActions,
                mSmartReplies,
                mCanBubble);
                mCanBubble,
                mIsVisuallyInterruptive);
        return ranking;
    }

+2 −2
Original line number Diff line number Diff line
@@ -183,7 +183,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
                    0,
                    NotificationManager.IMPORTANCE_DEFAULT,
                    null, null,
                    null, null, null, true, sentiment, false, -1, false, null, null, false);
                    null, null, null, true, sentiment, false, -1, false, null, null, false, false);
            return true;
        }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
    }
@@ -202,7 +202,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
                    null, null,
                    null, null, null, true,
                    NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
                    false, smartActions, null, false);
                    false, smartActions, null, false, false);
            return true;
        }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
    }
Loading