Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +19 −3 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ public class BubbleController implements ConfigurationChangeListener, * the pointer might need to be updated. */ void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer); /** Called when the bubble overflow empty state changes, used to show/hide the overflow. */ void bubbleOverflowChanged(boolean hasBubbles); } private final Context mContext; Loading Loading @@ -1401,7 +1403,7 @@ public class BubbleController implements ConfigurationChangeListener, Bubble b = mBubbleData.getOverflowBubbleWithKey(appBubbleKey); if (b != null) { // It's in the overflow, so remove it & reinflate mBubbleData.removeOverflowBubble(b); mBubbleData.dismissBubbleWithKey(appBubbleKey, Bubbles.DISMISS_NOTIF_CANCEL); } else { // App bubble does not exist, lets add and expand it b = Bubble.createAppBubble(intent, user, icon, mMainExecutor); Loading Loading @@ -1844,6 +1846,11 @@ public class BubbleController implements ConfigurationChangeListener, } } @Override public void bubbleOverflowChanged(boolean hasBubbles) { // TODO (b/334175587): tell stack view to hide / show the overflow } }; /** When bubbles are in the bubble bar, this will be used to notify bubble bar views. */ Loading Loading @@ -1875,6 +1882,11 @@ public class BubbleController implements ConfigurationChangeListener, // Nothing to do for order changes, these are handled by launcher / in the bubble bar. } @Override public void bubbleOverflowChanged(boolean hasBubbles) { // Nothing to do for our views, handled by launcher / in the bubble bar. } @Override public void suppressionChanged(Bubble bubble, boolean isSuppressed) { if (mLayerView != null) { Loading Loading @@ -1914,7 +1926,7 @@ public class BubbleController implements ConfigurationChangeListener, ProtoLog.d(WM_SHELL_BUBBLES, "mBubbleDataListener#applyUpdate:" + " added=%s removed=%b updated=%s orderChanged=%b expansionChanged=%b" + " expanded=%b selectionChanged=%b selected=%s" + " suppressed=%s unsupressed=%s shouldShowEducation=%b", + " suppressed=%s unsupressed=%s shouldShowEducation=%b showOverflowChanged=%b", update.addedBubble != null ? update.addedBubble.getKey() : "null", !update.removedBubbles.isEmpty(), update.updatedBubble != null ? update.updatedBubble.getKey() : "null", Loading @@ -1923,13 +1935,17 @@ public class BubbleController implements ConfigurationChangeListener, update.selectedBubble != null ? update.selectedBubble.getKey() : "null", update.suppressedBubble != null ? update.suppressedBubble.getKey() : "null", update.unsuppressedBubble != null ? update.unsuppressedBubble.getKey() : "null", update.shouldShowEducation); update.shouldShowEducation, update.showOverflowChanged); ensureBubbleViewsAndWindowCreated(); // Lazy load overflow bubbles from disk loadOverflowBubblesFromDisk(); if (update.showOverflowChanged) { mBubbleViewCallback.bubbleOverflowChanged(!update.overflowBubbles.isEmpty()); } // If bubbles in the overflow have a dot, make sure the overflow shows a dot updateOverflowButtonDot(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +10 −15 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ public class BubbleData { boolean suppressedSummaryChanged; boolean expanded; boolean shouldShowEducation; boolean showOverflowChanged; @Nullable BubbleViewProvider selectedBubble; @Nullable Bubble addedBubble; @Nullable Bubble updatedBubble; Loading Loading @@ -109,7 +110,8 @@ public class BubbleData { || suppressedBubble != null || unsuppressedBubble != null || suppressedSummaryChanged || suppressedSummaryGroup != null; || suppressedSummaryGroup != null || showOverflowChanged; } void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) { Loading Loading @@ -410,6 +412,9 @@ public class BubbleData { if (bubbleToReturn != null) { // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { // Update while it was pending bubbleToReturn = mPendingBubbles.get(key); Loading Loading @@ -496,19 +501,6 @@ public class BubbleData { dispatchPendingChanges(); } /** * Explicitly removes a bubble from the overflow, if it exists. * * @param bubble the bubble to remove. */ public void removeOverflowBubble(Bubble bubble) { if (bubble == null) return; if (mOverflowBubbles.remove(bubble)) { mStateChange.removedOverflowBubble = bubble; dispatchPendingChanges(); } } /** * Adds a group key indicating that the summary for this group should be suppressed. * Loading Loading @@ -683,7 +675,6 @@ public class BubbleData { if (indexToRemove == -1) { if (hasOverflowBubbleWithKey(key) && shouldRemoveHiddenBubble) { Bubble b = getOverflowBubbleWithKey(key); ProtoLog.d(WM_SHELL_BUBBLES, "doRemove - cancel overflow bubble=%s", key); if (b != null) { Loading @@ -693,6 +684,7 @@ public class BubbleData { mOverflowBubbles.remove(b); mStateChange.bubbleRemoved(b, reason); mStateChange.removedOverflowBubble = b; mStateChange.showOverflowChanged = mOverflowBubbles.isEmpty(); } if (hasSuppressedBubbleWithKey(key) && shouldRemoveHiddenBubble) { Bubble b = getSuppressedBubbleWithKey(key); Loading Loading @@ -792,6 +784,9 @@ public class BubbleData { } ProtoLog.d(WM_SHELL_BUBBLES, "overflowBubble=%s", bubble.getKey()); mLogger.logOverflowAdd(bubble, reason); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } mOverflowBubbles.remove(bubble); mOverflowBubbles.add(0, bubble); mStateChange.addedOverflowBubble = bubble; Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +45 −17 Original line number Diff line number Diff line Loading @@ -1192,23 +1192,6 @@ public class BubbleDataTest extends ShellTestCase { assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull(); } @Test public void test_removeOverflowBubble() { sendUpdatedEntryAtTime(mEntryA1, 2000); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertOverflowChangedTo(ImmutableList.of(mBubbleA1)); mBubbleData.removeOverflowBubble(mBubbleA1); verifyUpdateReceived(); BubbleData.Update update = mUpdateCaptor.getValue(); assertThat(update.removedOverflowBubble).isEqualTo(mBubbleA1); assertOverflowChangedTo(ImmutableList.of()); } @Test public void test_getInitialStateForBubbleBar_includesInitialBubblesAndPosition() { sendUpdatedEntryAtTime(mEntryA1, 1000); Loading @@ -1235,6 +1218,51 @@ public class BubbleDataTest extends ShellTestCase { assertExpandedChangedTo(true); } @Test public void testShowOverflowChanged_hasOverflowBubbles() { assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); sendUpdatedEntryAtTime(mEntryA1, 1000); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); } @Test public void testShowOverflowChanged_false_hasOverflowBubbles() { assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 1000); mBubbleData.setListener(mListener); // First overflowed causes change event mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); // Second overflow does not mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isFalse(); } @Test public void testShowOverflowChanged_noOverflowBubbles() { sendUpdatedEntryAtTime(mEntryA1, 1000); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); } private void verifyUpdateReceived() { verify(mListener).applyUpdate(mUpdateCaptor.capture()); reset(mListener); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +19 −3 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ public class BubbleController implements ConfigurationChangeListener, * the pointer might need to be updated. */ void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer); /** Called when the bubble overflow empty state changes, used to show/hide the overflow. */ void bubbleOverflowChanged(boolean hasBubbles); } private final Context mContext; Loading Loading @@ -1401,7 +1403,7 @@ public class BubbleController implements ConfigurationChangeListener, Bubble b = mBubbleData.getOverflowBubbleWithKey(appBubbleKey); if (b != null) { // It's in the overflow, so remove it & reinflate mBubbleData.removeOverflowBubble(b); mBubbleData.dismissBubbleWithKey(appBubbleKey, Bubbles.DISMISS_NOTIF_CANCEL); } else { // App bubble does not exist, lets add and expand it b = Bubble.createAppBubble(intent, user, icon, mMainExecutor); Loading Loading @@ -1844,6 +1846,11 @@ public class BubbleController implements ConfigurationChangeListener, } } @Override public void bubbleOverflowChanged(boolean hasBubbles) { // TODO (b/334175587): tell stack view to hide / show the overflow } }; /** When bubbles are in the bubble bar, this will be used to notify bubble bar views. */ Loading Loading @@ -1875,6 +1882,11 @@ public class BubbleController implements ConfigurationChangeListener, // Nothing to do for order changes, these are handled by launcher / in the bubble bar. } @Override public void bubbleOverflowChanged(boolean hasBubbles) { // Nothing to do for our views, handled by launcher / in the bubble bar. } @Override public void suppressionChanged(Bubble bubble, boolean isSuppressed) { if (mLayerView != null) { Loading Loading @@ -1914,7 +1926,7 @@ public class BubbleController implements ConfigurationChangeListener, ProtoLog.d(WM_SHELL_BUBBLES, "mBubbleDataListener#applyUpdate:" + " added=%s removed=%b updated=%s orderChanged=%b expansionChanged=%b" + " expanded=%b selectionChanged=%b selected=%s" + " suppressed=%s unsupressed=%s shouldShowEducation=%b", + " suppressed=%s unsupressed=%s shouldShowEducation=%b showOverflowChanged=%b", update.addedBubble != null ? update.addedBubble.getKey() : "null", !update.removedBubbles.isEmpty(), update.updatedBubble != null ? update.updatedBubble.getKey() : "null", Loading @@ -1923,13 +1935,17 @@ public class BubbleController implements ConfigurationChangeListener, update.selectedBubble != null ? update.selectedBubble.getKey() : "null", update.suppressedBubble != null ? update.suppressedBubble.getKey() : "null", update.unsuppressedBubble != null ? update.unsuppressedBubble.getKey() : "null", update.shouldShowEducation); update.shouldShowEducation, update.showOverflowChanged); ensureBubbleViewsAndWindowCreated(); // Lazy load overflow bubbles from disk loadOverflowBubblesFromDisk(); if (update.showOverflowChanged) { mBubbleViewCallback.bubbleOverflowChanged(!update.overflowBubbles.isEmpty()); } // If bubbles in the overflow have a dot, make sure the overflow shows a dot updateOverflowButtonDot(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +10 −15 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ public class BubbleData { boolean suppressedSummaryChanged; boolean expanded; boolean shouldShowEducation; boolean showOverflowChanged; @Nullable BubbleViewProvider selectedBubble; @Nullable Bubble addedBubble; @Nullable Bubble updatedBubble; Loading Loading @@ -109,7 +110,8 @@ public class BubbleData { || suppressedBubble != null || unsuppressedBubble != null || suppressedSummaryChanged || suppressedSummaryGroup != null; || suppressedSummaryGroup != null || showOverflowChanged; } void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) { Loading Loading @@ -410,6 +412,9 @@ public class BubbleData { if (bubbleToReturn != null) { // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { // Update while it was pending bubbleToReturn = mPendingBubbles.get(key); Loading Loading @@ -496,19 +501,6 @@ public class BubbleData { dispatchPendingChanges(); } /** * Explicitly removes a bubble from the overflow, if it exists. * * @param bubble the bubble to remove. */ public void removeOverflowBubble(Bubble bubble) { if (bubble == null) return; if (mOverflowBubbles.remove(bubble)) { mStateChange.removedOverflowBubble = bubble; dispatchPendingChanges(); } } /** * Adds a group key indicating that the summary for this group should be suppressed. * Loading Loading @@ -683,7 +675,6 @@ public class BubbleData { if (indexToRemove == -1) { if (hasOverflowBubbleWithKey(key) && shouldRemoveHiddenBubble) { Bubble b = getOverflowBubbleWithKey(key); ProtoLog.d(WM_SHELL_BUBBLES, "doRemove - cancel overflow bubble=%s", key); if (b != null) { Loading @@ -693,6 +684,7 @@ public class BubbleData { mOverflowBubbles.remove(b); mStateChange.bubbleRemoved(b, reason); mStateChange.removedOverflowBubble = b; mStateChange.showOverflowChanged = mOverflowBubbles.isEmpty(); } if (hasSuppressedBubbleWithKey(key) && shouldRemoveHiddenBubble) { Bubble b = getSuppressedBubbleWithKey(key); Loading Loading @@ -792,6 +784,9 @@ public class BubbleData { } ProtoLog.d(WM_SHELL_BUBBLES, "overflowBubble=%s", bubble.getKey()); mLogger.logOverflowAdd(bubble, reason); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } mOverflowBubbles.remove(bubble); mOverflowBubbles.add(0, bubble); mStateChange.addedOverflowBubble = bubble; Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +45 −17 Original line number Diff line number Diff line Loading @@ -1192,23 +1192,6 @@ public class BubbleDataTest extends ShellTestCase { assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull(); } @Test public void test_removeOverflowBubble() { sendUpdatedEntryAtTime(mEntryA1, 2000); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertOverflowChangedTo(ImmutableList.of(mBubbleA1)); mBubbleData.removeOverflowBubble(mBubbleA1); verifyUpdateReceived(); BubbleData.Update update = mUpdateCaptor.getValue(); assertThat(update.removedOverflowBubble).isEqualTo(mBubbleA1); assertOverflowChangedTo(ImmutableList.of()); } @Test public void test_getInitialStateForBubbleBar_includesInitialBubblesAndPosition() { sendUpdatedEntryAtTime(mEntryA1, 1000); Loading @@ -1235,6 +1218,51 @@ public class BubbleDataTest extends ShellTestCase { assertExpandedChangedTo(true); } @Test public void testShowOverflowChanged_hasOverflowBubbles() { assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); sendUpdatedEntryAtTime(mEntryA1, 1000); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); } @Test public void testShowOverflowChanged_false_hasOverflowBubbles() { assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 1000); mBubbleData.setListener(mListener); // First overflowed causes change event mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); // Second overflow does not mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isFalse(); } @Test public void testShowOverflowChanged_noOverflowBubbles() { sendUpdatedEntryAtTime(mEntryA1, 1000); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty(); mBubbleData.setListener(mListener); mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL); verifyUpdateReceived(); assertThat(mUpdateCaptor.getValue().showOverflowChanged).isTrue(); assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); } private void verifyUpdateReceived() { verify(mListener).applyUpdate(mUpdateCaptor.capture()); reset(mListener); Loading