Decouple BubbleController from more classes
This change creates BubbleExpandedViewManager and BubbleTaskViewFactory interfaces.
These interfaces allow decoupling BubbleController from more classes so it's easier to write unit tests for Bubble classes.
After this change it's possible to create a unit test for BubbleStackView that does not depend on BubbleController, but there is a blocking robolectric issue b/323188766, so I will add the test once that issue is resolved.
Flag: NA
Bug: 321265700
Test: atest BubblesTest
Test: atest BubbleViewInfoTest
Test: atest BubbleOverflowTest
Test: manual -- build and play with bubbles
Change-Id: Id1c79643c2ad9e88173d6c25a9e88643afaf5564
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index a2a2914..e18d9ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -53,8 +53,6 @@
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.common.bubbles.BubbleInfo;
-import com.android.wm.shell.taskview.TaskView;
-import com.android.wm.shell.taskview.TaskViewTaskController;
import java.io.PrintWriter;
import java.util.List;
@@ -403,13 +401,9 @@
* Returns the existing {@link #mBubbleTaskView} if it's not {@code null}. Otherwise a new
* instance of {@link BubbleTaskView} is created.
*/
- public BubbleTaskView getOrCreateBubbleTaskView(Context context, BubbleController controller) {
+ public BubbleTaskView getOrCreateBubbleTaskView(BubbleTaskViewFactory taskViewFactory) {
if (mBubbleTaskView == null) {
- TaskViewTaskController taskViewTaskController = new TaskViewTaskController(context,
- controller.getTaskOrganizer(),
- controller.getTaskViewTransitions(), controller.getSyncTransactionQueue());
- TaskView taskView = new TaskView(context, taskViewTaskController);
- mBubbleTaskView = new BubbleTaskView(taskView, controller.getMainExecutor());
+ mBubbleTaskView = taskViewFactory.create();
}
return mBubbleTaskView;
}
@@ -514,14 +508,18 @@
*
* @param callback the callback to notify one the bubble is ready to be displayed.
* @param context the context for the bubble.
- * @param controller the bubble controller.
+ * @param expandedViewManager the bubble expanded view manager.
+ * @param taskViewFactory the task view factory used to create the task view for the bubble.
+ * @param positioner the bubble positioner.
* @param stackView the view the bubble is added to, iff showing as floating.
* @param layerView the layer the bubble is added to, iff showing in the bubble bar.
- * @param iconFactory the icon factory use to create images for the bubble.
+ * @param iconFactory the icon factory used to create images for the bubble.
*/
void inflate(BubbleViewInfoTask.Callback callback,
Context context,
- BubbleController controller,
+ BubbleExpandedViewManager expandedViewManager,
+ BubbleTaskViewFactory taskViewFactory,
+ BubblePositioner positioner,
@Nullable BubbleStackView stackView,
@Nullable BubbleBarLayerView layerView,
BubbleIconFactory iconFactory,
@@ -531,7 +529,9 @@
}
mInflationTask = new BubbleViewInfoTask(this,
context,
- controller,
+ expandedViewManager,
+ taskViewFactory,
+ positioner,
stackView,
layerView,
iconFactory,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 621c453..29a7c42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -113,6 +113,7 @@
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.taskview.TaskView;
+import com.android.wm.shell.taskview.TaskViewTaskController;
import com.android.wm.shell.taskview.TaskViewTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -190,6 +191,8 @@
private final ShellCommandHandler mShellCommandHandler;
private final IWindowManager mWmService;
private final BubbleProperties mBubbleProperties;
+ private final BubbleTaskViewFactory mBubbleTaskViewFactory;
+ private final BubbleExpandedViewManager mExpandedViewManager;
// Used to post to main UI thread
private final ShellExecutor mMainExecutor;
@@ -333,6 +336,16 @@
mWmService = wmService;
mBubbleProperties = bubbleProperties;
shellInit.addInitCallback(this::onInit, this);
+ mBubbleTaskViewFactory = new BubbleTaskViewFactory() {
+ @Override
+ public BubbleTaskView create() {
+ TaskViewTaskController taskViewTaskController = new TaskViewTaskController(
+ context, organizer, taskViewTransitions, syncQueue);
+ TaskView taskView = new TaskView(context, taskViewTaskController);
+ return new BubbleTaskView(taskView, mainExecutor);
+ }
+ };
+ mExpandedViewManager = BubbleExpandedViewManager.fromBubbleController(this);
}
private void registerOneHandedState(OneHandedController oneHanded) {
@@ -802,7 +815,13 @@
try {
mAddedToWindowManager = true;
registerBroadcastReceiver();
- mBubbleData.getOverflow().initialize(this, isShowingAsBubbleBar());
+ if (isShowingAsBubbleBar()) {
+ mBubbleData.getOverflow().initializeForBubbleBar(
+ mExpandedViewManager, mBubblePositioner);
+ } else {
+ mBubbleData.getOverflow().initialize(
+ mExpandedViewManager, mStackView, mBubblePositioner);
+ }
// (TODO: b/273314541) some duplication in the inset listener
if (isShowingAsBubbleBar()) {
mWindowManager.addView(mLayerView, mWmLayoutParams);
@@ -981,7 +1000,9 @@
for (Bubble b : mBubbleData.getBubbles()) {
b.inflate(null /* callback */,
mContext,
- this,
+ mExpandedViewManager,
+ mBubbleTaskViewFactory,
+ mBubblePositioner,
mStackView,
mLayerView,
mBubbleIconFactory,
@@ -990,7 +1011,9 @@
for (Bubble b : mBubbleData.getOverflowBubbles()) {
b.inflate(null /* callback */,
mContext,
- this,
+ mExpandedViewManager,
+ mBubbleTaskViewFactory,
+ mBubblePositioner,
mStackView,
mLayerView,
mBubbleIconFactory,
@@ -1374,7 +1397,9 @@
bubble.inflate(
(b) -> mBubbleData.overflowBubble(Bubbles.DISMISS_RELOAD_FROM_DISK, bubble),
mContext,
- this,
+ mExpandedViewManager,
+ mBubbleTaskViewFactory,
+ mBubblePositioner,
mStackView,
mLayerView,
mBubbleIconFactory,
@@ -1421,7 +1446,9 @@
Bubble bubble = mBubbleData.getBubbles().get(i);
bubble.inflate(callback,
mContext,
- this,
+ mExpandedViewManager,
+ mBubbleTaskViewFactory,
+ mBubblePositioner,
mStackView,
mLayerView,
mBubbleIconFactory,
@@ -1496,8 +1523,14 @@
// Lazy init stack view when a bubble is created
ensureBubbleViewsAndWindowCreated();
bubble.setInflateSynchronously(mInflateSynchronously);
- bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
- mContext, this, mStackView, mLayerView,
+ bubble.inflate(
+ b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
+ mContext,
+ mExpandedViewManager,
+ mBubbleTaskViewFactory,
+ mBubblePositioner,
+ mStackView,
+ mLayerView,
mBubbleIconFactory,
false /* skipInflation */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 6d3f0c3..6c2f925 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -37,10 +37,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubbles.DismissReason;
-import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import com.android.wm.shell.common.bubbles.RemovedBubble;
@@ -180,7 +178,7 @@
* This interface reports changes to the state and appearance of bubbles which should be applied
* as necessary to the UI.
*/
- interface Listener {
+ public interface Listener {
/** Reports changes have have occurred as a result of the most recent operation. */
void applyUpdate(Update update);
}
@@ -419,8 +417,10 @@
/**
* When this method is called it is expected that all info in the bubble has completed loading.
- * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleController, BubbleStackView,
- * BubbleBarLayerView, BubbleIconFactory, boolean)
+ * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleExpandedViewManager,
+ * BubbleTaskViewFactory, BubblePositioner, BubbleStackView,
+ * com.android.wm.shell.bubbles.bar.BubbleBarLayerView,
+ * com.android.launcher3.icons.BubbleIconFactory, boolean)
*/
void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 088660e..df9ba63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -184,7 +184,7 @@
private boolean mIsOverflow;
private boolean mIsClipping;
- private BubbleController mController;
+ private BubbleExpandedViewManager mManager;
private BubbleStackView mStackView;
private BubblePositioner mPositioner;
@@ -261,7 +261,7 @@
// the bubble again so we'll just remove it.
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ ", " + e.getMessage() + "; removing bubble");
- mController.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
+ mManager.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
}
});
mInitialized = true;
@@ -281,7 +281,7 @@
if (mBubble != null && mBubble.isAppBubble()) {
// Let the controller know sooner what the taskId is.
- mController.setAppBubbleTaskId(mBubble.getKey(), mTaskId);
+ mManager.setAppBubbleTaskId(mBubble.getKey(), mTaskId);
}
// With the task org, the taskAppeared callback will only happen once the task has
@@ -301,7 +301,7 @@
ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
taskId, getBubbleKey());
if (mBubble != null) {
- mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ mManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
}
if (mTaskView != null) {
// Release the surface
@@ -421,17 +421,20 @@
* Initialize {@link BubbleController} and {@link BubbleStackView} here, this method must need
* to be called after view inflate.
*/
- void initialize(BubbleController controller, BubbleStackView stackView, boolean isOverflow,
+ void initialize(BubbleExpandedViewManager expandedViewManager,
+ BubbleStackView stackView,
+ BubblePositioner positioner,
+ boolean isOverflow,
@Nullable BubbleTaskView bubbleTaskView) {
- mController = controller;
+ mManager = expandedViewManager;
mStackView = stackView;
mIsOverflow = isOverflow;
- mPositioner = mController.getPositioner();
+ mPositioner = positioner;
if (mIsOverflow) {
mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate(
R.layout.bubble_overflow_container, null /* root */);
- mOverflowView.setBubbleController(mController);
+ mOverflowView.initialize(expandedViewManager, positioner);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
mExpandedViewContainer.addView(mOverflowView, lp);
mExpandedViewContainer.setLayoutParams(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt
new file mode 100644
index 0000000..b0d3cc4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.bubbles
+
+/** Manager interface for bubble expanded views. */
+interface BubbleExpandedViewManager {
+
+ val overflowBubbles: List<Bubble>
+ fun setOverflowListener(listener: BubbleData.Listener)
+ fun collapseStack()
+ fun updateWindowFlagsForBackpress(intercept: Boolean)
+ fun promoteBubbleFromOverflow(bubble: Bubble)
+ fun removeBubble(key: String, reason: Int)
+ fun dismissBubble(bubble: Bubble, reason: Int)
+ fun setAppBubbleTaskId(key: String, taskId: Int)
+ fun isStackExpanded(): Boolean
+ fun isShowingAsBubbleBar(): Boolean
+
+ companion object {
+ /**
+ * Convenience function for creating a [BubbleExpandedViewManager] that delegates to the
+ * given `controller`.
+ */
+ @JvmStatic
+ fun fromBubbleController(controller: BubbleController): BubbleExpandedViewManager {
+ return object : BubbleExpandedViewManager {
+
+ override val overflowBubbles: List<Bubble>
+ get() = controller.overflowBubbles
+
+ override fun setOverflowListener(listener: BubbleData.Listener) {
+ controller.setOverflowListener(listener)
+ }
+
+ override fun collapseStack() {
+ controller.collapseStack()
+ }
+
+ override fun updateWindowFlagsForBackpress(intercept: Boolean) {
+ controller.updateWindowFlagsForBackpress(intercept)
+ }
+
+ override fun promoteBubbleFromOverflow(bubble: Bubble) {
+ controller.promoteBubbleFromOverflow(bubble)
+ }
+
+ override fun removeBubble(key: String, reason: Int) {
+ controller.removeBubble(key, reason)
+ }
+
+ override fun dismissBubble(bubble: Bubble, reason: Int) {
+ controller.dismissBubble(bubble, reason)
+ }
+
+ override fun setAppBubbleTaskId(key: String, taskId: Int) {
+ controller.setAppBubbleTaskId(key, taskId)
+ }
+
+ override fun isStackExpanded(): Boolean = controller.isStackExpanded
+
+ override fun isShowingAsBubbleBar(): Boolean = controller.isShowingAsBubbleBar
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index e5d9ace..f32974e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -56,19 +56,32 @@
}
/** Call before use and again if cleanUpExpandedState was called. */
- fun initialize(controller: BubbleController, forBubbleBar: Boolean) {
- if (forBubbleBar) {
- createBubbleBarExpandedView()
- .initialize(controller, /* isOverflow= */ true, /* bubbleTaskView= */ null)
- } else {
- createExpandedView()
+ fun initialize(
+ expandedViewManager: BubbleExpandedViewManager,
+ stackView: BubbleStackView,
+ positioner: BubblePositioner
+ ) {
+ createExpandedView()
.initialize(
- controller,
- controller.stackView,
+ expandedViewManager,
+ stackView,
+ positioner,
/* isOverflow= */ true,
/* bubbleTaskView= */ null
)
- }
+ }
+
+ fun initializeForBubbleBar(
+ expandedViewManager: BubbleExpandedViewManager,
+ positioner: BubblePositioner
+ ) {
+ createBubbleBarExpandedView()
+ .initialize(
+ expandedViewManager,
+ positioner,
+ /* isOverflow= */ true,
+ /* bubbleTaskView= */ null
+ )
}
fun cleanUpExpandedState() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 70cdc82..b06de4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -62,7 +62,8 @@
private ImageView mEmptyStateImage;
private int mHorizontalMargin;
private int mVerticalMargin;
- private BubbleController mController;
+ private BubbleExpandedViewManager mExpandedViewManager;
+ private BubblePositioner mPositioner;
private BubbleOverflowAdapter mAdapter;
private RecyclerView mRecyclerView;
private List<Bubble> mOverflowBubbles = new ArrayList<>();
@@ -70,7 +71,7 @@
private View.OnKeyListener mKeyListener = (view, i, keyEvent) -> {
if (keyEvent.getAction() == KeyEvent.ACTION_UP
&& keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- mController.collapseStack();
+ mExpandedViewManager.collapseStack();
return true;
}
return false;
@@ -126,8 +127,11 @@
setFocusableInTouchMode(true);
}
- public void setBubbleController(BubbleController controller) {
- mController = controller;
+ /** Initializes the view. Must be called after creation. */
+ public void initialize(BubbleExpandedViewManager expandedViewManager,
+ BubblePositioner positioner) {
+ mExpandedViewManager = expandedViewManager;
+ mPositioner = positioner;
}
public void show() {
@@ -149,9 +153,9 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mController != null) {
+ if (mExpandedViewManager != null) {
// For the overflow to get key events (e.g. back press) we need to adjust the flags
- mController.updateWindowFlagsForBackpress(true);
+ mExpandedViewManager.updateWindowFlagsForBackpress(true);
}
setOnKeyListener(mKeyListener);
}
@@ -159,8 +163,8 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mController != null) {
- mController.updateWindowFlagsForBackpress(false);
+ if (mExpandedViewManager != null) {
+ mExpandedViewManager.updateWindowFlagsForBackpress(false);
}
setOnKeyListener(null);
}
@@ -177,15 +181,15 @@
mRecyclerView.addItemDecoration(new OverflowItemDecoration());
}
mAdapter = new BubbleOverflowAdapter(getContext(), mOverflowBubbles,
- mController::promoteBubbleFromOverflow,
- mController.getPositioner());
+ mExpandedViewManager::promoteBubbleFromOverflow,
+ mPositioner);
mRecyclerView.setAdapter(mAdapter);
mOverflowBubbles.clear();
- mOverflowBubbles.addAll(mController.getOverflowBubbles());
+ mOverflowBubbles.addAll(mExpandedViewManager.getOverflowBubbles());
mAdapter.notifyDataSetChanged();
- mController.setOverflowListener(mDataListener);
+ mExpandedViewManager.setOverflowListener(mDataListener);
updateEmptyStateVisibility();
updateTheme();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewFactory.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewFactory.kt
new file mode 100644
index 0000000..230626f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewFactory.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.bubbles
+
+/** Factory for creating [BubbleTaskView]s. */
+fun interface BubbleTaskViewFactory {
+ /** Creates a new instance of [BubbleTaskView]. */
+ fun create(): BubbleTaskView
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 530ec5a..21b70b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -62,7 +62,7 @@
}
private final Context mContext;
- private final BubbleController mController;
+ private final BubbleExpandedViewManager mExpandedViewManager;
private final BubbleTaskViewHelper.Listener mListener;
private final View mParentView;
@@ -142,7 +142,8 @@
// the bubble again so we'll just remove it.
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ ", " + e.getMessage() + "; removing bubble");
- mController.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
+ mExpandedViewManager.removeBubble(
+ getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
}
mInitialized = true;
});
@@ -175,7 +176,7 @@
ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
taskId, getBubbleKey());
if (mBubble != null) {
- mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ mExpandedViewManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
}
if (mTaskView != null) {
mTaskView.release();
@@ -186,19 +187,19 @@
@Override
public void onBackPressedOnTaskRoot(int taskId) {
- if (mTaskId == taskId && mController.isStackExpanded()) {
+ if (mTaskId == taskId && mExpandedViewManager.isStackExpanded()) {
mListener.onBackPressed();
}
}
};
public BubbleTaskViewHelper(Context context,
- BubbleController controller,
+ BubbleExpandedViewManager expandedViewManager,
BubbleTaskViewHelper.Listener listener,
BubbleTaskView bubbleTaskView,
View parent) {
mContext = context;
- mController = controller;
+ mExpandedViewManager = expandedViewManager;
mListener = listener;
mParentView = parent;
mTaskView = bubbleTaskView.getTaskView();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 5fc10a9..69119cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -70,7 +70,9 @@
private Bubble mBubble;
private WeakReference<Context> mContext;
- private WeakReference<BubbleController> mController;
+ private WeakReference<BubbleExpandedViewManager> mExpandedViewManager;
+ private WeakReference<BubbleTaskViewFactory> mTaskViewFactory;
+ private WeakReference<BubblePositioner> mPositioner;
private WeakReference<BubbleStackView> mStackView;
private WeakReference<BubbleBarLayerView> mLayerView;
private BubbleIconFactory mIconFactory;
@@ -84,7 +86,9 @@
*/
BubbleViewInfoTask(Bubble b,
Context context,
- BubbleController controller,
+ BubbleExpandedViewManager expandedViewManager,
+ BubbleTaskViewFactory taskViewFactory,
+ BubblePositioner positioner,
@Nullable BubbleStackView stackView,
@Nullable BubbleBarLayerView layerView,
BubbleIconFactory factory,
@@ -93,7 +97,9 @@
Executor mainExecutor) {
mBubble = b;
mContext = new WeakReference<>(context);
- mController = new WeakReference<>(controller);
+ mExpandedViewManager = new WeakReference<>(expandedViewManager);
+ mTaskViewFactory = new WeakReference<>(taskViewFactory);
+ mPositioner = new WeakReference<>(positioner);
mStackView = new WeakReference<>(stackView);
mLayerView = new WeakReference<>(layerView);
mIconFactory = factory;
@@ -109,11 +115,13 @@
return null;
}
if (mLayerView.get() != null) {
- return BubbleViewInfo.populateForBubbleBar(mContext.get(), mController.get(),
- mLayerView.get(), mIconFactory, mBubble, mSkipInflation);
+ return BubbleViewInfo.populateForBubbleBar(mContext.get(), mExpandedViewManager.get(),
+ mTaskViewFactory.get(), mPositioner.get(), mLayerView.get(), mIconFactory,
+ mBubble, mSkipInflation);
} else {
- return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(),
- mIconFactory, mBubble, mSkipInflation);
+ return BubbleViewInfo.populate(mContext.get(), mExpandedViewManager.get(),
+ mTaskViewFactory.get(), mPositioner.get(), mStackView.get(), mIconFactory,
+ mBubble, mSkipInflation);
}
}
@@ -135,7 +143,7 @@
}
private boolean verifyState() {
- if (mController.get().isShowingAsBubbleBar()) {
+ if (mExpandedViewManager.get().isShowingAsBubbleBar()) {
return mLayerView.get() != null;
} else {
return mStackView.get() != null;
@@ -167,18 +175,23 @@
Bitmap badgeBitmap;
@Nullable
- public static BubbleViewInfo populateForBubbleBar(Context c, BubbleController controller,
- BubbleBarLayerView layerView, BubbleIconFactory iconFactory, Bubble b,
+ public static BubbleViewInfo populateForBubbleBar(Context c,
+ BubbleExpandedViewManager expandedViewManager,
+ BubbleTaskViewFactory taskViewFactory,
+ BubblePositioner positioner,
+ BubbleBarLayerView layerView,
+ BubbleIconFactory iconFactory,
+ Bubble b,
boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
if (!skipInflation && !b.isInflated()) {
- BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(c, controller);
+ BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(taskViewFactory);
LayoutInflater inflater = LayoutInflater.from(c);
info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
info.bubbleBarExpandedView.initialize(
- controller, false /* isOverflow */, bubbleTaskView);
+ expandedViewManager, positioner, false /* isOverflow */, bubbleTaskView);
}
if (!populateCommonInfo(info, c, b, iconFactory)) {
@@ -191,8 +204,13 @@
@VisibleForTesting
@Nullable
- public static BubbleViewInfo populate(Context c, BubbleController controller,
- BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b,
+ public static BubbleViewInfo populate(Context c,
+ BubbleExpandedViewManager expandedViewManager,
+ BubbleTaskViewFactory taskViewFactory,
+ BubblePositioner positioner,
+ BubbleStackView stackView,
+ BubbleIconFactory iconFactory,
+ Bubble b,
boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
@@ -201,13 +219,14 @@
LayoutInflater inflater = LayoutInflater.from(c);
info.imageView = (BadgedImageView) inflater.inflate(
R.layout.bubble_view, stackView, false /* attachToRoot */);
- info.imageView.initialize(controller.getPositioner());
+ info.imageView.initialize(positioner);
- BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(c, controller);
+ BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(taskViewFactory);
info.expandedView = (BubbleExpandedView) inflater.inflate(
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
info.expandedView.initialize(
- controller, stackView, false /* isOverflow */, bubbleTaskView);
+ expandedViewManager, stackView, positioner, false /* isOverflow */,
+ bubbleTaskView);
}
if (!populateCommonInfo(info, c, b, iconFactory)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 73a9cf4..ebb8e3e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -36,8 +36,9 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
-import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleExpandedViewManager;
import com.android.wm.shell.bubbles.BubbleOverflowContainerView;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleTaskView;
import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
import com.android.wm.shell.bubbles.Bubbles;
@@ -45,11 +46,7 @@
import java.util.function.Supplier;
-/**
- * Expanded view of a bubble when it's part of the bubble bar.
- *
- * {@link BubbleController#isShowingAsBubbleBar()}
- */
+/** Expanded view of a bubble when it's part of the bubble bar. */
public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener {
/**
* The expanded view listener notifying the {@link BubbleBarLayerView} about the internal
@@ -67,7 +64,7 @@
private static final String TAG = BubbleBarExpandedView.class.getSimpleName();
private static final int INVALID_TASK_ID = -1;
- private BubbleController mController;
+ private BubbleExpandedViewManager mManager;
private boolean mIsOverflow;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
@@ -133,20 +130,22 @@
mMenuViewController.hideMenu(false /* animated */);
}
- /** Set the BubbleController on the view, must be called before doing anything else. */
- public void initialize(BubbleController controller, boolean isOverflow,
+ /** Initializes the view, must be called before doing anything else. */
+ public void initialize(BubbleExpandedViewManager expandedViewManager,
+ BubblePositioner positioner,
+ boolean isOverflow,
@Nullable BubbleTaskView bubbleTaskView) {
- mController = controller;
+ mManager = expandedViewManager;
mIsOverflow = isOverflow;
if (mIsOverflow) {
mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate(
R.layout.bubble_overflow_container, null /* root */);
- mOverflowView.setBubbleController(mController);
+ mOverflowView.initialize(expandedViewManager, positioner);
addView(mOverflowView);
} else {
mTaskView = bubbleTaskView.getTaskView();
- mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, mController,
+ mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager,
/* listener= */ this, bubbleTaskView,
/* viewParent= */ this);
if (mTaskView.getParent() != null) {
@@ -178,13 +177,13 @@
@Override
public void onOpenAppSettings(Bubble bubble) {
- mController.collapseStack();
+ mManager.collapseStack();
mContext.startActivityAsUser(bubble.getSettingsIntent(mContext), bubble.getUser());
}
@Override
public void onDismissBubble(Bubble bubble) {
- mController.dismissBubble(bubble, Bubbles.DISMISS_USER_REMOVED);
+ mManager.dismissBubble(bubble, Bubbles.DISMISS_USER_REMOVED);
}
});
mHandleView.setOnClickListener(view -> {
@@ -279,7 +278,7 @@
if (mMenuViewController.isMenuVisible()) {
mMenuViewController.hideMenu(/* animated = */ true);
} else {
- mController.collapseStack();
+ mManager.collapseStack();
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
index f5b0174..094af96 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleOverflowTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -45,18 +44,22 @@
private TestableBubblePositioner mPositioner;
private BubbleOverflow mOverflow;
+ private BubbleExpandedViewManager mExpandedViewManager;
@Mock
private BubbleController mBubbleController;
+ @Mock
+ private BubbleStackView mBubbleStackView;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
MockitoAnnotations.initMocks(this);
+ mExpandedViewManager = BubbleExpandedViewManager.fromBubbleController(mBubbleController);
mPositioner = new TestableBubblePositioner(mContext,
mContext.getSystemService(WindowManager.class));
when(mBubbleController.getPositioner()).thenReturn(mPositioner);
- when(mBubbleController.getStackView()).thenReturn(mock(BubbleStackView.class));
+ when(mBubbleController.getStackView()).thenReturn(mBubbleStackView);
mOverflow = new BubbleOverflow(mContext, mPositioner);
}
@@ -65,7 +68,7 @@
public void test_initialize_forStack() {
assertThat(mOverflow.getExpandedView()).isNull();
- mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
+ mOverflow.initialize(mExpandedViewManager, mBubbleStackView, mPositioner);
assertThat(mOverflow.getExpandedView()).isNotNull();
assertThat(mOverflow.getExpandedView().getBubbleKey()).isEqualTo(BubbleOverflow.KEY);
@@ -74,7 +77,7 @@
@Test
public void test_initialize_forBubbleBar() {
- mOverflow.initialize(mBubbleController, /* forBubbleBar= */ true);
+ mOverflow.initializeForBubbleBar(mExpandedViewManager, mPositioner);
assertThat(mOverflow.getBubbleBarExpandedView()).isNotNull();
assertThat(mOverflow.getExpandedView()).isNull();
@@ -82,11 +85,10 @@
@Test
public void test_cleanUpExpandedState() {
- mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
+ mOverflow.initialize(mExpandedViewManager, mBubbleStackView, mPositioner);
assertThat(mOverflow.getExpandedView()).isNotNull();
mOverflow.cleanUpExpandedState();
assertThat(mOverflow.getExpandedView()).isNull();
}
-
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
index 1668e37..ae39fbc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
@@ -44,6 +44,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.taskview.TaskView
import com.android.wm.shell.taskview.TaskViewTransitions
import com.android.wm.shell.transition.Transitions
import com.google.common.truth.Truth.assertThat
@@ -55,6 +56,7 @@
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
+import java.util.concurrent.Executor
/** Tests for loading / inflating views & icons for a bubble. */
@SmallTest
@@ -65,11 +67,16 @@
private lateinit var metadataFlagListener: Bubbles.BubbleMetadataFlagListener
private lateinit var iconFactory: BubbleIconFactory
private lateinit var bubble: Bubble
-
private lateinit var bubbleController: BubbleController
private lateinit var mainExecutor: ShellExecutor
private lateinit var bubbleStackView: BubbleStackView
private lateinit var bubbleBarLayerView: BubbleBarLayerView
+ private lateinit var bubblePositioner: BubblePositioner
+ private lateinit var expandedViewManager: BubbleExpandedViewManager
+
+ private val bubbleTaskViewFactory = BubbleTaskViewFactory {
+ BubbleTaskView(mock<TaskView>(), mock<Executor>())
+ }
@Before
fun setup() {
@@ -88,7 +95,7 @@
val shellInit = ShellInit(mainExecutor)
val shellCommandHandler = ShellCommandHandler()
val shellController = ShellController(context, shellInit, shellCommandHandler, mainExecutor)
- val bubblePositioner = BubblePositioner(context, windowManager)
+ bubblePositioner = BubblePositioner(context, windowManager)
val bubbleData =
BubbleData(
context,
@@ -143,6 +150,7 @@
bubbleController,
mainExecutor
)
+ expandedViewManager = BubbleExpandedViewManager.fromBubbleController(bubbleController)
bubbleBarLayerView = BubbleBarLayerView(context, bubbleController, bubbleData)
}
@@ -152,7 +160,9 @@
val info =
BubbleViewInfoTask.BubbleViewInfo.populate(
context,
- bubbleController,
+ expandedViewManager,
+ bubbleTaskViewFactory,
+ bubblePositioner,
bubbleStackView,
iconFactory,
bubble,
@@ -178,7 +188,9 @@
val info =
BubbleViewInfoTask.BubbleViewInfo.populateForBubbleBar(
context,
- bubbleController,
+ expandedViewManager,
+ bubbleTaskViewFactory,
+ bubblePositioner,
bubbleBarLayerView,
iconFactory,
bubble,
@@ -212,7 +224,9 @@
val info =
BubbleViewInfoTask.BubbleViewInfo.populateForBubbleBar(
context,
- bubbleController,
+ expandedViewManager,
+ bubbleTaskViewFactory,
+ bubblePositioner,
bubbleBarLayerView,
iconFactory,
bubble,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 1d428c8..138396e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -95,7 +95,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
@@ -179,9 +178,11 @@
import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleEducationController;
import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.BubbleExpandedViewManager;
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.BubbleTaskView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.Bubbles;
@@ -198,6 +199,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.taskview.TaskView;
import com.android.wm.shell.taskview.TaskViewTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -217,6 +219,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.Executor;
import kotlinx.coroutines.test.TestScope;
@@ -1428,7 +1431,9 @@
.thenReturn(userContext);
BubbleViewInfoTask.BubbleViewInfo info = BubbleViewInfoTask.BubbleViewInfo.populate(context,
- mBubbleController,
+ BubbleExpandedViewManager.fromBubbleController(mBubbleController),
+ () -> new BubbleTaskView(mock(TaskView.class), mock(Executor.class)),
+ mPositioner,
mBubbleController.getStackView(),
new BubbleIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(com.android.wm.shell.R.dimen.bubble_size),