summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java976
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java217
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java725
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java85
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java)244
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java)261
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java)2
44 files changed, 1727 insertions, 1433 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 8ac6edb9dfa2..cf576dd6b964 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -37,7 +37,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -308,7 +307,6 @@ public class Dependency {
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@Inject Lazy<SmartReplyController> mSmartReplyController;
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
- @Inject Lazy<Bubbles> mBubbles;
@Inject Lazy<NotificationEntryManager> mNotificationEntryManager;
@Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
@Inject Lazy<AutoHideController> mAutoHideController;
@@ -506,7 +504,6 @@ public class Dependency {
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
mRemoteInputQuickSettingsDisabler::get);
- mProviders.put(Bubbles.class, mBubbles::get);
mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
mProviders.put(ForegroundServiceNotificationListener.class,
mForegroundServiceNotificationListener::get);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 1891daf59007..6b8af3ebe1ed 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -53,7 +53,8 @@ import java.util.Objects;
/**
* Encapsulates the data and UI elements of a bubble.
*/
-class Bubble implements BubbleViewProvider {
+@VisibleForTesting
+public class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble";
private final String mKey;
@@ -62,7 +63,7 @@ class Bubble implements BubbleViewProvider {
private long mLastAccessed;
@Nullable
- private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
+ private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
/** Whether the bubble should show a dot for the notification indicating updated content. */
private boolean mShowBubbleUpdateDot = true;
@@ -173,8 +174,8 @@ class Bubble implements BubbleViewProvider {
@VisibleForTesting(visibility = PRIVATE)
Bubble(@NonNull final BubbleEntry entry,
- @Nullable final BubbleController.NotificationSuppressionChangedListener listener,
- final BubbleController.PendingIntentCanceledListener intentCancelListener) {
+ @Nullable final Bubbles.NotificationSuppressionChangedListener listener,
+ final Bubbles.PendingIntentCanceledListener intentCancelListener) {
mKey = entry.getKey();
mSuppressionListener = listener;
mIntentCancelListener = intent -> {
@@ -309,11 +310,13 @@ class Bubble implements BubbleViewProvider {
*
* @param callback the callback to notify one the bubble is ready to be displayed.
* @param context the context for the bubble.
+ * @param controller
* @param stackView the stackView the bubble is eventually added to.
* @param iconFactory the iconfactory use to create badged images for the bubble.
*/
void inflate(BubbleViewInfoTask.Callback callback,
Context context,
+ BubbleController controller,
BubbleStackView stackView,
BubbleIconFactory iconFactory,
boolean skipInflation) {
@@ -322,6 +325,7 @@ class Bubble implements BubbleViewProvider {
}
mInflationTask = new BubbleViewInfoTask(this,
context,
+ controller,
stackView,
iconFactory,
skipInflation,
@@ -522,7 +526,8 @@ class Bubble implements BubbleViewProvider {
/**
* Sets whether this notification should be suppressed in the shade.
*/
- void setSuppressNotification(boolean suppressNotification) {
+ @VisibleForTesting
+ public void setSuppressNotification(boolean suppressNotification) {
boolean prevShowInShade = showInShade();
if (suppressNotification) {
mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
@@ -559,7 +564,8 @@ class Bubble implements BubbleViewProvider {
/**
* Whether the flyout for the bubble should be shown.
*/
- boolean showFlyout() {
+ @VisibleForTesting
+ public boolean showFlyout() {
return !mSuppressFlyout && !mShouldSuppressPeek
&& !shouldSuppressNotification()
&& !mShouldSuppressNotificationList;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 0c3dc8222a34..598a604099ac 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -17,39 +17,19 @@
package com.android.systemui.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.Notification.FLAG_BUBBLE;
-import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
-import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
-import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
-import static android.service.notification.NotificationListenerService.REASON_CLICK;
-import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.INotificationManager;
import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -65,7 +45,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -74,45 +53,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import androidx.annotation.IntDef;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dumpable;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationRemoveInterceptor;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.notification.NotificationChannelHelper;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -120,11 +68,10 @@ import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.function.IntConsumer;
/**
* Bubbles are a special type of content that can "float" on top of other apps or System UI.
@@ -132,52 +79,23 @@ import java.util.Objects;
*
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
-public class BubbleController implements Bubbles, ConfigurationController.ConfigurationListener,
- Dumpable {
+public class BubbleController implements Bubbles {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
- @Retention(SOURCE)
- @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
- DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
- DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
- DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP})
- @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
- @interface DismissReason {}
-
- static final int DISMISS_USER_GESTURE = 1;
- static final int DISMISS_AGED = 2;
- static final int DISMISS_TASK_FINISHED = 3;
- static final int DISMISS_BLOCKED = 4;
- static final int DISMISS_NOTIF_CANCEL = 5;
- static final int DISMISS_ACCESSIBILITY_ACTION = 6;
- static final int DISMISS_NO_LONGER_BUBBLE = 7;
- static final int DISMISS_USER_CHANGED = 8;
- static final int DISMISS_GROUP_CANCELLED = 9;
- static final int DISMISS_INVALID_INTENT = 10;
- static final int DISMISS_OVERFLOW_MAX_REACHED = 11;
- static final int DISMISS_SHORTCUT_REMOVED = 12;
- static final int DISMISS_PACKAGE_REMOVED = 13;
- static final int DISMISS_NO_BUBBLE_UP = 14;
-
private final Context mContext;
- private final NotificationEntryManager mNotificationEntryManager;
- private final NotifPipeline mNotifPipeline;
- private final BubbleTaskStackListener mTaskStackListener;
private BubbleExpandListener mExpandListener;
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
- private final NotificationGroupManagerLegacy mNotificationGroupManager;
- private final ShadeController mShadeController;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
private BubbleLogger mLogger;
private final Handler mMainHandler;
private BubbleData mBubbleData;
- private ScrimView mBubbleScrim;
+ private View mBubbleScrim;
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
private BubblePositioner mBubblePositioner;
+ private SysuiProxy mSysuiProxy;
/**
* The relative position of the stack when we removed it and nulled it out. If the stack is
@@ -193,12 +111,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
// Used when ranking updates occur and we check if things should bubble / unbubble
private NotificationListenerService.Ranking mTmpRanking;
- // Bubbles get added to the status bar view
- private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final ZenModeController mZenModeController;
- private StatusBarStateListener mStatusBarStateListener;
- private INotificationManager mINotificationManager;
-
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private BubbleData.Listener mOverflowListener = null;
@@ -209,12 +121,10 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
* When the shade status changes to SHADE (from anything but SHADE, like LOCKED) we'll select
* this bubble and expand the stack.
*/
- @Nullable private NotificationEntry mNotifEntryToExpandOnShadeUnlock;
+ @Nullable private BubbleEntry mNotifEntryToExpandOnShadeUnlock;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
private WindowManager mWindowManager;
- private SysUiState mSysUiState;
// Used to post to main UI thread
private Handler mHandler = new Handler();
@@ -224,9 +134,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
/** Whether or not the BubbleStackView has been added to the WindowManager. */
private boolean mAddedToWindowManager = false;
- // Listens to user switch so bubbles can be saved and restored.
- private final NotificationLockscreenUserManager mNotifUserManager;
-
/** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -247,9 +154,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
private ShellTaskOrganizer mTaskOrganizer;
- // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
- private final List<NotifCallback> mCallbacks = new ArrayList<>();
-
/**
* Whether the IME is visible, as reported by the BubbleStackView. If it is, we'll make the
* Bubbles window NOT_FOCUSABLE so that touches on the Bubbles UI doesn't steal focus from the
@@ -257,122 +161,15 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
*/
private boolean mImeVisible = false;
- /**
- * Listener to find out about stack expansion / collapse events.
- */
- public interface BubbleExpandListener {
- /**
- * Called when the expansion state of the bubble stack changes.
- *
- * @param isExpanding whether it's expanding or collapsing
- * @param key the notification key associated with bubble being expanded
- */
- void onBubbleExpandChanged(boolean isExpanding, String key);
- }
-
- /**
- * Listener to be notified when a bubbles' notification suppression state changes.
- */
- public interface NotificationSuppressionChangedListener {
- /**
- * Called when the notification suppression state of a bubble changes.
- */
- void onBubbleNotificationSuppressionChange(Bubble bubble);
- }
-
- /**
- * Listener to be notified when a pending intent has been canceled for a bubble.
- */
- public interface PendingIntentCanceledListener {
- /**
- * Called when the pending intent for a bubble has been canceled.
- */
- void onPendingIntentCanceled(Bubble bubble);
- }
-
- /**
- * Callback for when the BubbleController wants to interact with the notification pipeline to:
- * - Remove a previously bubbled notification
- * - Update the notification shade since bubbled notification should/shouldn't be showing
- */
- public interface NotifCallback {
- /**
- * Called when a bubbled notification that was hidden from the shade is now being removed
- * This can happen when an app cancels a bubbled notification or when the user dismisses a
- * bubble.
- */
- void removeNotification(
- @NonNull NotificationEntry entry,
- @NonNull DismissedByUserStats stats,
- int reason);
-
- /**
- * Called when a bubbled notification has changed whether it should be
- * filtered from the shade.
- */
- void invalidateNotifications(@NonNull String reason);
-
- /**
- * Called on a bubbled entry that has been removed when there are no longer
- * bubbled entries in its group.
- *
- * Checks whether its group has any other (non-bubbled) children. If it doesn't,
- * removes all remnants of the group's summary from the notification pipeline.
- * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
- */
- void maybeCancelSummary(@NonNull NotificationEntry entry);
- }
-
- /**
- * Listens for the current state of the status bar and updates the visibility state
- * of bubbles as needed.
- */
- private class StatusBarStateListener implements StatusBarStateController.StateListener {
- private int mState;
- /**
- * Returns the current status bar state.
- */
- public int getCurrentState() {
- return mState;
- }
-
- @Override
- public void onStateChanged(int newState) {
- mState = newState;
- boolean shouldCollapse = (mState != SHADE);
- if (shouldCollapse) {
- collapseStack();
- }
-
- if (mNotifEntryToExpandOnShadeUnlock != null) {
- expandStackAndSelectBubble(mNotifEntryToExpandOnShadeUnlock);
- mNotifEntryToExpandOnShadeUnlock = null;
- }
-
- updateStack();
- }
- }
+ /** true when user is in status bar unlock shade. */
+ private boolean mIsStatusBarShade = true;
/**
* Injected constructor. See {@link BubbleModule}.
*/
public static BubbleController create(Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
- ShadeController shadeController,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
- ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController,
- NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- FeatureFlags featureFlags,
- DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
- SysUiState sysUiState,
- INotificationManager notificationManager,
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -381,39 +178,23 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
@Main Handler mainHandler,
ShellTaskOrganizer organizer) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
- return new BubbleController(context, notificationShadeWindowController,
- statusBarStateController, shadeController, new BubbleData(context, logger),
- synchronizer, configurationController, interruptionStateProvider, zenModeController,
- notifUserManager, groupManager, entryManager, notifPipeline, featureFlags,
- dumpManager, floatingContentCoordinator,
- new BubbleDataRepository(context, launcherApps), sysUiState, notificationManager,
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps, logger,
- mainHandler, organizer, new BubblePositioner(context, windowManager));
+ return new BubbleController(context,
+ new BubbleData(context, logger), synchronizer,
+ floatingContentCoordinator, new BubbleDataRepository(context, launcherApps),
+ statusBarService, windowManager,
+ windowManagerShellWrapper, launcherApps, logger, mainHandler, organizer,
+ new BubblePositioner(context, windowManager));
}
/**
* Testing constructor.
*/
@VisibleForTesting
- BubbleController(Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
- ShadeController shadeController,
+ public BubbleController(Context context,
BubbleData data,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
- ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController,
- NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- FeatureFlags featureFlags,
- DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
BubbleDataRepository dataRepository,
- SysUiState sysUiState,
- INotificationManager notificationManager,
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -422,82 +203,35 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
Handler mainHandler,
ShellTaskOrganizer organizer,
BubblePositioner positioner) {
- dumpManager.registerDumpable(TAG, this);
mContext = context;
- mShadeController = shadeController;
- mNotificationInterruptStateProvider = interruptionStateProvider;
- mNotifUserManager = notifUserManager;
- mZenModeController = zenModeController;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
- mINotificationManager = notificationManager;
mLogger = bubbleLogger;
mMainHandler = mainHandler;
- mZenModeController.addCallback(new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- for (Bubble b : mBubbleData.getBubbles()) {
- b.setShowDot(b.showInShade());
- }
- }
-
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- for (Bubble b : mBubbleData.getBubbles()) {
- b.setShowDot(b.showInShade());
- }
- }
- });
-
- configurationController.addCallback(this /* configurationListener */);
- mSysUiState = sysUiState;
mBubbleData = data;
mBubbleData.setListener(mBubbleDataListener);
- mBubbleData.setSuppressionChangedListener(new NotificationSuppressionChangedListener() {
- @Override
- public void onBubbleNotificationSuppressionChange(Bubble bubble) {
- // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it
- // can tell.
- try {
- mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
- !bubble.showInShade());
- } catch (RemoteException e) {
- // Bad things have happened
- }
+ mBubbleData.setSuppressionChangedListener(bubble -> {
+ // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it
+ // can tell.
+ try {
+ mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
+ !bubble.showInShade());
+ } catch (RemoteException e) {
+ // Bad things have happened
}
});
mBubbleData.setPendingIntentCancelledListener(bubble -> {
if (bubble.getBubbleIntent() == null) {
return;
}
- if (bubble.isIntentActive()
- || mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
+ if (bubble.isIntentActive() || mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
bubble.setPendingIntentCanceled();
return;
}
- mHandler.post(
- () -> removeBubble(bubble.getKey(),
- BubbleController.DISMISS_INVALID_INTENT));
+ mHandler.post(() -> removeBubble(bubble.getKey(), DISMISS_INVALID_INTENT));
});
- mNotificationEntryManager = entryManager;
- mNotificationGroupManager = groupManager;
- mNotifPipeline = notifPipeline;
-
- if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
- setupNEM();
- } else {
- setupNotifPipeline();
- }
-
- mNotificationShadeWindowController = notificationShadeWindowController;
- mStatusBarStateListener = new StatusBarStateListener();
- statusBarStateController.addCallback(mStatusBarStateListener);
-
- mTaskStackListener = new BubbleTaskStackListener();
- TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
-
try {
windowManagerShellWrapper.addPinnedStackListener(new BubblesImeListener());
} catch (RemoteException e) {
@@ -511,25 +245,10 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
ServiceManager.getService(Context.STATUS_BAR_SERVICE))
: statusBarService;
- mBubbleScrim = new ScrimView(mContext);
- mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-
mSavedBubbleKeysPerUser = new SparseSetArray<>();
- mCurrentUserId = mNotifUserManager.getCurrentUserId();
+ mCurrentUserId = ActivityManager.getCurrentUser();
mBubbleData.setCurrentUserId(mCurrentUserId);
- mNotifUserManager.addUserChangedListener(
- new NotificationLockscreenUserManager.UserChangedListener() {
- @Override
- public void onUserChanged(int newUserId) {
- BubbleController.this.saveBubbles(mCurrentUserId);
- mBubbleData.dismissAll(DISMISS_USER_CHANGED);
- BubbleController.this.restoreBubbles(newUserId);
- mCurrentUserId = newUserId;
- mBubbleData.setCurrentUserId(newUserId);
- }
- });
-
mBubbleIconFactory = new BubbleIconFactory(context);
mTaskOrganizer = organizer;
mBubblePositioner = positioner;
@@ -549,10 +268,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
@Override
- public void onPackagesAvailable(String[] strings, UserHandle userHandle,
- boolean b) {
-
- }
+ public void onPackagesAvailable(String[] strings, UserHandle userHandle, boolean b) {}
@Override
public void onPackagesUnavailable(String[] packages, UserHandle userHandle,
@@ -577,17 +293,9 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
/**
- * See {@link NotifCallback}.
- */
- @Override
- public void addNotifCallback(NotifCallback callback) {
- mCallbacks.add(callback);
- }
-
- /**
* Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
*/
- public void hideCurrentInputMethod() {
+ void hideCurrentInputMethod() {
try {
mBarService.hideCurrentInputMethodForBubbles();
} catch (RemoteException e) {
@@ -595,183 +303,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- private void onBubbleExpandChanged(boolean shouldExpand) {
- mSysUiState
- .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
- .commitUpdate(mContext.getDisplayId());
- }
-
- private void setupNEM() {
- mNotificationEntryManager.addNotificationEntryListener(
- new NotificationEntryListener() {
- @Override
- public void onPendingEntryAdded(NotificationEntry entry) {
- onEntryAdded(entry);
- }
-
- @Override
- public void onPreEntryUpdated(NotificationEntry entry) {
- onEntryUpdated(entry);
- }
-
- @Override
- public void onEntryRemoved(
- NotificationEntry entry,
- @android.annotation.Nullable NotificationVisibility visibility,
- boolean removedByUser,
- int reason) {
- BubbleController.this.onEntryRemoved(entry);
- }
-
- @Override
- public void onNotificationRankingUpdated(RankingMap rankingMap) {
- onRankingUpdated(rankingMap);
- }
- });
-
- // The new pipeline takes care of this as a NotifDismissInterceptor BubbleCoordinator
- mNotificationEntryManager.addNotificationRemoveInterceptor(
- new NotificationRemoveInterceptor() {
- @Override
- public boolean onNotificationRemoveRequested(
- String key,
- NotificationEntry entry,
- int dismissReason) {
- final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
- final boolean isUserDismiss = dismissReason == REASON_CANCEL
- || dismissReason == REASON_CLICK;
- final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
- || dismissReason == REASON_APP_CANCEL_ALL;
- final boolean isSummaryCancel =
- dismissReason == REASON_GROUP_SUMMARY_CANCELED;
-
- // Need to check for !appCancel here because the notification may have
- // previously been dismissed & entry.isRowDismissed would still be true
- boolean userRemovedNotif =
- (entry != null && entry.isRowDismissed() && !isAppCancel)
- || isClearAll || isUserDismiss || isSummaryCancel;
-
- if (userRemovedNotif) {
- return handleDismissalInterception(entry);
- }
- return false;
- }
- });
-
- mNotificationGroupManager.registerGroupChangeListener(
- new NotificationGroupManagerLegacy.OnGroupChangeListener() {
- @Override
- public void onGroupSuppressionChanged(
- NotificationGroupManagerLegacy.NotificationGroup group,
- boolean suppressed) {
- // More notifications could be added causing summary to no longer
- // be suppressed -- in this case need to remove the key.
- final String groupKey = group.summary != null
- ? group.summary.getSbn().getGroupKey()
- : null;
- if (!suppressed && groupKey != null
- && mBubbleData.isSummarySuppressed(groupKey)) {
- mBubbleData.removeSuppressedSummary(groupKey);
- }
- }
- });
-
- addNotifCallback(new NotifCallback() {
- @Override
- public void removeNotification(
- NotificationEntry entry,
- DismissedByUserStats dismissedByUserStats,
- int reason
- ) {
- mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
- dismissedByUserStats, reason);
- }
-
- @Override
- public void invalidateNotifications(String reason) {
- mNotificationEntryManager.updateNotifications(reason);
- }
-
- @Override
- public void maybeCancelSummary(NotificationEntry entry) {
- // Check if removed bubble has an associated suppressed group summary that needs
- // to be removed now.
- final String groupKey = entry.getSbn().getGroupKey();
- if (mBubbleData.isSummarySuppressed(groupKey)) {
- mBubbleData.removeSuppressedSummary(groupKey);
-
- final NotificationEntry summary =
- mNotificationEntryManager.getActiveNotificationUnfiltered(
- mBubbleData.getSummaryKey(groupKey));
- if (summary != null) {
- mNotificationEntryManager.performRemoveNotification(
- summary.getSbn(),
- getDismissedByUserStats(summary, false),
- UNDEFINED_DISMISS_REASON);
- }
- }
-
- // Check if we still need to remove the summary from NoManGroup because the summary
- // may not be in the mBubbleData.mSuppressedGroupKeys list and removed above.
- // For example:
- // 1. Bubbled notifications (group) is posted to shade and are visible bubbles
- // 2. User expands bubbles so now their respective notifications in the shade are
- // hidden, including the group summary
- // 3. User removes all bubbles
- // 4. We expect all the removed bubbles AND the summary (note: the summary was
- // never added to the suppressedSummary list in BubbleData, so we add this check)
- NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(entry);
- if (summary != null) {
- ArrayList<NotificationEntry> summaryChildren =
- mNotificationGroupManager.getLogicalChildren(summary.getSbn());
- boolean isSummaryThisNotif = summary.getKey().equals(entry.getKey());
- if (!isSummaryThisNotif && (summaryChildren == null
- || summaryChildren.isEmpty())) {
- mNotificationEntryManager.performRemoveNotification(
- summary.getSbn(),
- getDismissedByUserStats(summary, false),
- UNDEFINED_DISMISS_REASON);
- }
- }
- }
- });
- }
-
- private void setupNotifPipeline() {
- mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
- @Override
- public void onEntryAdded(NotificationEntry entry) {
- BubbleController.this.onEntryAdded(entry);
- }
-
- @Override
- public void onEntryUpdated(NotificationEntry entry) {
- BubbleController.this.onEntryUpdated(entry);
- }
-
- @Override
- public void onRankingUpdate(RankingMap rankingMap) {
- onRankingUpdated(rankingMap);
- }
-
- @Override
- public void onEntryRemoved(NotificationEntry entry,
- @NotifCollection.CancellationReason int reason) {
- BubbleController.this.onEntryRemoved(entry);
- }
- });
- }
-
- /**
- * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
- * since we want the scrim's appearance and behavior to be identical to that of the notification
- * shade scrim.
- */
- @Override
- public ScrimView getScrimForBubble() {
- return mBubbleScrim;
- }
-
/**
* Called when the status bar has become visible or invisible (either permanently or
* temporarily).
@@ -785,16 +316,47 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
+ @Override
+ public void onZenStateChanged() {
+ for (Bubble b : mBubbleData.getBubbles()) {
+ b.setShowDot(b.showInShade());
+ }
+ }
+
+ @Override
+ public void onStatusBarStateChanged(boolean isShade) {
+ mIsStatusBarShade = isShade;
+ if (!mIsStatusBarShade) {
+ collapseStack();
+ }
+
+ if (mNotifEntryToExpandOnShadeUnlock != null) {
+ expandStackAndSelectBubble(mNotifEntryToExpandOnShadeUnlock);
+ mNotifEntryToExpandOnShadeUnlock = null;
+ }
+
+ updateStack();
+ }
+
+ @Override
+ public void onUserChanged(int newUserId) {
+ saveBubbles(mCurrentUserId);
+ mBubbleData.dismissAll(DISMISS_USER_CHANGED);
+ restoreBubbles(newUserId);
+ mCurrentUserId = newUserId;
+ mBubbleData.setCurrentUserId(newUserId);
+ }
+
/**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
*/
@VisibleForTesting
- void setInflateSynchronously(boolean inflateSynchronously) {
+ public void setInflateSynchronously(boolean inflateSynchronously) {
mInflateSynchronously = inflateSynchronously;
}
- @Override
+ /** Set a listener to be notified of when overflow view update. */
public void setOverflowListener(BubbleData.Listener listener) {
mOverflowListener = listener;
}
@@ -802,21 +364,24 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
/**
* @return Bubbles for updating overflow.
*/
- @Override
- public List<Bubble> getOverflowBubbles() {
+ List<Bubble> getOverflowBubbles() {
return mBubbleData.getOverflowBubbles();
}
- @Override
+ /** The task listener for events in bubble tasks. */
public ShellTaskOrganizer getTaskOrganizer() {
return mTaskOrganizer;
}
- @Override
- public BubblePositioner getPositioner() {
+ /** Contains information to help position things on the screen. */
+ BubblePositioner getPositioner() {
return mBubblePositioner;
}
+ SysuiProxy getSysuiProxy() {
+ return mSysuiProxy;
+ }
+
/**
* BubbleStackView is lazily created by this method the first time a Bubble is added. This
* method initializes the stack view and adds it to the StatusBar just above the scrim.
@@ -824,23 +389,14 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
private void ensureStackViewCreated() {
if (mStackView == null) {
mStackView = new BubbleStackView(
- mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
- this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
- this::hideCurrentInputMethod, this::onBubbleExpandChanged, mBubblePositioner);
+ mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator);
mStackView.setStackStartPosition(mPositionFromRemovedStack);
mStackView.addView(mBubbleScrim);
mStackView.onOrientationChanged();
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
}
-
- mStackView.setUnbubbleConversationCallback(key -> {
- final NotificationEntry entry =
- mNotificationEntryManager.getPendingOrActiveNotif(key);
- if (entry != null) {
- onUserChangedBubble(entry, false /* shouldBubble */);
- }
- });
+ mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
}
addToWindowManagerMaybe();
@@ -882,7 +438,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- private void onImeVisibilityChanged(boolean imeVisible) {
+ void onImeVisibilityChanged(boolean imeVisible) {
mImeVisible = imeVisible;
}
@@ -913,7 +469,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
* Called by the BubbleStackView and whenever all bubbles have animated out, and none have been
* added in the meantime.
*/
- private void onAllBubblesAnimatedOut() {
+ void onAllBubblesAnimatedOut() {
if (mStackView != null) {
mStackView.setVisibility(INVISIBLE);
removeFromWindowManagerMaybe();
@@ -946,12 +502,8 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
// There were no bubbles saved for this used.
return;
}
- for (NotificationEntry e :
- mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
- if (savedBubbleKeys.contains(e.getKey())
- && mNotificationInterruptStateProvider.shouldBubbleUp(e)
- && e.isBubble()
- && canLaunchInActivityView(mContext, e)) {
+ for (BubbleEntry e : mSysuiProxy.getShouldRestoredEntries(savedBubbleKeys)) {
+ if (canLaunchInActivityView(mContext, e)) {
updateBubble(e, true /* suppressFlyout */, false /* showInShade */);
}
}
@@ -960,27 +512,18 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
@Override
- public void onUiModeChanged() {
- updateForThemeChanges();
- }
-
- @Override
- public void onOverlayChanged() {
- updateForThemeChanges();
- }
-
- private void updateForThemeChanges() {
+ public void updateForThemeChanges() {
if (mStackView != null) {
mStackView.onThemeChanged();
}
mBubbleIconFactory = new BubbleIconFactory(mContext);
// Reload each bubble
for (Bubble b: mBubbleData.getBubbles()) {
- b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
+ b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory,
false /* skipInflation */);
}
for (Bubble b: mBubbleData.getOverflowBubbles()) {
- b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
+ b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory,
false /* skipInflation */);
}
}
@@ -1012,9 +555,16 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- /**
- * Set a listener to be notified of bubble expand events.
- */
+ @Override
+ public void setBubbleScrim(View view) {
+ mBubbleScrim = view;
+ }
+
+ @Override
+ public void setSysuiProxy(SysuiProxy proxy) {
+ mSysuiProxy = proxy;
+ }
+
@Override
public void setExpandListener(BubbleExpandListener listener) {
mExpandListener = ((isExpanding, key) -> {
@@ -1032,7 +582,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
* screen (e.g. if on AOD).
*/
@VisibleForTesting
- boolean hasBubbles() {
+ public boolean hasBubbles() {
if (mStackView == null) {
return false;
}
@@ -1050,24 +600,37 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
@Override
- public boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry) {
- String key = entry.getKey();
+ public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key)
&& !mBubbleData.getAnyBubbleWithkey(key).showInShade());
- String groupKey = entry.getSbn().getGroupKey();
boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey));
return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
@Override
- public boolean isBubbleExpanded(NotificationEntry entry) {
- return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
- && mBubbleData.getSelectedBubble().getKey().equals(entry.getKey());
+ public boolean isSummarySuppressed(String groupKey) {
+ return mBubbleData.isSummarySuppressed(groupKey);
}
@Override
+ public void removeSuppressedSummary(String groupKey) {
+ mBubbleData.removeSuppressedSummary(groupKey);
+ }
+
+ @Override
+ public String getSummaryKey(String groupKey) {
+ return mBubbleData.getSummaryKey(groupKey);
+ }
+
+ @Override
+ public boolean isBubbleExpanded(String key) {
+ return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
+ && mBubbleData.getSelectedBubble().getKey().equals(key);
+ }
+
+ /** Promote the provided bubble from the overflow view. */
public void promoteBubbleFromOverflow(Bubble bubble) {
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
bubble.setInflateSynchronously(mInflateSynchronously);
@@ -1077,8 +640,8 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
@Override
- public void expandStackAndSelectBubble(NotificationEntry entry) {
- if (mStatusBarStateListener.getCurrentState() == SHADE) {
+ public void expandStackAndSelectBubble(BubbleEntry entry) {
+ if (mIsStatusBarShade) {
mNotifEntryToExpandOnShadeUnlock = null;
String key = entry.getKey();
@@ -1104,27 +667,13 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- @Override
- public void onUserChangedImportance(NotificationEntry entry) {
- try {
- int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
- flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
- mBarService.onNotificationBubbleChanged(entry.getKey(), true, flags);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage());
- }
- mShadeController.collapsePanel(true);
- if (entry.getRow() != null) {
- entry.getRow().updateBubbleButton();
- }
- }
-
/**
* Adds or updates a bubble associated with the provided notification entry.
*
* @param notif the notification associated with this bubble.
*/
- void updateBubble(NotificationEntry notif) {
+ @VisibleForTesting
+ public void updateBubble(BubbleEntry notif) {
updateBubble(notif, false /* suppressFlyout */, true /* showInShade */);
}
@@ -1144,27 +693,32 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
return;
}
bubble.inflate((b) -> mBubbleData.overflowBubble(DISMISS_AGED, bubble),
- mContext, mStackView, mBubbleIconFactory, true /* skipInflation */);
+ mContext, this, mStackView, mBubbleIconFactory, true /* skipInflation */);
});
return null;
});
}
- void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
+ /**
+ * Adds or updates a bubble associated with the provided notification entry.
+ *
+ * @param notif the notification associated with this bubble.
+ * @param suppressFlyout this bubble suppress flyout or not.
+ * @param showInShade this bubble show in shade or not.
+ */
+ @VisibleForTesting
+ public void updateBubble(BubbleEntry notif, boolean suppressFlyout, boolean showInShade) {
// If this is an interruptive notif, mark that it's interrupted
- if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
- notif.setInterruption();
- }
+ mSysuiProxy.setNotificationInterruption(notif.getKey());
if (!notif.getRanking().visuallyInterruptive()
&& (notif.getBubbleMetadata() != null
&& !notif.getBubbleMetadata().getAutoExpandBubble())
&& mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) {
// Update the bubble but don't promote it out of overflow
Bubble b = mBubbleData.getOverflowBubbleWithKey(notif.getKey());
- b.setEntry(notifToBubbleEntry(notif));
+ b.setEntry(notif);
} else {
- Bubble bubble = mBubbleData.getOrCreateBubble(
- notifToBubbleEntry(notif), null /* persistedBubble */);
+ Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
inflateAndAdd(bubble, suppressFlyout, showInShade);
}
}
@@ -1174,68 +728,33 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
ensureStackViewCreated();
bubble.setInflateSynchronously(mInflateSynchronously);
bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
- mContext, mStackView, mBubbleIconFactory, false /* skipInflation */);
- }
-
- @Override
- public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
- NotificationChannel channel = entry.getChannel();
- final String appPkg = entry.getSbn().getPackageName();
- final int appUid = entry.getSbn().getUid();
- if (channel == null || appPkg == null) {
- return;
- }
-
- // Update the state in NotificationManagerService
- try {
- int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
- flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
- mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags);
- } catch (RemoteException e) {
- }
-
- // Change the settings
- channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext,
- mINotificationManager, entry, channel);
- channel.setAllowBubbles(shouldBubble);
- try {
- int currentPref = mINotificationManager.getBubblePreferenceForPackage(appPkg, appUid);
- if (shouldBubble && currentPref == BUBBLE_PREFERENCE_NONE) {
- mINotificationManager.setBubblesAllowed(appPkg, appUid, BUBBLE_PREFERENCE_SELECTED);
- }
- mINotificationManager.updateNotificationChannelForPackage(appPkg, appUid, channel);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage());
- }
-
- if (shouldBubble) {
- mShadeController.collapsePanel(true);
- if (entry.getRow() != null) {
- entry.getRow().updateBubbleButton();
- }
- }
+ mContext, this, mStackView, mBubbleIconFactory, false /* skipInflation */);
}
+ /**
+ * Removes the bubble with the given key.
+ * <p>
+ * Must be called from the main thread.
+ */
+ @VisibleForTesting
@MainThread
- @Override
public void removeBubble(String key, int reason) {
if (mBubbleData.hasAnyBubbleWithKey(key)) {
mBubbleData.dismissBubbleWithKey(key, reason);
}
}
- private void onEntryAdded(NotificationEntry entry) {
- if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
- && entry.isBubble()
- && canLaunchInActivityView(mContext, entry)) {
+ @Override
+ public void onEntryAdded(BubbleEntry entry) {
+ if (canLaunchInActivityView(mContext, entry)) {
updateBubble(entry);
}
}
- private void onEntryUpdated(NotificationEntry entry) {
+ @Override
+ public void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
// shouldBubbleUp checks canBubble & for bubble metadata
- boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
- && canLaunchInActivityView(mContext, entry);
+ boolean shouldBubble = shouldBubbleUp && canLaunchInActivityView(mContext, entry);
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
@@ -1244,9 +763,10 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- private void onEntryRemoved(NotificationEntry entry) {
+ @Override
+ public void onEntryRemoved(BubbleEntry entry) {
if (isSummaryOfBubbles(entry)) {
- final String groupKey = entry.getSbn().getGroupKey();
+ final String groupKey = entry.getStatusBarNotification().getGroupKey();
mBubbleData.removeSuppressedSummary(groupKey);
// Remove any associated bubble children with the summary
@@ -1259,39 +779,30 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
- /**
- * Called when NotificationListener has received adjusted notification rank and reapplied
- * filtering and sorting. This is used to dismiss or create bubbles based on changes in
- * permissions on the notification channel or the global setting.
- *
- * @param rankingMap the updated ranking map from NotificationListenerService
- */
- private void onRankingUpdated(RankingMap rankingMap) {
+ @Override
+ public void onRankingUpdated(RankingMap rankingMap) {
if (mTmpRanking == null) {
mTmpRanking = new NotificationListenerService.Ranking();
}
String[] orderedKeys = rankingMap.getOrderedKeys();
for (int i = 0; i < orderedKeys.length; i++) {
String key = orderedKeys[i];
- NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
+ BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(key);
rankingMap.getRanking(key, mTmpRanking);
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
if (isActiveBubble && !mTmpRanking.canBubble()) {
// If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason.
// This means that the app or channel's ability to bubble has been revoked.
- mBubbleData.dismissBubbleWithKey(
- key, BubbleController.DISMISS_BLOCKED);
- } else if (isActiveBubble
- && !mNotificationInterruptStateProvider.shouldBubbleUp(entry)) {
+ mBubbleData.dismissBubbleWithKey(key, DISMISS_BLOCKED);
+ } else if (isActiveBubble && !mSysuiProxy.shouldBubbleUp(key)) {
// If this entry is allowed to bubble, but cannot currently bubble up, dismiss it.
// This happens when DND is enabled and configured to hide bubbles. Dismissing with
// the reason DISMISS_NO_BUBBLE_UP will retain the underlying notification, so that
// the bubble will be re-created if shouldBubbleUp returns true.
- mBubbleData.dismissBubbleWithKey(
- key, BubbleController.DISMISS_NO_BUBBLE_UP);
+ mBubbleData.dismissBubbleWithKey(key, DISMISS_NO_BUBBLE_UP);
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
entry.setFlagBubble(true);
- onEntryUpdated(entry);
+ onEntryUpdated(entry, true /* shouldBubbleUp */);
}
}
}
@@ -1306,23 +817,18 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
return bubbleChildren;
}
for (Bubble bubble : mBubbleData.getActiveBubbles()) {
- final NotificationEntry entry =
- mNotificationEntryManager.getPendingOrActiveNotif(bubble.getKey());
- if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) {
+ final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(bubble.getKey());
+ if (entry != null && groupKey.equals(entry.getStatusBarNotification().getGroupKey())) {
bubbleChildren.add(bubble);
}
}
return bubbleChildren;
}
- private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble,
+ private void setIsBubble(@NonNull final BubbleEntry entry, final boolean isBubble,
final boolean autoExpand) {
Objects.requireNonNull(entry);
- if (isBubble) {
- entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
- } else {
- entry.getSbn().getNotification().flags &= ~FLAG_BUBBLE;
- }
+ entry.setFlagBubble(isBubble);
try {
int flags = 0;
if (autoExpand) {
@@ -1338,8 +844,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) {
Objects.requireNonNull(b);
b.setIsBubble(isBubble);
- final NotificationEntry entry = mNotificationEntryManager
- .getPendingOrActiveNotif(b.getKey());
+ final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(b.getKey());
if (entry != null) {
// Updating the entry to be a bubble will trigger our normal update flow
setIsBubble(entry, isBubble, b.shouldAutoExpand());
@@ -1372,7 +877,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
// Collapsing? Do this first before remaining steps.
if (update.expandedChanged && !update.expanded) {
mStackView.setExpanded(false);
- mNotificationShadeWindowController.setRequestTopUi(false, TAG);
+ mSysuiProxy.requestNotificationShadeTopUi(false, TAG);
}
// Do removals, if any.
@@ -1396,8 +901,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
if (reason == DISMISS_NOTIF_CANCEL) {
bubblesToBeRemovedFromRepository.add(bubble);
}
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- bubble.getKey());
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
&& (!bubble.showInShade()
@@ -1405,31 +908,21 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
|| reason == DISMISS_GROUP_CANCELLED)) {
// The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it
- for (NotifCallback cb : mCallbacks) {
- if (entry != null) {
- cb.removeNotification(
- entry,
- getDismissedByUserStats(entry, true),
- REASON_CANCEL);
- }
- }
+ mSysuiProxy.notifyRemoveNotification(bubble.getKey(), REASON_CANCEL);
} else {
if (bubble.isBubble()) {
setIsBubble(bubble, false /* isBubble */);
}
- if (entry != null && entry.getRow() != null) {
- entry.getRow().updateBubbleButton();
- }
+ mSysuiProxy.updateNotificationBubbleButton(bubble.getKey());
}
}
+ final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(bubble.getKey());
if (entry != null) {
- final String groupKey = entry.getSbn().getGroupKey();
+ final String groupKey = entry.getStatusBarNotification().getGroupKey();
if (getBubblesInGroup(groupKey).isEmpty()) {
// Time to potentially remove the summary
- for (NotifCallback cb : mCallbacks) {
- cb.maybeCancelSummary(entry);
- }
+ mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
}
}
}
@@ -1454,11 +947,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
if (update.selectionChanged && mStackView != null) {
mStackView.setSelectedBubble(update.selectedBubble);
if (update.selectedBubble != null) {
- final NotificationEntry entry = mNotificationEntryManager
- .getPendingOrActiveNotif(update.selectedBubble.getKey());
- if (entry != null) {
- mNotificationGroupManager.updateSuppression(entry);
- }
+ mSysuiProxy.updateNotificationSuppression(update.selectedBubble.getKey());
}
}
@@ -1466,24 +955,20 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
if (update.expandedChanged && update.expanded) {
if (mStackView != null) {
mStackView.setExpanded(true);
- mNotificationShadeWindowController.setRequestTopUi(true, TAG);
+ mSysuiProxy.requestNotificationShadeTopUi(true, TAG);
}
}
- for (NotifCallback cb : mCallbacks) {
- cb.invalidateNotifications("BubbleData.Listener.applyUpdate");
- }
+ mSysuiProxy.notifyInvalidateNotifications("BubbleData.Listener.applyUpdate");
updateStack();
}
};
@Override
- public boolean handleDismissalInterception(NotificationEntry entry) {
- if (entry == null) {
- return false;
- }
+ public boolean handleDismissalInterception(BubbleEntry entry,
+ @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
if (isSummaryOfBubbles(entry)) {
- handleSummaryDismissalInterception(entry);
+ handleSummaryDismissalInterception(entry, children, removeCallback);
} else {
Bubble bubble = mBubbleData.getBubbleInStackWithKey(entry.getKey());
if (bubble == null || !entry.isBubble()) {
@@ -1496,87 +981,50 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
bubble.setShowDot(false /* show */);
}
// Update the shade
- for (NotifCallback cb : mCallbacks) {
- cb.invalidateNotifications("BubbleController.handleDismissalInterception");
- }
+ mSysuiProxy.notifyInvalidateNotifications("BubbleController.handleDismissalInterception");
return true;
}
- private boolean isSummaryOfBubbles(NotificationEntry entry) {
- if (entry == null) {
- return false;
- }
-
- String groupKey = entry.getSbn().getGroupKey();
+ private boolean isSummaryOfBubbles(BubbleEntry entry) {
+ String groupKey = entry.getStatusBarNotification().getGroupKey();
ArrayList<Bubble> bubbleChildren = getBubblesInGroup(groupKey);
boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
&& mBubbleData.getSummaryKey(groupKey).equals(entry.getKey()));
- boolean isSummary = entry.getSbn().getNotification().isGroupSummary();
- return (isSuppressedSummary || isSummary)
- && bubbleChildren != null
- && !bubbleChildren.isEmpty();
+ boolean isSummary = entry.getStatusBarNotification().getNotification().isGroupSummary();
+ return (isSuppressedSummary || isSummary) && !bubbleChildren.isEmpty();
}
- private void handleSummaryDismissalInterception(NotificationEntry summary) {
- // current children in the row:
- final List<NotificationEntry> children = summary.getAttachedNotifChildren();
+ private void handleSummaryDismissalInterception(
+ BubbleEntry summary, @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
if (children != null) {
for (int i = 0; i < children.size(); i++) {
- NotificationEntry child = children.get(i);
+ BubbleEntry child = children.get(i);
if (mBubbleData.hasAnyBubbleWithKey(child.getKey())) {
// Suppress the bubbled child
// As far as group manager is concerned, once a child is no longer shown
// in the shade, it is essentially removed.
Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey());
if (bubbleChild != null) {
- final NotificationEntry entry = mNotificationEntryManager
- .getPendingOrActiveNotif(bubbleChild.getKey());
- if (entry != null) {
- mNotificationGroupManager.onEntryRemoved(entry);
- }
+ mSysuiProxy.removeNotificationEntry(bubbleChild.getKey());
bubbleChild.setSuppressNotification(true);
bubbleChild.setShowDot(false /* show */);
}
} else {
// non-bubbled children can be removed
- for (NotifCallback cb : mCallbacks) {
- cb.removeNotification(
- child,
- getDismissedByUserStats(child, true),
- REASON_GROUP_SUMMARY_CANCELED);
- }
+ removeCallback.accept(i);
}
}
}
// And since all children are removed, remove the summary.
- mNotificationGroupManager.onEntryRemoved(summary);
+ removeCallback.accept(-1);
// TODO: (b/145659174) remove references to mSuppressedGroupKeys once fully migrated
- mBubbleData.addSummaryToSuppress(summary.getSbn().getGroupKey(),
+ mBubbleData.addSummaryToSuppress(summary.getStatusBarNotification().getGroupKey(),
summary.getKey());
}
/**
- * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
- * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
- * Instead, this is taken care of by {@link BubbleCoordinator}.
- */
- private DismissedByUserStats getDismissedByUserStats(
- NotificationEntry entry,
- boolean isVisible) {
- return new DismissedByUserStats(
- DISMISSAL_BUBBLE,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(
- entry.getKey(),
- entry.getRanking().getRank(),
- mNotificationEntryManager.getActiveNotificationsCount(),
- isVisible,
- NotificationLogger.getNotificationLocation(entry)));
- }
-
- /**
* Updates the visibility of the bubbles based on current state.
* Does not un-bubble, just hides or un-hides.
* Updates stack description for TalkBack focus.
@@ -1586,7 +1034,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
return;
}
- if (mStatusBarStateListener.getCurrentState() != SHADE) {
+ if (!mIsStatusBarShade) {
// Bubbles don't appear over the locked shade.
mStackView.setVisibility(INVISIBLE);
} else if (hasBubbles()) {
@@ -1610,20 +1058,21 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
final BubbleViewProvider expandedViewProvider = mStackView.getExpandedBubble();
if (expandedViewProvider != null && isStackExpanded()
&& !mStackView.isExpansionAnimating()
- && !mNotificationShadeWindowController.getPanelExpanded()) {
+ && !mSysuiProxy.isNotificationShadeExpand()) {
return expandedViewProvider.getTaskId();
}
return INVALID_TASK_ID;
}
@VisibleForTesting
- BubbleStackView getStackView() {
+ public BubbleStackView getStackView() {
return mStackView;
}
/**
* Description of current bubble state.
*/
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BubbleController state:");
mBubbleData.dump(fd, pw, args);
@@ -1635,39 +1084,6 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
/**
- * This task stack listener is responsible for responding to tasks moved to the front
- * which are on the default (main) display. When this happens, expanded bubbles must be
- * collapsed so the user may interact with the app which was just moved to the front.
- * <p>
- * This listener is registered with SystemUI's ActivityManagerWrapper which dispatches
- * these calls via a main thread Handler.
- */
- @MainThread
- private class BubbleTaskStackListener extends TaskStackChangeListener {
-
- @Override
- public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
- int expandedId = getExpandedTaskId();
- if (expandedId != INVALID_TASK_ID && expandedId != taskInfo.taskId) {
- mBubbleData.setExpanded(false);
- }
- }
-
- @Override
- public void onActivityRestartAttempt(RunningTaskInfo taskInfo, boolean homeTaskVisible,
- boolean clearedTask, boolean wasVisible) {
- for (Bubble b : mBubbleData.getBubbles()) {
- if (taskInfo.taskId == b.getTaskId()) {
- mBubbleData.setSelectedBubble(b);
- mBubbleData.setExpanded(true);
- return;
- }
- }
- }
-
- }
-
- /**
* Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
*
* Keep checks in sync with NotificationManagerService#canLaunchInActivityView. Typically
@@ -1676,7 +1092,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
* @param context the context to use.
* @param entry the entry to bubble.
*/
- static boolean canLaunchInActivityView(Context context, NotificationEntry entry) {
+ static boolean canLaunchInActivityView(Context context, BubbleEntry entry) {
PendingIntent intent = entry.getBubbleMetadata() != null
? entry.getBubbleMetadata().getIntent()
: null;
@@ -1688,8 +1104,8 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
return false;
}
- PackageManager packageManager = StatusBar.getPackageManagerForUser(
- context, entry.getSbn().getUser().getIdentifier());
+ PackageManager packageManager = getPackageManagerForUser(
+ context, entry.getStatusBarNotification().getUser().getIdentifier());
ActivityInfo info =
intent.getIntent().resolveActivityInfo(packageManager, 0);
if (info == null) {
@@ -1707,6 +1123,24 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
return true;
}
+ static PackageManager getPackageManagerForUser(Context context, int userId) {
+ Context contextForUser = context;
+ // UserHandle defines special userId as negative values, e.g. USER_ALL
+ if (userId >= 0) {
+ try {
+ // Create a context for the correct user so if a package isn't installed
+ // for user 0 we can still load information about the package.
+ contextForUser =
+ context.createPackageContextAsUser(context.getPackageName(),
+ Context.CONTEXT_RESTRICTED,
+ new UserHandle(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ // Shouldn't fail to find the package name for system ui.
+ }
+ }
+ return contextForUser.getPackageManager();
+ }
+
/** PinnedStackListener that dispatches IME visibility updates to the stack. */
//TODO(b/170442945): Better way to do this / insets listener?
private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
@@ -1717,10 +1151,4 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
}
}
}
-
- static BubbleEntry notifToBubbleEntry(NotificationEntry e) {
- return new BubbleEntry(e.getSbn(), e.getRanking(), e.isClearable(),
- e.shouldSuppressNotificationDot(), e.shouldSuppressNotificationList(),
- e.shouldSuppressPeek());
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index b4626f27d370..8cacc8f2ef01 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -34,7 +34,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.R;
-import com.android.systemui.bubbles.BubbleController.DismissReason;
+import com.android.systemui.bubbles.Bubbles.DismissReason;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -137,8 +137,8 @@ public class BubbleData {
private Listener mListener;
@Nullable
- private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
- private BubbleController.PendingIntentCanceledListener mCancelledListener;
+ private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
+ private Bubbles.PendingIntentCanceledListener mCancelledListener;
/**
* We track groups with summaries that aren't visibly displayed but still kept around because
@@ -165,12 +165,12 @@ public class BubbleData {
}
public void setSuppressionChangedListener(
- BubbleController.NotificationSuppressionChangedListener listener) {
+ Bubbles.NotificationSuppressionChangedListener listener) {
mSuppressionListener = listener;
}
public void setPendingIntentCancelledListener(
- BubbleController.PendingIntentCanceledListener listener) {
+ Bubbles.PendingIntentCanceledListener listener) {
mCancelledListener = listener;
}
@@ -344,7 +344,8 @@ public class BubbleData {
/**
* Whether the summary for the provided group key is suppressed.
*/
- boolean isSummarySuppressed(String groupKey) {
+ @VisibleForTesting
+ public boolean isSummarySuppressed(String groupKey) {
return mSuppressedGroupKeys.containsKey(groupKey);
}
@@ -415,7 +416,7 @@ public class BubbleData {
// skip the selected bubble
.filter((b) -> !b.equals(mSelectedBubble))
.findFirst()
- .ifPresent((b) -> doRemove(b.getKey(), BubbleController.DISMISS_AGED));
+ .ifPresent((b) -> doRemove(b.getKey(), Bubbles.DISMISS_AGED));
}
}
@@ -459,12 +460,12 @@ public class BubbleData {
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
if (hasOverflowBubbleWithKey(key)
- && (reason == BubbleController.DISMISS_NOTIF_CANCEL
- || reason == BubbleController.DISMISS_GROUP_CANCELLED
- || reason == BubbleController.DISMISS_NO_LONGER_BUBBLE
- || reason == BubbleController.DISMISS_BLOCKED
- || reason == BubbleController.DISMISS_SHORTCUT_REMOVED
- || reason == BubbleController.DISMISS_PACKAGE_REMOVED)) {
+ && (reason == Bubbles.DISMISS_NOTIF_CANCEL
+ || reason == Bubbles.DISMISS_GROUP_CANCELLED
+ || reason == Bubbles.DISMISS_NO_LONGER_BUBBLE
+ || reason == Bubbles.DISMISS_BLOCKED
+ || reason == Bubbles.DISMISS_SHORTCUT_REMOVED
+ || reason == Bubbles.DISMISS_PACKAGE_REMOVED)) {
Bubble b = getOverflowBubbleWithKey(key);
if (DEBUG_BUBBLE_DATA) {
@@ -512,8 +513,8 @@ public class BubbleData {
void overflowBubble(@DismissReason int reason, Bubble bubble) {
if (bubble.getPendingIntentCanceled()
- || !(reason == BubbleController.DISMISS_AGED
- || reason == BubbleController.DISMISS_USER_GESTURE)) {
+ || !(reason == Bubbles.DISMISS_AGED
+ || reason == Bubbles.DISMISS_USER_GESTURE)) {
return;
}
if (DEBUG_BUBBLE_DATA) {
@@ -529,7 +530,7 @@ public class BubbleData {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "Overflow full. Remove: " + oldest);
}
- mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
+ mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
mOverflowBubbles.remove(oldest);
mStateChange.removedOverflowBubble = oldest;
@@ -694,7 +695,7 @@ public class BubbleData {
}
private void maybeSendDeleteIntent(@DismissReason int reason, @NonNull final Bubble bubble) {
- if (reason != BubbleController.DISMISS_USER_GESTURE) return;
+ if (reason != Bubbles.DISMISS_USER_GESTURE) return;
PendingIntent deleteIntent = bubble.getDeleteIntent();
if (deleteIntent == null) return;
try {
@@ -726,7 +727,7 @@ public class BubbleData {
* The set of bubbles in overflow.
*/
@VisibleForTesting(visibility = PRIVATE)
- List<Bubble> getOverflowBubbles() {
+ public List<Bubble> getOverflowBubbles() {
return Collections.unmodifiableList(mOverflowBubbles);
}
@@ -742,7 +743,7 @@ public class BubbleData {
@VisibleForTesting(visibility = PRIVATE)
@Nullable
- Bubble getBubbleInStackWithKey(String key) {
+ public Bubble getBubbleInStackWithKey(String key) {
for (int i = 0; i < mBubbles.size(); i++) {
Bubble bubble = mBubbles.get(i);
if (bubble.getKey().equals(key)) {
@@ -764,7 +765,7 @@ public class BubbleData {
}
@VisibleForTesting(visibility = PRIVATE)
- Bubble getOverflowBubbleWithKey(String key) {
+ public Bubble getOverflowBubbleWithKey(String key) {
for (int i = 0; i < mOverflowBubbles.size(); i++) {
Bubble bubble = mOverflowBubbles.get(i);
if (bubble.getKey().equals(key)) {
@@ -788,7 +789,7 @@ public class BubbleData {
* This method should only be used in tests, not in production.
*/
@VisibleForTesting
- void setMaxOverflowBubbles(int maxOverflowBubbles) {
+ public void setMaxOverflowBubbles(int maxOverflowBubbles) {
mMaxOverflowBubbles = maxOverflowBubbles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
index d98fee399470..3937422750cc 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
@@ -33,10 +33,10 @@ public class BubbleDebugConfig {
// to figure-out the origin of a log message while debugging the Bubbles a little painful. By
// setting this constant to true, log messages from the Bubbles package will be tagged with
// their class names instead fot the generic tag.
- static final boolean TAG_WITH_CLASS_NAME = false;
+ public static final boolean TAG_WITH_CLASS_NAME = false;
// Default log tag for the Bubbles package.
- static final String TAG_BUBBLES = "Bubbles";
+ public static final String TAG_BUBBLES = "Bubbles";
static final boolean DEBUG_BUBBLE_CONTROLLER = false;
static final boolean DEBUG_BUBBLE_DATA = false;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
index 6a1302518699..a0d3391f8347 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
@@ -16,6 +16,9 @@
package com.android.systemui.bubbles;
+import static android.app.Notification.FLAG_BUBBLE;
+
+import android.app.Notification;
import android.app.Notification.BubbleMetadata;
import android.app.NotificationManager.Policy;
import android.service.notification.NotificationListenerService.Ranking;
@@ -67,12 +70,45 @@ public class BubbleEntry {
return mSbn.getKey();
}
+ /** @return the group key in the {@link StatusBarNotification}. */
+ public String getGroupKey() {
+ return mSbn.getGroupKey();
+ }
+
/** @return the {@link BubbleMetadata} in the {@link StatusBarNotification}. */
@Nullable
public BubbleMetadata getBubbleMetadata() {
return getStatusBarNotification().getNotification().getBubbleMetadata();
}
+ /**
+ * Updates the {@link Notification#FLAG_BUBBLE} flag on this notification to indicate
+ * whether it is a bubble or not. If this entry is set to not bubble, or does not have
+ * the required info to bubble, the flag cannot be set to true.
+ *
+ * @param shouldBubble whether this notification should be flagged as a bubble.
+ * @return true if the value changed.
+ */
+ public boolean setFlagBubble(boolean shouldBubble) {
+ boolean wasBubble = isBubble();
+ if (!shouldBubble) {
+ mSbn.getNotification().flags &= ~FLAG_BUBBLE;
+ } else if (getBubbleMetadata() != null && canBubble()) {
+ // wants to be bubble & can bubble, set flag
+ mSbn.getNotification().flags |= FLAG_BUBBLE;
+ }
+ return wasBubble != isBubble();
+ }
+
+ public boolean isBubble() {
+ return (mSbn.getNotification().flags & FLAG_BUBBLE) != 0;
+ }
+
+ /** @see Ranking#canBubble() */
+ public boolean canBubble() {
+ return mRanking.canBubble();
+ }
+
/** @return true if this notification is clearable. */
public boolean isClearable() {
return mIsClearable;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index cf2e13356cca..ae3c683cb165 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -54,7 +54,6 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.AlphaOptimizedButton;
@@ -99,7 +98,7 @@ public class BubbleExpandedView extends LinearLayout {
// TODO(b/170891664): Don't use a flag, set the BubbleOverflow object instead
private boolean mIsOverflow;
- private Bubbles mBubbles = Dependency.get(Bubbles.class);
+ private BubbleController mController;
private BubbleStackView mStackView;
private BubblePositioner mPositioner;
@@ -156,8 +155,7 @@ public class BubbleExpandedView extends LinearLayout {
// the bubble again so we'll just remove it.
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ ", " + e.getMessage() + "; removing bubble");
- mBubbles.removeBubble(getBubbleKey(),
- BubbleController.DISMISS_INVALID_INTENT);
+ mController.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
}
});
mInitialized = true;
@@ -195,15 +193,15 @@ public class BubbleExpandedView extends LinearLayout {
}
if (mBubble != null) {
// Must post because this is called from a binder thread.
- post(() -> mBubbles.removeBubble(mBubble.getKey(),
- BubbleController.DISMISS_TASK_FINISHED));
+ post(() -> mController.removeBubble(
+ mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED));
}
}
@Override
public void onBackPressedOnTaskRoot(int taskId) {
if (mTaskId == taskId && mStackView.isExpanded()) {
- mBubbles.collapseStack();
+ mController.collapseStack();
}
}
};
@@ -250,9 +248,6 @@ public class BubbleExpandedView extends LinearLayout {
R.dimen.bubble_manage_button_height);
mSettingsIcon = findViewById(R.id.settings_button);
- mPositioner = mBubbles.getPositioner();
-
- mTaskView = new TaskView(mContext, mBubbles.getTaskOrganizer());
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
@@ -263,7 +258,6 @@ public class BubbleExpandedView extends LinearLayout {
}
});
mExpandedViewContainer.setClipToOutline(true);
- mExpandedViewContainer.addView(mTaskView);
mExpandedViewContainer.setLayoutParams(
new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
addView(mExpandedViewContainer);
@@ -274,9 +268,7 @@ public class BubbleExpandedView extends LinearLayout {
// ==> expanded view
// ==> activity view
// ==> manage button
- bringChildToFront(mTaskView);
bringChildToFront(mSettingsIcon);
- mTaskView.setListener(mTaskViewListener);
applyThemeAttrs();
@@ -314,6 +306,20 @@ public class BubbleExpandedView extends LinearLayout {
super.onAttachedToWindow();
mTaskView.setExecutor(new HandlerExecutor(getHandler()));
}
+ /**
+ * Initialize {@link BubbleController} and {@link BubbleStackView} here, this method must need
+ * to be called after view inflate.
+ */
+ void initialize(BubbleController controller, BubbleStackView stackView) {
+ mController = controller;
+ mStackView = stackView;
+
+ mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
+ mExpandedViewContainer.addView(mTaskView);
+ bringChildToFront(mTaskView);
+ mTaskView.setListener(mTaskViewListener);
+ mPositioner = mController.getPositioner();
+ }
void updateDimensions() {
Resources res = getResources();
@@ -464,16 +470,12 @@ public class BubbleExpandedView extends LinearLayout {
return mTaskId;
}
- void setStackView(BubbleStackView stackView) {
- mStackView = stackView;
- }
-
public void setOverflow(boolean overflow) {
mIsOverflow = overflow;
Intent target = new Intent(mContext, BubbleOverflowActivity.class);
Bundle extras = new Bundle();
- extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mBubbles));
+ extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mController));
target.putExtras(extras);
mPendingIntent = PendingIntent.getActivity(mContext, 0 /* requestCode */,
target, PendingIntent.FLAG_UPDATE_CURRENT);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
index 48c809d1b0a7..a24f5c2b54c5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
@@ -91,14 +91,14 @@ public class BubbleLogger {
* @param b Bubble removed from overflow
* @param r Reason that bubble was removed
*/
- public void logOverflowRemove(Bubble b, @BubbleController.DismissReason int r) {
- if (r == BubbleController.DISMISS_NOTIF_CANCEL) {
+ public void logOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
+ if (r == Bubbles.DISMISS_NOTIF_CANCEL) {
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
- } else if (r == BubbleController.DISMISS_GROUP_CANCELLED) {
+ } else if (r == Bubbles.DISMISS_GROUP_CANCELLED) {
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_GROUP_CANCEL);
- } else if (r == BubbleController.DISMISS_NO_LONGER_BUBBLE) {
+ } else if (r == Bubbles.DISMISS_NO_LONGER_BUBBLE) {
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_NO_LONGER_BUBBLE);
- } else if (r == BubbleController.DISMISS_BLOCKED) {
+ } else if (r == Bubbles.DISMISS_BLOCKED) {
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BLOCKED);
}
}
@@ -107,10 +107,10 @@ public class BubbleLogger {
* @param b Bubble added to overflow
* @param r Reason that bubble was added to overflow
*/
- public void logOverflowAdd(Bubble b, @BubbleController.DismissReason int r) {
- if (r == BubbleController.DISMISS_AGED) {
+ public void logOverflowAdd(Bubble b, @Bubbles.DismissReason int r) {
+ if (r == Bubbles.DISMISS_AGED) {
log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
- } else if (r == BubbleController.DISMISS_USER_GESTURE) {
+ } else if (r == Bubbles.DISMISS_USER_GESTURE) {
log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
index 102055de2bea..297144a86143 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
@@ -35,6 +35,7 @@ import com.android.systemui.R
class BubbleOverflow(
private val context: Context,
+ private val controller: BubbleController,
private val stack: BubbleStackView
) : BubbleViewProvider {
@@ -56,8 +57,8 @@ class BubbleOverflow(
init {
updateResources()
with(expandedView) {
+ initialize(controller, stack)
setOverflow(true)
- setStackView(stack)
applyThemeAttrs()
}
with(overflowBtn) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index fc3f5b6cbf5e..bc841730833c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -63,7 +63,7 @@ public class BubbleOverflowActivity extends Activity {
private TextView mEmptyStateTitle;
private TextView mEmptyStateSubtitle;
private ImageView mEmptyStateImage;
- private Bubbles mBubbles;
+ private BubbleController mController;
private BubbleOverflowAdapter mAdapter;
private RecyclerView mRecyclerView;
private List<Bubble> mOverflowBubbles = new ArrayList<>();
@@ -111,7 +111,7 @@ public class BubbleOverflowActivity extends Activity {
if (intent != null && intent.getExtras() != null) {
IBinder binder = intent.getExtras().getBinder(EXTRA_BUBBLE_CONTROLLER);
if (binder instanceof ObjectWrapper) {
- mBubbles = ((ObjectWrapper<Bubbles>) binder).get();
+ mController = ((ObjectWrapper<BubbleController>) binder).get();
}
} else {
Log.w(TAG, "Bubble overflow activity created without bubble controller!");
@@ -139,15 +139,15 @@ public class BubbleOverflowActivity extends Activity {
final int viewHeight = recyclerViewHeight / rows;
mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles,
- mBubbles::promoteBubbleFromOverflow, viewWidth, viewHeight);
+ mController::promoteBubbleFromOverflow, viewWidth, viewHeight);
mRecyclerView.setAdapter(mAdapter);
mOverflowBubbles.clear();
- mOverflowBubbles.addAll(mBubbles.getOverflowBubbles());
+ mOverflowBubbles.addAll(mController.getOverflowBubbles());
mAdapter.notifyDataSetChanged();
updateEmptyStateVisibility();
- mBubbles.setOverflowListener(mDataListener);
+ mController.setOverflowListener(mDataListener);
updateTheme();
}
@@ -217,7 +217,7 @@ public class BubbleOverflowActivity extends Activity {
if (DEBUG_OVERFLOW) {
Log.d(TAG, BubbleDebugConfig.formatBubblesString(
- mBubbles.getOverflowBubbles(), null));
+ mController.getOverflowBubbles(), null));
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 1201d42b1fc5..e89b2526456a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -155,7 +155,7 @@ public class BubbleStackView extends FrameLayout
*
* {@hide}
*/
- interface SurfaceSynchronizer {
+ public interface SurfaceSynchronizer {
/**
* Wait until requested change on a {@link View} is reflected on the screen.
*
@@ -186,7 +186,7 @@ public class BubbleStackView extends FrameLayout
});
}
};
-
+ private final BubbleController mBubbleController;
private final BubbleData mBubbleData;
private final ValueAnimator mDesaturateAndDarkenAnimator;
@@ -384,22 +384,6 @@ public class BubbleStackView extends FrameLayout
private final SurfaceSynchronizer mSurfaceSynchronizer;
/**
- * Callback to run when the IME visibility changes - BubbleController uses this to update the
- * Bubbles window focusability flags with the WindowManager.
- */
- public final Consumer<Boolean> mOnImeVisibilityChanged;
-
- /**
- * Callback to run when the bubble expand status changes.
- */
- private final Consumer<Boolean> mOnBubbleExpandChanged;
-
- /**
- * Callback to run to ask BubbleController to hide the current IME.
- */
- private final Runnable mHideCurrentInputMethodCallback;
-
- /**
* The currently magnetized object, which is being dragged and will be attracted to the magnetic
* dismiss target.
*
@@ -733,16 +717,12 @@ public class BubbleStackView extends FrameLayout
private BubblePositioner mPositioner;
@SuppressLint("ClickableViewAccessibility")
- public BubbleStackView(Context context, BubbleData data,
- @Nullable SurfaceSynchronizer synchronizer,
- FloatingContentCoordinator floatingContentCoordinator,
- Runnable allBubblesAnimatedOutAction,
- Consumer<Boolean> onImeVisibilityChanged,
- Runnable hideCurrentInputMethodCallback,
- Consumer<Boolean> onBubbleExpandChanged,
- BubblePositioner positioner) {
+ public BubbleStackView(Context context, BubbleController bubbleController,
+ BubbleData data, @Nullable SurfaceSynchronizer synchronizer,
+ FloatingContentCoordinator floatingContentCoordinator) {
super(context);
+ mBubbleController = bubbleController;
mBubbleData = data;
Resources res = getResources();
@@ -755,7 +735,7 @@ public class BubbleStackView extends FrameLayout
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
- mPositioner = positioner;
+ mPositioner = mBubbleController.getPositioner();
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
@@ -767,7 +747,7 @@ public class BubbleStackView extends FrameLayout
final Runnable onBubbleAnimatedOut = () -> {
if (getBubbleCount() == 0) {
- allBubblesAnimatedOutAction.run();
+ mBubbleController.onAllBubblesAnimatedOut();
}
};
@@ -839,7 +819,7 @@ public class BubbleStackView extends FrameLayout
setFocusable(true);
mBubbleContainer.bringToFront();
- mBubbleOverflow = new BubbleOverflow(getContext(), this);
+ mBubbleOverflow = new BubbleOverflow(getContext(), bubbleController, this);
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
mBubbleContainer.getChildCount() /* index */,
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -850,12 +830,9 @@ public class BubbleStackView extends FrameLayout
showManageMenu(false);
});
- mOnImeVisibilityChanged = onImeVisibilityChanged;
- mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
- mOnBubbleExpandChanged = onBubbleExpandChanged;
-
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
+ mBubbleController.onImeVisibilityChanged(
+ insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
if (!mIsExpanded || mIsExpansionAnimating) {
return view.onApplyWindowInsets(insets);
}
@@ -1299,7 +1276,7 @@ public class BubbleStackView extends FrameLayout
// R constants are not final so we cannot use switch-case here.
if (action == AccessibilityNodeInfo.ACTION_DISMISS) {
- mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
+ mBubbleData.dismissAll(Bubbles.DISMISS_ACCESSIBILITY_ACTION);
announceForAccessibility(
getResources().getString(R.string.accessibility_bubble_dismissed));
return true;
@@ -1402,8 +1379,9 @@ public class BubbleStackView extends FrameLayout
/**
* The {@link Bubble} that is expanded, null if one does not exist.
*/
+ @VisibleForTesting
@Nullable
- BubbleViewProvider getExpandedBubble() {
+ public BubbleViewProvider getExpandedBubble() {
return mExpandedBubble;
}
@@ -1617,7 +1595,7 @@ public class BubbleStackView extends FrameLayout
hideCurrentInputMethod();
- mOnBubbleExpandChanged.accept(shouldExpand);
+ mBubbleController.getSysuiProxy().onStackExpandChanged(shouldExpand);
if (mIsExpanded) {
animateCollapse();
@@ -1637,7 +1615,7 @@ public class BubbleStackView extends FrameLayout
* not.
*/
void hideCurrentInputMethod() {
- mHideCurrentInputMethodCallback.run();
+ mBubbleController.hideCurrentInputMethod();
}
private void beforeExpandedViewAnimation() {
@@ -2135,14 +2113,13 @@ public class BubbleStackView extends FrameLayout
final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject();
dismissBubbleIfExists(mBubbleData.getBubbleWithView(draggedOutBubbleView));
} else {
- mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
}
}
private void dismissBubbleIfExists(@Nullable Bubble bubble) {
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
- mBubbleData.dismissBubbleWithKey(
- bubble.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(bubble.getKey(), Bubbles.DISMISS_USER_GESTURE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 010a29e3560a..a3e6a1ecc387 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -66,6 +66,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
private Bubble mBubble;
private WeakReference<Context> mContext;
+ private WeakReference<BubbleController> mController;
private WeakReference<BubbleStackView> mStackView;
private BubbleIconFactory mIconFactory;
private boolean mSkipInflation;
@@ -77,12 +78,14 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
*/
BubbleViewInfoTask(Bubble b,
Context context,
+ BubbleController controller,
BubbleStackView stackView,
BubbleIconFactory factory,
boolean skipInflation,
Callback c) {
mBubble = b;
mContext = new WeakReference<>(context);
+ mController = new WeakReference<>(controller);
mStackView = new WeakReference<>(stackView);
mIconFactory = factory;
mSkipInflation = skipInflation;
@@ -91,8 +94,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
@Override
protected BubbleViewInfo doInBackground(Void... voids) {
- return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble,
- mSkipInflation);
+ return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(),
+ mIconFactory, mBubble, mSkipInflation);
}
@Override
@@ -121,8 +124,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Bubble.FlyoutMessage flyoutMessage;
@Nullable
- static BubbleViewInfo populate(Context c, BubbleStackView stackView,
- BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) {
+ static BubbleViewInfo populate(Context c, BubbleController controller,
+ BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b,
+ boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
// View inflation: only should do this once per bubble
@@ -133,7 +137,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
info.expandedView = (BubbleExpandedView) inflater.inflate(
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
- info.expandedView.setStackView(stackView);
+ info.expandedView.initialize(controller, stackView);
}
if (b.getShortcutInfo() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
index 5cc24ce5a775..589017242311 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
@@ -26,7 +26,7 @@ import androidx.annotation.Nullable;
/**
* Interface to represent actual Bubbles and UI elements that act like bubbles, like BubbleOverflow.
*/
-interface BubbleViewProvider {
+public interface BubbleViewProvider {
@Nullable BubbleExpandedView getExpandedView();
void setContentVisibility(boolean visible);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
index 4882abc51ed6..415edb1b647c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
@@ -16,62 +16,93 @@
package com.android.systemui.bubbles;
-import android.annotation.NonNull;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
-import androidx.annotation.MainThread;
+import android.content.res.Configuration;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.util.ArraySet;
+import android.view.View;
-import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.wm.shell.ShellTaskOrganizer;
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
import java.util.List;
+import java.util.function.IntConsumer;
/**
* Interface to engage bubbles feature.
*/
public interface Bubbles {
+ @Retention(SOURCE)
+ @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
+ DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
+ DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
+ DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
+ DISMISS_NO_BUBBLE_UP})
+ @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
+ @interface DismissReason {}
+
+ int DISMISS_USER_GESTURE = 1;
+ int DISMISS_AGED = 2;
+ int DISMISS_TASK_FINISHED = 3;
+ int DISMISS_BLOCKED = 4;
+ int DISMISS_NOTIF_CANCEL = 5;
+ int DISMISS_ACCESSIBILITY_ACTION = 6;
+ int DISMISS_NO_LONGER_BUBBLE = 7;
+ int DISMISS_USER_CHANGED = 8;
+ int DISMISS_GROUP_CANCELLED = 9;
+ int DISMISS_INVALID_INTENT = 10;
+ int DISMISS_OVERFLOW_MAX_REACHED = 11;
+ int DISMISS_SHORTCUT_REMOVED = 12;
+ int DISMISS_PACKAGE_REMOVED = 13;
+ int DISMISS_NO_BUBBLE_UP = 14;
+
/**
* @return {@code true} if there is a bubble associated with the provided key and if its
* notification is hidden from the shade or there is a group summary associated with the
* provided key that is hidden from the shade because it has been dismissed but still has child
* bubbles active.
*/
- boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry);
+ boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey);
/**
* @return {@code true} if the current notification entry same as selected bubble
* notification entry and the stack is currently expanded.
*/
- boolean isBubbleExpanded(NotificationEntry entry);
+ boolean isBubbleExpanded(String key);
/** @return {@code true} if stack of bubbles is expanded or not. */
boolean isStackExpanded();
+ /** @return {@code true} if the summary for the provided group key is suppressed. */
+ boolean isSummarySuppressed(String groupKey);
+
/**
- * @return the {@link ScrimView} drawn behind the bubble stack. This is managed by
- * {@link ScrimController} since we want the scrim's appearance and behavior to be identical to
- * that of the notification shade scrim.
+ * Removes a group key indicating that summary for this group should no longer be suppressed.
*/
- ScrimView getScrimForBubble();
-
- /** @return Bubbles for updating overflow. */
- List<Bubble> getOverflowBubbles();
+ void removeSuppressedSummary(String groupKey);
/** Tell the stack of bubbles to collapse. */
void collapseStack();
+ /** Tell the controller need update its UI to fit theme. */
+ void updateForThemeChanges();
+
/**
* Request the stack expand if needed, then select the specified Bubble as current.
* If no bubble exists for this entry, one is created.
*
* @param entry the notification for the bubble to be selected
*/
- void expandStackAndSelectBubble(NotificationEntry entry);
-
- /** Promote the provided bubbles when overflow view. */
- void promoteBubbleFromOverflow(Bubble bubble);
+ void expandStackAndSelectBubble(BubbleEntry entry);
/**
* We intercept notification entries (including group summaries) dismissed by the user when
@@ -81,26 +112,65 @@ public interface Bubbles {
* {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
* {@link BubbleData#addSummaryToSuppress}.
*
+ * @param entry the notification of the BubbleEntry should be removed.
+ * @param children the list of child notification of the BubbleEntry from 1st param entry,
+ * this will be null if entry does have no children.
+ * @param removeCallback the remove callback for SystemUI side to remove notification, the int
+ * number should be list position of children list and use -1 for
+ * removing the parent notification.
+ *
* @return true if we want to intercept the dismissal of the entry, else false.
*/
- boolean handleDismissalInterception(NotificationEntry entry);
+ boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
+ IntConsumer removeCallback);
/**
- * Removes the bubble with the given key.
- * <p>
- * Must be called from the main thread.
+ * Retrieves the notif entry key of the summary associated with the provided group key.
+ *
+ * @param groupKey the group to look up
+ * @return the key for the notification that is the summary of this group.
*/
- @MainThread
- void removeBubble(String key, int reason);
+ String getSummaryKey(String groupKey);
+
+ /** Set the proxy to commnuicate with SysUi side components. */
+ void setSysuiProxy(SysuiProxy proxy);
+
+ /** Set the scrim view for bubbles. */
+ void setBubbleScrim(View view);
+
+ /** Set a listener to be notified of bubble expand events. */
+ void setExpandListener(BubbleExpandListener listener);
+ /**
+ * Called when new notification entry added.
+ *
+ * @param entry the {@link BubbleEntry} by the notification.
+ */
+ void onEntryAdded(BubbleEntry entry);
+
+ /**
+ * Called when new notification entry updated.
+ *
+ * @param entry the {@link BubbleEntry} by the notification.
+ * @param shouldBubbleUp {@code true} if this notification should bubble up.
+ */
+ void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp);
+
+ /**
+ * Called when new notification entry removed.
+ *
+ * @param entry the {@link BubbleEntry} by the notification.
+ */
+ void onEntryRemoved(BubbleEntry entry);
/**
- * When a notification is marked Priority, expand the stack if needed,
- * then (maybe create and) select the given bubble.
+ * Called when NotificationListener has received adjusted notification rank and reapplied
+ * filtering and sorting. This is used to dismiss or create bubbles based on changes in
+ * permissions on the notification channel or the global setting.
*
- * @param entry the notification for the bubble to show
+ * @param rankingMap the updated ranking map from NotificationListenerService
*/
- void onUserChangedImportance(NotificationEntry entry);
+ void onRankingUpdated(RankingMap rankingMap);
/**
* Called when the status bar has become visible or invisible (either permanently or
@@ -108,30 +178,85 @@ public interface Bubbles {
*/
void onStatusBarVisibilityChanged(boolean visible);
+ /** Called when system zen mode state changed. */
+ void onZenStateChanged();
+
/**
- * Called when a user has indicated that an active notification should be shown as a bubble.
- * <p>
- * This method will collapse the shade, create the bubble without a flyout or dot, and suppress
- * the notification from appearing in the shade.
+ * Called when statusBar state changed.
*
- * @param entry the notification to change bubble state for.
- * @param shouldBubble whether the notification should show as a bubble or not.
+ * @param isShade {@code true} is state is SHADE.
*/
- void onUserChangedBubble(@NonNull NotificationEntry entry, boolean shouldBubble);
+ void onStatusBarStateChanged(boolean isShade);
+ /**
+ * Called when the current user changed.
+ *
+ * @param newUserId the new user's id.
+ */
+ void onUserChanged(int newUserId);
- /** See {@link BubbleController.NotifCallback}. */
- void addNotifCallback(BubbleController.NotifCallback callback);
+ /**
+ * Called when config changed.
+ *
+ * @param newConfig the new config.
+ */
+ void onConfigChanged(Configuration newConfig);
- /** Set a listener to be notified of bubble expand events. */
- void setExpandListener(BubbleController.BubbleExpandListener listener);
+ /** Description of current bubble state. */
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+
+ /** Listener to find out about stack expansion / collapse events. */
+ interface BubbleExpandListener {
+ /**
+ * Called when the expansion state of the bubble stack changes.
+ *
+ * @param isExpanding whether it's expanding or collapsing
+ * @param key the notification key associated with bubble being expanded
+ */
+ void onBubbleExpandChanged(boolean isExpanding, String key);
+ }
+
+ /** Listener to be notified when a bubbles' notification suppression state changes.*/
+ interface NotificationSuppressionChangedListener {
+ /** Called when the notification suppression state of a bubble changes. */
+ void onBubbleNotificationSuppressionChange(Bubble bubble);
+ }
+
+ /** Listener to be notified when a pending intent has been canceled for a bubble. */
+ interface PendingIntentCanceledListener {
+ /** Called when the pending intent for a bubble has been canceled. */
+ void onPendingIntentCanceled(Bubble bubble);
+ }
+
+ /** Callback to tell SysUi components execute some methods. */
+ interface SysuiProxy {
+ @Nullable
+ BubbleEntry getPendingOrActiveEntry(String key);
+
+ List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys);
+
+ boolean isNotificationShadeExpand();
+
+ boolean shouldBubbleUp(String key);
+
+ void setNotificationInterruption(String key);
+
+ void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag);
+
+ void notifyRemoveNotification(String key, int reason);
+
+ void notifyInvalidateNotifications(String reason);
+
+ void notifyMaybeCancelSummary(String key);
+
+ void removeNotificationEntry(String key);
+
+ void updateNotificationBubbleButton(String key);
- /** Set a listener to be notified of when overflow view update. */
- void setOverflowListener(BubbleData.Listener listener);
+ void updateNotificationSuppression(String key);
- /** The task listener for events in bubble tasks. **/
- ShellTaskOrganizer getTaskOrganizer();
+ void onStackExpandChanged(boolean shouldExpand);
- /** Contains information to help position things on the screen. */
- BubblePositioner getPositioner();
+ void onUnbubbleConversation(String key);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 6b5f237ac76f..5a7e033607f8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -22,6 +22,8 @@ import android.content.pm.LauncherApps;
import android.os.Handler;
import android.view.WindowManager;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.bubbles.BubbleController;
@@ -41,10 +43,13 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
+import java.util.Optional;
+
import dagger.Module;
import dagger.Provides;
@@ -56,23 +61,8 @@ public interface BubbleModule {
*/
@SysUISingleton
@Provides
- static Bubbles newBubbleController(
- Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
- ShadeController shadeController,
- ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController,
- NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- FeatureFlags featureFlags,
- DumpManager dumpManager,
+ static Bubbles newBubbleController(Context context,
FloatingContentCoordinator floatingContentCoordinator,
- SysUiState sysUiState,
- INotificationManager notifManager,
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -80,30 +70,29 @@ public interface BubbleModule {
UiEventLogger uiEventLogger,
@Main Handler mainHandler,
ShellTaskOrganizer organizer) {
- return BubbleController.create(
- context,
- notificationShadeWindowController,
- statusBarStateController,
- shadeController,
- null /* synchronizer */,
- configurationController,
- interruptionStateProvider,
- zenModeController,
- notifUserManager,
- groupManager,
- entryManager,
- notifPipeline,
- featureFlags,
- dumpManager,
- floatingContentCoordinator,
- sysUiState,
- notifManager,
- statusBarService,
- windowManager,
- windowManagerShellWrapper,
- launcherApps,
- uiEventLogger,
- mainHandler,
- organizer);
+ return BubbleController.create(context, null /* synchronizer */, floatingContentCoordinator,
+ statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
+ uiEventLogger, mainHandler, organizer);
+ }
+
+ /** Provides Optional of BubbleManager */
+ @SysUISingleton
+ @Provides
+ static Optional<BubblesManager> provideBubblesManager(Context context,
+ Optional<Bubbles> bubblesOptional,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController, ShadeController shadeController,
+ ConfigurationController configurationController,
+ @Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
+ NotificationInterruptStateProvider interruptionStateProvider,
+ ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
+ DumpManager dumpManager) {
+ return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
+ notificationShadeWindowController, statusBarStateController, shadeController,
+ configurationController, statusBarService, notificationManager,
+ interruptionStateProvider, zenModeController, notifUserManager,
+ groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 53179ba4be90..a92b9e4818b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -159,7 +159,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
for (int i = 0; i < N; i++) {
NotificationEntry ent = activeNotifications.get(i);
final boolean isBubbleNotificationSuppressedFromShade = mBubblesOptional.isPresent()
- && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(ent);
+ && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(
+ ent.getKey(), ent.getSbn().getGroupKey());
if (ent.isRowDismissed() || ent.isRowRemoved()
|| isBubbleNotificationSuppressedFromShade
|| mFgsSectionController.hasEntry(ent)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 0455b0f18afc..83a569bd6573 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -25,6 +25,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
+import com.android.systemui.wmshell.BubblesManager;
import java.util.HashSet;
import java.util.Optional;
@@ -56,6 +57,7 @@ import javax.inject.Inject;
public class BubbleCoordinator implements Coordinator {
private static final String TAG = "BubbleCoordinator";
+ private final Optional<BubblesManager> mBubblesManagerOptional;
private final Optional<Bubbles> mBubblesOptional;
private final NotifCollection mNotifCollection;
private final Set<String> mInterceptedDismissalEntries = new HashSet<>();
@@ -64,8 +66,10 @@ public class BubbleCoordinator implements Coordinator {
@Inject
public BubbleCoordinator(
+ Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
NotifCollection notifCollection) {
+ mBubblesManagerOptional = bubblesManagerOptional;
mBubblesOptional = bubblesOptional;
mNotifCollection = notifCollection;
}
@@ -75,8 +79,8 @@ public class BubbleCoordinator implements Coordinator {
mNotifPipeline = pipeline;
mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
mNotifPipeline.addFinalizeFilter(mNotifFilter);
- if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().addNotifCallback(mNotifCallback);
+ if (mBubblesManagerOptional.isPresent()) {
+ mBubblesManagerOptional.get().addNotifCallback(mNotifCallback);
}
}
@@ -85,7 +89,8 @@ public class BubbleCoordinator implements Coordinator {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
return mBubblesOptional.isPresent()
- && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(entry);
+ && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(
+ entry.getKey(), entry.getSbn().getGroupKey());
}
};
@@ -102,9 +107,8 @@ public class BubbleCoordinator implements Coordinator {
@Override
public boolean shouldInterceptDismissal(NotificationEntry entry) {
- // for experimental bubbles
- if (mBubblesOptional.isPresent()
- && mBubblesOptional.get().handleDismissalInterception(entry)) {
+ if (mBubblesManagerOptional.isPresent()
+ && mBubblesManagerOptional.get().handleDismissalInterception(entry)) {
mInterceptedDismissalEntries.add(entry.getKey());
return true;
} else {
@@ -119,8 +123,7 @@ public class BubbleCoordinator implements Coordinator {
}
};
- private final BubbleController.NotifCallback mNotifCallback =
- new BubbleController.NotifCallback() {
+ private final BubblesManager.NotifCallback mNotifCallback = new BubblesManager.NotifCallback() {
@Override
public void removeNotification(
NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index 490989dbb39e..36adfac21bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -64,7 +64,7 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
new ArraySet<>();
private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
- private final Optional<Lazy<Bubbles>> mBubblesOptional;
+ private final Optional<Bubbles> mBubblesOptional;
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
private HeadsUpManager mHeadsUpManager;
@@ -74,7 +74,7 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
public NotificationGroupManagerLegacy(
StatusBarStateController statusBarStateController,
Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier,
- Optional<Lazy<Bubbles>> bubblesOptional) {
+ Optional<Bubbles> bubblesOptional) {
statusBarStateController.addCallback(this);
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesOptional = bubblesOptional;
@@ -242,8 +242,9 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
int childCount = 0;
boolean hasBubbles = false;
for (NotificationEntry entry : group.children.values()) {
- if (mBubblesOptional.isPresent() && !mBubblesOptional.get().get()
- .isBubbleNotificationSuppressedFromShade(entry)) {
+ if (mBubblesOptional.isPresent() && !mBubblesOptional.get()
+ .isBubbleNotificationSuppressedFromShade(
+ entry.getKey(), entry.getSbn().getGroupKey())) {
childCount++;
} else {
hasBubbles = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 4fff99b482d8..ff55cd60ab3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -26,7 +26,6 @@ import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -73,6 +72,7 @@ import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogC
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
+import com.android.systemui.wmshell.BubblesManager;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -133,7 +133,7 @@ public interface NotificationsModule {
UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
- Optional<Bubbles> bubblesOptional,
+ Optional<BubblesManager> bubblesManagerOptional,
UiEventLogger uiEventLogger,
OnUserInteractionCallback onUserInteractionCallback) {
return new NotificationGutsManager(
@@ -150,7 +150,7 @@ public interface NotificationsModule {
contextTracker,
builderProvider,
assistantFeedbackController,
- bubblesOptional,
+ bubblesManagerOptional,
uiEventLogger,
onUserInteractionCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5ee66fabe55a..280c525f41cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -72,7 +72,6 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -102,12 +101,14 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
+import com.android.systemui.wmshell.BubblesManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -147,6 +148,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private LayoutListener mLayoutListener;
private RowContentBindStage mRowContentBindStage;
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ private Optional<BubblesManager> mBubblesManagerOptional;
private int mIconTransformContentShift;
private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP;
@@ -1078,13 +1080,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
/** The click listener for the bubble button. */
public View.OnClickListener getBubbleClickListener() {
- return new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Dependency.get(Bubbles.class)
- .onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */);
- mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
+ return v -> {
+ if (mBubblesManagerOptional.isPresent()) {
+ mBubblesManagerOptional.get()
+ .onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */);
}
+ mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
};
}
@@ -1553,7 +1554,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
FalsingManager falsingManager,
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
- OnUserInteractionCallback onUserInteractionCallback) {
+ OnUserInteractionCallback onUserInteractionCallback,
+ Optional<BubblesManager> bubblesManagerOptional) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1581,6 +1583,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
}
mOnUserInteractionCallback = onUserInteractionCallback;
+ mBubblesManagerOptional = bubblesManagerOptional;
cacheIsSystemNotification();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c995e324ecfe..05b1dba36a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -43,8 +43,10 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.time.SystemClock;
+import com.android.systemui.wmshell.BubblesManager;
import java.util.List;
+import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
@@ -79,6 +81,7 @@ public class ExpandableNotificationRowController implements NodeController {
private final FalsingManager mFalsingManager;
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ private final Optional<BubblesManager> mBubblesManagerOptional;
@Inject
public ExpandableNotificationRowController(
@@ -102,7 +105,8 @@ public class ExpandableNotificationRowController implements NodeController {
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
OnUserInteractionCallback onUserInteractionCallback,
FalsingManager falsingManager,
- PeopleNotificationIdentifier peopleNotificationIdentifier) {
+ PeopleNotificationIdentifier peopleNotificationIdentifier,
+ Optional<BubblesManager> bubblesManagerOptional) {
mView = view;
mListContainer = listContainer;
mActivatableNotificationViewController = activatableNotificationViewController;
@@ -125,6 +129,7 @@ public class ExpandableNotificationRowController implements NodeController {
mAllowLongPress = allowLongPress;
mFalsingManager = falsingManager;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
+ mBubblesManagerOptional = bubblesManagerOptional;
}
/**
@@ -148,8 +153,8 @@ public class ExpandableNotificationRowController implements NodeController {
mFalsingManager,
mStatusBarStateController,
mPeopleNotificationIdentifier,
- mOnUserInteractionCallback
-
+ mOnUserInteractionCallback,
+ mBubblesManagerOptional
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 07a4a188bc48..7000ba82b3af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -67,12 +67,12 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.wmshell.BubblesManager;
import java.lang.annotation.Retention;
import java.util.Optional;
@@ -94,7 +94,7 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnUserInteractionCallback mOnUserInteractionCallback;
private Handler mMainHandler;
private Handler mBgHandler;
- private Optional<Bubbles> mBubblesOptional;
+ private Optional<BubblesManager> mBubblesManagerOptional;
private String mPackageName;
private String mAppName;
private int mAppUid;
@@ -223,7 +223,7 @@ public class NotificationConversationInfo extends LinearLayout implements
@Main Handler mainHandler,
@Background Handler bgHandler,
OnConversationSettingsClickListener onConversationSettingsClickListener,
- Optional<Bubbles> bubblesOptional) {
+ Optional<BubblesManager> bubblesManagerOptional) {
mSelectedAction = -1;
mINotificationManager = iNotificationManager;
mOnUserInteractionCallback = onUserInteractionCallback;
@@ -242,7 +242,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mIconFactory = conversationIconFactory;
mUserContext = userContext;
mBubbleMetadata = bubbleMetadata;
- mBubblesOptional = bubblesOptional;
+ mBubblesManagerOptional = bubblesManagerOptional;
mBuilderProvider = builderProvider;
mMainHandler = mainHandler;
mBgHandler = bgHandler;
@@ -641,9 +641,9 @@ public class NotificationConversationInfo extends LinearLayout implements
mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid,
BUBBLE_PREFERENCE_SELECTED);
}
- if (mBubblesOptional.isPresent()) {
+ if (mBubblesManagerOptional.isPresent()) {
post(() -> {
- mBubblesOptional.get().onUserChangedImportance(mEntry);
+ mBubblesManagerOptional.get().onUserChangedImportance(mEntry);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 373f20e6ba96..d2cfb2908e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -47,7 +47,6 @@ import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -67,6 +66,7 @@ import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSav
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.wmshell.BubblesManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -117,7 +117,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private final Lazy<StatusBar> mStatusBarLazy;
private final Handler mMainHandler;
private final Handler mBgHandler;
- private final Optional<Bubbles> mBubblesOptional;
+ private final Optional<BubblesManager> mBubblesManagerOptional;
private Runnable mOpenRunnable;
private final INotificationManager mNotificationManager;
private final LauncherApps mLauncherApps;
@@ -142,7 +142,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
- Optional<Bubbles> bubblesOptional,
+ Optional<BubblesManager> bubblesManagerOptional,
UiEventLogger uiEventLogger,
OnUserInteractionCallback onUserInteractionCallback) {
mContext = context;
@@ -158,7 +158,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mBuilderProvider = builderProvider;
mChannelEditorDialogController = channelEditorDialogController;
mAssistantFeedbackController = assistantFeedbackController;
- mBubblesOptional = bubblesOptional;
+ mBubblesManagerOptional = bubblesManagerOptional;
mUiEventLogger = uiEventLogger;
mOnUserInteractionCallback = onUserInteractionCallback;
}
@@ -491,7 +491,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mMainHandler,
mBgHandler,
onConversationSettingsListener,
- mBubblesOptional);
+ mBubblesManagerOptional);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e065b47ef5b1..f2ae3da73f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -306,7 +306,8 @@ public class NotificationIconAreaController implements
|| !entry.isPulseSuppressed())) {
return false;
}
- if (mBubblesOptional.isPresent() && mBubblesOptional.get().isBubbleExpanded(entry)) {
+ if (mBubblesOptional.isPresent()
+ && mBubblesOptional.get().isBubbleExpanded(entry.getKey())) {
return false;
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9bd98f2e8c24..a8d41046a1eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -144,7 +144,6 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingLog;
@@ -229,6 +228,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -648,8 +648,9 @@ public class StatusBar extends SystemUI implements DemoMode,
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
+ private final Optional<BubblesManager> mBubblesManagerOptional;
private final Optional<Bubbles> mBubblesOptional;
- private final BubbleController.BubbleExpandListener mBubbleExpandListener;
+ private final Bubbles.BubbleExpandListener mBubbleExpandListener;
private ActivityIntentHelper mActivityIntentHelper;
private NotificationStackScrollLayoutController mStackScrollerController;
@@ -697,6 +698,7 @@ public class StatusBar extends SystemUI implements DemoMode,
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
VibratorHelper vibratorHelper,
+ Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
@@ -776,6 +778,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
mVibratorHelper = vibratorHelper;
+ mBubblesManagerOptional = bubblesManagerOptional;
mBubblesOptional = bubblesOptional;
mVisualStabilityManager = visualStabilityManager;
mDeviceProvisionedController = deviceProvisionedController;
@@ -1141,8 +1144,8 @@ public class StatusBar extends SystemUI implements DemoMode,
ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
- ScrimView scrimForBubble = mBubblesOptional.isPresent()
- ? mBubblesOptional.get().getScrimForBubble() : null;
+ ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
+ ? mBubblesManagerOptional.get().getScrimForBubble() : null;
mScrimController.setScrimVisibleListener(scrimsVisible -> {
mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 014d5c274c1f..acca953629c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -48,7 +48,6 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -76,6 +75,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.wmshell.BubblesManager;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -104,7 +104,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardManager mKeyguardManager;
private final IDreamManager mDreamManager;
- private final Optional<Bubbles> mBubblesOptional;
+ private final Optional<BubblesManager> mBubblesManagerOptional;
private final Lazy<AssistManager> mAssistManagerLazy;
private final NotificationRemoteInputManager mRemoteInputManager;
private final GroupMembershipManager mGroupMembershipManager;
@@ -142,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
KeyguardManager keyguardManager,
IDreamManager dreamManager,
- Optional<Bubbles> bubblesOptional,
+ Optional<BubblesManager> bubblesManagerOptional,
Lazy<AssistManager> assistManagerLazy,
NotificationRemoteInputManager remoteInputManager,
GroupMembershipManager groupMembershipManager,
@@ -176,7 +176,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardManager = keyguardManager;
mDreamManager = dreamManager;
- mBubblesOptional = bubblesOptional;
+ mBubblesManagerOptional = bubblesManagerOptional;
mAssistManagerLazy = assistManagerLazy;
mRemoteInputManager = remoteInputManager;
mGroupMembershipManager = groupMembershipManager;
@@ -399,14 +399,15 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
private void expandBubbleStackOnMainThread(NotificationEntry entry) {
- if (!mBubblesOptional.isPresent()) {
+ if (!mBubblesManagerOptional.isPresent()) {
return;
}
if (Looper.getMainLooper().isCurrentThread()) {
- mBubblesOptional.get().expandStackAndSelectBubble(entry);
+ mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
} else {
- mMainThreadHandler.post(() -> mBubblesOptional.get().expandStackAndSelectBubble(entry));
+ mMainThreadHandler.post(
+ () -> mBubblesManagerOptional.get().expandStackAndSelectBubble(entry));
}
}
@@ -606,7 +607,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardManager mKeyguardManager;
private final IDreamManager mDreamManager;
- private final Optional<Bubbles> mBubblesOptional;
+ private final Optional<BubblesManager> mBubblesManagerOptional;
private final Lazy<AssistManager> mAssistManagerLazy;
private final NotificationRemoteInputManager mRemoteInputManager;
private final GroupMembershipManager mGroupMembershipManager;
@@ -643,7 +644,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
KeyguardManager keyguardManager,
IDreamManager dreamManager,
- Optional<Bubbles> bubblesOptional,
+ Optional<BubblesManager> bubblesManager,
Lazy<AssistManager> assistManagerLazy,
NotificationRemoteInputManager remoteInputManager,
GroupMembershipManager groupMembershipManager,
@@ -673,7 +674,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardManager = keyguardManager;
mDreamManager = dreamManager;
- mBubblesOptional = bubblesOptional;
+ mBubblesManagerOptional = bubblesManager;
mAssistManagerLazy = assistManagerLazy;
mRemoteInputManager = remoteInputManager;
mGroupMembershipManager = groupMembershipManager;
@@ -729,7 +730,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mStatusBarKeyguardViewManager,
mKeyguardManager,
mDreamManager,
- mBubblesOptional,
+ mBubblesManagerOptional,
mAssistManagerLazy,
mRemoteInputManager,
mGroupMembershipManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 6d4099b656cb..b69da859b3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -97,6 +97,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -155,6 +156,7 @@ public interface StatusBarPhoneModule {
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
VibratorHelper vibratorHelper,
+ Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
@@ -233,6 +235,7 @@ public interface StatusBarPhoneModule {
wakefulnessLifecycle,
statusBarStateController,
vibratorHelper,
+ bubblesManagerOptional,
bubblesOptional,
visualStabilityManager,
deviceProvisionedController,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
new file mode 100644
index 000000000000..ad596c27ba97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dumpable;
+import com.android.systemui.bubbles.BubbleEntry;
+import com.android.systemui.bubbles.Bubbles;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.notification.NotificationChannelHelper;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.IntConsumer;
+
+/**
+ * The SysUi side bubbles manager which communicate with other SysUi components.
+ */
+@SysUISingleton
+public class BubblesManager implements Dumpable {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BubblesManager" : TAG_BUBBLES;
+
+ private final Context mContext;
+ private final Bubbles mBubbles;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final ShadeController mShadeController;
+ private final IStatusBarService mBarService;
+ private final INotificationManager mNotificationManager;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationGroupManagerLegacy mNotificationGroupManager;
+ private final NotificationEntryManager mNotificationEntryManager;
+ private final NotifPipeline mNotifPipeline;
+
+ private final ScrimView mBubbleScrim;
+ private final Bubbles.SysuiProxy mSysuiProxy;
+ // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
+ private final List<NotifCallback> mCallbacks = new ArrayList<>();
+
+ /**
+ * Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
+ * which means bubbles feature not support.
+ */
+ @Nullable
+ public static BubblesManager create(Context context,
+ Optional<Bubbles> bubblesOptional,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController,
+ ShadeController shadeController,
+ ConfigurationController configurationController,
+ @Nullable IStatusBarService statusBarService,
+ INotificationManager notificationManager,
+ NotificationInterruptStateProvider interruptionStateProvider,
+ ZenModeController zenModeController,
+ NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager,
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ SysUiState sysUiState,
+ FeatureFlags featureFlags,
+ DumpManager dumpManager) {
+ if (bubblesOptional.isPresent()) {
+ return new BubblesManager(context, bubblesOptional.get(),
+ notificationShadeWindowController, statusBarStateController, shadeController,
+ configurationController, statusBarService, notificationManager,
+ interruptionStateProvider, zenModeController, notifUserManager,
+ groupManager, entryManager, notifPipeline, sysUiState, featureFlags,
+ dumpManager);
+ } else {
+ return null;
+ }
+ }
+
+ @VisibleForTesting
+ BubblesManager(Context context,
+ Bubbles bubbles,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController,
+ ShadeController shadeController,
+ ConfigurationController configurationController,
+ @Nullable IStatusBarService statusBarService,
+ INotificationManager notificationManager,
+ NotificationInterruptStateProvider interruptionStateProvider,
+ ZenModeController zenModeController,
+ NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager,
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ SysUiState sysUiState,
+ FeatureFlags featureFlags,
+ DumpManager dumpManager) {
+ mContext = context;
+ mBubbles = bubbles;
+ mNotificationShadeWindowController = notificationShadeWindowController;
+ mShadeController = shadeController;
+ mNotificationManager = notificationManager;
+ mNotificationInterruptStateProvider = interruptionStateProvider;
+ mNotificationGroupManager = groupManager;
+ mNotificationEntryManager = entryManager;
+ mNotifPipeline = notifPipeline;
+
+ mBarService = statusBarService == null
+ ? IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE))
+ : statusBarService;
+
+ mBubbleScrim = new ScrimView(mContext);
+ mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mBubbles.setBubbleScrim(mBubbleScrim);
+
+ if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ setupNotifPipeline();
+ } else {
+ setupNEM();
+ }
+
+ dumpManager.registerDumpable(TAG, this);
+
+ statusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ boolean isShade = newState == SHADE;
+ bubbles.onStatusBarStateChanged(isShade);
+ }
+ });
+
+ configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mBubbles.onConfigChanged(newConfig);
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ mBubbles.updateForThemeChanges();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ mBubbles.updateForThemeChanges();
+ }
+ });
+
+ zenModeController.addCallback(new ZenModeController.Callback() {
+ @Override
+ public void onZenChanged(int zen) {
+ mBubbles.onZenStateChanged();
+ }
+
+ @Override
+ public void onConfigChanged(ZenModeConfig config) {
+ mBubbles.onZenStateChanged();
+ }
+ });
+
+ notifUserManager.addUserChangedListener(
+ new NotificationLockscreenUserManager.UserChangedListener() {
+ @Override
+ public void onUserChanged(int userId) {
+ mBubbles.onUserChanged(userId);
+ }
+ });
+
+ mSysuiProxy = new Bubbles.SysuiProxy() {
+ @Override
+ @Nullable
+ public BubbleEntry getPendingOrActiveEntry(String key) {
+ NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
+ return entry == null ? null : notifToBubbleEntry(entry);
+ }
+
+ @Override
+ public List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys) {
+ List<BubbleEntry> result = new ArrayList<>();
+ List<NotificationEntry> activeEntries =
+ mNotificationEntryManager.getActiveNotificationsForCurrentUser();
+ for (int i = 0; i < activeEntries.size(); i++) {
+ NotificationEntry entry = activeEntries.get(i);
+ if (savedBubbleKeys.contains(entry.getKey())
+ && mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ && entry.isBubble()) {
+ result.add(notifToBubbleEntry(entry));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isNotificationShadeExpand() {
+ return mNotificationShadeWindowController.getPanelExpanded();
+ }
+
+ @Override
+ public boolean shouldBubbleUp(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null) {
+ return mNotificationInterruptStateProvider.shouldBubbleUp(entry);
+ }
+ return false;
+ }
+
+ @Override
+ public void setNotificationInterruption(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null && entry.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
+ entry.setInterruption();
+ }
+ }
+
+ @Override
+ public void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag) {
+ mNotificationShadeWindowController.setRequestTopUi(requestTopUi, componentTag);
+ }
+
+ @Override
+ public void notifyRemoveNotification(String key, int reason) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.removeNotification(entry, getDismissedByUserStats(entry, true), reason);
+ }
+ }
+ }
+
+ @Override
+ public void notifyInvalidateNotifications(String reason) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.invalidateNotifications(reason);
+ }
+ }
+
+ @Override
+ public void notifyMaybeCancelSummary(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.maybeCancelSummary(entry);
+ }
+ }
+ }
+
+ @Override
+ public void removeNotificationEntry(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null) {
+ mNotificationGroupManager.onEntryRemoved(entry);
+ }
+ }
+
+ @Override
+ public void updateNotificationBubbleButton(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null && entry.getRow() != null) {
+ entry.getRow().updateBubbleButton();
+ }
+ }
+
+ @Override
+ public void updateNotificationSuppression(String key) {
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ key);
+ if (entry != null) {
+ mNotificationGroupManager.updateSuppression(entry);
+ }
+ }
+
+ @Override
+ public void onStackExpandChanged(boolean shouldExpand) {
+ sysUiState
+ .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
+ .commitUpdate(mContext.getDisplayId());
+ }
+
+ @Override
+ public void onUnbubbleConversation(String key) {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ onUserChangedBubble(entry, false /* shouldBubble */);
+ }
+ }
+ };
+ mBubbles.setSysuiProxy(mSysuiProxy);
+ }
+
+ private void setupNEM() {
+ mNotificationEntryManager.addNotificationEntryListener(
+ new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationEntry entry) {
+ BubblesManager.this.onEntryAdded(entry);
+ }
+
+ @Override
+ public void onPreEntryUpdated(NotificationEntry entry) {
+ BubblesManager.this.onEntryUpdated(entry);
+ }
+
+ @Override
+ public void onEntryRemoved(NotificationEntry entry,
+ @Nullable NotificationVisibility visibility,
+ boolean removedByUser, int reason) {
+ BubblesManager.this.onEntryRemoved(entry);
+ }
+
+ @Override
+ public void onNotificationRankingUpdated(RankingMap rankingMap) {
+ BubblesManager.this.onRankingUpdate(rankingMap);
+ }
+ });
+
+ // The new pipeline takes care of this as a NotifDismissInterceptor BubbleCoordinator
+ mNotificationEntryManager.addNotificationRemoveInterceptor(
+ (key, entry, dismissReason) -> {
+ final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
+ final boolean isUserDismiss = dismissReason == REASON_CANCEL
+ || dismissReason == REASON_CLICK;
+ final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
+ || dismissReason == REASON_APP_CANCEL_ALL;
+ final boolean isSummaryCancel =
+ dismissReason == REASON_GROUP_SUMMARY_CANCELED;
+
+ // Need to check for !appCancel here because the notification may have
+ // previously been dismissed & entry.isRowDismissed would still be true
+ boolean userRemovedNotif =
+ (entry != null && entry.isRowDismissed() && !isAppCancel)
+ || isClearAll || isUserDismiss || isSummaryCancel;
+
+ if (userRemovedNotif) {
+ return handleDismissalInterception(entry);
+ }
+ return false;
+ });
+
+ mNotificationGroupManager.registerGroupChangeListener(
+ new NotificationGroupManagerLegacy.OnGroupChangeListener() {
+ @Override
+ public void onGroupSuppressionChanged(
+ NotificationGroupManagerLegacy.NotificationGroup group,
+ boolean suppressed) {
+ // More notifications could be added causing summary to no longer
+ // be suppressed -- in this case need to remove the key.
+ final String groupKey = group.summary != null
+ ? group.summary.getSbn().getGroupKey()
+ : null;
+ if (!suppressed && groupKey != null
+ && mBubbles.isSummarySuppressed(groupKey)) {
+ mBubbles.removeSuppressedSummary(groupKey);
+ }
+ }
+ });
+
+ addNotifCallback(new NotifCallback() {
+ @Override
+ public void removeNotification(NotificationEntry entry,
+ DismissedByUserStats dismissedByUserStats, int reason) {
+ mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
+ dismissedByUserStats, reason);
+ }
+
+ @Override
+ public void invalidateNotifications(String reason) {
+ mNotificationEntryManager.updateNotifications(reason);
+ }
+
+ @Override
+ public void maybeCancelSummary(NotificationEntry entry) {
+ // Check if removed bubble has an associated suppressed group summary that needs
+ // to be removed now.
+ final String groupKey = entry.getSbn().getGroupKey();
+ if (mBubbles.isSummarySuppressed(groupKey)) {
+ mBubbles.removeSuppressedSummary(groupKey);
+
+ final NotificationEntry summary =
+ mNotificationEntryManager.getActiveNotificationUnfiltered(
+ mBubbles.getSummaryKey(groupKey));
+ if (summary != null) {
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
+ UNDEFINED_DISMISS_REASON);
+ }
+ }
+
+ // Check if we still need to remove the summary from NoManGroup because the summary
+ // may not be in the mBubbleData.mSuppressedGroupKeys list and removed above.
+ // For example:
+ // 1. Bubbled notifications (group) is posted to shade and are visible bubbles
+ // 2. User expands bubbles so now their respective notifications in the shade are
+ // hidden, including the group summary
+ // 3. User removes all bubbles
+ // 4. We expect all the removed bubbles AND the summary (note: the summary was
+ // never added to the suppressedSummary list in BubbleData, so we add this check)
+ NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(entry);
+ if (summary != null) {
+ ArrayList<NotificationEntry> summaryChildren =
+ mNotificationGroupManager.getLogicalChildren(summary.getSbn());
+ boolean isSummaryThisNotif = summary.getKey().equals(entry.getKey());
+ if (!isSummaryThisNotif && (summaryChildren == null
+ || summaryChildren.isEmpty())) {
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
+ UNDEFINED_DISMISS_REASON);
+ }
+ }
+ }
+ });
+ }
+
+ private void setupNotifPipeline() {
+ mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
+ @Override
+ public void onEntryAdded(NotificationEntry entry) {
+ BubblesManager.this.onEntryAdded(entry);
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationEntry entry) {
+ BubblesManager.this.onEntryUpdated(entry);
+ }
+
+ @Override
+ public void onEntryRemoved(NotificationEntry entry,
+ @NotifCollection.CancellationReason int reason) {
+ BubblesManager.this.onEntryRemoved(entry);
+ }
+
+ @Override
+ public void onRankingUpdate(RankingMap rankingMap) {
+ BubblesManager.this.onRankingUpdate(rankingMap);
+ }
+ });
+ }
+
+ void onEntryAdded(NotificationEntry entry) {
+ if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ && entry.isBubble()) {
+ mBubbles.onEntryAdded(notifToBubbleEntry(entry));
+ }
+ }
+
+ void onEntryUpdated(NotificationEntry entry) {
+ mBubbles.onEntryUpdated(notifToBubbleEntry(entry),
+ mNotificationInterruptStateProvider.shouldBubbleUp(entry));
+ }
+
+ void onEntryRemoved(NotificationEntry entry) {
+ mBubbles.onEntryRemoved(notifToBubbleEntry(entry));
+ }
+
+ void onRankingUpdate(RankingMap rankingMap) {
+ mBubbles.onRankingUpdated(rankingMap);
+ }
+
+ /**
+ * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
+ * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
+ * Instead, this is taken care of by {@link BubbleCoordinator}.
+ */
+ private DismissedByUserStats getDismissedByUserStats(
+ NotificationEntry entry,
+ boolean isVisible) {
+ return new DismissedByUserStats(
+ DISMISSAL_BUBBLE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotificationEntryManager.getActiveNotificationsCount(),
+ isVisible,
+ NotificationLogger.getNotificationLocation(entry)));
+ }
+
+ /**
+ * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
+ * since we want the scrim's appearance and behavior to be identical to that of the notification
+ * shade scrim.
+ */
+ public ScrimView getScrimForBubble() {
+ return mBubbleScrim;
+ }
+
+ /**
+ * We intercept notification entries (including group summaries) dismissed by the user when
+ * there is an active bubble associated with it. We do this so that developers can still
+ * cancel it (and hence the bubbles associated with it).
+ *
+ * @return true if we want to intercept the dismissal of the entry, else false.
+ * @see Bubbles#handleDismissalInterception(BubbleEntry, List, IntConsumer)
+ */
+ public boolean handleDismissalInterception(NotificationEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+
+ List<NotificationEntry> children = entry.getAttachedNotifChildren();
+ List<BubbleEntry> bubbleChildren = null;
+ if (children != null) {
+ bubbleChildren = new ArrayList<>();
+ for (int i = 0; i < children.size(); i++) {
+ bubbleChildren.add(notifToBubbleEntry(children.get(i)));
+ }
+ }
+
+ return mBubbles.handleDismissalInterception(notifToBubbleEntry(entry), bubbleChildren,
+ // TODO : b/171847985 should re-work on notification side to make this more clear.
+ (int i) -> {
+ if (i >= 0) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.removeNotification(children.get(i),
+ getDismissedByUserStats(children.get(i), true),
+ REASON_GROUP_SUMMARY_CANCELED);
+ }
+ } else {
+ mNotificationGroupManager.onEntryRemoved(entry);
+ }
+ });
+ }
+
+ /**
+ * Request the stack expand if needed, then select the specified Bubble as current.
+ * If no bubble exists for this entry, one is created.
+ *
+ * @param entry the notification for the bubble to be selected
+ */
+ public void expandStackAndSelectBubble(NotificationEntry entry) {
+ mBubbles.expandStackAndSelectBubble(notifToBubbleEntry(entry));
+ }
+
+ /** See {@link NotifCallback}. */
+ public void addNotifCallback(NotifCallback callback) {
+ mCallbacks.add(callback);
+ }
+
+ /**
+ * When a notification is marked Priority, expand the stack if needed,
+ * then (maybe create and) select the given bubble.
+ *
+ * @param entry the notification for the bubble to show
+ */
+ public void onUserChangedImportance(NotificationEntry entry) {
+ try {
+ int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
+ mBarService.onNotificationBubbleChanged(entry.getKey(), true, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mShadeController.collapsePanel(true);
+ if (entry.getRow() != null) {
+ entry.getRow().updateBubbleButton();
+ }
+ }
+
+ /**
+ * Called when a user has indicated that an active notification should be shown as a bubble.
+ * <p>
+ * This method will collapse the shade, create the bubble without a flyout or dot, and suppress
+ * the notification from appearing in the shade.
+ *
+ * @param entry the notification to change bubble state for.
+ * @param shouldBubble whether the notification should show as a bubble or not.
+ */
+ public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
+ NotificationChannel channel = entry.getChannel();
+ final String appPkg = entry.getSbn().getPackageName();
+ final int appUid = entry.getSbn().getUid();
+ if (channel == null || appPkg == null) {
+ return;
+ }
+
+ // Update the state in NotificationManagerService
+ try {
+ int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
+ mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags);
+ } catch (RemoteException e) {
+ }
+
+ // Change the settings
+ channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext,
+ mNotificationManager, entry, channel);
+ channel.setAllowBubbles(shouldBubble);
+ try {
+ int currentPref = mNotificationManager.getBubblePreferenceForPackage(appPkg, appUid);
+ if (shouldBubble && currentPref == BUBBLE_PREFERENCE_NONE) {
+ mNotificationManager.setBubblesAllowed(appPkg, appUid, BUBBLE_PREFERENCE_SELECTED);
+ }
+ mNotificationManager.updateNotificationChannelForPackage(appPkg, appUid, channel);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+
+ if (shouldBubble) {
+ mShadeController.collapsePanel(true);
+ if (entry.getRow() != null) {
+ entry.getRow().updateBubbleButton();
+ }
+ }
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ mBubbles.dump(fd, pw, args);
+ }
+
+ static BubbleEntry notifToBubbleEntry(NotificationEntry e) {
+ return new BubbleEntry(e.getSbn(), e.getRanking(), e.isClearable(),
+ e.shouldSuppressNotificationDot(), e.shouldSuppressNotificationList(),
+ e.shouldSuppressPeek());
+ }
+
+ /**
+ * Callback for when the BubbleController wants to interact with the notification pipeline to:
+ * - Remove a previously bubbled notification
+ * - Update the notification shade since bubbled notification should/shouldn't be showing
+ */
+ public interface NotifCallback {
+ /**
+ * Called when a bubbled notification that was hidden from the shade is now being removed
+ * This can happen when an app cancels a bubbled notification or when the user dismisses a
+ * bubble.
+ */
+ void removeNotification(@NonNull NotificationEntry entry,
+ @NonNull DismissedByUserStats stats, int reason);
+
+ /**
+ * Called when a bubbled notification has changed whether it should be
+ * filtered from the shade.
+ */
+ void invalidateNotifications(@NonNull String reason);
+
+ /**
+ * Called on a bubbled entry that has been removed when there are no longer
+ * bubbled entries in its group.
+ *
+ * Checks whether its group has any other (non-bubbled) children. If it doesn't,
+ * removes all remnants of the group's summary from the notification pipeline.
+ * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
+ */
+ void maybeCancelSummary(@NonNull NotificationEntry entry);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 0c872db45194..31c08ae471ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -102,10 +102,10 @@ public class BubbleDataTest extends SysuiTestCase {
private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
@Mock
- private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
+ private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
@Mock
- private BubbleController.PendingIntentCanceledListener mPendingIntentCanceledListener;
+ private Bubbles.PendingIntentCanceledListener mPendingIntentCanceledListener;
@Before
public void setUp() throws Exception {
@@ -171,12 +171,11 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
// Verify
verifyUpdateReceived();
- assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_USER_GESTURE);
+ assertBubbleRemoved(mBubbleA1, Bubbles.DISMISS_USER_GESTURE);
}
@Test
@@ -269,7 +268,7 @@ public class BubbleDataTest extends SysuiTestCase {
sendUpdatedEntryAtTime(mEntryC1, 6000);
verifyUpdateReceived();
- assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
+ assertBubbleRemoved(mBubbleA1, Bubbles.DISMISS_AGED);
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1, null /* persistedBubble */);
@@ -277,7 +276,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/,
true /* showInShade */);
verifyUpdateReceived();
- assertBubbleRemoved(mBubbleA2, BubbleController.DISMISS_AGED);
+ assertBubbleRemoved(mBubbleA2, Bubbles.DISMISS_AGED);
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
}
@@ -294,14 +293,12 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
mBubbleData.setMaxOverflowBubbles(1);
- mBubbleData.dismissBubbleWithKey(
- mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
// Overflow max of 1 is reached; A1 is oldest, so it gets removed
- mBubbleData.dismissBubbleWithKey(
- mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
}
@@ -322,14 +319,12 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(),
- BubbleController.DISMISS_NOTIF_CANCEL);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
// Test
- mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(),
- BubbleController.DISMISS_GROUP_CANCELLED);
+ mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_GROUP_CANCELLED);
verifyUpdateReceived();
assertOverflowChangedTo(ImmutableList.of());
}
@@ -409,8 +404,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
// TODO: this should fail if things work as I expect them to?
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
@@ -430,8 +424,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertOrderNotChanged();
}
@@ -450,8 +443,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA2.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
+ mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
verifyUpdateReceived();
assertSelectionChangedTo(mBubbleB2);
}
@@ -545,8 +537,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
// Verify the selection was cleared.
verifyUpdateReceived();
@@ -646,8 +637,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryB2.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryB2.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleA1);
}
@@ -671,13 +661,11 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertSelectionChangedTo(mBubbleB1);
- mBubbleData.dismissBubbleWithKey(
- mEntryB1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryB1.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertSelectionChangedTo(mBubbleA1);
}
@@ -791,8 +779,7 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.dismissBubbleWithKey(
- mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
verifyUpdateReceived();
assertExpandedChangedTo(false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 29ead593c51a..690a1ad42861 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -60,7 +60,7 @@ public class BubbleTest extends SysuiTestCase {
private Bubble mBubble;
@Mock
- private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
+ private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
@Before
public void setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
deleted file mode 100644
index aaeee16dc1fd..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bubbles;
-
-import android.app.INotificationManager;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.os.Handler;
-import android.view.WindowManager;
-
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.FloatingContentCoordinator;
-
-/**
- * Testable BubbleController subclass that immediately synchronizes surfaces.
- */
-public class TestableBubbleController extends BubbleController {
-
- // Let's assume surfaces can be synchronized immediately.
- TestableBubbleController(Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
- ShadeController shadeController,
- BubbleData data,
- ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController,
- NotificationLockscreenUserManager lockscreenUserManager,
- NotificationGroupManagerLegacy groupManager,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- FeatureFlags featureFlags,
- DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator,
- BubbleDataRepository dataRepository,
- SysUiState sysUiState,
- INotificationManager notificationManager,
- IStatusBarService statusBarService,
- WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps,
- BubbleLogger bubbleLogger,
- Handler mainHandler,
- ShellTaskOrganizer shellTaskOrganizer,
- BubblePositioner positioner) {
- super(context,
- notificationShadeWindowController, statusBarStateController, shadeController,
- data, Runnable::run, configurationController, interruptionStateProvider,
- zenModeController, lockscreenUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
- dataRepository, sysUiState, notificationManager, statusBarService,
- windowManager, windowManagerShellWrapper, launcherApps, bubbleLogger,
- mainHandler, shellTaskOrganizer, positioner);
- setInflateSynchronously(true);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index d835123e4cad..cd46dda772e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -116,7 +116,7 @@ public class NotificationFilterTest extends SysuiTestCase {
new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class),
- Optional.of(() -> mock(Bubbles.class))));
+ Optional.of(mock(Bubbles.class))));
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 61edcf9c200c..4698b8e50efb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -76,12 +76,12 @@ import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.wmshell.BubblesManager;
import org.junit.Before;
import org.junit.Rule;
@@ -137,7 +137,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
@Mock
private OnUserInteractionCallback mOnUserInteractionCallback;
@Mock
- private Bubbles mBubbles;
+ private BubblesManager mBubblesManager;
@Mock
private LauncherApps mLauncherApps;
@Mock
@@ -255,7 +255,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
assertEquals(mIconDrawable, view.getDrawable());
}
@@ -279,7 +279,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -330,7 +330,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertTrue(textView.getText().toString().contains(group.getName()));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -355,7 +355,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(GONE, textView.getVisibility());
@@ -379,7 +379,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
}
@@ -414,7 +414,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -442,7 +442,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -468,7 +468,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -495,7 +495,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
false,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -520,7 +520,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View view = mNotificationInfo.findViewById(R.id.silence);
assertThat(view.isSelected()).isTrue();
}
@@ -548,7 +548,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -579,7 +579,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -609,7 +609,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -653,7 +653,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mTestableLooper.processAllMessages();
@@ -696,7 +696,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View silence = mNotificationInfo.findViewById(R.id.silence);
@@ -740,7 +740,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -777,7 +777,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -813,7 +813,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -851,7 +851,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -887,7 +887,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -923,7 +923,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -958,7 +958,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
View silence = mNotificationInfo.findViewById(R.id.silence);
silence.performClick();
@@ -992,7 +992,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
anyString(), anyInt(), any(), eq(CONVERSATION_ID));
@@ -1017,7 +1017,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), any(), eq(CONVERSATION_ID));
@@ -1052,7 +1052,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
@@ -1092,7 +1092,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler, null, Optional.of(mBubbles));
+ mTestHandler, null, Optional.of(mBubblesManager));
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 8a5afe6ce667..dbaf5c467c45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -84,6 +84,7 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.wmshell.BubblesManager;
import org.junit.After;
import org.junit.Before;
@@ -96,6 +97,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.util.Optional;
import java.util.concurrent.CountDownLatch;
/**
@@ -243,7 +245,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
true,
null,
mFalsingManager,
- mPeopleNotificationIdentifier
+ mPeopleNotificationIdentifier,
+ Optional.of(mock(BubblesManager.class))
));
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index bbc1df21237f..3000b8b449c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -67,7 +67,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -81,6 +80,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager.O
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.wmshell.BubblesManager;
import org.junit.Before;
import org.junit.Ignore;
@@ -131,7 +131,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Mock private ChannelEditorDialogController mChannelEditorDialogController;
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@Mock private UserContextProvider mContextTracker;
- @Mock private Bubbles mBubbles;
+ @Mock private BubblesManager mBubblesManager;
@Mock(answer = Answers.RETURNS_SELF)
private PriorityOnboardingDialogController.Builder mBuilder;
private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder;
@@ -156,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
() -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider,
mINotificationManager, mLauncherApps, mShortcutManager,
mChannelEditorDialogController, mContextTracker, mProvider,
- mAssistantFeedbackController, Optional.of(mBubbles),
+ mAssistantFeedbackController, Optional.of(mBubblesManager),
new UiEventLoggerFake(), mOnUserInteractionCallback);
mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
mCheckSaveListener, mOnSettingsClickListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 847e0a474a6a..48375e02f64f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
+import com.android.systemui.wmshell.BubblesManager;
import org.mockito.ArgumentCaptor;
@@ -121,7 +122,7 @@ public class NotificationTestHelper {
mGroupMembershipManager = new NotificationGroupManagerLegacy(
mStatusBarStateController,
() -> mock(PeopleNotificationIdentifier.class),
- Optional.of(() -> mock(Bubbles.class)));
+ Optional.of((mock(Bubbles.class))));
mGroupExpansionManager = mGroupMembershipManager;
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class),
@@ -430,7 +431,8 @@ public class NotificationTestHelper {
mock(FalsingManager.class),
mStatusBarStateController,
mPeopleNotificationIdentifier,
- mock(OnUserInteractionCallback.class));
+ mock(OnUserInteractionCallback.class),
+ Optional.of(mock(BubblesManager.class)));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 7d84f86cc7b3..b0086ef1d4fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -92,7 +92,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
mGroupManager = new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class),
- Optional.of(() -> mock(Bubbles.class)));
+ Optional.of(mock(Bubbles.class)));
mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index 29e445a13e24..f81672ab6a37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -70,7 +70,7 @@ public class NotificationGroupManagerLegacyTest extends SysuiTestCase {
mGroupManager = new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class),
- Optional.of(() -> mock(Bubbles.class)));
+ Optional.of(mock(Bubbles.class)));
mGroupManager.setHeadsUpManager(mHeadsUpManager);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index f7489b1c164a..1f31fcd2a2bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -53,7 +53,6 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -77,6 +76,7 @@ import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.wmshell.BubblesManager;
import org.junit.Before;
import org.junit.Test;
@@ -116,7 +116,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
@Mock
private Handler mHandler;
@Mock
- private Bubbles mBubbles;
+ private BubblesManager mBubblesManager;
@Mock
private ShadeControllerImpl mShadeController;
@Mock
@@ -193,7 +193,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mock(KeyguardManager.class),
mock(IDreamManager.class),
- Optional.of(mBubbles),
+ Optional.of(mBubblesManager),
() -> mAssistManager,
mRemoteInputManager,
mock(NotificationGroupManagerLegacy.class),
@@ -280,7 +280,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
// Then
- verify(mBubbles).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
+ verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
// This is called regardless, and simply short circuits when there is nothing to do.
verify(mShadeController, atLeastOnce()).collapsePanel();
@@ -312,7 +312,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
// Then
- verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
+ verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
verify(mShadeController, atLeastOnce()).collapsePanel();
@@ -342,7 +342,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
// Then
- verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
+ verify(mBubblesManager).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
verify(mShadeController, atLeastOnce()).collapsePanel();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d6a7acbcbd78..9f096dada6f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -145,6 +145,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -223,6 +224,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private UserSwitcherController mUserSwitcherController;
@Mock private NetworkController mNetworkController;
@Mock private VibratorHelper mVibratorHelper;
+ @Mock private BubblesManager mBubblesManager;
@Mock private Bubbles mBubbles;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@@ -377,6 +379,7 @@ public class StatusBarTest extends SysuiTestCase {
wakefulnessLifecycle,
mStatusBarStateController,
mVibratorHelper,
+ Optional.of(mBubblesManager),
Optional.of(mBubbles),
mVisualStabilityManager,
mDeviceProvisionedController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index d9e9a8b26f0f..88d04011e738 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.systemui.wmshell;
import static android.app.Notification.FLAG_BUBBLE;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
@@ -64,6 +64,14 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.Bubble;
+import com.android.systemui.bubbles.BubbleData;
+import com.android.systemui.bubbles.BubbleDataRepository;
+import com.android.systemui.bubbles.BubbleEntry;
+import com.android.systemui.bubbles.BubbleLogger;
+import com.android.systemui.bubbles.BubblePositioner;
+import com.android.systemui.bubbles.BubbleStackView;
+import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -112,12 +120,12 @@ import java.util.List;
/**
* Tests the NotificationEntryManager setup with BubbleController.
* The {@link NotifPipeline} setup with BubbleController is tested in
- * {@link NewNotifPipelineBubbleControllerTest}.
+ * {@link NewNotifPipelineBubblesTest}.
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class BubbleControllerTest extends SysuiTestCase {
+public class BubblesTest extends SysuiTestCase {
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
@@ -157,6 +165,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
+ private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
private NotificationEntryListener mEntryListener;
@@ -167,9 +176,12 @@ public class BubbleControllerTest extends SysuiTestCase {
private ExpandableNotificationRow mRow2;
private ExpandableNotificationRow mRow3;
private ExpandableNotificationRow mNonBubbleNotifRow;
+ private BubbleEntry mBubbleEntry;
+ private BubbleEntry mBubbleEntry2;
+ private BubbleEntry mBubbleEntry3;
@Mock
- private BubbleController.BubbleExpandListener mBubbleExpandListener;
+ private Bubbles.BubbleExpandListener mBubbleExpandListener;
@Mock
private PendingIntent mDeleteIntent;
@Mock
@@ -226,6 +238,9 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
mRow3 = mNotificationTestHelper.createBubble(mDeleteIntent);
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
+ mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
+ mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
+ mBubbleEntry3 = BubblesManager.notifToBubbleEntry(mRow3.getEntry());
// Return non-null notification data from the NEM
when(mNotificationEntryManager
@@ -258,26 +273,13 @@ public class BubbleControllerTest extends SysuiTestCase {
mock(HeadsUpManager.class),
mock(Handler.class)
);
+
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(
mContext,
- mNotificationShadeWindowController,
- mStatusBarStateController,
- mShadeController,
mBubbleData,
- mConfigurationController,
- interruptionStateProvider,
- mZenModeController,
- mLockscreenUserManager,
- mNotificationGroupManager,
- mNotificationEntryManager,
- mNotifPipeline,
- mFeatureFlagsOldPipeline,
- mDumpManager,
mFloatingContentCoordinator,
mDataRepository,
- mSysUiState,
- mock(INotificationManager.class),
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
@@ -288,6 +290,25 @@ public class BubbleControllerTest extends SysuiTestCase {
mPositioner);
mBubbleController.setExpandListener(mBubbleExpandListener);
+ mBubblesManager = new BubblesManager(
+ mContext,
+ mBubbleController,
+ mNotificationShadeWindowController,
+ mStatusBarStateController,
+ mShadeController,
+ mConfigurationController,
+ mStatusBarService,
+ mock(INotificationManager.class),
+ interruptionStateProvider,
+ mZenModeController,
+ mLockscreenUserManager,
+ mNotificationGroupManager,
+ mNotificationEntryManager,
+ mNotifPipeline,
+ mSysUiState,
+ mFeatureFlagsOldPipeline,
+ mDumpManager);
+
// Get a reference to the BubbleController's entry listener
verify(mNotificationEntryManager, atLeastOnce())
.addNotificationEntryListener(mEntryListenerCaptor.capture());
@@ -300,7 +321,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testAddBubble() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
@@ -309,20 +330,20 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testHasBubbles() {
assertFalse(mBubbleController.hasBubbles());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
}
@Test
public void testRemoveBubble() {
- mBubbleController.updateBubble(mRow.getEntry());
- assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertNotNull(mBubbleData.getBubbleInStackWithKey(mBubbleEntry.getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotificationEntryManager).updateNotifications(any());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
@@ -331,14 +352,14 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testPromoteBubble_autoExpand() throws Exception {
- mBubbleController.updateBubble(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry2);
+ mBubbleController.updateBubble(mBubbleEntry);
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
.thenReturn(mRow.getEntry());
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
.thenReturn(mRow2.getEntry());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
@@ -361,18 +382,18 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testCancelOverflowBubble() {
- mBubbleController.updateBubble(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
+ mBubbleController.updateBubble(mBubbleEntry2);
+ mBubbleController.updateBubble(mBubbleEntry, /* suppressFlyout */
false, /* showInShade */ true);
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
.thenReturn(mRow.getEntry());
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
.thenReturn(mRow2.getEntry());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
eq(mRow.getEntry().getSbn()), any(), anyInt());
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
@@ -381,11 +402,11 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testUserChange_doesNotRemoveNotif() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_CHANGED);
verify(mNotificationEntryManager, never()).performRemoveNotification(
eq(mRow.getEntry().getSbn()), any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
@@ -395,15 +416,15 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testDismissStack() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
verify(mNotificationEntryManager, times(1)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry2);
verify(mNotificationEntryManager, times(2)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
- mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -417,12 +438,12 @@ public class BubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand the stack
BubbleStackView stackView = mBubbleController.getStackView();
@@ -434,7 +455,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Make sure the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Collapse
mBubbleController.collapseStack();
@@ -450,15 +471,15 @@ public class BubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow2.getEntry()));
+ mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -472,7 +493,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Last added is the one that is expanded
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow2.getEntry()));
+ mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Switch which bubble is expanded
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
@@ -481,7 +502,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// collapse for previous bubble
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
@@ -501,12 +522,12 @@ public class BubbleControllerTest extends SysuiTestCase {
public void testExpansionRemovesShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -520,7 +541,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@@ -529,12 +550,12 @@ public class BubbleControllerTest extends SysuiTestCase {
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -548,7 +569,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -558,7 +579,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Nothing should have changed
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@@ -568,8 +589,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -584,13 +605,13 @@ public class BubbleControllerTest extends SysuiTestCase {
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow2.getEntry()));
+ mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Dismiss currently expanded
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey(),
- BubbleController.DISMISS_USER_GESTURE);
+ Bubbles.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
@@ -602,7 +623,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey(),
- BubbleController.DISMISS_USER_GESTURE);
+ Bubbles.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
@@ -619,7 +640,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Add the auto expand bubble
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Expansion shouldn't change
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
@@ -636,7 +657,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Add the auto expand bubble
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Expansion should change
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
@@ -653,11 +674,11 @@ public class BubbleControllerTest extends SysuiTestCase {
// Add the suppress notif bubble
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed because we were foreground
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
@@ -667,22 +688,22 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testSuppressNotif_onUpdateNotif() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Should not be suppressed
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should show dot
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Update to suppress notif
setMetadataFlags(mRow.getEntry(),
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
@@ -695,13 +716,13 @@ public class BubbleControllerTest extends SysuiTestCase {
final String key = mRow.getEntry().getKey();
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Simulate notification cancellation.
mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
- mBubbleController.expandStackAndSelectBubble(mRow.getEntry());
+ mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
assertTrue(mSysUiStateBubblesExpanded);
}
@@ -710,7 +731,7 @@ public class BubbleControllerTest extends SysuiTestCase {
public void testMarkNewNotificationAsShowInShade() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -726,31 +747,31 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
verify(mDeleteIntent, never()).send();
}
@Test
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(1)).send();
}
@Test
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
- mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+ mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(2)).send();
}
@Test
public void testRemoveBubble_noLongerBubbleAfterUpdate()
throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
@@ -766,7 +787,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble_succeeds_appCancel() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
@@ -780,7 +801,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble_entryListenerRemove() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
@@ -792,11 +813,11 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void removeBubble_clearAllIntercepted() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL_ALL);
@@ -805,17 +826,17 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(intercepted);
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
}
@Test
public void removeBubble_userDismissNotifIntercepted() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
@@ -824,21 +845,21 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(intercepted);
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
}
@Test
public void removeNotif_inOverflow_intercepted() {
// Get bubble with notif in shade.
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble into overflow.
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles());
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
@@ -852,14 +873,14 @@ public class BubbleControllerTest extends SysuiTestCase {
public void removeNotif_notInOverflow_notIntercepted() {
// Get bubble with notif in shade.
mEntryListener.onPendingEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
assertFalse(mBubbleController.hasBubbles());
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
@@ -872,11 +893,11 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testOverflowBubble_maxReached_notInShade_bubbleRemoved() {
mBubbleController.updateBubble(
- mRow.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ mBubbleEntry, /* suppressFlyout */ false, /* showInShade */ false);
mBubbleController.updateBubble(
- mRow2.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ mBubbleEntry2, /* suppressFlyout */ false, /* showInShade */ false);
mBubbleController.updateBubble(
- mRow3.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ mBubbleEntry3, /* suppressFlyout */ false, /* showInShade */ false);
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
.thenReturn(mRow.getEntry());
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
@@ -887,12 +908,12 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleData.setMaxOverflowBubbles(1);
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertEquals(mBubbleData.getBubbles().size(), 2);
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
mBubbleController.removeBubble(
- mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow2.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
eq(mRow.getEntry().getSbn()), any(), eq(REASON_CANCEL));
@@ -902,22 +923,22 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testNotifyShadeSuppressionChange_notificationDismiss() {
- BubbleController.NotificationSuppressionChangedListener listener =
- mock(BubbleController.NotificationSuppressionChangedListener.class);
+ Bubbles.NotificationSuppressionChangedListener listener =
+ mock(Bubbles.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mRemoveInterceptor.onNotificationRemoveRequested(
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
@@ -926,21 +947,21 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testNotifyShadeSuppressionChange_bubbleExpanded() {
- BubbleController.NotificationSuppressionChangedListener listener =
- mock(BubbleController.NotificationSuppressionChangedListener.class);
+ Bubbles.NotificationSuppressionChangedListener listener =
+ mock(Bubbles.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleData.setExpanded(true);
// Once a bubble is expanded the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
@@ -959,11 +980,11 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// WHEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// THEN the summary and bubbled child are suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- groupedBubble.getEntry()));
+ groupedBubble.getEntry().getKey(), groupSummary.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
}
@@ -979,7 +1000,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// GIVEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// WHEN the summary is cancelled by the app
mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL);
@@ -1002,7 +1023,7 @@ public class BubbleControllerTest extends SysuiTestCase {
groupSummary.addChildNotification(groupedBubble);
// WHEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
@@ -1017,7 +1038,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// THEN the bubble child is suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- groupedBubble.getEntry()));
+ groupedBubble.getEntry().getKey(),
+ groupedBubble.getEntry().getSbn().getGroupKey()));
// THEN the summary is removed from GroupManager
verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry());
@@ -1031,18 +1053,18 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void test_notVisuallyInterruptive_updateOverflowBubble_notAdded() {
// Setup
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
assertTrue(mBubbleController.hasBubbles());
// Overflow it
mBubbleData.dismissBubbleWithKey(mRow.getEntry().getKey(),
- BubbleController.DISMISS_USER_GESTURE);
+ Bubbles.DISMISS_USER_GESTURE);
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
assertThat(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())).isTrue();
// Test
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index b9394ff3f26a..99c8ca417778 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.systemui.wmshell;
import static android.app.Notification.FLAG_BUBBLE;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
@@ -46,7 +46,6 @@ import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.hardware.face.FaceManager;
import android.os.Handler;
import android.os.PowerManager;
import android.service.dreams.IDreamManager;
@@ -60,8 +59,14 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleData;
+import com.android.systemui.bubbles.BubbleDataRepository;
+import com.android.systemui.bubbles.BubbleEntry;
+import com.android.systemui.bubbles.BubbleLogger;
+import com.android.systemui.bubbles.BubblePositioner;
+import com.android.systemui.bubbles.BubbleStackView;
+import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -69,9 +74,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
@@ -81,10 +84,8 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -92,7 +93,6 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.InjectionInflationController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -111,18 +111,18 @@ import java.util.List;
/**
* Tests the NotifPipeline setup with BubbleController.
* The NotificationEntryManager setup with BubbleController is tested in
- * {@link BubbleControllerTest}.
+ * {@link BubblesTest}.
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
+public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
private NotificationGroupManagerLegacy mNotificationGroupManager;
@Mock
- private BubbleController.NotifCallback mNotifCallback;
+ private BubblesManager.NotifCallback mNotifCallback;
@Mock
private WindowManager mWindowManager;
@Mock
@@ -136,8 +136,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Mock
private ZenModeConfig mZenModeConfig;
@Mock
- private FaceManager mFaceManager;
- @Mock
private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
@@ -156,6 +154,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
+ private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
private NotifCollectionListener mEntryListener;
@@ -163,8 +162,10 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
private ExpandableNotificationRow mRow;
private ExpandableNotificationRow mRow2;
private ExpandableNotificationRow mNonBubbleNotifRow;
+ private BubbleEntry mBubbleEntry;
+ private BubbleEntry mBubbleEntry2;
@Mock
- private BubbleController.BubbleExpandListener mBubbleExpandListener;
+ private Bubbles.BubbleExpandListener mBubbleExpandListener;
@Mock
private PendingIntent mDeleteIntent;
@Mock
@@ -174,16 +175,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Mock
private ShadeController mShadeController;
@Mock
- private NotificationShelfComponent mNotificationShelfComponent;
- @Mock
private NotifPipeline mNotifPipeline;
@Mock
private FeatureFlags mFeatureFlagsNewPipeline;
@Mock
private DumpManager mDumpManager;
@Mock
- private LockscreenLockIconController mLockIconController;
- @Mock
private IStatusBarService mStatusBarService;
@Mock
private LauncherApps mLauncherApps;
@@ -197,7 +194,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
private BubbleData mBubbleData;
private TestableLooper mTestableLooper;
- private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Before
public void setUp() throws Exception {
@@ -205,26 +201,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
- mContext.addMockSystemService(FaceManager.class, mFaceManager);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
- mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
- new InjectionInflationController(SystemUIFactory.getInstance().getSysUIComponent()
- .createViewInstanceCreatorFactory()),
- new NotificationShelfComponent.Builder() {
- @Override
- public NotificationShelfComponent.Builder notificationShelf(
- NotificationShelf view) {
- return this;
- }
-
- @Override
- public NotificationShelfComponent build() {
- return mNotificationShelfComponent;
- }
- },
- mLockIconController);
-
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mKeyguardViewMediator, mKeyguardBypassController,
@@ -240,6 +218,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
+ mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
+ mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
@@ -265,23 +245,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
mBubbleController = new TestableBubbleController(
mContext,
- mNotificationShadeWindowController,
- mStatusBarStateController,
- mShadeController,
mBubbleData,
- mConfigurationController,
- interruptionStateProvider,
- mZenModeController,
- mLockscreenUserManager,
- mNotificationGroupManager,
- mNotificationEntryManager,
- mNotifPipeline,
- mFeatureFlagsNewPipeline,
- mDumpManager,
mFloatingContentCoordinator,
mDataRepository,
- mSysUiState,
- mock(INotificationManager.class),
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
@@ -290,9 +256,28 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mock(Handler.class),
mock(ShellTaskOrganizer.class),
mPositioner);
- mBubbleController.addNotifCallback(mNotifCallback);
mBubbleController.setExpandListener(mBubbleExpandListener);
+ mBubblesManager = new BubblesManager(
+ mContext,
+ mBubbleController,
+ mNotificationShadeWindowController,
+ mStatusBarStateController,
+ mShadeController,
+ mConfigurationController,
+ mStatusBarService,
+ mock(INotificationManager.class),
+ interruptionStateProvider,
+ mZenModeController,
+ mLockscreenUserManager,
+ mNotificationGroupManager,
+ mNotificationEntryManager,
+ mNotifPipeline,
+ mSysUiState,
+ mFeatureFlagsNewPipeline,
+ mDumpManager);
+ mBubblesManager.addNotifCallback(mNotifCallback);
+
// Get a reference to the BubbleController's entry listener
verify(mNotifPipeline, atLeastOnce())
.addCollectionListener(mNotifListenerCaptor.capture());
@@ -301,26 +286,26 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testAddBubble() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
}
@Test
public void testHasBubbles() {
assertFalse(mBubbleController.hasBubbles());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
}
@Test
public void testRemoveBubble() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
}
@@ -328,17 +313,18 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble_withDismissedNotif_inOverflow() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
- assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Make it look like dismissed notif
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
// Now remove the bubble
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// We don't remove the notification since the bubble is still in overflow.
@@ -349,19 +335,20 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble_withDismissedNotif_notInOverflow() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
.thenReturn(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
- assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Make it look like dismissed notif
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
// Now remove the bubble
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// Since the notif is dismissed and not in overflow, once the bubble is removed,
@@ -373,15 +360,15 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testDismissStack() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry2);
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
- mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -393,12 +380,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand the stack
BubbleStackView stackView = mBubbleController.getStackView();
@@ -407,7 +394,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Make sure the notif is suppressed
- assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Collapse
mBubbleController.collapseStack();
@@ -421,15 +409,15 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
mEntryListener.onEntryAdded(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow2.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -440,15 +428,17 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Last added is the one that is expanded
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
- assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Switch which bubble is expanded
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
+ mRow.getEntry().getKey()));
mBubbleData.setExpanded(true);
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// collapse for previous bubble
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
@@ -467,11 +457,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testExpansionRemovesShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
- assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -483,7 +474,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@@ -492,12 +483,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// We should have bubbles & their notifs should not be suppressed
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -509,7 +500,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -519,7 +510,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Nothing should have changed
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Notif shouldn't show dot after expansion
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
}
@@ -529,8 +520,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
mEntryListener.onEntryAdded(mRow2.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -543,13 +534,13 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow2.getEntry()));
+ mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
// Dismiss currently expanded
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey(),
- BubbleController.DISMISS_USER_GESTURE);
+ Bubbles.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
@@ -561,7 +552,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
stackView.getExpandedBubble().getKey()).getKey(),
- BubbleController.DISMISS_USER_GESTURE);
+ Bubbles.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
@@ -576,7 +567,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Add the auto expand bubble
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Expansion shouldn't change
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
@@ -591,7 +582,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Add the auto expand bubble
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Expansion should change
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
@@ -606,11 +597,11 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Add the suppress notif bubble
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed because we were foreground
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
@@ -618,22 +609,22 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testSuppressNotif_onUpdateNotif() {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Should not be suppressed
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should show dot
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
// Update to suppress notif
setMetadataFlags(mRow.getEntry(),
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
// Notif should be suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
@@ -643,7 +634,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testMarkNewNotificationAsShowInShade() {
mEntryListener.onEntryAdded(mRow.getEntry());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mTestableLooper.processAllMessages();
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
@@ -659,31 +650,31 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
verify(mDeleteIntent, never()).send();
}
@Test
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(1)).send();
}
@Test
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.updateBubble(mRow2.getEntry());
- mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.updateBubble(mBubbleEntry2);
+ mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(2)).send();
}
@Test
public void testRemoveBubble_noLongerBubbleAfterUpdate()
throws PendingIntent.CanceledException {
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
@@ -699,7 +690,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testRemoveBubble_entryListenerRemove() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
@@ -711,36 +702,36 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void removeBubble_intercepted() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
- boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+ boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
// Intercept!
assertTrue(intercepted);
// Should update show in shade state
- assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
}
@Test
public void removeBubble_dismissIntoOverflow_intercepted() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble
- mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles());
// Dismiss the notification
- boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+ boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
// Intercept dismissal since bubble is going into overflow
assertTrue(intercepted);
@@ -749,19 +740,18 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void removeBubble_notIntercepted() {
mEntryListener.onEntryAdded(mRow.getEntry());
- mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Dismiss the bubble
- mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
+ mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
assertFalse(mBubbleController.hasBubbles());
// Dismiss the notification
- boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+ boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
// Not a bubble anymore so we don't intercept dismissal.
assertFalse(intercepted);
@@ -769,21 +759,21 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testNotifyShadeSuppressionChange_notificationDismiss() {
- BubbleController.NotificationSuppressionChangedListener listener =
- mock(BubbleController.NotificationSuppressionChangedListener.class);
+ Bubbles.NotificationSuppressionChangedListener listener =
+ mock(Bubbles.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
- mBubbleController.handleDismissalInterception(mRow.getEntry());
+ mBubblesManager.handleDismissalInterception(mRow.getEntry());
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
@@ -792,21 +782,21 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Test
public void testNotifyShadeSuppressionChange_bubbleExpanded() {
- BubbleController.NotificationSuppressionChangedListener listener =
- mock(BubbleController.NotificationSuppressionChangedListener.class);
+ Bubbles.NotificationSuppressionChangedListener listener =
+ mock(Bubbles.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
mEntryListener.onEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
mBubbleData.setExpanded(true);
// Once a bubble is expanded the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- mRow.getEntry()));
+ mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
// Should notify delegate that shade state changed
verify(listener).onBubbleNotificationSuppressionChange(
@@ -825,11 +815,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// WHEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// THEN the summary and bubbled child are suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- groupedBubble.getEntry()));
+ groupedBubble.getEntry().getKey(),
+ groupedBubble.getEntry().getSbn().getGroupKey()));
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
}
@@ -845,7 +836,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
// GIVEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// WHEN the summary is cancelled by the app
mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
@@ -868,7 +859,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
groupSummary.addChildNotification(groupedBubble);
// WHEN the summary is dismissed
- mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+ mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
@@ -882,11 +873,13 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// THEN the bubble child still exists as a bubble and is suppressed from the shade
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- groupedBubble.getEntry()));
+ groupedBubble.getEntry().getKey(),
+ groupedBubble.getEntry().getSbn().getGroupKey()));
// THEN the summary is also suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
- groupSummary.getEntry()));
+ groupSummary.getEntry().getKey(),
+ groupSummary.getEntry().getSbn().getGroupKey()));
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
new file mode 100644
index 000000000000..2273bc48ce8b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.os.Handler;
+import android.view.WindowManager;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.bubbles.BubbleData;
+import com.android.systemui.bubbles.BubbleDataRepository;
+import com.android.systemui.bubbles.BubbleLogger;
+import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+
+/**
+ * Testable BubbleController subclass that immediately synchronizes surfaces.
+ */
+public class TestableBubbleController extends BubbleController {
+
+ // Let's assume surfaces can be synchronized immediately.
+ TestableBubbleController(Context context,
+ BubbleData data,
+ FloatingContentCoordinator floatingContentCoordinator,
+ BubbleDataRepository dataRepository,
+ IStatusBarService statusBarService,
+ WindowManager windowManager,
+ WindowManagerShellWrapper windowManagerShellWrapper,
+ LauncherApps launcherApps,
+ BubbleLogger bubbleLogger,
+ Handler mainHandler,
+ ShellTaskOrganizer shellTaskOrganizer,
+ BubblePositioner positioner) {
+ super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
+ statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
+ bubbleLogger, mainHandler, shellTaskOrganizer, positioner);
+ setInflateSynchronously(true);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index 17dc76b38a56..7847c57dbc32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.systemui.wmshell;
import android.content.ContentResolver;
import android.hardware.display.AmbientDisplayConfiguration;