summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java190
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java247
3 files changed, 278 insertions, 250 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 55d3a4c85256..4ec79a64b2a3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -56,6 +56,7 @@ import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.util.Log;
+import android.util.Pair;
import android.view.Display;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
@@ -514,62 +515,66 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
@Override
- public void onBubbleAdded(Bubble bubble) {
- ensureStackViewCreated();
- mStackView.addBubble(bubble);
- }
+ public void applyUpdate(BubbleData.Update update) {
+ if (mStackView == null && update.addedBubble != null) {
+ // Lazy init stack view when the first bubble is added.
+ ensureStackViewCreated();
+ }
- @Override
- public void onBubbleRemoved(Bubble bubble, @DismissReason int reason) {
- if (mStackView != null) {
- mStackView.removeBubble(bubble);
+ // If not yet initialized, ignore all other changes.
+ if (mStackView == null) {
+ return;
}
- if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
- && !bubble.entry.showInShadeWhenBubble()) {
- // The bubble is gone & the notification is gone, time to actually remove it
- mNotificationEntryManager.performRemoveNotification(bubble.entry.notification,
- UNDEFINED_DISMISS_REASON);
- } else {
- // The notification is still in the shade but we've removed the bubble so
- // lets make sure NoMan knows it's not a bubble anymore
- try {
- mBarService.onNotificationBubbleChanged(bubble.getKey(), false /* isBubble */);
- } catch (RemoteException e) {
- // Bad things have happened
+
+ if (update.addedBubble != null) {
+ mStackView.addBubble(update.addedBubble);
+ }
+
+ // Collapsing? Do this first before remaining steps.
+ if (update.expandedChanged && !update.expanded) {
+ mStackView.setExpanded(false);
+ }
+
+ // Do removals, if any.
+ for (Pair<Bubble, Integer> removed : update.removedBubbles) {
+ final Bubble bubble = removed.first;
+ @DismissReason final int reason = removed.second;
+ mStackView.removeBubble(bubble);
+
+ if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
+ && !bubble.entry.showInShadeWhenBubble()) {
+ // The bubble is gone & the notification is gone, time to actually remove it
+ mNotificationEntryManager.performRemoveNotification(bubble.entry.notification,
+ UNDEFINED_DISMISS_REASON);
+ } else {
+ // The notification is still in the shade but we've removed the bubble so
+ // lets make sure NoMan knows it's not a bubble anymore
+ try {
+ mBarService.onNotificationBubbleChanged(bubble.getKey(),
+ false /* isBubble */);
+ } catch (RemoteException e) {
+ // Bad things have happened
+ }
}
}
- }
- public void onBubbleUpdated(Bubble bubble) {
- if (mStackView != null) {
- mStackView.updateBubble(bubble);
+ if (update.updatedBubble != null) {
+ mStackView.updateBubble(update.updatedBubble);
}
- }
- @Override
- public void onOrderChanged(List<Bubble> bubbles) {
- if (mStackView != null) {
- mStackView.updateBubbleOrder(bubbles);
+ if (update.orderChanged) {
+ mStackView.updateBubbleOrder(update.bubbles);
}
- }
- @Override
- public void onSelectionChanged(@Nullable Bubble selectedBubble) {
- if (mStackView != null) {
- mStackView.setSelectedBubble(selectedBubble);
+ if (update.selectionChanged) {
+ mStackView.setSelectedBubble(update.selectedBubble);
}
- }
- @Override
- public void onExpandedChanged(boolean expanded) {
- if (mStackView != null) {
- mStackView.setExpanded(expanded);
+ // Expanding? Apply this last.
+ if (update.expandedChanged && update.expanded) {
+ mStackView.setExpanded(true);
}
- }
- // Runs on state change.
- @Override
- public void apply() {
mNotificationEntryManager.updateNotifications();
updateStack();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 1858244d13bc..6ab973eb3065 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -60,54 +60,46 @@ public class BubbleData {
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();
+ /** Contains information about changes that have been made to the state of bubbles. */
+ static final class Update {
+ boolean expandedChanged;
+ boolean selectionChanged;
+ boolean orderChanged;
+ boolean expanded;
+ @Nullable Bubble selectedBubble;
+ @Nullable Bubble addedBubble;
+ @Nullable Bubble updatedBubble;
+ // Pair with Bubble and @DismissReason Integer
+ final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>();
+
+ // A read-only view of the bubbles list, changes there will be reflected here.
+ final List<Bubble> bubbles;
+
+ private Update(List<Bubble> bubbleOrder) {
+ bubbles = Collections.unmodifiableList(bubbleOrder);
+ }
+
+ boolean anythingChanged() {
+ return expandedChanged
+ || selectionChanged
+ || addedBubble != null
+ || updatedBubble != null
+ || !removedBubbles.isEmpty()
+ || orderChanged;
+ }
+
+ void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
+ removedBubbles.add(new Pair<>(bubbleToRemove, reason));
+ }
+ }
+
/**
* This interface reports changes to the state and appearance of bubbles which should be applied
* as necessary to the UI.
- * <p>
- * Each operation is a report of a pending operation. Each should be considered in
- * combination, when {@link #apply()} is called. For example, both: onExpansionChanged,
- * and onOrderChanged
*/
interface Listener {
-
- /**
- * A new Bubble has been added. A call to {@link #onOrderChanged(List)} will
- * follow, including the new Bubble in position
- */
- void onBubbleAdded(Bubble bubble);
-
- /**
- * A Bubble has been removed. A call to {@link #onOrderChanged(List)} will
- * follow.
- */
- void onBubbleRemoved(Bubble bubble, @DismissReason int reason);
-
- /**
- * An existing bubble has been updated.
- *
- * @param bubble the bubble which was updated
- */
- void onBubbleUpdated(Bubble bubble);
-
- /**
- * Indicates that one or more bubbles should change position. This may be result of insert,
- * or removal of a Bubble, in addition to re-sorting existing Bubbles.
- *
- * @param bubbles an immutable list of the bubbles in the new order
- */
- void onOrderChanged(List<Bubble> bubbles);
-
- /** Indicates the selected bubble changed. */
- void onSelectionChanged(@Nullable Bubble selectedBubble);
-
- /**
- * The UI should transition to the given state, incorporating any pending changes during
- * the animation.
- */
- void onExpandedChanged(boolean expanded);
-
- /** Commit any pending operations (since last call of apply()) */
- void apply();
+ /** Reports changes have have occurred as a result of the most recent operation. */
+ void applyUpdate(Update update);
}
interface TimeSource {
@@ -115,17 +107,12 @@ public class BubbleData {
}
private final Context mContext;
- private List<Bubble> mBubbles;
+ private final List<Bubble> mBubbles;
private Bubble mSelectedBubble;
private boolean mExpanded;
// State tracked during an operation -- keeps track of what listener events to dispatch.
- 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 Update mStateChange;
private TimeSource mTimeSource = System::currentTimeMillis;
@@ -136,6 +123,7 @@ public class BubbleData {
public BubbleData(Context context) {
mContext = context;
mBubbles = new ArrayList<>();
+ mStateChange = new Update(mBubbles);
}
public boolean hasBubbles() {
@@ -185,7 +173,6 @@ public class BubbleData {
// Updates an existing bubble
bubble.setEntry(entry);
doUpdate(bubble);
- mUpdatedBubble = bubble;
}
if (shouldAutoExpand(entry)) {
setSelectedBubbleInternal(bubble);
@@ -217,11 +204,11 @@ public class BubbleData {
minInsertPoint = newGroup ? 0 : findFirstIndexForGroup(bubble.getGroupId());
}
if (insertBubble(minInsertPoint, bubble) < mBubbles.size() - 1) {
- mOrderChanged = true;
+ mStateChange.orderChanged = true;
}
- mAddedBubble = bubble;
+ mStateChange.addedBubble = bubble;
if (!isExpanded()) {
- mOrderChanged |= packGroup(findFirstIndexForGroup(bubble.getGroupId()));
+ mStateChange.orderChanged |= packGroup(findFirstIndexForGroup(bubble.getGroupId()));
// Top bubble becomes selected.
setSelectedBubbleInternal(mBubbles.get(0));
}
@@ -243,6 +230,7 @@ public class BubbleData {
if (DEBUG) {
Log.d(TAG, "doUpdate: " + bubble);
}
+ mStateChange.updatedBubble = bubble;
if (!isExpanded()) {
// while collapsed, update causes re-pack
int prevPos = mBubbles.indexOf(bubble);
@@ -250,7 +238,7 @@ public class BubbleData {
int newPos = insertBubble(0, bubble);
if (prevPos != newPos) {
packGroup(newPos);
- mOrderChanged = true;
+ mStateChange.orderChanged = true;
}
setSelectedBubbleInternal(mBubbles.get(0));
}
@@ -269,12 +257,12 @@ public class BubbleData {
}
if (indexToRemove < mBubbles.size() - 1) {
// Removing anything but the last bubble means positions will change.
- mOrderChanged = true;
+ mStateChange.orderChanged = true;
}
mBubbles.remove(indexToRemove);
- mRemovedBubbles.add(Pair.create(bubbleToRemove, reason));
+ mStateChange.bubbleRemoved(bubbleToRemove, reason);
if (!isExpanded()) {
- mOrderChanged |= repackAll();
+ mStateChange.orderChanged |= repackAll();
}
// Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
@@ -301,77 +289,20 @@ public class BubbleData {
Bubble bubble = mBubbles.remove(0);
bubble.setDismissed();
maybeSendDeleteIntent(reason, bubble.entry);
- mRemovedBubbles.add(Pair.create(bubble, reason));
+ mStateChange.bubbleRemoved(bubble, reason);
}
dispatchPendingChanges();
}
-
private void dispatchPendingChanges() {
- if (mListener == null) {
- mExpandedChanged = false;
- mAddedBubble = null;
- mSelectionChanged = false;
- mRemovedBubbles.clear();
- mUpdatedBubble = null;
- mOrderChanged = false;
- return;
- }
- boolean anythingChanged = false;
-
- if (mAddedBubble != null) {
- mListener.onBubbleAdded(mAddedBubble);
- mAddedBubble = null;
- anythingChanged = true;
- }
-
- // Compat workaround: Always collapse first.
- if (mExpandedChanged && !mExpanded) {
- mListener.onExpandedChanged(mExpanded);
- mExpandedChanged = false;
- anythingChanged = true;
- }
-
- if (mSelectionChanged) {
- mListener.onSelectionChanged(mSelectedBubble);
- mSelectionChanged = false;
- anythingChanged = true;
- }
-
- if (!mRemovedBubbles.isEmpty()) {
- for (Pair<Bubble, Integer> removed : mRemovedBubbles) {
- mListener.onBubbleRemoved(removed.first, removed.second);
- }
- mRemovedBubbles.clear();
- anythingChanged = true;
- }
-
- if (mUpdatedBubble != null) {
- mListener.onBubbleUpdated(mUpdatedBubble);
- mUpdatedBubble = null;
- anythingChanged = true;
- }
-
- if (mOrderChanged) {
- mListener.onOrderChanged(mBubbles);
- mOrderChanged = false;
- anythingChanged = true;
- }
-
- if (mExpandedChanged) {
- mListener.onExpandedChanged(mExpanded);
- mExpandedChanged = false;
- anythingChanged = true;
- }
-
- if (anythingChanged) {
- mListener.apply();
+ if (mListener != null && mStateChange.anythingChanged()) {
+ mListener.applyUpdate(mStateChange);
}
+ mStateChange = new Update(mBubbles);
}
/**
- * Requests a change to the selected bubble. Calls {@link Listener#onSelectionChanged} if
- * the value changes.
+ * Requests a change to the selected bubble.
*
* @param bubble the new selected bubble
*/
@@ -391,13 +322,12 @@ public class BubbleData {
bubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
}
mSelectedBubble = bubble;
- mSelectionChanged = true;
- return;
+ mStateChange.selectedBubble = bubble;
+ mStateChange.selectionChanged = true;
}
/**
- * Requests a change to the expanded state. Calls {@link Listener#onExpandedChanged} if
- * the value changes.
+ * Requests a change to the expanded state.
*
* @param shouldExpand the new requested state
*/
@@ -418,11 +348,11 @@ public class BubbleData {
return;
}
mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
- mOrderChanged |= repackAll();
+ mStateChange.orderChanged |= repackAll();
} else if (!mBubbles.isEmpty()) {
// Apply ordering and grouping rules from expanded -> collapsed, then save
// the result.
- mOrderChanged |= repackAll();
+ mStateChange.orderChanged |= repackAll();
// Save the state which should be returned to when expanded (with no other changes)
if (mBubbles.indexOf(mSelectedBubble) > 0) {
@@ -442,7 +372,8 @@ public class BubbleData {
}
}
mExpanded = shouldExpand;
- mExpandedChanged = true;
+ mStateChange.expanded = shouldExpand;
+ mStateChange.expandedChanged = true;
}
private static long sortKey(Bubble bubble) {
@@ -569,7 +500,8 @@ public class BubbleData {
if (repacked.equals(mBubbles)) {
return false;
}
- mBubbles = repacked;
+ mBubbles.clear();
+ mBubbles.addAll(repacked);
return true;
}
@@ -595,7 +527,7 @@ public class BubbleData {
for (Iterator<Bubble> i = mBubbles.iterator(); i.hasNext(); ) {
Bubble bubble = i.next();
if (bubble.getGroupId().equals(blockedGroupId)) {
- mRemovedBubbles.add(Pair.create(bubble, BubbleController.DISMISS_BLOCKED));
+ mStateChange.bubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED);
i.remove();
}
}
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 364a0f7ed2e9..815a70ae3026 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -16,19 +16,12 @@
package com.android.systemui.bubbles;
-import static com.android.systemui.bubbles.BubbleController.DISMISS_AGED;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
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.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -38,6 +31,7 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -51,11 +45,20 @@ import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
+/**
+ * Tests operations and the resulting state managed by BubbleData.
+ * <p>
+ * After each operation to verify, {@link #verifyUpdateReceived()} ensures the listener was called
+ * and captures the Update object received there.
+ * <p>
+ * Other methods beginning with 'assert' access the captured update object and assert on specific
+ * aspects of it.
+ */
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -90,6 +93,9 @@ public class BubbleDataTest extends SysuiTestCase {
private NotificationTestHelper mNotificationTestHelper;
+ @Captor
+ private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
+
@Before
public void setUp() throws Exception {
mNotificationTestHelper = new NotificationTestHelper(mContext);
@@ -132,9 +138,9 @@ public class BubbleDataTest extends SysuiTestCase {
sendUpdatedEntryAtTime(mEntryA1, 1000);
// Verify
- verify(mListener).onBubbleAdded(eq(mBubbleA1));
- verify(mListener).onSelectionChanged(eq(mBubbleA1));
- verify(mListener).apply();
+ verifyUpdateReceived();
+ assertBubbleAdded(mBubbleA1);
+ assertSelectionChangedTo(mBubbleA1);
}
@Test
@@ -149,8 +155,8 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
// Verify
- verify(mListener).onBubbleRemoved(eq(mBubbleA1), eq(BubbleController.DISMISS_USER_GESTURE));
- verify(mListener).apply();
+ verifyUpdateReceived();
+ assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_USER_GESTURE);
}
// COLLAPSED / ADD
@@ -171,7 +177,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryC1, 6000);
- verify(mListener).onBubbleRemoved(eq(mBubbleA1), eq(DISMISS_AGED));
+ verifyUpdateReceived();
+ assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
}
/**
@@ -190,19 +197,20 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryA1, 1000);
- verify(mListener, never()).onOrderChanged(anyList());
+ verifyUpdateReceived();
+ assertOrderNotChanged();
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB1, 2000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB1, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB1, mBubbleA1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB2, 3000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB2, mBubbleB1, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryA2, 4000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1);
}
/**
@@ -223,19 +231,20 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
setOngoing(mEntryA1, true);
sendUpdatedEntryAtTime(mEntryA1, 1000);
- verify(mListener, never()).onOrderChanged(anyList());
+ verifyUpdateReceived();
+ assertOrderNotChanged();
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB1, 2000);
- verify(mListener, never()).onOrderChanged(eq(listOf(mBubbleA1, mBubbleB1)));
+ verifyUpdateReceived();
+ assertOrderNotChanged();
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB2, 3000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA1, mBubbleB2, mBubbleB1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA1, mBubbleB2, mBubbleB1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryA2, 4000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA1, mBubbleA2, mBubbleB2, mBubbleB1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleB2, mBubbleB1);
}
/**
@@ -252,20 +261,22 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryA1, 1000);
- verify(mListener).onSelectionChanged(eq(mBubbleA1));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleA1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB1, 2000);
- verify(mListener).onSelectionChanged(eq(mBubbleB1));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleB1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryB2, 3000);
- verify(mListener).onSelectionChanged(eq(mBubbleB2));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleB2);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryA2, 4000);
- verify(mListener).onSelectionChanged(eq(mBubbleA2));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleA2);
}
+
/**
* Verifies that while collapsed, the selection will not change if the selected bubble is
* ongoing. It remains the top bubble and as such remains selected.
@@ -282,9 +293,17 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryB1, 2000);
+ verifyUpdateReceived();
+ assertSelectionNotChanged();
+
sendUpdatedEntryAtTime(mEntryB2, 3000);
+ verifyUpdateReceived();
+ assertSelectionNotChanged();
+
sendUpdatedEntryAtTime(mEntryA2, 4000);
- verify(mListener, never()).onSelectionChanged(any(Bubble.class));
+ verifyUpdateReceived();
+ assertSelectionNotChanged();
+
assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1); // selection unchanged
}
@@ -305,7 +324,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB2, mBubbleB1, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
}
@@ -324,7 +344,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener, never()).onOrderChanged(anyList());
+ verifyUpdateReceived();
+ assertOrderNotChanged();
}
/**
@@ -343,7 +364,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB2, mBubbleB1, mBubbleA2)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA2);
}
/**
@@ -361,7 +383,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_NOTIF_CANCEL);
- verify(mListener).onSelectionChanged(eq(mBubbleB2));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleB2);
}
// COLLAPSED / UPDATE
@@ -381,11 +404,12 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryB1, 5000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB1, mBubbleB2, mBubbleA2, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB1, mBubbleB2, mBubbleA2, mBubbleA1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryA1, 6000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA1, mBubbleA2, mBubbleB1, mBubbleB2)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleB1, mBubbleB2);
}
/**
@@ -402,11 +426,12 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryB1, 5000);
- verify(mListener).onSelectionChanged(eq(mBubbleB1));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleB1);
- reset(mListener);
sendUpdatedEntryAtTime(mEntryA1, 6000);
- verify(mListener).onSelectionChanged(eq(mBubbleA1));
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleA1);
}
/**
@@ -425,7 +450,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryB2, 5000); // [A1*, A2, B2, B1]
- verify(mListener, never()).onSelectionChanged(any(Bubble.class));
+ verifyUpdateReceived();
+ assertSelectionNotChanged();
}
/**
@@ -434,10 +460,10 @@ public class BubbleDataTest extends SysuiTestCase {
@Test
public void test_collapsed_expansion_whenEmpty_doesNothing() {
assertThat(mBubbleData.hasBubbles()).isFalse();
- changeExpandedStateAtTime(true, 2000L);
+ mBubbleData.setListener(mListener);
- verify(mListener, never()).onExpandedChanged(anyBoolean());
- verify(mListener, never()).apply();
+ changeExpandedStateAtTime(true, 2000L);
+ verifyZeroInteractions(mListener);
}
@Test
@@ -450,7 +476,8 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
// Verify the selection was cleared.
- verify(mListener).onSelectionChanged(isNull());
+ verifyUpdateReceived();
+ assertSelectionCleared();
}
// EXPANDED / ADD
@@ -476,7 +503,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryC1, 4000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleC1, mBubbleB1, mBubbleA2, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleC1, mBubbleB1, mBubbleA2, mBubbleA1);
}
/**
@@ -498,7 +526,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryC1, 4000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA1, mBubbleA2, mBubbleC1, mBubbleB1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleC1, mBubbleB1);
}
/**
@@ -519,7 +548,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryA3, 4000);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB1, mBubbleA3, mBubbleA2, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB1, mBubbleA3, mBubbleA2, mBubbleA1);
}
// EXPANDED / UPDATE
@@ -543,7 +573,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryA1, 4000);
- verify(mListener, never()).onOrderChanged(anyList());
+ verifyUpdateReceived();
+ assertOrderNotChanged();
}
/**
@@ -564,9 +595,16 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
sendUpdatedEntryAtTime(mEntryA1, 6000);
+ verifyUpdateReceived();
+ assertOrderNotChanged();
+
sendUpdatedEntryAtTime(mEntryA2, 7000);
+ verifyUpdateReceived();
+ assertOrderNotChanged();
+
sendUpdatedEntryAtTime(mEntryB1, 8000);
- verify(mListener, never()).onSelectionChanged(any(Bubble.class));
+ verifyUpdateReceived();
+ assertOrderNotChanged();
}
// EXPANDED / REMOVE
@@ -590,7 +628,8 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB1, mBubbleA2, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB1, mBubbleA2, mBubbleA1);
}
/**
@@ -614,11 +653,12 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener).onSelectionChanged(mBubbleA1);
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleA1);
- reset(mListener);
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener).onSelectionChanged(mBubbleB1);
+ verifyUpdateReceived();
+ assertSelectionChangedTo(mBubbleB1);
}
@Test
@@ -629,11 +669,12 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
changeExpandedStateAtTime(true, 3000L);
- verify(mListener).onExpandedChanged(eq(true));
+ verifyUpdateReceived();
+ assertExpandedChangedTo(true);
- reset(mListener);
changeExpandedStateAtTime(false, 4000L);
- verify(mListener).onExpandedChanged(eq(false));
+ verifyUpdateReceived();
+ assertExpandedChangedTo(false);
}
/**
@@ -663,7 +704,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setSelectedBubble(mBubbleA2);
mBubbleData.setListener(mListener);
assertThat(mBubbleData.getBubbles()).isEqualTo(
- listOf(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
// Test
@@ -678,12 +719,13 @@ public class BubbleDataTest extends SysuiTestCase {
//
// collapse -> selected bubble (A2) moves first.
changeExpandedStateAtTime(false, 8000L);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2);
// expand -> "original" order/grouping restored
- reset(mListener);
changeExpandedStateAtTime(true, 10000L);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleB1, mBubbleB2, mBubbleA2, mBubbleA1)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleB1, mBubbleB2, mBubbleA2, mBubbleA1);
}
/**
@@ -717,15 +759,17 @@ public class BubbleDataTest extends SysuiTestCase {
//
// collapse -> selected bubble (A2) moves first.
changeExpandedStateAtTime(false, 8000L);
- verify(mListener).onOrderChanged(eq(listOf(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2)));
+ verifyUpdateReceived();
+ assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2);
// An update occurs, which causes sorting, and this invalidates the previously saved order.
sendUpdatedEntryAtTime(mEntryA2, 9000);
+ verifyUpdateReceived();
// No order changes when expanding because the new sorted order remains.
- reset(mListener);
changeExpandedStateAtTime(true, 10000L);
- verify(mListener, never()).onOrderChanged(anyList());
+ verifyUpdateReceived();
+ assertOrderNotChanged();
}
@Test
@@ -737,9 +781,61 @@ public class BubbleDataTest extends SysuiTestCase {
// Test
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
- verify(mListener).onExpandedChanged(eq(false));
+ verifyUpdateReceived();
+ assertExpandedChangedTo(false);
}
+ private void verifyUpdateReceived() {
+ verify(mListener).applyUpdate(mUpdateCaptor.capture());
+ reset(mListener);
+ }
+
+ private void assertBubbleAdded(Bubble expected) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.addedBubble).named("addedBubble").isEqualTo(expected);
+ }
+
+ private void assertBubbleRemoved(Bubble expected, @BubbleController.DismissReason int reason) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.removedBubbles).named("removedBubbles")
+ .isEqualTo(ImmutableList.of(Pair.create(expected, reason)));
+ }
+
+ private void assertOrderNotChanged() {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.orderChanged).named("orderChanged").isFalse();
+ }
+
+ private void assertOrderChangedTo(Bubble... order) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.orderChanged).named("orderChanged").isTrue();
+ assertThat(update.bubbles).named("bubble order").isEqualTo(ImmutableList.copyOf(order));
+ }
+
+ private void assertSelectionNotChanged() {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.selectionChanged).named("selectionChanged").isFalse();
+ }
+
+ private void assertSelectionChangedTo(Bubble bubble) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.selectionChanged).named("selectionChanged").isTrue();
+ assertThat(update.selectedBubble).named("selectedBubble").isEqualTo(bubble);
+ }
+
+ private void assertSelectionCleared() {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.selectionChanged).named("selectionChanged").isTrue();
+ assertThat(update.selectedBubble).named("selectedBubble").isNull();
+ }
+
+ private void assertExpandedChangedTo(boolean expected) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.expandedChanged).named("expandedChanged").isTrue();
+ assertThat(update.expanded).named("expanded").isEqualTo(expected);
+ }
+
+
private NotificationEntry createBubbleEntry(int userId, String notifKey, String packageName) {
return createBubbleEntry(userId, notifKey, packageName, 1000);
}
@@ -798,9 +894,4 @@ public class BubbleDataTest extends SysuiTestCase {
setCurrentTime(time);
mBubbleData.setExpanded(shouldBeExpanded);
}
-
- /** Syntactic sugar to keep assertions more readable */
- private static <T> List<T> listOf(T... a) {
- return ImmutableList.copyOf(a);
- }
} \ No newline at end of file