summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lyn Han <lynhan@google.com> 2020-04-15 10:01:01 -0700
committer Lyn Han <lynhan@google.com> 2020-04-22 13:01:05 -0700
commit2f6e89d2649f8f3498a105de60204aaca2b8c1f0 (patch)
treed74d7691959e22839a948c35789073efb6276e88
parent323d63572df3c4bff249302a8bbe526129928d7e (diff)
Notification removal with overflow bubbles
Intercept dismissal for overflow bubbles. Remove notifications for inactive (not in stack and overflow) bubbles cancelled or suppressed from shade. Set "isBubble" SysUI flag - false for inactive bubbles still in shade, - true for bubbles promoted from overflow. Account for overflow bubbles in event handling - onEntryUpdated: remove overflow bubble if no longer a bubble - onRankingUpdated: remove overflow bubble if blocked - expandStackAndSelectBubble: promote overflow bubble then expand - isBubbleNotificationSuppressedFromShade: check overflow bubbles Update tests Enable overflow flag ---------------- Fixes: 151104690 Test: manual: cancel oldest bubble => oldest overflow bubble removed Test: atest SystemUITests Change-Id: I44bb623f99f9473055787cf10693f7a3bfd1c768
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java152
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java112
7 files changed, 368 insertions, 167 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e488cf271fdf..4b503785b3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -123,7 +123,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Retention(SOURCE)
@IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
- DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT})
+ DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
+ DISMISS_OVERFLOW_MAX_REACHED})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
@interface DismissReason {}
@@ -137,6 +138,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
static final int DISMISS_USER_CHANGED = 8;
static final int DISMISS_GROUP_CANCELLED = 9;
static final int DISMISS_INVALID_INTENT = 10;
+ static final int DISMISS_OVERFLOW_MAX_REACHED = 11;
private final Context mContext;
private final NotificationEntryManager mNotificationEntryManager;
@@ -465,7 +467,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (userRemovedNotif) {
return handleDismissalInterception(entry);
}
-
return false;
}
});
@@ -736,18 +737,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
*/
public boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry) {
String key = entry.getKey();
- boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
- && !mBubbleData.getBubbleWithKey(key).showInShade();
+ boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key)
+ && !mBubbleData.getAnyBubbleWithkey(key).showInShade());
String groupKey = entry.getSbn().getGroupKey();
boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey));
-
- return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed;
+ return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
void promoteBubbleFromOverflow(Bubble bubble) {
bubble.setInflateSynchronously(mInflateSynchronously);
+ setIsBubble(bubble, /* isBubble */ true);
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
}
@@ -757,11 +758,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* @param notificationKey the notification key for the bubble to be selected
*/
public void expandStackAndSelectBubble(String notificationKey) {
- Bubble bubble = mBubbleData.getBubbleWithKey(notificationKey);
- if (bubble != null) {
+ Bubble bubble = mBubbleData.getBubbleInStackWithKey(notificationKey);
+ if (bubble == null) {
+ bubble = mBubbleData.getOverflowBubbleWithKey(notificationKey);
+ if (bubble != null) {
+ mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
+ }
+ } else if (bubble.getEntry().isBubble()){
mBubbleData.setSelectedBubble(bubble);
- mBubbleData.setExpanded(true);
}
+ mBubbleData.setExpanded(true);
}
/**
@@ -856,7 +862,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
*/
@MainThread
void removeBubble(NotificationEntry entry, int reason) {
- if (mBubbleData.hasBubbleWithKey(entry.getKey())) {
+ if (mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
mBubbleData.notificationEntryRemoved(entry, reason);
}
}
@@ -871,7 +877,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private void onEntryUpdated(NotificationEntry entry) {
boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
&& canLaunchInActivityView(mContext, entry);
- if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
+ if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
removeBubble(entry, DISMISS_NO_LONGER_BUBBLE);
} else if (shouldBubble) {
@@ -910,7 +916,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
String key = orderedKeys[i];
NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
rankingMap.getRanking(key, mTmpRanking);
- boolean isActiveBubble = mBubbleData.hasBubbleWithKey(key);
+ boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
if (isActiveBubble && !mTmpRanking.canBubble()) {
mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
@@ -920,6 +926,19 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
+ private void setIsBubble(Bubble b, boolean isBubble) {
+ if (isBubble) {
+ b.getEntry().getSbn().getNotification().flags |= FLAG_BUBBLE;
+ } else {
+ b.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
+ }
+ try {
+ mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
+ } catch (RemoteException e) {
+ // Bad things have happened
+ }
+ }
+
@SuppressWarnings("FieldCanBeLocal")
private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
@@ -942,36 +961,36 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
final Bubble bubble = removed.first;
@DismissReason final int reason = removed.second;
mStackView.removeBubble(bubble);
+
// If the bubble is removed for user switching, leave the notification in place.
- if (reason != DISMISS_USER_CHANGED) {
- if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
- && !bubble.showInShade()) {
+ if (reason == DISMISS_USER_CHANGED) {
+ continue;
+ }
+ if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
+ if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
+ && (!bubble.showInShade()
+ || reason == DISMISS_NOTIF_CANCEL
+ || reason == DISMISS_GROUP_CANCELLED)) {
// The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
}
} else {
- // Update the flag for SysUI
- bubble.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
+ if (bubble.getEntry().isBubble() && bubble.showInShade()) {
+ setIsBubble(bubble, /* isBubble */ false);
+ }
if (bubble.getEntry().getRow() != null) {
bubble.getEntry().getRow().updateBubbleButton();
}
-
- // Update the state in NotificationManagerService
- try {
- mBarService.onNotificationBubbleChanged(bubble.getKey(),
- false /* isBubble */, 0 /* flags */);
- } catch (RemoteException e) {
- }
}
- final String groupKey = bubble.getEntry().getSbn().getGroupKey();
- if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
- // Time to potentially remove the summary
- for (NotifCallback cb : mCallbacks) {
- cb.maybeCancelSummary(bubble.getEntry());
- }
+ }
+ final String groupKey = bubble.getEntry().getSbn().getGroupKey();
+ if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
+ // Time to potentially remove the summary
+ for (NotifCallback cb : mCallbacks) {
+ cb.maybeCancelSummary(bubble.getEntry());
}
}
}
@@ -1020,7 +1039,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
Log.d(TAG, "\n[BubbleData] overflow:");
Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getOverflowBubbles(),
- null));
+ null) + "\n");
}
}
};
@@ -1039,21 +1058,19 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (entry == null) {
return false;
}
-
- final boolean interceptBubbleDismissal = mBubbleData.hasBubbleWithKey(entry.getKey())
- && entry.isBubble();
- final boolean interceptSummaryDismissal = isSummaryOfBubbles(entry);
-
- if (interceptSummaryDismissal) {
+ if (isSummaryOfBubbles(entry)) {
handleSummaryDismissalInterception(entry);
- } else if (interceptBubbleDismissal) {
- Bubble bubble = mBubbleData.getBubbleWithKey(entry.getKey());
+ } else {
+ Bubble bubble = mBubbleData.getBubbleInStackWithKey(entry.getKey());
+ if (bubble == null || !entry.isBubble()) {
+ bubble = mBubbleData.getOverflowBubbleWithKey(entry.getKey());
+ }
+ if (bubble == null) {
+ return false;
+ }
bubble.setSuppressNotification(true);
bubble.setShowDot(false /* show */);
- } else {
- return false;
}
-
// Update the shade
for (NotifCallback cb : mCallbacks) {
cb.invalidateNotifications("BubbleController.handleDismissalInterception");
@@ -1082,11 +1099,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (children != null) {
for (int i = 0; i < children.size(); i++) {
NotificationEntry child = children.get(i);
- if (mBubbleData.hasBubbleWithKey(child.getKey())) {
+ if (mBubbleData.hasAnyBubbleWithKey(child.getKey())) {
// Suppress the bubbled child
// As far as group manager is concerned, once a child is no longer shown
// in the shade, it is essentially removed.
- Bubble bubbleChild = mBubbleData.getBubbleWithKey(child.getKey());
+ Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey());
mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
bubbleChild.setSuppressNotification(true);
bubbleChild.setShowDot(false /* show */);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index a1393cddc9f6..35a4811110a8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -123,7 +123,7 @@ public class BubbleData {
private boolean mShowingOverflow;
private boolean mExpanded;
private final int mMaxBubbles;
- private final int mMaxOverflowBubbles;
+ private int mMaxOverflowBubbles;
// State tracked during an operation -- keeps track of what listener events to dispatch.
private Update mStateChange;
@@ -175,8 +175,16 @@ public class BubbleData {
return mExpanded;
}
- public boolean hasBubbleWithKey(String key) {
- return getBubbleWithKey(key) != null;
+ public boolean hasAnyBubbleWithKey(String key) {
+ return hasBubbleInStackWithKey(key) || hasOverflowBubbleWithKey(key);
+ }
+
+ public boolean hasBubbleInStackWithKey(String key) {
+ return getBubbleInStackWithKey(key) != null;
+ }
+
+ public boolean hasOverflowBubbleWithKey(String key) {
+ return getOverflowBubbleWithKey(key) != null;
}
@Nullable
@@ -206,6 +214,8 @@ public class BubbleData {
Log.d(TAG, "promoteBubbleFromOverflow: " + bubble);
}
moveOverflowBubbleToPending(bubble);
+ // Preserve new order for next repack, which sorts by last updated time.
+ bubble.markUpdatedAt(mTimeSource.currentTimeMillis());
bubble.inflate(
b -> {
notificationEntryUpdated(bubble, /* suppressFlyout */
@@ -221,8 +231,6 @@ public class BubbleData {
}
private void moveOverflowBubbleToPending(Bubble b) {
- // Preserve new order for next repack, which sorts by last updated time.
- b.markUpdatedAt(mTimeSource.currentTimeMillis());
mOverflowBubbles.remove(b);
mPendingBubbles.add(b);
}
@@ -233,15 +241,16 @@ public class BubbleData {
* for that.
*/
Bubble getOrCreateBubble(NotificationEntry entry) {
- Bubble bubble = getBubbleWithKey(entry.getKey());
- if (bubble == null) {
- for (int i = 0; i < mOverflowBubbles.size(); i++) {
- Bubble b = mOverflowBubbles.get(i);
- if (b.getKey().equals(entry.getKey())) {
- moveOverflowBubbleToPending(b);
- b.setEntry(entry);
- return b;
- }
+ String key = entry.getKey();
+ Bubble bubble = getBubbleInStackWithKey(entry.getKey());
+ if (bubble != null) {
+ bubble.setEntry(entry);
+ } else {
+ bubble = getOverflowBubbleWithKey(key);
+ if (bubble != null) {
+ moveOverflowBubbleToPending(bubble);
+ bubble.setEntry(entry);
+ return bubble;
}
// Check for it in pending
for (int i = 0; i < mPendingBubbles.size(); i++) {
@@ -253,8 +262,6 @@ public class BubbleData {
}
bubble = new Bubble(entry, mSuppressionListener);
mPendingBubbles.add(bubble);
- } else {
- bubble.setEntry(entry);
}
return bubble;
}
@@ -269,7 +276,7 @@ public class BubbleData {
Log.d(TAG, "notificationEntryUpdated: " + bubble);
}
mPendingBubbles.remove(bubble); // No longer pending once we're here
- Bubble prevBubble = getBubbleWithKey(bubble.getKey());
+ Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive();
if (prevBubble == null) {
@@ -422,6 +429,19 @@ public class BubbleData {
}
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
+ if (hasOverflowBubbleWithKey(key)
+ && (reason == BubbleController.DISMISS_NOTIF_CANCEL
+ || reason == BubbleController.DISMISS_GROUP_CANCELLED
+ || reason == BubbleController.DISMISS_NO_LONGER_BUBBLE
+ || reason == BubbleController.DISMISS_BLOCKED)) {
+
+ Bubble b = getOverflowBubbleWithKey(key);
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "Cancel overflow bubble: " + b);
+ }
+ mStateChange.bubbleRemoved(b, reason);
+ mOverflowBubbles.remove(b);
+ }
return;
}
Bubble bubbleToRemove = mBubbles.get(indexToRemove);
@@ -453,21 +473,23 @@ public class BubbleData {
}
void overflowBubble(@DismissReason int reason, Bubble bubble) {
- if (reason == BubbleController.DISMISS_AGED
- || reason == BubbleController.DISMISS_USER_GESTURE) {
+ if (!(reason == BubbleController.DISMISS_AGED
+ || reason == BubbleController.DISMISS_USER_GESTURE)) {
+ return;
+ }
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "Overflowing: " + bubble);
+ }
+ mOverflowBubbles.add(0, bubble);
+ bubble.stopInflation();
+ if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
+ // Remove oldest bubble.
+ Bubble oldest = mOverflowBubbles.get(mOverflowBubbles.size() - 1);
if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Overflowing: " + bubble);
- }
- mOverflowBubbles.add(0, bubble);
- bubble.stopInflation();
- if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
- // Remove oldest bubble.
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Overflow full. Remove: " + mOverflowBubbles.get(
- mOverflowBubbles.size() - 1));
- }
- mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
+ Log.d(TAG, "Overflow full. Remove: " + oldest);
}
+ mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
+ mOverflowBubbles.remove(oldest);
}
}
@@ -764,7 +786,17 @@ public class BubbleData {
@VisibleForTesting(visibility = PRIVATE)
@Nullable
- Bubble getBubbleWithKey(String key) {
+ Bubble getAnyBubbleWithkey(String key) {
+ Bubble b = getBubbleInStackWithKey(key);
+ if (b == null) {
+ b = getOverflowBubbleWithKey(key);
+ }
+ return b;
+ }
+
+ @VisibleForTesting(visibility = PRIVATE)
+ @Nullable
+ Bubble getBubbleInStackWithKey(String key) {
for (int i = 0; i < mBubbles.size(); i++) {
Bubble bubble = mBubbles.get(i);
if (bubble.getKey().equals(key)) {
@@ -806,6 +838,15 @@ public class BubbleData {
}
/**
+ * Set maximum number of bubbles allowed in overflow.
+ * This method should only be used in tests, not in production.
+ */
+ @VisibleForTesting
+ void setMaxOverflowBubbles(int maxOverflowBubbles) {
+ mMaxOverflowBubbles = maxOverflowBubbles;
+ }
+
+ /**
* Description of current bubble data state.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 2060391d38a3..a888bd57c699 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -71,7 +71,7 @@ public class BubbleExperimentConfig {
private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
- private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
+ private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = true;
/**
* When true, if a notification has the information necessary to bubble (i.e. valid
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index c9069316028c..d870c1191512 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -906,7 +906,7 @@ public class BubbleStackView extends FrameLayout {
view -> {
showManageMenu(false /* show */);
final Bubble bubble = mBubbleData.getSelectedBubble();
- if (bubble != null && mBubbleData.hasBubbleWithKey(bubble.getKey())) {
+ if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
mUnbubbleConversationCallback.accept(bubble.getEntry());
}
});
@@ -915,7 +915,7 @@ public class BubbleStackView extends FrameLayout {
view -> {
showManageMenu(false /* show */);
final Bubble bubble = mBubbleData.getSelectedBubble();
- if (bubble != null && mBubbleData.hasBubbleWithKey(bubble.getKey())) {
+ if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
final Intent intent = bubble.getSettingsIntent();
collapseStack(() -> {
mContext.startActivityAsUser(
@@ -1756,14 +1756,13 @@ public class BubbleStackView extends FrameLayout {
if (mIsExpanded) {
final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject();
dismissBubbleIfExists(mBubbleData.getBubbleWithView(draggedOutBubbleView));
-
} else {
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
}
}
private void dismissBubbleIfExists(@Nullable Bubble bubble) {
- if (bubble != null && mBubbleData.hasBubbleWithKey(bubble.getKey())) {
+ if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
mBubbleData.notificationEntryRemoved(
bubble.getEntry(), BubbleController.DISMISS_USER_GESTURE);
}
@@ -2024,8 +2023,8 @@ public class BubbleStackView extends FrameLayout {
// If available, update the manage menu's settings option with the expanded bubble's app
// name and icon.
- if (show && mBubbleData.hasBubbleWithKey(mExpandedBubble.getKey())) {
- final Bubble bubble = mBubbleData.getBubbleWithKey(mExpandedBubble.getKey());
+ if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {
+ final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey());
mManageSettingsIcon.setImageDrawable(bubble.getBadgedAppIcon());
mManageSettingsText.setText(getResources().getString(
R.string.bubbles_app_settings, bubble.getAppName()));
@@ -2241,7 +2240,7 @@ public class BubbleStackView extends FrameLayout {
View child = mBubbleContainer.getChildAt(i);
if (child instanceof BadgedImageView) {
String key = ((BadgedImageView) child).getKey();
- Bubble bubble = mBubbleData.getBubbleWithKey(key);
+ Bubble bubble = mBubbleData.getBubbleInStackWithKey(key);
bubbles.add(bubble);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 3ef693a1ec98..c2b35069a4ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -158,6 +158,7 @@ public class BubbleControllerTest extends SysuiTestCase {
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mRow;
private ExpandableNotificationRow mRow2;
+ private ExpandableNotificationRow mRow3;
private ExpandableNotificationRow mNonBubbleNotifRow;
@Mock
@@ -232,6 +233,7 @@ public class BubbleControllerTest extends SysuiTestCase {
TestableLooper.get(this));
mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
+ mRow3 = mNotificationTestHelper.createBubble(mDeleteIntent);
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
// Return non-null notification data from the NEM
@@ -311,7 +313,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble() {
mBubbleController.updateBubble(mRow.getEntry());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotificationEntryManager).updateNotifications(any());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
@@ -319,7 +321,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
- assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
@@ -335,8 +337,11 @@ public class BubbleControllerTest extends SysuiTestCase {
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
+ verify(mNotificationEntryManager, never()).performRemoveNotification(
+ eq(mRow.getEntry().getSbn()), anyInt());
+ assertFalse(mRow.getEntry().isBubble());
- Bubble b2 = mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey());
+ Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
mBubbleController.promoteBubbleFromOverflow(b);
@@ -344,45 +349,49 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void testRemoveBubble_withDismissedNotif() {
- mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
-
- assertTrue(mBubbleController.hasBubbles());
- assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
-
- // Make it look like dismissed notif
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
-
- // Now remove the bubble
+ public void testCancelOverflowBubble() {
+ mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
+ false, /* showInShade */ true);
mBubbleController.removeBubble(
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
- // Since the notif is dismissed, once the bubble is removed, performRemoveNotification gets
- // called to really remove the notif
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
eq(mRow.getEntry().getSbn()), anyInt());
- assertFalse(mBubbleController.hasBubbles());
+ assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
+ assertFalse(mRow.getEntry().isBubble());
+ }
+
+ @Test
+ public void testUserChange_doesNotRemoveNotif() {
+ mBubbleController.updateBubble(mRow.getEntry());
+ assertTrue(mBubbleController.hasBubbles());
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_CHANGED);
+ verify(mNotificationEntryManager, never()).performRemoveNotification(
+ eq(mRow.getEntry().getSbn()), anyInt());
+ assertFalse(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
+ assertTrue(mRow.getEntry().isBubble());
}
@Test
public void testDismissStack() {
mBubbleController.updateBubble(mRow.getEntry());
verify(mNotificationEntryManager, times(1)).updateNotifications(any());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
mBubbleController.updateBubble(mRow2.getEntry());
verify(mNotificationEntryManager, times(2)).updateNotifications(any());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
- assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
- assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -452,10 +461,10 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow2.getEntry()));
// Switch which bubble is expanded
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
mBubbleData.setExpanded(true);
assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -483,7 +492,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Expand
mBubbleData.setExpanded(true);
@@ -496,7 +505,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -511,7 +520,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Expand
mBubbleData.setExpanded(true);
@@ -524,7 +533,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Send update
mEntryListener.onPreEntryUpdated(mRow.getEntry());
@@ -534,7 +543,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -557,24 +566,24 @@ public class BubbleControllerTest extends SysuiTestCase {
// Last added is the one that is expanded
assertEquals(mRow2.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
mBubbleController.removeBubble(
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
mBubbleController.removeBubble(
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -639,8 +648,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Dot + flyout is hidden because notif is suppressed
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
@@ -656,7 +665,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Should show dot
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Update to suppress notif
setMetadataFlags(mRow.getEntry(),
@@ -667,8 +676,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Dot + flyout is hidden because notif is suppressed
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
@@ -699,7 +708,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -812,28 +821,73 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
+ public void removeNotif_inOverflow_intercepted() {
+ // Get bubble with notif in shade.
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
-
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
- // Dismiss the bubble
+ // Dismiss the bubble into overflow.
mBubbleController.removeBubble(
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles());
- // Dismiss the notification
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
- // It's no longer a bubble so we shouldn't intercept
+ // Notif is no longer a bubble, but still in overflow, so we intercept removal.
+ assertTrue(intercepted);
+ }
+
+ @Test
+ public void removeNotif_notInOverflow_notIntercepted() {
+ // Get bubble with notif in shade.
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
+ assertFalse(mBubbleController.hasBubbles());
+
+ boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
+
+ // Notif is no longer a bubble, so we should not intercept removal.
assertFalse(intercepted);
}
@Test
+ public void testOverflowBubble_maxReached_notInShade_bubbleRemoved() {
+ mBubbleController.updateBubble(
+ mRow.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ mBubbleController.updateBubble(
+ mRow2.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ mBubbleController.updateBubble(
+ mRow3.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ assertEquals(mBubbleData.getBubbles().size(), 3);
+
+ mBubbleData.setMaxOverflowBubbles(1);
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ assertEquals(mBubbleData.getBubbles().size(), 2);
+ assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
+
+ mBubbleController.removeBubble(
+ mRow2.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ // Overflow max of 1 is reached; mRow is oldest, so it gets removed
+ verify(mNotificationEntryManager, times(1)).performRemoveNotification(
+ mRow.getEntry().getSbn(), REASON_CANCEL);
+ assertEquals(mBubbleData.getBubbles().size(), 1);
+ assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
+ }
+
+ @Test
public void testNotifyShadeSuppressionChange_notificationDismiss() {
BubbleController.NotificationSuppressionChangedListener listener =
mock(BubbleController.NotificationSuppressionChangedListener.class);
@@ -854,7 +908,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
}
@Test
@@ -877,7 +931,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
}
@Test
@@ -887,7 +941,7 @@ public class BubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
- assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// WHEN the summary is dismissed
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
@@ -905,7 +959,7 @@ public class BubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
- assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// GIVEN the summary is dismissed
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
@@ -914,7 +968,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL);
// THEN the summary and its children are removed from bubble data
- assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertFalse(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
assertFalse(mBubbleData.isSummarySuppressed(
groupSummary.getEntry().getSbn().getGroupKey()));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index d2f912770577..66f119a082a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -20,8 +20,11 @@ import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanki
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -285,6 +288,25 @@ public class BubbleDataTest extends SysuiTestCase {
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
}
+ @Test
+ public void testOverflowBubble_maxReached_bubbleRemoved() {
+ // Setup
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryA3, 3000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.setMaxOverflowBubbles(1);
+ mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
+
+ // Overflow max of 1 is reached; A1 is oldest, so it gets removed
+ mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
+ }
+
/**
* Verifies that new bubbles insert to the left when collapsed, carrying along grouped bubbles.
* <p>
@@ -473,6 +495,32 @@ public class BubbleDataTest extends SysuiTestCase {
}
/**
+ * Verifies that overflow bubbles are canceled on notif entry removal.
+ */
+ @Test
+ public void test_removeOverflowBubble_forCanceledNotif() {
+ // Setup
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryA3, 3000);
+ sendUpdatedEntryAtTime(mEntryB1, 4000);
+ sendUpdatedEntryAtTime(mEntryB2, 5000);
+ sendUpdatedEntryAtTime(mEntryB3, 6000); // [A2, A3, B1, B2, B3], overflow: [A1]
+ sendUpdatedEntryAtTime(mEntryC1, 7000); // [A3, B1, B2, B3, C1], overflow: [A2, A1]
+ mBubbleData.setListener(mListener);
+
+ // Test
+ mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
+
+ // Test
+ mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_GROUP_CANCELLED);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of());
+ }
+
+ /**
* Verifies that when the selected bubble is removed with the stack in the collapsed state,
* the selection moves to the next most-recently updated bubble.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 8e6fc8a24b31..23dfb7c2a3a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -283,20 +283,20 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble() {
mBubbleController.updateBubble(mRow.getEntry());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
- assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
}
@Test
- public void testRemoveBubble_withDismissedNotif() {
+ public void testRemoveBubble_withDismissedNotif_inOverflow() {
mEntryListener.onEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
@@ -304,13 +304,34 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
// Make it look like dismissed notif
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
// Now remove the bubble
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
- // Since the notif is dismissed, once the bubble is removed, removeNotification gets
- // called to really remove the notif
+ // We don't remove the notification since the bubble is still in overflow.
+ verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), anyInt());
+ assertFalse(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void testRemoveBubble_withDismissedNotif_notInOverflow() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+
+ // Make it look like dismissed notif
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
+
+ // Now remove the bubble
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
+ assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
+
+ // Since the notif is dismissed and not in overflow, once the bubble is removed,
+ // removeNotification gets called to really remove the notif
verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -319,17 +340,17 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testDismissStack() {
mBubbleController.updateBubble(mRow.getEntry());
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
mBubbleController.updateBubble(mRow2.getEntry());
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
- assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
- assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
- assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
}
@Test
@@ -389,10 +410,10 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
// Switch which bubble is expanded
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
mBubbleData.setExpanded(true);
assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -417,7 +438,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Expand
mBubbleData.setExpanded(true);
@@ -428,7 +449,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -443,7 +464,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Expand
mBubbleData.setExpanded(true);
@@ -454,7 +475,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Send update
mEntryListener.onEntryUpdated(mRow.getEntry());
@@ -464,7 +485,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Notif shouldn't show dot after expansion
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -485,24 +506,24 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Last added is the one that is expanded
assertEquals(mRow2.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
mBubbleController.removeBubble(
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
mBubbleController.removeBubble(
- mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
+ mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -561,8 +582,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Dot + flyout is hidden because notif is suppressed
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
@@ -576,7 +597,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Should show dot
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Update to suppress notif
setMetadataFlags(mRow.getEntry(),
@@ -587,8 +608,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
// Dot + flyout is hidden because notif is suppressed
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
- assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
@@ -601,7 +622,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
mTestableLooper.processAllMessages();
- assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@Test
@@ -679,7 +700,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
}
@Test
- public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
+ public void removeBubble_dismissIntoOverflow_intercepted() {
mEntryListener.onEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
@@ -695,7 +716,28 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Dismiss the notification
boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
- // It's no longer a bubble so we shouldn't intercept
+ // Intercept dismissal since bubble is going into overflow
+ assertTrue(intercepted);
+ }
+
+ @Test
+ public void removeBubble_notIntercepted() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ // Dismiss the bubble
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
+ assertFalse(mBubbleController.hasBubbles());
+
+ // Dismiss the notification
+ boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+
+ // Not a bubble anymore so we don't intercept dismissal.
assertFalse(intercepted);
}
@@ -719,7 +761,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
}
@Test
@@ -742,7 +784,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
- mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
}
@Test
@@ -752,7 +794,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
- assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// WHEN the summary is dismissed
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
@@ -770,7 +812,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
- assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// GIVEN the summary is dismissed
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
@@ -779,7 +821,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
// THEN the summary and its children are removed from bubble data
- assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertFalse(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
assertFalse(mBubbleData.isSummarySuppressed(
groupSummary.getEntry().getSbn().getGroupKey()));
}
@@ -805,7 +847,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
// THEN the bubble child still exists as a bubble and is suppressed from the shade
- assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry()));