Merge "Add cached state to prevent blocking calls from SysUI->Shell" into sc-dev am: 979fe90f43

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14964835

Change-Id: I526730dd7183ae1b7f5314e77910a1474441e58f
This commit is contained in:
Winson Chung
2021-06-18 21:52:34 +00:00
committed by Automerger Merge Worker
6 changed files with 332 additions and 183 deletions

View File

@@ -284,6 +284,15 @@ public class Bubble implements BubbleViewProvider {
return mTitle; return mTitle;
} }
/**
* @return the ShortcutInfo id if it exists, or the metadata shortcut id otherwise.
*/
String getShortcutId() {
return getShortcutInfo() != null
? getShortcutInfo().getId()
: getMetadataShortcutId();
}
String getMetadataShortcutId() { String getMetadataShortcutId() {
return mMetadataShortcutId; return mMetadataShortcutId;
} }

View File

@@ -93,6 +93,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -265,15 +266,7 @@ public class BubbleController {
public void initialize() { public void initialize() {
mBubbleData.setListener(mBubbleDataListener); mBubbleData.setListener(mBubbleDataListener);
mBubbleData.setSuppressionChangedListener(bubble -> { mBubbleData.setSuppressionChangedListener(this::onBubbleNotificationSuppressionChanged);
// Make sure NoMan knows suppression state so that anyone querying it can tell.
try {
mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
!bubble.showInShade(), bubble.isSuppressed());
} catch (RemoteException e) {
// Bad things have happened
}
});
mBubbleData.setPendingIntentCancelledListener(bubble -> { mBubbleData.setPendingIntentCancelledListener(bubble -> {
if (bubble.getBubbleIntent() == null) { if (bubble.getBubbleIntent() == null) {
@@ -401,6 +394,11 @@ public class BubbleController {
return mImpl; return mImpl;
} }
@VisibleForTesting
public BubblesImpl.CachedState getImplCachedState() {
return mImpl.mCachedState;
}
public ShellExecutor getMainExecutor() { public ShellExecutor getMainExecutor() {
return mMainExecutor; return mMainExecutor;
} }
@@ -500,6 +498,18 @@ public class BubbleController {
updateStack(); updateStack();
} }
@VisibleForTesting
public void onBubbleNotificationSuppressionChanged(Bubble bubble) {
// Make sure NoMan knows suppression state so that anyone querying it can tell.
try {
mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
!bubble.showInShade(), bubble.isSuppressed());
} catch (RemoteException e) {
// Bad things have happened
}
mImpl.mCachedState.updateBubbleSuppressedState(bubble);
}
/** Called when the current user changes. */ /** Called when the current user changes. */
@VisibleForTesting @VisibleForTesting
public void onUserChanged(int newUserId) { public void onUserChanged(int newUserId) {
@@ -808,11 +818,6 @@ public class BubbleController {
} }
} }
private boolean isBubbleExpanded(String key) {
return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
&& mBubbleData.getSelectedBubble().getKey().equals(key);
}
/** Promote the provided bubble from the overflow view. */ /** Promote the provided bubble from the overflow view. */
public void promoteBubbleFromOverflow(Bubble bubble) { public void promoteBubbleFromOverflow(Bubble bubble) {
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK); mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
@@ -1191,6 +1196,9 @@ public class BubbleController {
mSysuiProxy.notifyInvalidateNotifications("BubbleData.Listener.applyUpdate"); mSysuiProxy.notifyInvalidateNotifications("BubbleData.Listener.applyUpdate");
updateStack(); updateStack();
// Update the cached state for queries from SysUI
mImpl.mCachedState.update(update);
} }
}; };
@@ -1364,25 +1372,124 @@ public class BubbleController {
} }
private class BubblesImpl implements Bubbles { private class BubblesImpl implements Bubbles {
// Up-to-date cached state of bubbles data for SysUI to query from the calling thread
@VisibleForTesting
public class CachedState {
private boolean mIsStackExpanded;
private String mSelectedBubbleKey;
private HashSet<String> mSuppressedBubbleKeys = new HashSet<>();
private HashMap<String, String> mSuppressedGroupToNotifKeys = new HashMap<>();
private HashMap<String, Bubble> mShortcutIdToBubble = new HashMap<>();
private ArrayList<Bubble> mTmpBubbles = new ArrayList<>();
/**
* Updates the cached state based on the last full BubbleData change.
*/
synchronized void update(BubbleData.Update update) {
if (update.selectionChanged) {
mSelectedBubbleKey = update.selectedBubble != null
? update.selectedBubble.getKey()
: null;
}
if (update.expandedChanged) {
mIsStackExpanded = update.expanded;
}
if (update.suppressedSummaryChanged) {
String summaryKey =
mBubbleData.getSummaryKey(update.suppressedSummaryGroup);
if (summaryKey != null) {
mSuppressedGroupToNotifKeys.put(update.suppressedSummaryGroup, summaryKey);
} else {
mSuppressedGroupToNotifKeys.remove(update.suppressedSummaryGroup);
}
}
mTmpBubbles.clear();
mTmpBubbles.addAll(update.bubbles);
mTmpBubbles.addAll(update.overflowBubbles);
mSuppressedBubbleKeys.clear();
mShortcutIdToBubble.clear();
for (Bubble b : mTmpBubbles) {
mShortcutIdToBubble.put(b.getShortcutId(), b);
updateBubbleSuppressedState(b);
}
}
/**
* Updates a specific bubble suppressed state. This is used mainly because notification
* suppression changes don't go through the same BubbleData update mechanism.
*/
synchronized void updateBubbleSuppressedState(Bubble b) {
if (!b.showInShade()) {
mSuppressedBubbleKeys.add(b.getKey());
} else {
mSuppressedBubbleKeys.remove(b.getKey());
}
}
public synchronized boolean isStackExpanded() {
return mIsStackExpanded;
}
public synchronized boolean isBubbleExpanded(String key) {
return mIsStackExpanded && key.equals(mSelectedBubbleKey);
}
public synchronized boolean isBubbleNotificationSuppressedFromShade(String key,
String groupKey) {
return mSuppressedBubbleKeys.contains(key)
|| (mSuppressedGroupToNotifKeys.containsKey(groupKey)
&& key.equals(mSuppressedGroupToNotifKeys.get(groupKey)));
}
@Nullable
public synchronized Bubble getBubbleWithShortcutId(String id) {
return mShortcutIdToBubble.get(id);
}
synchronized void dump(PrintWriter pw) {
pw.println("BubbleImpl.CachedState state:");
pw.println("mIsStackExpanded: " + mIsStackExpanded);
pw.println("mSelectedBubbleKey: " + mSelectedBubbleKey);
pw.print("mSuppressedBubbleKeys: ");
pw.println(mSuppressedBubbleKeys.size());
for (String key : mSuppressedBubbleKeys) {
pw.println(" suppressing: " + key);
}
pw.print("mSuppressedGroupToNotifKeys: ");
pw.println(mSuppressedGroupToNotifKeys.size());
for (String key : mSuppressedGroupToNotifKeys.keySet()) {
pw.println(" suppressing: " + key);
}
}
}
private CachedState mCachedState = new CachedState();
@Override @Override
public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) { public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
return mMainExecutor.executeBlockingForResult(() -> { return mCachedState.isBubbleNotificationSuppressedFromShade(key, groupKey);
return BubbleController.this.isBubbleNotificationSuppressedFromShade(key, groupKey);
}, Boolean.class);
} }
@Override @Override
public boolean isBubbleExpanded(String key) { public boolean isBubbleExpanded(String key) {
return mMainExecutor.executeBlockingForResult(() -> { return mCachedState.isBubbleExpanded(key);
return BubbleController.this.isBubbleExpanded(key);
}, Boolean.class);
} }
@Override @Override
public boolean isStackExpanded() { public boolean isStackExpanded() {
return mMainExecutor.executeBlockingForResult(() -> { return mCachedState.isStackExpanded();
return BubbleController.this.isStackExpanded(); }
}, Boolean.class);
@Override
@Nullable
public Bubble getBubbleWithShortcutId(String shortcutId) {
return mCachedState.getBubbleWithShortcutId(shortcutId);
} }
@Override @Override
@@ -1424,14 +1531,6 @@ public class BubbleController {
}); });
} }
@Override
@Nullable
public Bubble getBubbleWithShortcutId(String shortcutId) {
return mMainExecutor.executeBlockingForResult(() -> {
return BubbleController.this.mBubbleData.getAnyBubbleWithShortcutId(shortcutId);
}, Bubble.class);
}
@Override @Override
public void onTaskbarChanged(Bundle b) { public void onTaskbarChanged(Bundle b) {
mMainExecutor.execute(() -> { mMainExecutor.execute(() -> {
@@ -1555,6 +1654,7 @@ public class BubbleController {
try { try {
mMainExecutor.executeBlocking(() -> { mMainExecutor.executeBlocking(() -> {
BubbleController.this.dump(fd, pw, args); BubbleController.this.dump(fd, pw, args);
mCachedState.dump(pw);
}); });
} catch (InterruptedException e) { } catch (InterruptedException e) {
Slog.e(TAG, "Failed to dump BubbleController in 2s"); Slog.e(TAG, "Failed to dump BubbleController in 2s");

View File

@@ -73,6 +73,7 @@ public class BubbleData {
boolean expandedChanged; boolean expandedChanged;
boolean selectionChanged; boolean selectionChanged;
boolean orderChanged; boolean orderChanged;
boolean suppressedSummaryChanged;
boolean expanded; boolean expanded;
@Nullable BubbleViewProvider selectedBubble; @Nullable BubbleViewProvider selectedBubble;
@Nullable Bubble addedBubble; @Nullable Bubble addedBubble;
@@ -81,6 +82,7 @@ public class BubbleData {
@Nullable Bubble removedOverflowBubble; @Nullable Bubble removedOverflowBubble;
@Nullable Bubble suppressedBubble; @Nullable Bubble suppressedBubble;
@Nullable Bubble unsuppressedBubble; @Nullable Bubble unsuppressedBubble;
@Nullable String suppressedSummaryGroup;
// Pair with Bubble and @DismissReason Integer // Pair with Bubble and @DismissReason Integer
final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>(); final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>();
@@ -103,7 +105,9 @@ public class BubbleData {
|| removedOverflowBubble != null || removedOverflowBubble != null
|| orderChanged || orderChanged
|| suppressedBubble != null || suppressedBubble != null
|| unsuppressedBubble != null; || unsuppressedBubble != null
|| suppressedSummaryChanged
|| suppressedSummaryGroup != null;
} }
void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) { void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
@@ -380,6 +384,9 @@ public class BubbleData {
*/ */
void addSummaryToSuppress(String groupKey, String notifKey) { void addSummaryToSuppress(String groupKey, String notifKey) {
mSuppressedGroupKeys.put(groupKey, notifKey); mSuppressedGroupKeys.put(groupKey, notifKey);
mStateChange.suppressedSummaryChanged = true;
mStateChange.suppressedSummaryGroup = groupKey;
dispatchPendingChanges();
} }
/** /**
@@ -397,6 +404,9 @@ public class BubbleData {
*/ */
void removeSuppressedSummary(String groupKey) { void removeSuppressedSummary(String groupKey) {
mSuppressedGroupKeys.remove(groupKey); mSuppressedGroupKeys.remove(groupKey);
mStateChange.suppressedSummaryChanged = true;
mStateChange.suppressedSummaryGroup = groupKey;
dispatchPendingChanges();
} }
/** /**

View File

@@ -617,7 +617,7 @@ public class BubblesManager implements Dumpable {
* cancel it (and hence the bubbles associated with it). * cancel it (and hence the bubbles associated with it).
* *
* @return true if we want to intercept the dismissal of the entry, else false. * @return true if we want to intercept the dismissal of the entry, else false.
* @see Bubbles#handleDismissalInterception(BubbleEntry, List, IntConsumer) * @see Bubbles#handleDismissalInterception(BubbleEntry, List, IntConsumer, Executor)
*/ */
public boolean handleDismissalInterception(NotificationEntry entry) { public boolean handleDismissalInterception(NotificationEntry entry) {
if (entry == null) { if (entry == null) {

View File

@@ -23,6 +23,8 @@ import static android.service.notification.NotificationListenerService.REASON_CA
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -37,6 +39,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -324,6 +327,7 @@ public class BubblesTest extends SysuiTestCase {
syncExecutor, syncExecutor,
mock(Handler.class)); mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener); mBubbleController.setExpandListener(mBubbleExpandListener);
spyOn(mBubbleController);
mBubblesManager = new BubblesManager( mBubblesManager = new BubblesManager(
mContext, mContext,
@@ -470,7 +474,7 @@ public class BubblesTest extends SysuiTestCase {
@Test @Test
public void testExpandCollapseStack() { public void testExpandCollapseStack() {
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
// Mark it as a bubble and add it explicitly // Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow); mEntryListener.onPendingEntryAdded(mRow);
@@ -478,25 +482,23 @@ public class BubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand the stack // Expand the stack
BubbleStackView stackView = mBubbleController.getStackView(); BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
// Make sure the notif is suppressed // Make sure the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Collapse // Collapse
mBubbleController.collapseStack(); mBubbleController.collapseStack();
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
assertFalse(mSysUiStateBubblesExpanded); assertFalse(mSysUiStateBubblesExpanded);
} }
@@ -512,15 +514,13 @@ public class BubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey())); assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry2);
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Expand // Expand
BubbleStackView stackView = mBubbleController.getStackView(); BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
true, mRow2.getKey()); true, mRow2.getKey());
@@ -528,8 +528,7 @@ public class BubblesTest extends SysuiTestCase {
// Last added is the one that is expanded // Last added is the one that is expanded
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey()); assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry2);
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Switch which bubble is expanded // Switch which bubble is expanded
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey( mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
@@ -537,8 +536,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey( assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey()); stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// collapse for previous bubble // collapse for previous bubble
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
@@ -549,7 +547,7 @@ public class BubblesTest extends SysuiTestCase {
// Collapse // Collapse
mBubbleController.collapseStack(); mBubbleController.collapseStack();
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
assertFalse(mSysUiStateBubblesExpanded); assertFalse(mSysUiStateBubblesExpanded);
} }
@@ -562,22 +560,20 @@ public class BubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
// Expand // Expand
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
} }
@@ -590,22 +586,20 @@ public class BubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
// Expand // Expand
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -614,8 +608,7 @@ public class BubblesTest extends SysuiTestCase {
// Nothing should have changed // Nothing should have changed
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
} }
@@ -634,14 +627,13 @@ public class BubblesTest extends SysuiTestCase {
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
// Last added is the one that is expanded // Last added is the one that is expanded
assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey( assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey()); stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry2);
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Dismiss currently expanded // Dismiss currently expanded
mBubbleController.removeBubble( mBubbleController.removeBubble(
@@ -679,7 +671,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
// Block the bubble so it won't be in the overflow // Block the bubble so it won't be in the overflow
@@ -698,7 +690,7 @@ public class BubblesTest extends SysuiTestCase {
@Test @Test
public void testAutoExpand_fails_noFlag() { public void testAutoExpand_fails_noFlag() {
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
setMetadataFlags(mRow, setMetadataFlags(mRow,
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */); Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
@@ -709,7 +701,7 @@ public class BubblesTest extends SysuiTestCase {
// Expansion shouldn't change // Expansion shouldn't change
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */, verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
mRow.getKey()); mRow.getKey());
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
assertFalse(mSysUiStateBubblesExpanded); assertFalse(mSysUiStateBubblesExpanded);
} }
@@ -726,7 +718,7 @@ public class BubblesTest extends SysuiTestCase {
// Expansion should change // Expansion should change
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */, verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
mRow.getKey()); mRow.getKey());
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
assertTrue(mSysUiStateBubblesExpanded); assertTrue(mSysUiStateBubblesExpanded);
} }
@@ -741,8 +733,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed because we were foreground // Notif should be suppressed because we were foreground
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed // Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
@@ -755,8 +746,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Should not be suppressed // Should not be suppressed
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should show dot // Should show dot
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -766,8 +756,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed // Notif should be suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed // Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
@@ -792,8 +781,7 @@ public class BubblesTest extends SysuiTestCase {
@Test @Test
public void testMarkNewNotificationAsShowInShade() { public void testMarkNewNotificationAsShowInShade() {
mEntryListener.onPendingEntryAdded(mRow); mEntryListener.onPendingEntryAdded(mRow);
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -878,8 +866,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getKey(), mRow, REASON_CANCEL_ALL); mRow.getKey(), mRow, REASON_CANCEL_ALL);
@@ -887,8 +874,7 @@ public class BubblesTest extends SysuiTestCase {
// Intercept! // Intercept!
assertTrue(intercepted); assertTrue(intercepted);
// Should update show in shade state // Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
} }
@Test @Test
@@ -897,8 +883,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getKey(), mRow, REASON_CANCEL); mRow.getKey(), mRow, REASON_CANCEL);
@@ -906,8 +891,7 @@ public class BubblesTest extends SysuiTestCase {
// Intercept! // Intercept!
assertTrue(intercepted); assertTrue(intercepted);
// Should update show in shade state // Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
} }
@Test @Test
@@ -916,8 +900,7 @@ public class BubblesTest extends SysuiTestCase {
mEntryListener.onPendingEntryAdded(mRow); mEntryListener.onPendingEntryAdded(mRow);
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble into overflow. // Dismiss the bubble into overflow.
mBubbleController.removeBubble( mBubbleController.removeBubble(
@@ -938,8 +921,7 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE); mRow.getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
@@ -985,48 +967,36 @@ public class BubblesTest extends SysuiTestCase {
@Test @Test
public void testNotifyShadeSuppressionChange_notificationDismiss() { public void testNotifyShadeSuppressionChange_notificationDismiss() {
Bubbles.SuppressionChangedListener listener =
mock(Bubbles.SuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onPendingEntryAdded(mRow); mEntryListener.onPendingEntryAdded(mRow);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mRemoveInterceptor.onNotificationRemoveRequested( mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getKey(), mRow, REASON_CANCEL); mRow.getKey(), mRow, REASON_CANCEL);
// Should update show in shade state // Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed // Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange( verify(mBubbleController).onBubbleNotificationSuppressionChanged(
mBubbleData.getBubbleInStackWithKey(mRow.getKey())); mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
} }
@Test @Test
public void testNotifyShadeSuppressionChange_bubbleExpanded() { public void testNotifyShadeSuppressionChange_bubbleExpanded() {
Bubbles.SuppressionChangedListener listener =
mock(Bubbles.SuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onPendingEntryAdded(mRow); mEntryListener.onPendingEntryAdded(mRow);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
// Once a bubble is expanded the notif is suppressed // Once a bubble is expanded the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed // Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange( verify(mBubbleController).onBubbleNotificationSuppressionChanged(
mBubbleData.getBubbleInStackWithKey(mRow.getKey())); mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
} }
@@ -1046,7 +1016,11 @@ public class BubblesTest extends SysuiTestCase {
// THEN the summary and bubbled child are suppressed from the shade // THEN the summary and bubbled child are suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(), groupSummary.getEntry().getSbn().getGroupKey())); groupedBubble.getEntry().getKey(),
groupSummary.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(),
groupSummary.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey())); assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
} }
@@ -1102,6 +1076,9 @@ public class BubblesTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(), groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey())); groupedBubble.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey()));
// THEN the summary is removed from GroupManager // THEN the summary is removed from GroupManager
verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry()); verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry());
@@ -1257,4 +1234,42 @@ public class BubblesTest extends SysuiTestCase {
Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble)) Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
.build(); .build();
} }
/**
* Asserts that the bubble stack is expanded and also validates the cached state is updated.
*/
private void assertStackExpanded() {
assertTrue(mBubbleController.isStackExpanded());
assertTrue(mBubbleController.getImplCachedState().isStackExpanded());
}
/**
* Asserts that the bubble stack is collapsed and also validates the cached state is updated.
*/
private void assertStackCollapsed() {
assertFalse(mBubbleController.isStackExpanded());
assertFalse(mBubbleController.getImplCachedState().isStackExpanded());
}
/**
* Asserts that a bubble notification is suppressed from the shade and also validates the cached
* state is updated.
*/
private void assertBubbleNotificationSuppressedFromShade(BubbleEntry entry) {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
}
/**
* Asserts that a bubble notification is not suppressed from the shade and also validates the
* cached state is updated.
*/
private void assertBubbleNotificationNotSuppressedFromShade(BubbleEntry entry) {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
assertFalse(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
}
} }

View File

@@ -19,6 +19,8 @@ package com.android.systemui.wmshell;
import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_BUBBLE;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -268,6 +270,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
syncExecutor, syncExecutor,
mock(Handler.class)); mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener); mBubbleController.setExpandListener(mBubbleExpandListener);
spyOn(mBubbleController);
mBubblesManager = new BubblesManager( mBubblesManager = new BubblesManager(
mContext, mContext,
@@ -328,8 +331,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Make it look like dismissed notif // Make it look like dismissed notif
mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true); mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true);
@@ -352,8 +354,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
.thenReturn(mRow); .thenReturn(mRow);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Make it look like dismissed notif // Make it look like dismissed notif
mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true); mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true);
@@ -388,7 +389,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Test @Test
public void testExpandCollapseStack() { public void testExpandCollapseStack() {
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
// Mark it as a bubble and add it explicitly // Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow); mEntryListener.onEntryAdded(mRow);
@@ -396,23 +397,20 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand the stack // Expand the stack
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
// Make sure the notif is suppressed // Make sure the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Collapse // Collapse
mBubbleController.collapseStack(); mBubbleController.collapseStack();
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
} }
@Test @Test
@@ -426,22 +424,19 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey())); assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry2);
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand // Expand
BubbleStackView stackView = mBubbleController.getStackView(); BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
true, mRow2.getKey()); true, mRow2.getKey());
// Last added is the one that is expanded // Last added is the one that is expanded
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey()); assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry2);
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Switch which bubble is expanded // Switch which bubble is expanded
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey( mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
@@ -449,8 +444,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey( assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey()); stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// collapse for previous bubble // collapse for previous bubble
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
@@ -462,7 +456,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// Collapse // Collapse
mBubbleController.collapseStack(); mBubbleController.collapseStack();
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
} }
@Test @Test
@@ -473,20 +467,18 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
// Expand // Expand
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
} }
@@ -499,20 +491,18 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// We should have bubbles & their notifs should not be suppressed // We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
// Expand // Expand
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -521,8 +511,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// Nothing should have changed // Nothing should have changed
// Notif is suppressed after expansion // Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion // Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
} }
@@ -539,14 +528,13 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
BubbleStackView stackView = mBubbleController.getStackView(); BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
// Last added is the one that is expanded // Last added is the one that is expanded
assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey( assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey()); stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry2);
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Dismiss currently expanded // Dismiss currently expanded
mBubbleController.removeBubble( mBubbleController.removeBubble(
@@ -582,7 +570,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
BubbleStackView stackView = mBubbleController.getStackView(); BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
// Block the bubble so it won't be in the overflow // Block the bubble so it won't be in the overflow
@@ -601,7 +589,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Test @Test
public void testAutoExpand_fails_noFlag() { public void testAutoExpand_fails_noFlag() {
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
setMetadataFlags(mRow, setMetadataFlags(mRow,
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */); Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
@@ -612,7 +600,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// Expansion shouldn't change // Expansion shouldn't change
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */, verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
mRow.getKey()); mRow.getKey());
assertFalse(mBubbleController.isStackExpanded()); assertStackCollapsed();
} }
@Test @Test
@@ -627,7 +615,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
// Expansion should change // Expansion should change
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */, verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
mRow.getKey()); mRow.getKey());
assertTrue(mBubbleController.isStackExpanded()); assertStackExpanded();
} }
@Test @Test
@@ -640,8 +628,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed because we were foreground // Notif should be suppressed because we were foreground
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed // Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
@@ -652,8 +639,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Should not be suppressed // Should not be suppressed
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should show dot // Should show dot
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -663,8 +649,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed // Notif should be suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed // Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
@@ -673,8 +658,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Test @Test
public void testMarkNewNotificationAsShowInShade() { public void testMarkNewNotificationAsShowInShade() {
mEntryListener.onEntryAdded(mRow); mEntryListener.onEntryAdded(mRow);
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
@@ -745,16 +729,14 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow); boolean intercepted = mBubblesManager.handleDismissalInterception(mRow);
// Intercept! // Intercept!
assertTrue(intercepted); assertTrue(intercepted);
// Should update show in shade state // Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
} }
@Test @Test
@@ -763,8 +745,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble // Dismiss the bubble
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE); mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
@@ -783,8 +764,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mBubbleController.updateBubble(mBubbleEntry); mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble // Dismiss the bubble
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL); mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
@@ -799,47 +779,35 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Test @Test
public void testNotifyShadeSuppressionChange_notificationDismiss() { public void testNotifyShadeSuppressionChange_notificationDismiss() {
Bubbles.SuppressionChangedListener listener =
mock(Bubbles.SuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onEntryAdded(mRow); mEntryListener.onEntryAdded(mRow);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubblesManager.handleDismissalInterception(mRow); mBubblesManager.handleDismissalInterception(mRow);
// Should update show in shade state // Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed // Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange( verify(mBubbleController).onBubbleNotificationSuppressionChanged(
mBubbleData.getBubbleInStackWithKey(mRow.getKey())); mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
} }
@Test @Test
public void testNotifyShadeSuppressionChange_bubbleExpanded() { public void testNotifyShadeSuppressionChange_bubbleExpanded() {
Bubbles.SuppressionChangedListener listener =
mock(Bubbles.SuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onEntryAdded(mRow); mEntryListener.onEntryAdded(mRow);
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationNotSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
// Once a bubble is expanded the notif is suppressed // Once a bubble is expanded the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed // Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange( verify(mBubbleController).onBubbleNotificationSuppressionChanged(
mBubbleData.getBubbleInStackWithKey(mRow.getKey())); mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
} }
@@ -861,6 +829,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(), groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey())); groupedBubble.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey())); assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
} }
@@ -915,11 +886,17 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(), groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey())); groupedBubble.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
groupedBubble.getEntry().getKey(),
groupedBubble.getEntry().getSbn().getGroupKey()));
// THEN the summary is also suppressed from the shade // THEN the summary is also suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
groupSummary.getEntry().getKey(), groupSummary.getEntry().getKey(),
groupSummary.getEntry().getSbn().getGroupKey())); groupSummary.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
groupSummary.getEntry().getKey(),
groupSummary.getEntry().getSbn().getGroupKey()));
} }
/** /**
@@ -938,4 +915,42 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
} }
bubbleMetadata.setFlags(flags); bubbleMetadata.setFlags(flags);
} }
/**
* Asserts that the bubble stack is expanded and also validates the cached state is updated.
*/
private void assertStackExpanded() {
assertTrue(mBubbleController.isStackExpanded());
assertTrue(mBubbleController.getImplCachedState().isStackExpanded());
}
/**
* Asserts that the bubble stack is collapsed and also validates the cached state is updated.
*/
private void assertStackCollapsed() {
assertFalse(mBubbleController.isStackExpanded());
assertFalse(mBubbleController.getImplCachedState().isStackExpanded());
}
/**
* Asserts that a bubble notification is suppressed from the shade and also validates the cached
* state is updated.
*/
private void assertBubbleNotificationSuppressedFromShade(BubbleEntry entry) {
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
assertTrue(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
}
/**
* Asserts that a bubble notification is not suppressed from the shade and also validates the
* cached state is updated.
*/
private void assertBubbleNotificationNotSuppressedFromShade(BubbleEntry entry) {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
assertFalse(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade(
entry.getKey(), entry.getGroupKey()));
}
} }