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

Commit 3acc32fb authored by Mady Mellor's avatar Mady Mellor
Browse files

Include bubble changes in ranking & move flagging to BubbleExtractor

Previously, only changes to the "allowBubbles" on the channel or
package would trigger a ranking change. This bit only indicates that
the notification is allowed to bubble -- it doesn't indicate that
the notification *is* a bubble. To allow active notifications to
become bubbles if the user changes the setting, we need to
flag them in response to ranking changes.

This CL moves the bubble flagging code into BubbleExtractor that
way the flag is always updated during ranking changes.

BubbleController listens to ranking changes and adds / removes bubbles
based on the ranking. The ranking needs to have an isBubble bit on
it because ranking changes won't pipe flag updates through. SysUI
uses this bit to flag the entry on SysUI's side.

Moves the shortcut getting / validating code into a helper class.

Also removes the inline reply requirement.

Test: NotificationManagerTest NotificationManagerServiceTest BubbleExtractorTest ShortcutHelperTest BubbleCheckerTest
Bug: 149736441
Change-Id: Ib5b62923c123187ae5f7073ec7ca50d7e20c04b1
parent 0054c04f
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.widget.RemoteViews;

import com.android.internal.annotations.GuardedBy;
@@ -1594,6 +1593,7 @@ public abstract class NotificationListenerService extends Service {
        private boolean mIsConversation;
        private ShortcutInfo mShortcutInfo;
        private @RankingAdjustment int mRankingAdjustment;
        private boolean mIsBubble;

        private static final int PARCEL_VERSION = 2;

@@ -1629,6 +1629,7 @@ public abstract class NotificationListenerService extends Service {
            out.writeBoolean(mIsConversation);
            out.writeParcelable(mShortcutInfo, flags);
            out.writeInt(mRankingAdjustment);
            out.writeBoolean(mIsBubble);
        }

        /** @hide */
@@ -1665,6 +1666,7 @@ public abstract class NotificationListenerService extends Service {
            mIsConversation = in.readBoolean();
            mShortcutInfo = in.readParcelable(cl);
            mRankingAdjustment = in.readInt();
            mIsBubble = in.readBoolean();
        }


@@ -1869,6 +1871,14 @@ public abstract class NotificationListenerService extends Service {
            return mIsConversation;
        }

        /**
         * Returns whether this notification is actively a bubble.
         * @hide
         */
        public boolean isBubble() {
            return mIsBubble;
        }

        /**
         * @hide
         */
@@ -1897,7 +1907,7 @@ public abstract class NotificationListenerService extends Service {
                boolean noisy, ArrayList<Notification.Action> smartActions,
                ArrayList<CharSequence> smartReplies, boolean canBubble,
                boolean visuallyInterruptive, boolean isConversation, ShortcutInfo shortcutInfo,
                int rankingAdjustment) {
                int rankingAdjustment, boolean isBubble) {
            mKey = key;
            mRank = rank;
            mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1922,6 +1932,7 @@ public abstract class NotificationListenerService extends Service {
            mIsConversation = isConversation;
            mShortcutInfo = shortcutInfo;
            mRankingAdjustment = rankingAdjustment;
            mIsBubble = isBubble;
        }

        /**
@@ -1950,7 +1961,8 @@ public abstract class NotificationListenerService extends Service {
                    other.mVisuallyInterruptive,
                    other.mIsConversation,
                    other.mShortcutInfo,
                    other.mRankingAdjustment);
                    other.mRankingAdjustment,
                    other.mIsBubble);
        }

        /**
@@ -2008,7 +2020,8 @@ public abstract class NotificationListenerService extends Service {
                    // Shortcutinfo doesn't have equals either; use id
                    &&  Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()),
                    (other.mShortcutInfo == null ? 0 : other.mShortcutInfo.getId()))
                    && Objects.equals(mRankingAdjustment, other.mRankingAdjustment);
                    && Objects.equals(mRankingAdjustment, other.mRankingAdjustment)
                    && Objects.equals(mIsBubble, other.mIsBubble);
        }
    }

+26 −4
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
@@ -146,13 +147,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    private BubbleData mBubbleData;
    @Nullable private BubbleStackView mStackView;
    private BubbleIconFactory mBubbleIconFactory;
    private int mMaxBubbles;

    // Tracks the id of the current (foreground) user.
    private int mCurrentUserId;
    // Saves notification keys of active bubbles when users are switched.
    private final SparseSetArray<String> mSavedBubbleKeysPerUser;

    // Used when ranking updates occur and we check if things should bubble / unbubble
    private NotificationListenerService.Ranking mTmpRanking;

    // Saves notification keys of user created "fake" bubbles so that we can allow notifications
    // like these to bubble by default. Doesn't persist across reboots, not a long-term solution.
    private final HashSet<String> mUserCreatedBubbles;
@@ -338,7 +341,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

        configurationController.addCallback(this /* configurationListener */);

        mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
        mBubbleData = data;
        mBubbleData.setListener(mBubbleDataListener);
        mBubbleData.setSuppressionChangedListener(new NotificationSuppressionChangedListener() {
@@ -939,9 +941,29 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        }
    }

    /**
     * Called when NotificationListener has received adjusted notification rank and reapplied
     * filtering and sorting. This is used to dismiss or create bubbles based on changes in
     * permissions on the notification channel or the global setting.
     *
     * @param rankingMap the updated ranking map from NotificationListenerService
     */
    private void onRankingUpdated(RankingMap rankingMap) {
        // Forward to BubbleData to block any bubbles which should no longer be shown
        mBubbleData.notificationRankingUpdated(rankingMap);
        if (mTmpRanking == null) {
            mTmpRanking = new NotificationListenerService.Ranking();
        }
        String[] orderedKeys = rankingMap.getOrderedKeys();
        for (int i = 0; i < orderedKeys.length; i++) {
            String key = orderedKeys[i];
            NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
            rankingMap.getRanking(key, mTmpRanking);
            if (mBubbleData.hasBubbleWithKey(key) && !mTmpRanking.canBubble()) {
                mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
            } else if (entry != null && mTmpRanking.isBubble()) {
                entry.setFlagBubble(true);
                onEntryUpdated(entry);
            }
        }
    }

    @SuppressWarnings("FieldCanBeLocal")
+0 −26
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.Log;
import android.util.Pair;

@@ -288,31 +287,6 @@ public class BubbleData {
        dispatchPendingChanges();
    }

    /**
     * Called when NotificationListener has received adjusted notification rank and reapplied
     * filtering and sorting. This is used to dismiss any bubbles which should no longer be shown
     * due to changes in permissions on the notification channel or the global setting.
     *
     * @param rankingMap the updated ranking map from NotificationListenerService
     */
    public void notificationRankingUpdated(RankingMap rankingMap) {
        if (mTmpRanking == null) {
            mTmpRanking = new NotificationListenerService.Ranking();
        }

        String[] orderedKeys = rankingMap.getOrderedKeys();
        for (int i = 0; i < orderedKeys.length; i++) {
            String key = orderedKeys[i];
            if (hasBubbleWithKey(key)) {
                rankingMap.getRanking(key, mTmpRanking);
                if (!mTmpRanking.canBubble()) {
                    doRemove(key, BubbleController.DISMISS_BLOCKED);
                }
            }
        }
        dispatchPendingChanges();
    }

    /**
     * Adds a group key indicating that the summary for this group should be suppressed.
     *
+2 −1
Original line number Diff line number Diff line
@@ -207,7 +207,8 @@ public class NotificationListener extends NotificationListenerWithPlugins {
                    false,
                    false,
                    null,
                    0
                    0,
                    false
            );
        }
        return ranking;
+4 −1
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ public class RankingBuilder {
    private boolean mIsConversation = false;
    private ShortcutInfo mShortcutInfo = null;
    private int mRankingAdjustment = 0;
    private boolean mIsBubble = false;

    public RankingBuilder() {
    }
@@ -84,6 +85,7 @@ public class RankingBuilder {
        mIsConversation = ranking.isConversation();
        mShortcutInfo = ranking.getShortcutInfo();
        mRankingAdjustment = ranking.getRankingAdjustment();
        mIsBubble = ranking.isBubble();
    }

    public Ranking build() {
@@ -111,7 +113,8 @@ public class RankingBuilder {
                mIsVisuallyInterruptive,
                mIsConversation,
                mShortcutInfo,
                mRankingAdjustment);
                mRankingAdjustment,
                mIsBubble);
        return ranking;
    }

Loading