Merge "Revert "Persists bubbles to disk (part 4)"" into rvc-dev am: a5cc646a19 am: 7c0341e6b9 am: 4461aa8fc8

Change-Id: I0b16f7fa272b7a6a0cc7a32d48f22304ce0074d0
This commit is contained in:
Neil Fuller
2020-05-18 11:56:35 +00:00
committed by Automerger Merge Worker
12 changed files with 129 additions and 320 deletions

View File

@@ -16,7 +16,6 @@
package com.android.systemui.bubbles; package com.android.systemui.bubbles;
import static android.app.Notification.FLAG_BUBBLE;
import static android.os.AsyncTask.Status.FINISHED; import static android.os.AsyncTask.Status.FINISHED;
import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY;
@@ -28,7 +27,6 @@ import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps; import android.content.pm.LauncherApps;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
@@ -57,11 +55,6 @@ import java.util.Objects;
class Bubble implements BubbleViewProvider { class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble"; private static final String TAG = "Bubble";
/**
* NotificationEntry associated with the bubble. A null value implies this bubble is loaded
* from disk.
*/
@Nullable
private NotificationEntry mEntry; private NotificationEntry mEntry;
private final String mKey; private final String mKey;
private final String mGroupId; private final String mGroupId;
@@ -102,56 +95,18 @@ class Bubble implements BubbleViewProvider {
private Bitmap mBadgedImage; private Bitmap mBadgedImage;
private int mDotColor; private int mDotColor;
private Path mDotPath; private Path mDotPath;
private int mFlags;
/**
* Extract GroupId from {@link NotificationEntry}. See also {@link #groupId(ShortcutInfo)}.
*/
public static String groupId(NotificationEntry entry) { public static String groupId(NotificationEntry entry) {
UserHandle user = entry.getSbn().getUser(); UserHandle user = entry.getSbn().getUser();
return user.getIdentifier() + "|" + entry.getSbn().getPackageName(); return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
} }
/** // TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble
* Extract GroupId from {@link ShortcutInfo}. This should match the one generated from
* {@link NotificationEntry}. See also {@link #groupId(NotificationEntry)}.
*/
@NonNull
public static String groupId(@NonNull final ShortcutInfo shortcutInfo) {
return shortcutInfo.getUserId() + "|" + shortcutInfo.getPackage();
}
/**
* Generate a unique identifier for this bubble based on given {@link NotificationEntry}. If
* {@link ShortcutInfo} was found in the notification entry, the identifier would be generated
* from {@link ShortcutInfo} instead. See also {@link #key(ShortcutInfo)}.
*/
@NonNull
public static String key(@NonNull final NotificationEntry entry) {
final ShortcutInfo shortcutInfo = entry.getRanking().getShortcutInfo();
if (shortcutInfo != null) return key(shortcutInfo);
return entry.getKey();
}
/**
* Generate a unique identifier for this bubble based on given {@link ShortcutInfo}.
* See also {@link #key(NotificationEntry)}.
*/
@NonNull
public static String key(@NonNull final ShortcutInfo shortcutInfo) {
return shortcutInfo.getUserId() + "|" + shortcutInfo.getPackage() + "|"
+ shortcutInfo.getId();
}
/**
* Create a bubble with limited information based on given {@link ShortcutInfo}.
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
Bubble(ShortcutInfo shortcutInfo) { Bubble(ShortcutInfo shortcutInfo) {
mShortcutInfo = shortcutInfo; mShortcutInfo = shortcutInfo;
mKey = key(shortcutInfo); mKey = shortcutInfo.getId();
mGroupId = groupId(shortcutInfo); mGroupId = shortcutInfo.getId();
mFlags = 0;
} }
/** Used in tests when no UI is required. */ /** Used in tests when no UI is required. */
@@ -159,11 +114,10 @@ class Bubble implements BubbleViewProvider {
Bubble(NotificationEntry e, Bubble(NotificationEntry e,
BubbleController.NotificationSuppressionChangedListener listener) { BubbleController.NotificationSuppressionChangedListener listener) {
mEntry = e; mEntry = e;
mKey = key(e); mKey = e.getKey();
mLastUpdated = e.getSbn().getPostTime(); mLastUpdated = e.getSbn().getPostTime();
mGroupId = groupId(e); mGroupId = groupId(e);
mSuppressionListener = listener; mSuppressionListener = listener;
mFlags = e.getSbn().getNotification().flags;
} }
@Override @Override
@@ -171,26 +125,16 @@ class Bubble implements BubbleViewProvider {
return mKey; return mKey;
} }
@Nullable
public NotificationEntry getEntry() { public NotificationEntry getEntry() {
return mEntry; return mEntry;
} }
@Nullable
public UserHandle getUser() {
if (mEntry != null) return mEntry.getSbn().getUser();
if (mShortcutInfo != null) return mShortcutInfo.getUserHandle();
return null;
}
public String getGroupId() { public String getGroupId() {
return mGroupId; return mGroupId;
} }
public String getPackageName() { public String getPackageName() {
return mEntry == null return mEntry.getSbn().getPackageName();
? mShortcutInfo == null ? null : mShortcutInfo.getPackage()
: mEntry.getSbn().getPackageName();
} }
@Override @Override
@@ -274,8 +218,7 @@ class Bubble implements BubbleViewProvider {
void inflate(BubbleViewInfoTask.Callback callback, void inflate(BubbleViewInfoTask.Callback callback,
Context context, Context context,
BubbleStackView stackView, BubbleStackView stackView,
BubbleIconFactory iconFactory, BubbleIconFactory iconFactory) {
boolean skipInflation) {
if (isBubbleLoading()) { if (isBubbleLoading()) {
mInflationTask.cancel(true /* mayInterruptIfRunning */); mInflationTask.cancel(true /* mayInterruptIfRunning */);
} }
@@ -283,7 +226,6 @@ class Bubble implements BubbleViewProvider {
context, context,
stackView, stackView,
iconFactory, iconFactory,
skipInflation,
callback); callback);
if (mInflateSynchronously) { if (mInflateSynchronously) {
mInflationTask.onPostExecute(mInflationTask.doInBackground()); mInflationTask.onPostExecute(mInflationTask.doInBackground());
@@ -403,7 +345,6 @@ class Bubble implements BubbleViewProvider {
* Whether this notification should be shown in the shade. * Whether this notification should be shown in the shade.
*/ */
boolean showInShade() { boolean showInShade() {
if (mEntry == null) return false;
return !shouldSuppressNotification() || !mEntry.isClearable(); return !shouldSuppressNotification() || !mEntry.isClearable();
} }
@@ -411,8 +352,8 @@ class Bubble implements BubbleViewProvider {
* Sets whether this notification should be suppressed in the shade. * Sets whether this notification should be suppressed in the shade.
*/ */
void setSuppressNotification(boolean suppressNotification) { void setSuppressNotification(boolean suppressNotification) {
if (mEntry == null) return;
boolean prevShowInShade = showInShade(); boolean prevShowInShade = showInShade();
Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
int flags = data.getFlags(); int flags = data.getFlags();
if (suppressNotification) { if (suppressNotification) {
@@ -443,7 +384,6 @@ class Bubble implements BubbleViewProvider {
*/ */
@Override @Override
public boolean showDot() { public boolean showDot() {
if (mEntry == null) return false;
return mShowBubbleUpdateDot return mShowBubbleUpdateDot
&& !mEntry.shouldSuppressNotificationDot() && !mEntry.shouldSuppressNotificationDot()
&& !shouldSuppressNotification(); && !shouldSuppressNotification();
@@ -453,7 +393,6 @@ class Bubble implements BubbleViewProvider {
* Whether the flyout for the bubble should be shown. * Whether the flyout for the bubble should be shown.
*/ */
boolean showFlyout() { boolean showFlyout() {
if (mEntry == null) return false;
return !mSuppressFlyout && !mEntry.shouldSuppressPeek() return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
&& !shouldSuppressNotification() && !shouldSuppressNotification()
&& !mEntry.shouldSuppressNotificationList(); && !mEntry.shouldSuppressNotificationList();
@@ -477,13 +416,11 @@ class Bubble implements BubbleViewProvider {
* is an ongoing bubble. * is an ongoing bubble.
*/ */
boolean isOngoing() { boolean isOngoing() {
if (mEntry == null) return false;
int flags = mEntry.getSbn().getNotification().flags; int flags = mEntry.getSbn().getNotification().flags;
return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
} }
float getDesiredHeight(Context context) { float getDesiredHeight(Context context) {
if (mEntry == null) return 0;
Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
boolean useRes = data.getDesiredHeightResId() != 0; boolean useRes = data.getDesiredHeightResId() != 0;
if (useRes) { if (useRes) {
@@ -497,7 +434,6 @@ class Bubble implements BubbleViewProvider {
} }
String getDesiredHeightString() { String getDesiredHeightString() {
if (mEntry == null) return String.valueOf(0);
Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
boolean useRes = data.getDesiredHeightResId() != 0; boolean useRes = data.getDesiredHeightResId() != 0;
if (useRes) { if (useRes) {
@@ -514,13 +450,11 @@ class Bubble implements BubbleViewProvider {
* To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}. * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
*/ */
boolean usingShortcutInfo() { boolean usingShortcutInfo() {
return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null return mEntry.getBubbleMetadata().getShortcutId() != null;
|| mShortcutInfo != null;
} }
@Nullable @Nullable
PendingIntent getBubbleIntent() { PendingIntent getBubbleIntent() {
if (mEntry == null) return null;
Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
if (data != null) { if (data != null) {
return data.getIntent(); return data.getIntent();
@@ -528,32 +462,16 @@ class Bubble implements BubbleViewProvider {
return null; return null;
} }
Intent getSettingsIntent(final Context context) { Intent getSettingsIntent() {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS); final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
final int uid = getUid(context); intent.putExtra(Settings.EXTRA_APP_UID, mEntry.getSbn().getUid());
if (uid != -1) {
intent.putExtra(Settings.EXTRA_APP_UID, uid);
}
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return intent; return intent;
} }
private int getUid(final Context context) {
if (mEntry != null) return mEntry.getSbn().getUid();
final PackageManager pm = context.getPackageManager();
if (pm == null) return -1;
try {
final ApplicationInfo info = pm.getApplicationInfo(mShortcutInfo.getPackage(), 0);
return info.uid;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "cannot find uid", e);
}
return -1;
}
private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) { private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
Resources r; Resources r;
@@ -575,30 +493,15 @@ class Bubble implements BubbleViewProvider {
} }
private boolean shouldSuppressNotification() { private boolean shouldSuppressNotification() {
if (mEntry == null) return false;
return mEntry.getBubbleMetadata() != null return mEntry.getBubbleMetadata() != null
&& mEntry.getBubbleMetadata().isNotificationSuppressed(); && mEntry.getBubbleMetadata().isNotificationSuppressed();
} }
boolean shouldAutoExpand() { boolean shouldAutoExpand() {
if (mEntry == null) return false;
Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata(); Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
return metadata != null && metadata.getAutoExpandBubble(); return metadata != null && metadata.getAutoExpandBubble();
} }
public boolean isBubble() {
if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
}
public void enable(int option) {
mFlags |= option;
}
public void disable(int option) {
mFlags &= ~option;
}
@Override @Override
public String toString() { public String toString() {
return "Bubble{" + mKey + '}'; return "Bubble{" + mKey + '}';

View File

@@ -42,7 +42,6 @@ import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.NonNull;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.app.INotificationManager; import android.app.INotificationManager;
@@ -243,7 +242,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* This can happen when an app cancels a bubbled notification or when the user dismisses a * This can happen when an app cancels a bubbled notification or when the user dismisses a
* bubble. * bubble.
*/ */
void removeNotification(@NonNull NotificationEntry entry, int reason); void removeNotification(NotificationEntry entry, int reason);
/** /**
* Called when a bubbled notification has changed whether it should be * Called when a bubbled notification has changed whether it should be
@@ -259,7 +258,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* removes all remnants of the group's summary from the notification pipeline. * removes all remnants of the group's summary from the notification pipeline.
* TODO: (b/145659174) Only old pipeline needs this - delete post-migration. * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
*/ */
void maybeCancelSummary(@NonNull NotificationEntry entry); void maybeCancelSummary(NotificationEntry entry);
} }
/** /**
@@ -482,7 +481,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
addNotifCallback(new NotifCallback() { addNotifCallback(new NotifCallback() {
@Override @Override
public void removeNotification(@NonNull final NotificationEntry entry, int reason) { public void removeNotification(NotificationEntry entry, int reason) {
mNotificationEntryManager.performRemoveNotification(entry.getSbn(), mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
reason); reason);
} }
@@ -493,7 +492,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
} }
@Override @Override
public void maybeCancelSummary(@NonNull final NotificationEntry entry) { public void maybeCancelSummary(NotificationEntry entry) {
// Check if removed bubble has an associated suppressed group summary that needs // Check if removed bubble has an associated suppressed group summary that needs
// to be removed now. // to be removed now.
final String groupKey = entry.getSbn().getGroupKey(); final String groupKey = entry.getSbn().getGroupKey();
@@ -702,12 +701,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleIconFactory = new BubbleIconFactory(mContext);
// Reload each bubble // Reload each bubble
for (Bubble b: mBubbleData.getBubbles()) { for (Bubble b: mBubbleData.getBubbles()) {
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory, b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
false /* skipInflation */);
} }
for (Bubble b: mBubbleData.getOverflowBubbles()) { for (Bubble b: mBubbleData.getOverflowBubbles()) {
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory, b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
false /* skipInflation */);
} }
} }
@@ -806,7 +803,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (bubble != null) { if (bubble != null) {
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory); mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
} }
} else if (bubble.isBubble()) { } else if (bubble.getEntry().isBubble()){
mBubbleData.setSelectedBubble(bubble); mBubbleData.setSelectedBubble(bubble);
} }
mBubbleData.setExpanded(true); mBubbleData.setExpanded(true);
@@ -835,33 +832,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
updateBubble(notif, suppressFlyout, true /* showInShade */); updateBubble(notif, suppressFlyout, true /* showInShade */);
} }
/**
* Fills the overflow bubbles by loading them from disk.
*/
void loadOverflowBubblesFromDisk() {
if (!mBubbleData.getOverflowBubbles().isEmpty()) {
// we don't need to load overflow bubbles from disk if it is already in memory
return;
}
mDataRepository.loadBubbles((bubbles) -> {
bubbles.forEach(bubble -> {
if (mBubbleData.getBubbles().contains(bubble)) {
// if the bubble is already active, there's no need to push it to overflow
return;
}
bubble.inflate((b) -> mBubbleData.overflowBubble(DISMISS_AGED, bubble),
mContext, mStackView, mBubbleIconFactory, true /* skipInflation */);
});
return null;
});
}
void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) { void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
if (mStackView == null) { if (mStackView == null) {
// Lazy init stack view when a bubble is created // Lazy init stack view when a bubble is created
ensureStackViewCreated(); ensureStackViewCreated();
// Lazy load overflow bubbles from disk
loadOverflowBubblesFromDisk();
} }
// If this is an interruptive notif, mark that it's interrupted // If this is an interruptive notif, mark that it's interrupted
if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) { if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
@@ -881,11 +855,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
return; return;
} }
mHandler.post( mHandler.post(
() -> removeBubble(bubble.getKey(), () -> removeBubble(bubble.getEntry(),
BubbleController.DISMISS_INVALID_INTENT)); BubbleController.DISMISS_INVALID_INTENT));
}); });
}, },
mContext, mStackView, mBubbleIconFactory, false /* skipInflation */); mContext, mStackView, mBubbleIconFactory);
} }
/** /**
@@ -897,10 +871,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* @param entry the notification to change bubble state for. * @param entry the notification to change bubble state for.
* @param shouldBubble whether the notification should show as a bubble or not. * @param shouldBubble whether the notification should show as a bubble or not.
*/ */
public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) { public void onUserChangedBubble(NotificationEntry entry, boolean shouldBubble) {
if (entry == null) {
return;
}
NotificationChannel channel = entry.getChannel(); NotificationChannel channel = entry.getChannel();
final String appPkg = entry.getSbn().getPackageName(); final String appPkg = entry.getSbn().getPackageName();
final int appUid = entry.getSbn().getUid(); final int appUid = entry.getSbn().getUid();
@@ -939,14 +910,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
} }
/** /**
* Removes the bubble with the given key. * Removes the bubble with the given NotificationEntry.
* <p> * <p>
* Must be called from the main thread. * Must be called from the main thread.
*/ */
@MainThread @MainThread
void removeBubble(String key, int reason) { void removeBubble(NotificationEntry entry, int reason) {
if (mBubbleData.hasAnyBubbleWithKey(key)) { if (mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
mBubbleData.notificationEntryRemoved(key, reason); mBubbleData.notificationEntryRemoved(entry, reason);
} }
} }
@@ -962,7 +933,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
&& canLaunchInActivityView(mContext, entry); && canLaunchInActivityView(mContext, entry);
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) { if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it // It was previously a bubble but no longer a bubble -- lets remove it
removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE); removeBubble(entry, DISMISS_NO_LONGER_BUBBLE);
} else if (shouldBubble) { } else if (shouldBubble) {
updateBubble(entry); updateBubble(entry);
} }
@@ -976,10 +947,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// Remove any associated bubble children with the summary // Remove any associated bubble children with the summary
final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey); final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
for (int i = 0; i < bubbleChildren.size(); i++) { for (int i = 0; i < bubbleChildren.size(); i++) {
removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED); removeBubble(bubbleChildren.get(i).getEntry(), DISMISS_GROUP_CANCELLED);
} }
} else { } else {
removeBubble(entry.getKey(), DISMISS_NOTIF_CANCEL); removeBubble(entry, DISMISS_NOTIF_CANCEL);
} }
} }
@@ -1001,8 +972,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
rankingMap.getRanking(key, mTmpRanking); rankingMap.getRanking(key, mTmpRanking);
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key); boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
if (isActiveBubble && !mTmpRanking.canBubble()) { if (isActiveBubble && !mTmpRanking.canBubble()) {
mBubbleData.notificationEntryRemoved(entry.getKey(), mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
BubbleController.DISMISS_BLOCKED);
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) { } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
entry.setFlagBubble(true); entry.setFlagBubble(true);
onEntryUpdated(entry); onEntryUpdated(entry);
@@ -1012,15 +982,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private void setIsBubble(Bubble b, boolean isBubble) { private void setIsBubble(Bubble b, boolean isBubble) {
if (isBubble) { if (isBubble) {
if (b.getEntry() != null) { b.getEntry().getSbn().getNotification().flags |= FLAG_BUBBLE;
b.getEntry().getSbn().getNotification().flags |= FLAG_BUBBLE;
}
b.enable(FLAG_BUBBLE);
} else { } else {
if (b.getEntry() != null) { b.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
b.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
}
b.disable(FLAG_BUBBLE);
} }
try { try {
mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0); mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
@@ -1068,27 +1032,23 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// The bubble is now gone & the notification is hidden from the shade, so // The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it // time to actually remove it
for (NotifCallback cb : mCallbacks) { for (NotifCallback cb : mCallbacks) {
if (bubble.getEntry() != null) { cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
}
} }
} else { } else {
if (bubble.isBubble() && bubble.showInShade()) { if (bubble.getEntry().isBubble() && bubble.showInShade()) {
setIsBubble(bubble, /* isBubble */ false); setIsBubble(bubble, /* isBubble */ false);
} }
if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) { if (bubble.getEntry().getRow() != null) {
bubble.getEntry().getRow().updateBubbleButton(); bubble.getEntry().getRow().updateBubbleButton();
} }
} }
} }
if (bubble.getEntry() != null) { final String groupKey = bubble.getEntry().getSbn().getGroupKey();
final String groupKey = bubble.getEntry().getSbn().getGroupKey(); if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) { // Time to potentially remove the summary
// Time to potentially remove the summary for (NotifCallback cb : mCallbacks) {
for (NotifCallback cb : mCallbacks) { cb.maybeCancelSummary(bubble.getEntry());
cb.maybeCancelSummary(bubble.getEntry());
}
} }
} }
} }
@@ -1113,7 +1073,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (update.selectionChanged) { if (update.selectionChanged) {
mStackView.setSelectedBubble(update.selectedBubble); mStackView.setSelectedBubble(update.selectedBubble);
if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) { if (update.selectedBubble != null) {
mNotificationGroupManager.updateSuppression( mNotificationGroupManager.updateSuppression(
update.selectedBubble.getEntry()); update.selectedBubble.getEntry());
} }

View File

@@ -23,7 +23,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import android.annotation.NonNull;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
@@ -224,7 +223,7 @@ public class BubbleData {
false, /* showInShade */ true); false, /* showInShade */ true);
setSelectedBubble(bubble); setSelectedBubble(bubble);
}, },
mContext, stack, factory, false /* skipInflation */); mContext, stack, factory);
dispatchPendingChanges(); dispatchPendingChanges();
} }
@@ -279,8 +278,7 @@ public class BubbleData {
} }
mPendingBubbles.remove(bubble); // No longer pending once we're here mPendingBubbles.remove(bubble); // No longer pending once we're here
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey()); Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
suppressFlyout |= bubble.getEntry() == null suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive();
|| !bubble.getEntry().getRanking().visuallyInterruptive();
if (prevBubble == null) { if (prevBubble == null) {
// Create a new bubble // Create a new bubble
@@ -309,14 +307,11 @@ public class BubbleData {
dispatchPendingChanges(); dispatchPendingChanges();
} }
/** public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
* Called when a notification associated with a bubble is removed.
*/
public void notificationEntryRemoved(String key, @DismissReason int reason) {
if (DEBUG_BUBBLE_DATA) { if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason); Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
} }
doRemove(key, reason); doRemove(entry.getKey(), reason);
dispatchPendingChanges(); dispatchPendingChanges();
} }
@@ -364,7 +359,7 @@ public class BubbleData {
return bubbleChildren; return bubbleChildren;
} }
for (Bubble b : mBubbles) { for (Bubble b : mBubbles) {
if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) { if (groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
bubbleChildren.add(b); bubbleChildren.add(b);
} }
} }
@@ -475,9 +470,7 @@ public class BubbleData {
Bubble newSelected = mBubbles.get(newIndex); Bubble newSelected = mBubbles.get(newIndex);
setSelectedBubbleInternal(newSelected); setSelectedBubbleInternal(newSelected);
} }
if (bubbleToRemove.getEntry() != null) { maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
}
} }
void overflowBubble(@DismissReason int reason, Bubble bubble) { void overflowBubble(@DismissReason int reason, Bubble bubble) {
@@ -751,8 +744,7 @@ public class BubbleData {
return true; return true;
} }
private void maybeSendDeleteIntent(@DismissReason int reason, private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
@NonNull final NotificationEntry entry) {
if (reason == BubbleController.DISMISS_USER_GESTURE) { if (reason == BubbleController.DISMISS_USER_GESTURE) {
Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata(); Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
PendingIntent deleteIntent = bubbleMetadata != null PendingIntent deleteIntent = bubbleMetadata != null

View File

@@ -74,10 +74,7 @@ internal class BubbleDataRepository @Inject constructor(
private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> { private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b -> return bubbles.mapNotNull { b ->
var shortcutId = b.shortcutInfo?.id val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null
if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
if (shortcutId == null) shortcutId = b.entry?.ranking?.shortcutInfo?.id
if (shortcutId == null) return@mapNotNull null
BubbleEntity(userId, b.packageName, shortcutId) BubbleEntity(userId, b.packageName, shortcutId)
} }
} }
@@ -111,6 +108,7 @@ internal class BubbleDataRepository @Inject constructor(
/** /**
* Load bubbles from disk. * Load bubbles from disk.
*/ */
// TODO: call this method from BubbleController and update UI
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")
fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch { fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
/** /**

View File

@@ -65,6 +65,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape; import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.AlphaOptimizedButton; import com.android.systemui.statusbar.AlphaOptimizedButton;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/** /**
* Container for the expanded bubble view, handles rendering the caret and settings icon. * Container for the expanded bubble view, handles rendering the caret and settings icon.
@@ -160,7 +161,7 @@ public class BubbleExpandedView extends LinearLayout {
// the bubble again so we'll just remove it. // the bubble again so we'll just remove it.
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ ", " + e.getMessage() + "; removing bubble"); + ", " + e.getMessage() + "; removing bubble");
mBubbleController.removeBubble(getBubbleKey(), mBubbleController.removeBubble(getBubbleEntry(),
BubbleController.DISMISS_INVALID_INTENT); BubbleController.DISMISS_INVALID_INTENT);
} }
}); });
@@ -204,7 +205,7 @@ public class BubbleExpandedView extends LinearLayout {
} }
if (mBubble != null) { if (mBubble != null) {
// Must post because this is called from a binder thread. // Must post because this is called from a binder thread.
post(() -> mBubbleController.removeBubble(mBubble.getKey(), post(() -> mBubbleController.removeBubble(mBubble.getEntry(),
BubbleController.DISMISS_TASK_FINISHED)); BubbleController.DISMISS_TASK_FINISHED));
} }
} }
@@ -291,6 +292,10 @@ public class BubbleExpandedView extends LinearLayout {
return mBubble != null ? mBubble.getKey() : "null"; return mBubble != null ? mBubble.getKey() : "null";
} }
private NotificationEntry getBubbleEntry() {
return mBubble != null ? mBubble.getEntry() : null;
}
void setManageClickListener(OnClickListener manageClickListener) { void setManageClickListener(OnClickListener manageClickListener) {
findViewById(R.id.settings_button).setOnClickListener(manageClickListener); findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
} }

View File

@@ -49,6 +49,7 @@ import android.graphics.RectF;
import android.graphics.Region; import android.graphics.Region;
import android.os.Bundle; import android.os.Bundle;
import android.os.Vibrator; import android.os.Vibrator;
import android.service.notification.StatusBarNotification;
import android.util.Log; import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.DisplayCutout; import android.view.DisplayCutout;
@@ -918,10 +919,10 @@ public class BubbleStackView extends FrameLayout
showManageMenu(false /* show */); showManageMenu(false /* show */);
final Bubble bubble = mBubbleData.getSelectedBubble(); final Bubble bubble = mBubbleData.getSelectedBubble();
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
final Intent intent = bubble.getSettingsIntent(mContext); final Intent intent = bubble.getSettingsIntent();
collapseStack(() -> { collapseStack(() -> {
mContext.startActivityAsUser(
mContext.startActivityAsUser(intent, bubble.getUser()); intent, bubble.getEntry().getSbn().getUser());
logBubbleClickEvent( logBubbleClickEvent(
bubble, bubble,
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS); SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
@@ -1178,19 +1179,13 @@ public class BubbleStackView extends FrameLayout
for (int i = 0; i < mBubbleData.getBubbles().size(); i++) { for (int i = 0; i < mBubbleData.getBubbles().size(); i++) {
final Bubble bubble = mBubbleData.getBubbles().get(i); final Bubble bubble = mBubbleData.getBubbles().get(i);
final String appName = bubble.getAppName(); final String appName = bubble.getAppName();
final Notification notification = bubble.getEntry().getSbn().getNotification();
final CharSequence titleCharSeq =
notification.extras.getCharSequence(Notification.EXTRA_TITLE);
final CharSequence titleCharSeq; String titleStr = getResources().getString(R.string.notification_bubble_title);
if (bubble.getEntry() == null) {
titleCharSeq = null;
} else {
titleCharSeq = bubble.getEntry().getSbn().getNotification().extras.getCharSequence(
Notification.EXTRA_TITLE);
}
final String titleStr;
if (titleCharSeq != null) { if (titleCharSeq != null) {
titleStr = titleCharSeq.toString(); titleStr = titleCharSeq.toString();
} else {
titleStr = getResources().getString(R.string.notification_bubble_title);
} }
if (bubble.getIconView() != null) { if (bubble.getIconView() != null) {
@@ -1803,7 +1798,7 @@ public class BubbleStackView extends FrameLayout
private void dismissBubbleIfExists(@Nullable Bubble bubble) { private void dismissBubbleIfExists(@Nullable Bubble bubble) {
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(
bubble.getKey(), BubbleController.DISMISS_USER_GESTURE); bubble.getEntry(), BubbleController.DISMISS_USER_GESTURE);
} }
} }
@@ -2301,12 +2296,18 @@ public class BubbleStackView extends FrameLayout
* @param action the user interaction enum. * @param action the user interaction enum.
*/ */
private void logBubbleClickEvent(Bubble bubble, int action) { private void logBubbleClickEvent(Bubble bubble, int action) {
bubble.logUIEvent( StatusBarNotification notification = bubble.getEntry().getSbn();
SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
notification.getPackageName(),
notification.getNotification().getChannelId(),
notification.getId(),
getBubbleIndex(getExpandedBubble()),
getBubbleCount(), getBubbleCount(),
action, action,
getNormalizedXPosition(), getNormalizedXPosition(),
getNormalizedYPosition(), getNormalizedYPosition(),
getBubbleIndex(getExpandedBubble()) bubble.showInShade(),
); bubble.isOngoing(),
false /* isAppForeground (unused) */);
} }
} }

View File

@@ -37,7 +37,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -75,7 +74,6 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
private WeakReference<Context> mContext; private WeakReference<Context> mContext;
private WeakReference<BubbleStackView> mStackView; private WeakReference<BubbleStackView> mStackView;
private BubbleIconFactory mIconFactory; private BubbleIconFactory mIconFactory;
private boolean mSkipInflation;
private Callback mCallback; private Callback mCallback;
/** /**
@@ -86,20 +84,17 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Context context, Context context,
BubbleStackView stackView, BubbleStackView stackView,
BubbleIconFactory factory, BubbleIconFactory factory,
boolean skipInflation,
Callback c) { Callback c) {
mBubble = b; mBubble = b;
mContext = new WeakReference<>(context); mContext = new WeakReference<>(context);
mStackView = new WeakReference<>(stackView); mStackView = new WeakReference<>(stackView);
mIconFactory = factory; mIconFactory = factory;
mSkipInflation = skipInflation;
mCallback = c; mCallback = c;
} }
@Override @Override
protected BubbleViewInfo doInBackground(Void... voids) { protected BubbleViewInfo doInBackground(Void... voids) {
return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble, return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble);
mSkipInflation);
} }
@Override @Override
@@ -128,36 +123,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
@Nullable @Nullable
static BubbleViewInfo populate(Context c, BubbleStackView stackView, static BubbleViewInfo populate(Context c, BubbleStackView stackView,
BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) { BubbleIconFactory iconFactory, Bubble b) {
final NotificationEntry entry = b.getEntry();
if (entry == null) {
// populate from ShortcutInfo when NotificationEntry is not available
final ShortcutInfo s = b.getShortcutInfo();
return populate(c, stackView, iconFactory, skipInflation || b.isInflated(),
s.getPackage(), s.getUserHandle(), s, null);
}
final StatusBarNotification sbn = entry.getSbn();
final String bubbleShortcutId = entry.getBubbleMetadata().getShortcutId();
final ShortcutInfo si = bubbleShortcutId == null
? null : entry.getRanking().getShortcutInfo();
return populate(
c, stackView, iconFactory, skipInflation || b.isInflated(),
sbn.getPackageName(), sbn.getUser(), si, entry);
}
private static BubbleViewInfo populate(
@NonNull final Context c,
@NonNull final BubbleStackView stackView,
@NonNull final BubbleIconFactory iconFactory,
final boolean isInflated,
@NonNull final String packageName,
@NonNull final UserHandle user,
@Nullable final ShortcutInfo shortcutInfo,
@Nullable final NotificationEntry entry) {
BubbleViewInfo info = new BubbleViewInfo(); BubbleViewInfo info = new BubbleViewInfo();
// View inflation: only should do this once per bubble // View inflation: only should do this once per bubble
if (!isInflated) { if (!b.isInflated()) {
LayoutInflater inflater = LayoutInflater.from(c); LayoutInflater inflater = LayoutInflater.from(c);
info.imageView = (BadgedImageView) inflater.inflate( info.imageView = (BadgedImageView) inflater.inflate(
R.layout.bubble_view, stackView, false /* attachToRoot */); R.layout.bubble_view, stackView, false /* attachToRoot */);
@@ -167,8 +137,12 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
info.expandedView.setStackView(stackView); info.expandedView.setStackView(stackView);
} }
if (shortcutInfo != null) { StatusBarNotification sbn = b.getEntry().getSbn();
info.shortcutInfo = shortcutInfo; String packageName = sbn.getPackageName();
String bubbleShortcutId = b.getEntry().getBubbleMetadata().getShortcutId();
if (bubbleShortcutId != null) {
info.shortcutInfo = b.getEntry().getRanking().getShortcutInfo();
} }
// App name & app icon // App name & app icon
@@ -187,7 +161,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
info.appName = String.valueOf(pm.getApplicationLabel(appInfo)); info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
} }
appIcon = pm.getApplicationIcon(packageName); appIcon = pm.getApplicationIcon(packageName);
badgedIcon = pm.getUserBadgedIcon(appIcon, user); badgedIcon = pm.getUserBadgedIcon(appIcon, sbn.getUser());
} catch (PackageManager.NameNotFoundException exception) { } catch (PackageManager.NameNotFoundException exception) {
// If we can't find package... don't think we should show the bubble. // If we can't find package... don't think we should show the bubble.
Log.w(TAG, "Unable to find package: " + packageName); Log.w(TAG, "Unable to find package: " + packageName);
@@ -196,7 +170,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
// Badged bubble image // Badged bubble image
Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
entry == null ? null : entry.getBubbleMetadata()); b.getEntry().getBubbleMetadata());
if (bubbleDrawable == null) { if (bubbleDrawable == null) {
// Default to app icon // Default to app icon
bubbleDrawable = appIcon; bubbleDrawable = appIcon;
@@ -222,9 +196,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Color.WHITE, WHITE_SCRIM_ALPHA); Color.WHITE, WHITE_SCRIM_ALPHA);
// Flyout // Flyout
if (entry != null) { info.flyoutMessage = extractFlyoutMessage(c, b.getEntry());
info.flyoutMessage = extractFlyoutMessage(c, entry);
}
return info; return info;
} }
} }

View File

@@ -19,8 +19,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
import static android.service.notification.NotificationStats.DISMISSAL_OTHER; import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import android.annotation.NonNull;
import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.bubbles.BubbleController; import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollection;
@@ -123,7 +121,7 @@ public class BubbleCoordinator implements Coordinator {
private final BubbleController.NotifCallback mNotifCallback = private final BubbleController.NotifCallback mNotifCallback =
new BubbleController.NotifCallback() { new BubbleController.NotifCallback() {
@Override @Override
public void removeNotification(@NonNull final NotificationEntry entry, int reason) { public void removeNotification(NotificationEntry entry, int reason) {
if (isInterceptingDismissal(entry)) { if (isInterceptingDismissal(entry)) {
mInterceptedDismissalEntries.remove(entry.getKey()); mInterceptedDismissalEntries.remove(entry.getKey());
mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry, mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry,
@@ -143,7 +141,7 @@ public class BubbleCoordinator implements Coordinator {
} }
@Override @Override
public void maybeCancelSummary(@NonNull final NotificationEntry entry) { public void maybeCancelSummary(NotificationEntry entry) {
// no-op // no-op
} }
}; };

View File

@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone; package com.android.systemui.statusbar.phone;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
import android.util.ArraySet; import android.util.ArraySet;
@@ -455,7 +454,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
* If there is a {@link NotificationGroup} associated with the provided entry, this method * If there is a {@link NotificationGroup} associated with the provided entry, this method
* will update the suppression of that group. * will update the suppression of that group.
*/ */
public void updateSuppression(@NonNull final NotificationEntry entry) { public void updateSuppression(NotificationEntry entry) {
NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
if (group != null) { if (group != null) {
updateSuppression(group); updateSuppression(group);

View File

@@ -317,7 +317,7 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mNotificationEntryManager).updateNotifications(any()); verify(mNotificationEntryManager).updateNotifications(any());
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey())); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString()); verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
@@ -329,7 +329,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.updateBubble(mRow2.getEntry()); mBubbleController.updateBubble(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey()); Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b)); assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
@@ -350,10 +350,9 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */ mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
false, /* showInShade */ true); false, /* showInShade */ true);
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
mBubbleController.removeBubble( mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verify(mNotificationEntryManager, times(1)).performRemoveNotification( verify(mNotificationEntryManager, times(1)).performRemoveNotification(
eq(mRow.getEntry().getSbn()), anyInt()); eq(mRow.getEntry().getSbn()), anyInt());
assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
@@ -366,7 +365,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED); mRow.getEntry(), BubbleController.DISMISS_USER_CHANGED);
verify(mNotificationEntryManager, never()).performRemoveNotification( verify(mNotificationEntryManager, never()).performRemoveNotification(
eq(mRow.getEntry().getSbn()), anyInt()); eq(mRow.getEntry().getSbn()), anyInt());
assertFalse(mBubbleController.hasBubbles()); assertFalse(mBubbleController.hasBubbles());
@@ -564,8 +563,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Dismiss currently expanded // Dismiss currently expanded
mBubbleController.removeBubble( mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()) mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
.getEntry().getKey(),
BubbleController.DISMISS_USER_GESTURE); BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
@@ -576,8 +574,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Dismiss that one // Dismiss that one
mBubbleController.removeBubble( mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()) mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
.getEntry().getKey(),
BubbleController.DISMISS_USER_GESTURE); BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens // Make sure state changes and collapse happens
@@ -703,7 +700,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test @Test
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED); mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
verify(mDeleteIntent, never()).send(); verify(mDeleteIntent, never()).send();
} }
@@ -711,7 +708,7 @@ public class BubbleControllerTest extends SysuiTestCase {
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(1)).send(); verify(mDeleteIntent, times(1)).send();
} }
@@ -811,7 +808,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Dismiss the bubble into overflow. // Dismiss the bubble into overflow.
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles()); assertFalse(mBubbleController.hasBubbles());
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
@@ -832,7 +829,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry())); mRow.getEntry()));
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_NO_LONGER_BUBBLE); mRow.getEntry(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
assertFalse(mBubbleController.hasBubbles()); assertFalse(mBubbleController.hasBubbles());
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
@@ -854,12 +851,12 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleData.setMaxOverflowBubbles(1); mBubbleData.setMaxOverflowBubbles(1);
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertEquals(mBubbleData.getBubbles().size(), 2); assertEquals(mBubbleData.getBubbles().size(), 2);
assertEquals(mBubbleData.getOverflowBubbles().size(), 1); assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow2.getEntry(), BubbleController.DISMISS_USER_GESTURE);
// Overflow max of 1 is reached; mRow is oldest, so it gets removed // Overflow max of 1 is reached; mRow is oldest, so it gets removed
verify(mNotificationEntryManager, times(1)).performRemoveNotification( verify(mNotificationEntryManager, times(1)).performRemoveNotification(
mRow.getEntry().getSbn(), REASON_CANCEL); mRow.getEntry().getSbn(), REASON_CANCEL);

View File

@@ -20,8 +20,11 @@ import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanki
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -177,8 +180,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
// Verify // Verify
verifyUpdateReceived(); verifyUpdateReceived();
@@ -295,14 +297,12 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
mBubbleData.setMaxOverflowBubbles(1); mBubbleData.setMaxOverflowBubbles(1);
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA1)); assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
// Overflow max of 1 is reached; A1 is oldest, so it gets removed // Overflow max of 1 is reached; A1 is oldest, so it gets removed
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
} }
@@ -449,8 +449,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1); assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
} }
@@ -470,8 +469,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
mEntryB1.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertOrderNotChanged(); assertOrderNotChanged();
} }
@@ -491,8 +489,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL);
mEntryA1.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verifyUpdateReceived(); verifyUpdateReceived();
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA2); assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA2);
} }
@@ -513,14 +510,12 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL);
mEntryA1.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verifyUpdateReceived(); verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_GROUP_CANCELLED);
mEntryA2.getKey(), BubbleController.DISMISS_GROUP_CANCELLED);
verifyUpdateReceived(); verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of()); assertOverflowChangedTo(ImmutableList.of());
} }
@@ -539,8 +534,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_NOTIF_CANCEL);
mEntryA2.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verifyUpdateReceived(); verifyUpdateReceived();
assertSelectionChangedTo(mBubbleB2); assertSelectionChangedTo(mBubbleB2);
} }
@@ -631,8 +625,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
// Verify the selection was cleared. // Verify the selection was cleared.
verifyUpdateReceived(); verifyUpdateReceived();
@@ -786,8 +779,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
mEntryB2.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertOrderChangedTo(mBubbleB1, mBubbleA2, mBubbleA1); assertOrderChangedTo(mBubbleB1, mBubbleA2, mBubbleA1);
} }
@@ -812,13 +804,11 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertSelectionChangedTo(mBubbleA1); assertSelectionChangedTo(mBubbleA1);
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertSelectionChangedTo(mBubbleB1); assertSelectionChangedTo(mBubbleB1);
} }
@@ -933,8 +923,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener); mBubbleData.setListener(mListener);
// Test // Test
mBubbleData.notificationEntryRemoved( mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
verifyUpdateReceived(); verifyUpdateReceived();
assertExpandedChangedTo(false); assertExpandedChangedTo(false);
} }

View File

@@ -285,8 +285,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.hasBubbles()); assertTrue(mBubbleController.hasBubbles());
verify(mNotifCallback, times(1)).invalidateNotifications(anyString()); verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
mBubbleController.removeBubble( mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey())); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotifCallback, times(2)).invalidateNotifications(anyString()); verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
} }
@@ -303,8 +302,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true); mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
// Now remove the bubble // Now remove the bubble
mBubbleController.removeBubble( mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())); assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// We don't remove the notification since the bubble is still in overflow. // We don't remove the notification since the bubble is still in overflow.
@@ -324,8 +322,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true); mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
// Now remove the bubble // Now remove the bubble
mBubbleController.removeBubble( mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())); assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// Since the notif is dismissed and not in overflow, once the bubble is removed, // Since the notif is dismissed and not in overflow, once the bubble is removed,
@@ -505,8 +502,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Dismiss currently expanded // Dismiss currently expanded
mBubbleController.removeBubble( mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey( mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
stackView.getExpandedBubble().getKey()).getEntry().getKey(),
BubbleController.DISMISS_USER_GESTURE); BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey()); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
@@ -517,8 +513,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Dismiss that one // Dismiss that one
mBubbleController.removeBubble( mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey( mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
stackView.getExpandedBubble().getKey()).getEntry().getKey(),
BubbleController.DISMISS_USER_GESTURE); BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens // Make sure state changes and collapse happens
@@ -618,7 +613,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test @Test
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED); mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
verify(mDeleteIntent, never()).send(); verify(mDeleteIntent, never()).send();
} }
@@ -626,7 +621,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(1)).send(); verify(mDeleteIntent, times(1)).send();
} }
@@ -691,7 +686,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Dismiss the bubble // Dismiss the bubble
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles()); assertFalse(mBubbleController.hasBubbles());
// Dismiss the notification // Dismiss the notification
@@ -712,7 +707,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Dismiss the bubble // Dismiss the bubble
mBubbleController.removeBubble( mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL); mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
assertFalse(mBubbleController.hasBubbles()); assertFalse(mBubbleController.hasBubbles());
// Dismiss the notification // Dismiss the notification