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

Commit 5a3826be authored by Mark Renouf's avatar Mark Renouf Committed by android-build-merger
Browse files

Merge "Updates BubbleData sorting and grouping to spec" into qt-dev

am: d6cddfed

Change-Id: Id07b8330b9d85a81663ba8ba0154c01421deffab
parents a182f9c9 d6cddfed
Loading
Loading
Loading
Loading
+18 −1
Original line number Original line Diff line number Diff line
@@ -46,7 +46,7 @@ class Bubble {
    private long mLastUpdated;
    private long mLastUpdated;
    private long mLastAccessed;
    private long mLastAccessed;


    private static String groupId(NotificationEntry entry) {
    public static String groupId(NotificationEntry entry) {
        UserHandle user = entry.notification.getUser();
        UserHandle user = entry.notification.getUser();
        return user.getIdentifier() + "|" + entry.notification.getPackageName();
        return user.getIdentifier() + "|" + entry.notification.getPackageName();
    }
    }
@@ -120,10 +120,27 @@ class Bubble {
        }
        }
    }
    }


    /**
     * @return the newer of {@link #getLastUpdateTime()} and {@link #getLastAccessTime()}
     */
    public long getLastActivity() {
    public long getLastActivity() {
        return Math.max(mLastUpdated, mLastAccessed);
        return Math.max(mLastUpdated, mLastAccessed);
    }
    }


    /**
     * @return the timestamp in milliseconds of the most recent notification entry for this bubble
     */
    public long getLastUpdateTime() {
        return mLastUpdated;
    }

    /**
     * @return the timestamp in milliseconds when this bubble was last displayed in expanded state
     */
    public long getLastAccessTime() {
        return mLastAccessed;
    }

    /**
    /**
     * Should be invoked whenever a Bubble is accessed (selected while expanded).
     * Should be invoked whenever a Bubble is accessed (selected while expanded).
     */
     */
+9 −8
Original line number Original line Diff line number Diff line
@@ -29,6 +29,9 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;


import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import static java.lang.annotation.RetentionPolicy.SOURCE;


import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -73,6 +76,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController;


import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;
import java.util.List;


import javax.inject.Inject;
import javax.inject.Inject;
@@ -88,11 +92,12 @@ import javax.inject.Singleton;
public class BubbleController implements ConfigurationController.ConfigurationListener {
public class BubbleController implements ConfigurationController.ConfigurationListener {


    private static final String TAG = "BubbleController";
    private static final String TAG = "BubbleController";
    private static final boolean DEBUG = true;
    private static final boolean DEBUG = false;


    @Retention(SOURCE)
    @Retention(SOURCE)
    @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
    @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE})
            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE})
    @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
    @interface DismissReason {}
    @interface DismissReason {}


    static final int DISMISS_USER_GESTURE = 1;
    static final int DISMISS_USER_GESTURE = 1;
@@ -510,6 +515,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi


        @Override
        @Override
        public void onOrderChanged(List<Bubble> bubbles) {
        public void onOrderChanged(List<Bubble> bubbles) {
            if (mStackView != null) {
                mStackView.updateBubbleOrder(bubbles);
            }
        }
        }


        @Override
        @Override
@@ -526,13 +534,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            }
            }
        }
        }


        @Override
        public void showFlyoutText(Bubble bubble, String text) {
            if (mStackView != null) {
                mStackView.animateInFlyoutForBubble(bubble);
            }
        }

        @Override
        @Override
        public void apply() {
        public void apply() {
            mNotificationEntryManager.updateNotifications();
            mNotificationEntryManager.updateNotifications();
+193 −126
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Context;
import android.util.Log;
import android.util.Log;
import android.util.Pair;


import androidx.annotation.Nullable;
import androidx.annotation.Nullable;


@@ -53,10 +54,10 @@ public class BubbleData {


    private static final int MAX_BUBBLES = 5;
    private static final int MAX_BUBBLES = 5;


    private static final Comparator<Bubble> BUBBLES_BY_LAST_ACTIVITY_DESCENDING =
    private static final Comparator<Bubble> BUBBLES_BY_SORT_KEY_DESCENDING =
            Comparator.comparing(Bubble::getLastActivity).reversed();
            Comparator.comparing(BubbleData::sortKey).reversed();


    private static final Comparator<Map.Entry<String, Long>> GROUPS_BY_LAST_ACTIVITY_DESCENDING =
    private static final Comparator<Map.Entry<String, Long>> GROUPS_BY_MAX_SORT_KEY_DESCENDING =
            Comparator.<Map.Entry<String, Long>, Long>comparing(Map.Entry::getValue).reversed();
            Comparator.<Map.Entry<String, Long>, Long>comparing(Map.Entry::getValue).reversed();


    /**
    /**
@@ -105,9 +106,6 @@ public class BubbleData {
         */
         */
        void onExpandedChanged(boolean expanded);
        void onExpandedChanged(boolean expanded);


        /** Flyout text should animate in, showing the given text. */
        void showFlyoutText(Bubble bubble, String text);

        /** Commit any pending operations (since last call of apply()) */
        /** Commit any pending operations (since last call of apply()) */
        void apply();
        void apply();
    }
    }
@@ -121,15 +119,19 @@ public class BubbleData {
    private Bubble mSelectedBubble;
    private Bubble mSelectedBubble;
    private boolean mExpanded;
    private boolean mExpanded;


    // TODO: ensure this is invalidated at the appropriate time
    // State tracked during an operation -- keeps track of what listener events to dispatch.
    private int mSelectedBubbleExpandedPosition = -1;
    private boolean mExpandedChanged;
    private boolean mOrderChanged;
    private boolean mSelectionChanged;
    private Bubble mUpdatedBubble;
    private Bubble mAddedBubble;
    private final List<Pair<Bubble, Integer>> mRemovedBubbles = new ArrayList<>();


    private TimeSource mTimeSource = System::currentTimeMillis;
    private TimeSource mTimeSource = System::currentTimeMillis;


    @Nullable
    @Nullable
    private Listener mListener;
    private Listener mListener;


    @VisibleForTesting
    @Inject
    @Inject
    public BubbleData(Context context) {
    public BubbleData(Context context) {
        mContext = context;
        mContext = context;
@@ -154,18 +156,19 @@ public class BubbleData {
    }
    }


    public void setExpanded(boolean expanded) {
    public void setExpanded(boolean expanded) {
        if (setExpandedInternal(expanded)) {
        if (DEBUG) {
            dispatchApply();
            Log.d(TAG, "setExpanded: " + expanded);
        }
        }
        setExpandedInternal(expanded);
        dispatchPendingChanges();
    }
    }


    public void setSelectedBubble(Bubble bubble) {
    public void setSelectedBubble(Bubble bubble) {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "setSelectedBubble: " + bubble);
            Log.d(TAG, "setSelectedBubble: " + bubble);
        }
        }
        if (setSelectedBubbleInternal(bubble)) {
        setSelectedBubbleInternal(bubble);
            dispatchApply();
        dispatchPendingChanges();
        }
    }
    }


    public void notificationEntryUpdated(NotificationEntry entry) {
    public void notificationEntryUpdated(NotificationEntry entry) {
@@ -177,12 +180,12 @@ public class BubbleData {
            // Create a new bubble
            // Create a new bubble
            bubble = new Bubble(entry, this::onBubbleBlocked);
            bubble = new Bubble(entry, this::onBubbleBlocked);
            doAdd(bubble);
            doAdd(bubble);
            dispatchOnBubbleAdded(bubble);
            trim();
        } else {
        } else {
            // Updates an existing bubble
            // Updates an existing bubble
            bubble.setEntry(entry);
            bubble.setEntry(entry);
            doUpdate(bubble);
            doUpdate(bubble);
            dispatchOnBubbleUpdated(bubble);
            mUpdatedBubble = bubble;
        }
        }
        if (shouldAutoExpand(entry)) {
        if (shouldAutoExpand(entry)) {
            setSelectedBubbleInternal(bubble);
            setSelectedBubbleInternal(bubble);
@@ -192,7 +195,15 @@ public class BubbleData {
        } else if (mSelectedBubble == null) {
        } else if (mSelectedBubble == null) {
            setSelectedBubbleInternal(bubble);
            setSelectedBubbleInternal(bubble);
        }
        }
        dispatchApply();
        dispatchPendingChanges();
    }

    public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
        if (DEBUG) {
            Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
        }
        doRemove(entry.key, reason);
        dispatchPendingChanges();
    }
    }


    private void doAdd(Bubble bubble) {
    private void doAdd(Bubble bubble) {
@@ -202,14 +213,21 @@ public class BubbleData {
        int minInsertPoint = 0;
        int minInsertPoint = 0;
        boolean newGroup = !hasBubbleWithGroupId(bubble.getGroupId());
        boolean newGroup = !hasBubbleWithGroupId(bubble.getGroupId());
        if (isExpanded()) {
        if (isExpanded()) {
            // first bubble of a group goes to the end, otherwise it goes within the existing group
            // first bubble of a group goes to the beginning, otherwise within the existing group
            minInsertPoint =
            minInsertPoint = newGroup ? 0 : findFirstIndexForGroup(bubble.getGroupId());
                    newGroup ? mBubbles.size() : findFirstIndexForGroup(bubble.getGroupId());
        }
        if (insertBubble(minInsertPoint, bubble) < mBubbles.size() - 1) {
            mOrderChanged = true;
        }
        }
        insertBubble(minInsertPoint, bubble);
        mAddedBubble = bubble;
        if (!isExpanded()) {
        if (!isExpanded()) {
            packGroup(findFirstIndexForGroup(bubble.getGroupId()));
            mOrderChanged |= packGroup(findFirstIndexForGroup(bubble.getGroupId()));
            // Top bubble becomes selected.
            setSelectedBubbleInternal(mBubbles.get(0));
        }
        }
    }

    private void trim() {
        if (mBubbles.size() > MAX_BUBBLES) {
        if (mBubbles.size() > MAX_BUBBLES) {
            mBubbles.stream()
            mBubbles.stream()
                    // sort oldest first (ascending lastActivity)
                    // sort oldest first (ascending lastActivity)
@@ -217,10 +235,7 @@ public class BubbleData {
                    // skip the selected bubble
                    // skip the selected bubble
                    .filter((b) -> !b.equals(mSelectedBubble))
                    .filter((b) -> !b.equals(mSelectedBubble))
                    .findFirst()
                    .findFirst()
                    .ifPresent((b) -> {
                    .ifPresent((b) -> doRemove(b.getKey(), BubbleController.DISMISS_AGED));
                        doRemove(b.getKey(), BubbleController.DISMISS_AGED);
                        dispatchApply();
                    });
        }
        }
    }
    }


@@ -229,32 +244,38 @@ public class BubbleData {
            Log.d(TAG, "doUpdate: " + bubble);
            Log.d(TAG, "doUpdate: " + bubble);
        }
        }
        if (!isExpanded()) {
        if (!isExpanded()) {
            // while collapsed, update causes re-sort
            // while collapsed, update causes re-pack
            int prevPos = mBubbles.indexOf(bubble);
            mBubbles.remove(bubble);
            mBubbles.remove(bubble);
            insertBubble(0, bubble);
            int newPos = insertBubble(0, bubble);
            packGroup(findFirstIndexForGroup(bubble.getGroupId()));
            if (prevPos != newPos) {
                packGroup(newPos);
                mOrderChanged = true;
            }
            }
            setSelectedBubbleInternal(mBubbles.get(0));
        }
        }

    public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
        if (DEBUG) {
            Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
        }
        doRemove(entry.key, reason);
        dispatchApply();
    }
    }


    private void doRemove(String key, @DismissReason int reason) {
    private void doRemove(String key, @DismissReason int reason) {
        int indexToRemove = indexForKey(key);
        int indexToRemove = indexForKey(key);
        if (indexToRemove >= 0) {
        if (indexToRemove == -1) {
            return;
        }
        Bubble bubbleToRemove = mBubbles.get(indexToRemove);
        Bubble bubbleToRemove = mBubbles.get(indexToRemove);
        if (mBubbles.size() == 1) {
        if (mBubbles.size() == 1) {
            // Going to become empty, handle specially.
            // Going to become empty, handle specially.
            setExpandedInternal(false);
            setExpandedInternal(false);
            setSelectedBubbleInternal(null);
            setSelectedBubbleInternal(null);
        }
        }
        if (indexToRemove < mBubbles.size() - 1) {
            // Removing anything but the last bubble means positions will change.
            mOrderChanged = true;
        }
        mBubbles.remove(indexToRemove);
        mBubbles.remove(indexToRemove);
            dispatchOnBubbleRemoved(bubbleToRemove, reason);
        mRemovedBubbles.add(Pair.create(bubbleToRemove, reason));
        if (!isExpanded()) {
            mOrderChanged |= repackAll();
        }


        // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
        // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
        if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
        if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
@@ -266,7 +287,6 @@ public class BubbleData {
        bubbleToRemove.setDismissed();
        bubbleToRemove.setDismissed();
        maybeSendDeleteIntent(reason, bubbleToRemove.entry);
        maybeSendDeleteIntent(reason, bubbleToRemove.entry);
    }
    }
    }


    public void dismissAll(@DismissReason int reason) {
    public void dismissAll(@DismissReason int reason) {
        if (DEBUG) {
        if (DEBUG) {
@@ -281,56 +301,71 @@ public class BubbleData {
            Bubble bubble = mBubbles.remove(0);
            Bubble bubble = mBubbles.remove(0);
            bubble.setDismissed();
            bubble.setDismissed();
            maybeSendDeleteIntent(reason, bubble.entry);
            maybeSendDeleteIntent(reason, bubble.entry);
            dispatchOnBubbleRemoved(bubble, reason);
            mRemovedBubbles.add(Pair.create(bubble, reason));
        }
        }
        dispatchApply();
        dispatchPendingChanges();
    }
    }


    private void dispatchApply() {
        if (mListener != null) {
            mListener.apply();
        }
    }


    private void dispatchOnBubbleAdded(Bubble bubble) {
    private void dispatchPendingChanges() {
        if (mListener != null) {
        if (mListener == null) {
            mListener.onBubbleAdded(bubble);
            mExpandedChanged = false;
        }
            mAddedBubble = null;
            mSelectionChanged = false;
            mRemovedBubbles.clear();
            mUpdatedBubble = null;
            mOrderChanged = false;
            return;
        }
        }
        boolean anythingChanged = false;


    private void dispatchOnBubbleRemoved(Bubble bubble, @DismissReason int reason) {
        if (mAddedBubble != null) {
        if (mListener != null) {
            mListener.onBubbleAdded(mAddedBubble);
            mListener.onBubbleRemoved(bubble, reason);
            mAddedBubble = null;
        }
            anythingChanged = true;
        }
        }


    private void dispatchOnExpandedChanged(boolean expanded) {
        // Compat workaround: Always collapse first.
        if (mListener != null) {
        if (mExpandedChanged && !mExpanded) {
            mListener.onExpandedChanged(expanded);
            mListener.onExpandedChanged(mExpanded);
            mExpandedChanged = false;
            anythingChanged = true;
        }
        }

        if (mSelectionChanged) {
            mListener.onSelectionChanged(mSelectedBubble);
            mSelectionChanged = false;
            anythingChanged = true;
        }
        }


    private void dispatchOnSelectionChanged(@Nullable Bubble bubble) {
        if (!mRemovedBubbles.isEmpty()) {
        if (mListener != null) {
            for (Pair<Bubble, Integer> removed : mRemovedBubbles) {
            mListener.onSelectionChanged(bubble);
                mListener.onBubbleRemoved(removed.first, removed.second);
            }
            }
            mRemovedBubbles.clear();
            anythingChanged = true;
        }
        }


    private void dispatchOnBubbleUpdated(Bubble bubble) {
        if (mUpdatedBubble != null) {
        if (mListener != null) {
            mListener.onBubbleUpdated(mUpdatedBubble);
            mListener.onBubbleUpdated(bubble);
            mUpdatedBubble = null;
        }
            anythingChanged = true;
        }
        }


    private void dispatchOnOrderChanged(List<Bubble> bubbles) {
        if (mOrderChanged) {
        if (mListener != null) {
            mListener.onOrderChanged(mBubbles);
            mListener.onOrderChanged(bubbles);
            mOrderChanged = false;
            anythingChanged = true;
        }
        }

        if (mExpandedChanged) {
            mListener.onExpandedChanged(mExpanded);
            mExpandedChanged = false;
            anythingChanged = true;
        }
        }


    private void dispatchShowFlyoutText(Bubble bubble, String text) {
        if (anythingChanged) {
        if (mListener != null) {
            mListener.apply();
            mListener.showFlyoutText(bubble, text);
        }
        }
    }
    }


@@ -339,29 +374,25 @@ public class BubbleData {
     * the value changes.
     * the value changes.
     *
     *
     * @param bubble the new selected bubble
     * @param bubble the new selected bubble
     * @return true if the state changed as a result
     */
     */
    private boolean setSelectedBubbleInternal(@Nullable Bubble bubble) {
    private void setSelectedBubbleInternal(@Nullable Bubble bubble) {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
            Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
        }
        }
        if (Objects.equals(bubble, mSelectedBubble)) {
        if (Objects.equals(bubble, mSelectedBubble)) {
            return false;
            return;
        }
        }
        if (bubble != null && !mBubbles.contains(bubble)) {
        if (bubble != null && !mBubbles.contains(bubble)) {
            Log.e(TAG, "Cannot select bubble which doesn't exist!"
            Log.e(TAG, "Cannot select bubble which doesn't exist!"
                    + " (" + bubble + ") bubbles=" + mBubbles);
                    + " (" + bubble + ") bubbles=" + mBubbles);
            return false;
            return;
        }
        }
        if (mExpanded && bubble != null) {
        if (mExpanded && bubble != null) {
            bubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
            bubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
        }
        }
        mSelectedBubble = bubble;
        mSelectedBubble = bubble;
        dispatchOnSelectionChanged(mSelectedBubble);
        mSelectionChanged = true;
        if (!mExpanded || mSelectedBubble == null) {
        return;
            mSelectedBubbleExpandedPosition = -1;
        }
        return true;
    }
    }


    /**
    /**
@@ -369,37 +400,53 @@ public class BubbleData {
     * the value changes.
     * the value changes.
     *
     *
     * @param shouldExpand the new requested state
     * @param shouldExpand the new requested state
     * @return true if the state changed as a result
     */
     */
    private boolean setExpandedInternal(boolean shouldExpand) {
    private void setExpandedInternal(boolean shouldExpand) {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "setExpandedInternal: shouldExpand=" + shouldExpand);
            Log.d(TAG, "setExpandedInternal: shouldExpand=" + shouldExpand);
        }
        }
        if (mExpanded == shouldExpand) {
        if (mExpanded == shouldExpand) {
            return false;
            return;
        }
        if (mSelectedBubble != null) {
            mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
        }
        }
        if (shouldExpand) {
        if (shouldExpand) {
            if (mBubbles.isEmpty()) {
            if (mBubbles.isEmpty()) {
                Log.e(TAG, "Attempt to expand stack when empty!");
                Log.e(TAG, "Attempt to expand stack when empty!");
                return false;
                return;
            }
            }
            if (mSelectedBubble == null) {
            if (mSelectedBubble == null) {
                Log.e(TAG, "Attempt to expand stack without selected bubble!");
                Log.e(TAG, "Attempt to expand stack without selected bubble!");
                return false;
                return;
            }
            }
            mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
            mOrderChanged |= repackAll();
        } else if (!mBubbles.isEmpty()) {
            // Apply ordering and grouping rules from expanded -> collapsed, then save
            // the result.
            mOrderChanged |= repackAll();
            // Save the state which should be returned to when expanded (with no other changes)

            if (mBubbles.indexOf(mSelectedBubble) > 0) {
                // Move the selected bubble to the top while collapsed.
                if (!mSelectedBubble.isOngoing() && mBubbles.get(0).isOngoing()) {
                    // The selected bubble cannot be raised to the first position because
                    // there is an ongoing bubble there. Instead, force the top ongoing bubble
                    // to become selected.
                    setSelectedBubbleInternal(mBubbles.get(0));
                } else {
                } else {
            repackAll();
                    // Raise the selected bubble (and it's group) up to the front so the selected
                    // bubble remains on top.
                    mBubbles.remove(mSelectedBubble);
                    mBubbles.add(0, mSelectedBubble);
                    packGroup(0);
                }
            }
        }
        }
        mExpanded = shouldExpand;
        mExpanded = shouldExpand;
        dispatchOnExpandedChanged(mExpanded);
        mExpandedChanged = true;
        return true;
    }
    }


    private static long sortKey(Bubble bubble) {
    private static long sortKey(Bubble bubble) {
        long key = bubble.getLastActivity();
        long key = bubble.getLastUpdateTime();
        if (bubble.isOngoing()) {
        if (bubble.isOngoing()) {
            // Set 2nd highest bit (signed long int), to partition between ongoing and regular
            // Set 2nd highest bit (signed long int), to partition between ongoing and regular
            key |= 0x4000000000000000L;
            key |= 0x4000000000000000L;
@@ -456,8 +503,9 @@ public class BubbleData {
     * unchanged. Relative order of any other bubbles are also unchanged.
     * unchanged. Relative order of any other bubbles are also unchanged.
     *
     *
     * @param position the position of the first bubble for the group
     * @param position the position of the first bubble for the group
     * @return true if the position of any bubbles has changed as a result
     */
     */
    private void packGroup(int position) {
    private boolean packGroup(int position) {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "packGroup: position=" + position);
            Log.d(TAG, "packGroup: position=" + position);
        }
        }
@@ -471,16 +519,27 @@ public class BubbleData {
                moving.add(0, mBubbles.get(i));
                moving.add(0, mBubbles.get(i));
            }
            }
        }
        }
        if (moving.isEmpty()) {
            return false;
        }
        mBubbles.removeAll(moving);
        mBubbles.removeAll(moving);
        mBubbles.addAll(position + 1, moving);
        mBubbles.addAll(position + 1, moving);
        return true;
    }
    }


    private void repackAll() {
    /**
     * This applies a full sort and group pass to all existing bubbles. The bubbles are grouped
     * by groupId. Each group is then sorted by the max(lastUpdated) time of it's bubbles. Bubbles
     * within each group are then sorted by lastUpdated descending.
     *
     * @return true if the position of any bubbles changed as a result
     */
    private boolean repackAll() {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "repackAll()");
            Log.d(TAG, "repackAll()");
        }
        }
        if (mBubbles.isEmpty()) {
        if (mBubbles.isEmpty()) {
            return;
            return false;
        }
        }
        Map<String, Long> groupLastActivity = new HashMap<>();
        Map<String, Long> groupLastActivity = new HashMap<>();
        for (Bubble bubble : mBubbles) {
        for (Bubble bubble : mBubbles) {
@@ -494,7 +553,7 @@ public class BubbleData {
        // Sort groups by their most recently active bubble
        // Sort groups by their most recently active bubble
        List<String> groupsByMostRecentActivity =
        List<String> groupsByMostRecentActivity =
                groupLastActivity.entrySet().stream()
                groupLastActivity.entrySet().stream()
                        .sorted(GROUPS_BY_LAST_ACTIVITY_DESCENDING)
                        .sorted(GROUPS_BY_MAX_SORT_KEY_DESCENDING)
                        .map(Map.Entry::getKey)
                        .map(Map.Entry::getKey)
                        .collect(toList());
                        .collect(toList());


@@ -504,10 +563,14 @@ public class BubbleData {
        for (String appId : groupsByMostRecentActivity) {
        for (String appId : groupsByMostRecentActivity) {
            mBubbles.stream()
            mBubbles.stream()
                    .filter((b) -> b.getGroupId().equals(appId))
                    .filter((b) -> b.getGroupId().equals(appId))
                    .sorted(BUBBLES_BY_LAST_ACTIVITY_DESCENDING)
                    .sorted(BUBBLES_BY_SORT_KEY_DESCENDING)
                    .forEachOrdered(repacked::add);
                    .forEachOrdered(repacked::add);
        }
        }
        if (repacked.equals(mBubbles)) {
            return false;
        }
        mBubbles = repacked;
        mBubbles = repacked;
        return true;
    }
    }


    private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
    private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
@@ -527,21 +590,25 @@ public class BubbleData {
    }
    }


    private void onBubbleBlocked(NotificationEntry entry) {
    private void onBubbleBlocked(NotificationEntry entry) {
        boolean changed = false;
        final String blockedGroupId = Bubble.groupId(entry);
        final String blockedPackage = entry.notification.getPackageName();
        int selectedIndex = mBubbles.indexOf(mSelectedBubble);
        for (Iterator<Bubble> i = mBubbles.iterator(); i.hasNext(); ) {
        for (Iterator<Bubble> i = mBubbles.iterator(); i.hasNext(); ) {
            Bubble bubble = i.next();
            Bubble bubble = i.next();
            if (bubble.getPackageName().equals(blockedPackage)) {
            if (bubble.getGroupId().equals(blockedGroupId)) {
                mRemovedBubbles.add(Pair.create(bubble, BubbleController.DISMISS_BLOCKED));
                i.remove();
                i.remove();
                // TODO: handle removal of selected bubble, and collapse safely if emptied (see
                //  dismissAll)
                dispatchOnBubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED);
                changed = true;
            }
            }
        }
        }
        if (changed) {
        if (mBubbles.isEmpty()) {
            dispatchApply();
            setExpandedInternal(false);
            setSelectedBubbleInternal(null);
        } else if (!mBubbles.contains(mSelectedBubble)) {
            // choose a new one
            int newIndex = Math.min(selectedIndex, mBubbles.size() - 1);
            Bubble newSelected = mBubbles.get(newIndex);
            setSelectedBubbleInternal(newSelected);
        }
        }
        dispatchPendingChanges();
    }
    }


    private int indexForKey(String key) {
    private int indexForKey(String key) {
+10 −0
Original line number Original line Diff line number Diff line
@@ -549,6 +549,7 @@ public class BubbleStackView extends FrameLayout {
        mBubbleContainer.addView(bubble.iconView, 0,
        mBubbleContainer.addView(bubble.iconView, 0,
                new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
                new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        ViewClippingUtil.setClippingDeactivated(bubble.iconView, true, mClippingParameters);
        ViewClippingUtil.setClippingDeactivated(bubble.iconView, true, mClippingParameters);
        animateInFlyoutForBubble(bubble);
        requestUpdate();
        requestUpdate();
        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
    }
    }
@@ -570,10 +571,19 @@ public class BubbleStackView extends FrameLayout {


    // via BubbleData.Listener
    // via BubbleData.Listener
    void updateBubble(Bubble bubble) {
    void updateBubble(Bubble bubble) {
        animateInFlyoutForBubble(bubble);
        requestUpdate();
        requestUpdate();
        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
    }
    }


    public void updateBubbleOrder(List<Bubble> bubbles) {
        for (int i = 0; i < bubbles.size(); i++) {
            Bubble bubble = bubbles.get(i);
            mBubbleContainer.moveViewTo(bubble.iconView, i);
        }
    }


    /**
    /**
     * Changes the currently selected bubble. If the stack is already expanded, the newly selected
     * Changes the currently selected bubble. If the stack is already expanded, the newly selected
     * bubble will be shown immediately. This does not change the expanded state or change the
     * bubble will be shown immediately. This does not change the expanded state or change the
+19 −19

File changed.

Preview size limit exceeded, changes collapsed.

Loading