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

Commit f008f544 authored by Liran Binyamin's avatar Liran Binyamin Committed by Android (Google) Code Review
Browse files

Merge "Don't remove the bubble if there's a later update" into main

parents bd95b591 88d33f10
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -1230,10 +1230,14 @@ public class BubbleController implements ConfigurationChangeListener,
     * A bubble was dragged and is released in dismiss target in Launcher.
     *
     * @param bubbleKey key of the bubble being dragged to dismiss target
     * @param timestamp the timestamp of the removal
     */
    public void dragBubbleToDismiss(String bubbleKey) {
    public void dragBubbleToDismiss(String bubbleKey, long timestamp) {
        String selectedBubbleKey = mBubbleData.getSelectedBubbleKey();
        removeBubble(bubbleKey, Bubbles.DISMISS_USER_GESTURE);
        if (mBubbleData.hasAnyBubbleWithKey(bubbleKey)) {
            mBubbleData.dismissBubbleWithKey(
                    bubbleKey, Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, timestamp);
        }
        if (selectedBubbleKey != null && !selectedBubbleKey.equals(bubbleKey)) {
            // We did not remove the selected bubble. Expand it again
            mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ true);
@@ -2458,8 +2462,8 @@ public class BubbleController implements ConfigurationChangeListener,
        }

        @Override
        public void dragBubbleToDismiss(String key) {
            mMainExecutor.execute(() -> mController.dragBubbleToDismiss(key));
        public void dragBubbleToDismiss(String key, long timestamp) {
            mMainExecutor.execute(() -> mController.dragBubbleToDismiss(key, timestamp));
        }

        @Override
+30 −5
Original line number Diff line number Diff line
@@ -150,9 +150,12 @@ public class BubbleData {
                    : null;
            for (int i = 0; i < removedBubbles.size(); i++) {
                Pair<Bubble, Integer> pair = removedBubbles.get(i);
                // if the removal happened in launcher, don't send it back
                if (pair.second != Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER) {
                    bubbleBarUpdate.removedBubbles.add(
                            new RemovedBubble(pair.first.getKey(), pair.second));
                }
            }
            if (orderChanged) {
                // Include the new order
                for (int i = 0; i < bubbles.size(); i++) {
@@ -502,13 +505,35 @@ public class BubbleData {
        dispatchPendingChanges();
    }

    /** Dismisses the bubble with the matching key, if it exists. */
    public void dismissBubbleWithKey(String key, @DismissReason int reason) {
        dismissBubbleWithKey(key, reason, mTimeSource.currentTimeMillis());
    }

    /**
     * Dismisses the bubble with the matching key, if it exists.
     *
     * <p>This is used when the bubble was dismissed in launcher, where the {@code removalTimestamp}
     * represents when the removal happened and can be used to check whether or not the bubble has
     * been updated after the removal. If no updates, it's safe to remove the bubble, otherwise the
     * removal is ignored.
     */
    public void dismissBubbleWithKey(String key, @DismissReason int reason) {
    public void dismissBubbleWithKey(String key, @DismissReason int reason, long removalTimestamp) {
        boolean shouldRemove = true;
        // if the bubble was removed from launcher, verify that the removal happened after the last
        // time it was updated
        if (reason == Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER) {
            // if the bubble was removed from launcher it must be active.
            Bubble bubble = getBubbleInStackWithKey(key);
            if (bubble != null && bubble.getLastActivity() > removalTimestamp) {
                shouldRemove = false;
            }
        }
        if (shouldRemove) {
            doRemove(key, reason);
            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
@@ -62,7 +62,7 @@ public interface Bubbles {
            DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
            DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
            DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_ACCOUNT_REMOVED,
            DISMISS_SWITCH_TO_STACK})
            DISMISS_SWITCH_TO_STACK, DISMISS_USER_GESTURE_FROM_LAUNCHER})
    @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
    @interface DismissReason {
    }
@@ -84,6 +84,7 @@ public interface Bubbles {
    int DISMISS_RELOAD_FROM_DISK = 15;
    int DISMISS_USER_ACCOUNT_REMOVED = 16;
    int DISMISS_SWITCH_TO_STACK = 17;
    int DISMISS_USER_GESTURE_FROM_LAUNCHER = 18;

    /** Returns a binder that can be passed to an external process to manipulate Bubbles. */
    default IBubbles createExternalInterface() {
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ interface IBubbles {

    oneway void showBubble(in String key, in int topOnScreen) = 3;

    oneway void dragBubbleToDismiss(in String key) = 4;
    oneway void dragBubbleToDismiss(in String key, in long timestamp) = 4;

    oneway void removeAllBubbles() = 5;

+42 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

@@ -254,6 +255,45 @@ public class BubbleDataTest extends ShellTestCase {
        assertBubbleRemoved(mBubbleA1, Bubbles.DISMISS_USER_GESTURE);
    }

    @Test
    public void testRemoveBubbleInLauncher_beforeBubbleUpdate_processedAfter_shouldNotBeRemoved() {
        sendUpdatedEntryAtTime(mEntryA1, 1000);
        sendUpdatedEntryAtTime(mEntryA2, 2000);
        mBubbleData.setListener(mListener);

        sendUpdatedEntryAtTime(mEntryA2, 3000);

        verifyUpdateReceived();
        assertThat(mBubbleData.hasBubbleInStackWithKey(mEntryA2.getKey())).isTrue();
        assertThat(mBubbleData.getBubbleInStackWithKey(mEntryA2.getKey()).getLastActivity())
                .isEqualTo(3000);

        // dismiss the bubble with a timestamp in the past
        mBubbleData.dismissBubbleWithKey(
                mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, 2500);

        verifyNoMoreInteractions(mListener);
        assertThat(mBubbleData.hasBubbleInStackWithKey(mEntryA2.getKey())).isTrue();
    }

    @Test
    public void testRemoveBubbleInLauncher_isNotSentBackToLauncher() {
        sendUpdatedEntryAtTime(mEntryA1, 1000);
        sendUpdatedEntryAtTime(mEntryA2, 2000);
        mBubbleData.setListener(mListener);

        mBubbleData.dismissBubbleWithKey(
                mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, 4000);
        verifyUpdateReceived();

        BubbleData.Update update = mUpdateCaptor.getValue();
        assertThat(update.removedBubbles).hasSize(1);
        assertThat(update.removedBubbles.getFirst().first.getKey()).isEqualTo(mBubbleA2.getKey());

        BubbleBarUpdate bubbleBarUpdate = update.toBubbleBarUpdate();
        assertThat(bubbleBarUpdate.removedBubbles).isEmpty();
    }

    @Test
    public void ifSuppress_hideFlyout() {
        // Setup
@@ -1415,15 +1455,13 @@ public class BubbleDataTest extends ShellTestCase {
        sendUpdatedEntryAtTime(entry, postTime, true /* isTextChanged */);
    }

    private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime,
            boolean textChanged) {
    private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime, boolean textChanged) {
        setPostTime(entry, postTime);
        // BubbleController calls this:
        Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */);
        b.setTextChangedForTest(textChanged);
        // And then this
        mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/,
                true /* showInShade */);
        mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/, true /* showInShade */);
    }

    private void changeExpandedStateAtTime(boolean shouldBeExpanded, long time) {
Loading