summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Rosky <erosky@google.com> 2021-12-10 17:34:11 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-12-10 17:34:11 +0000
commit0c379593e58b6c0911e6d0deadb260034a0935fb (patch)
treef55415a38d61f63eb2c5749462c2a0c38465139f
parentc0fed62448b26719c41518f905d2781055d979bc (diff)
parent927f9f5c11e95f79b949a68ee85cdd42ced696a2 (diff)
Merge "Hook-up TaskView/bubbles to shell transition"
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java156
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java253
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java182
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java4
11 files changed, 619 insertions, 28 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 2f3214d1d1ab..54e743f72cc6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -41,6 +41,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -77,6 +78,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
private final ShellTaskOrganizer mTaskOrganizer;
private final Executor mShellExecutor;
private final SyncTransactionQueue mSyncQueue;
+ private final TaskViewTransitions mTaskViewTransitions;
private ActivityManager.RunningTaskInfo mTaskInfo;
private WindowContainerToken mTaskToken;
@@ -92,17 +94,27 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
private final Rect mTmpRootRect = new Rect();
private final int[] mTmpLocation = new int[2];
- public TaskView(Context context, ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue) {
+ public TaskView(Context context, ShellTaskOrganizer organizer,
+ TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) {
super(context, null, 0, 0, true /* disableBackgroundLayer */);
mTaskOrganizer = organizer;
mShellExecutor = organizer.getExecutor();
mSyncQueue = syncQueue;
+ mTaskViewTransitions = taskViewTransitions;
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.addTaskView(this);
+ }
setUseAlpha();
getHolder().addCallback(this);
mGuard.open("release");
}
+ /** Until all users are converted, we may have mixed-use (eg. Car). */
+ private boolean isUsingShellTransitions() {
+ return mTaskViewTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS;
+ }
+
/**
* Only one listener may be set on the view, throws an exception otherwise.
*/
@@ -129,6 +141,14 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
@NonNull ActivityOptions options, @Nullable Rect launchBounds) {
prepareActivityOptions(options, launchBounds);
LauncherApps service = mContext.getSystemService(LauncherApps.class);
+ if (isUsingShellTransitions()) {
+ mShellExecutor.execute(() -> {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.startShortcut(mContext.getPackageName(), shortcut, options.toBundle());
+ mTaskViewTransitions.startTaskView(wct, this);
+ });
+ return;
+ }
try {
service.startShortcut(shortcut, null /* sourceBounds */, options.toBundle());
} catch (Exception e) {
@@ -148,6 +168,14 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
@NonNull ActivityOptions options, @Nullable Rect launchBounds) {
prepareActivityOptions(options, launchBounds);
+ if (isUsingShellTransitions()) {
+ mShellExecutor.execute(() -> {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.sendPendingIntent(pendingIntent, fillInIntent, options.toBundle());
+ mTaskViewTransitions.startTaskView(wct, this);
+ });
+ return;
+ }
try {
pendingIntent.send(mContext, 0 /* code */, fillInIntent,
null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -177,6 +205,16 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
mObscuredTouchRect = obscuredRect;
}
+ private void onLocationChanged(WindowContainerTransaction wct) {
+ // Update based on the screen bounds
+ getBoundsOnScreen(mTmpRect);
+ getRootView().getBoundsOnScreen(mTmpRootRect);
+ if (!mTmpRootRect.contains(mTmpRect)) {
+ mTmpRect.offsetTo(0, 0);
+ }
+ wct.setBounds(mTaskToken, mTmpRect);
+ }
+
/**
* Call when view position or size has changed. Do not call when animating.
*/
@@ -184,15 +222,12 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
if (mTaskToken == null) {
return;
}
- // Update based on the screen bounds
- getBoundsOnScreen(mTmpRect);
- getRootView().getBoundsOnScreen(mTmpRootRect);
- if (!mTmpRootRect.contains(mTmpRect)) {
- mTmpRect.offsetTo(0, 0);
- }
+ // Sync Transactions can't operate simultaneously with shell transition collection.
+ // The transition animation (upon showing) will sync the location itself.
+ if (isUsingShellTransitions() && mTaskViewTransitions.hasPending()) return;
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mTaskToken, mTmpRect);
+ onLocationChanged(wct);
mSyncQueue.queue(wct);
}
@@ -217,6 +252,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
private void performRelease() {
getHolder().removeCallback(this);
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.removeTaskView(this);
+ }
mShellExecutor.execute(() -> {
mTaskOrganizer.removeListener(this);
resetTaskInfo();
@@ -254,6 +292,10 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl leash) {
+ if (isUsingShellTransitions()) {
+ // Everything else handled by enter transition.
+ return;
+ }
mTaskInfo = taskInfo;
mTaskToken = taskInfo.token;
mTaskLeash = leash;
@@ -288,6 +330,8 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ // Unlike Appeared, we can't yet guarantee that vanish will happen within a transition that
+ // we know about -- so leave clean-up here even if shell transitions are enabled.
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
if (mListener != null) {
@@ -355,6 +399,10 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
// Nothing to update, task is not yet available
return;
}
+ if (isUsingShellTransitions()) {
+ mTaskViewTransitions.setTaskViewVisible(this, true /* visible */);
+ return;
+ }
// Reparent the task when this surface is created
mTransaction.reparent(mTaskLeash, getSurfaceControl())
.show(mTaskLeash)
@@ -380,6 +428,11 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
return;
}
+ if (isUsingShellTransitions()) {
+ mTaskViewTransitions.setTaskViewVisible(this, false /* visible */);
+ return;
+ }
+
// Unparent the task when this surface is destroyed
mTransaction.reparent(mTaskLeash, null).apply();
updateTaskVisibility();
@@ -421,4 +474,91 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
super.onDetachedFromWindow();
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
}
+
+ ActivityManager.RunningTaskInfo getTaskInfo() {
+ return mTaskInfo;
+ }
+
+ void prepareHideAnimation(@NonNull SurfaceControl.Transaction finishTransaction) {
+ if (mTaskToken == null) {
+ // Nothing to update, task is not yet available
+ return;
+ }
+
+ finishTransaction.reparent(mTaskLeash, null).apply();
+
+ if (mListener != null) {
+ final int taskId = mTaskInfo.taskId;
+ mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated /* visible */);
+ }
+ }
+
+ /**
+ * Called when the associated Task closes. If the TaskView is just being hidden, prepareHide
+ * is used instead.
+ */
+ void prepareCloseAnimation() {
+ if (mTaskToken != null) {
+ if (mListener != null) {
+ final int taskId = mTaskInfo.taskId;
+ mListenerExecutor.execute(() -> {
+ mListener.onTaskRemovalStarted(taskId);
+ });
+ }
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
+ }
+ resetTaskInfo();
+ }
+
+ void prepareOpenAnimation(final boolean newTask,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash,
+ WindowContainerTransaction wct) {
+ mTaskInfo = taskInfo;
+ mTaskToken = mTaskInfo.token;
+ mTaskLeash = leash;
+ if (mSurfaceCreated) {
+ // Surface is ready, so just reparent the task to this surface control
+ startTransaction.reparent(mTaskLeash, getSurfaceControl())
+ .show(mTaskLeash)
+ .apply();
+ // Also reparent on finishTransaction since the finishTransaction will reparent back
+ // to its "original" parent by default.
+ finishTransaction.reparent(mTaskLeash, getSurfaceControl())
+ .setPosition(mTaskLeash, 0, 0)
+ .apply();
+
+ // TODO: determine if this is really necessary or not
+ onLocationChanged(wct);
+ } else {
+ // The surface has already been destroyed before the task has appeared,
+ // so go ahead and hide the task entirely
+ wct.setHidden(mTaskToken, true /* hidden */);
+ // listener callback is below
+ }
+ if (newTask) {
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true /* intercept */);
+ }
+
+ if (mTaskInfo.taskDescription != null) {
+ int backgroundColor = mTaskInfo.taskDescription.getBackgroundColor();
+ setResizeBackgroundColor(startTransaction, backgroundColor);
+ }
+
+ if (mListener != null) {
+ final int taskId = mTaskInfo.taskId;
+ final ComponentName baseActivity = mTaskInfo.baseActivity;
+
+ mListenerExecutor.execute(() -> {
+ if (newTask) {
+ mListener.onTaskCreated(taskId, baseActivity);
+ }
+ // Even if newTask, send a visibilityChange if the surface was destroyed.
+ if (!newTask || !mSurfaceCreated) {
+ mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated /* visible */);
+ }
+ });
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
index 8286d102791e..42844b57b92a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
@@ -31,13 +31,24 @@ public class TaskViewFactoryController {
private final ShellTaskOrganizer mTaskOrganizer;
private final ShellExecutor mShellExecutor;
private final SyncTransactionQueue mSyncQueue;
+ private final TaskViewTransitions mTaskViewTransitions;
private final TaskViewFactory mImpl = new TaskViewFactoryImpl();
public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
+ ShellExecutor shellExecutor, SyncTransactionQueue syncQueue,
+ TaskViewTransitions taskViewTransitions) {
+ mTaskOrganizer = taskOrganizer;
+ mShellExecutor = shellExecutor;
+ mSyncQueue = syncQueue;
+ mTaskViewTransitions = taskViewTransitions;
+ }
+
+ public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
ShellExecutor shellExecutor, SyncTransactionQueue syncQueue) {
mTaskOrganizer = taskOrganizer;
mShellExecutor = shellExecutor;
mSyncQueue = syncQueue;
+ mTaskViewTransitions = null;
}
public TaskViewFactory asTaskViewFactory() {
@@ -46,7 +57,7 @@ public class TaskViewFactoryController {
/** Creates an {@link TaskView} */
public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) {
- TaskView taskView = new TaskView(context, mTaskOrganizer, mSyncQueue);
+ TaskView taskView = new TaskView(context, mTaskOrganizer, mTaskViewTransitions, mSyncQueue);
executor.execute(() -> {
onCreate.accept(taskView);
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java
new file mode 100644
index 000000000000..83335ac24799
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.wm.shell.transition.Transitions;
+
+import java.util.ArrayList;
+
+/**
+ * Handles Shell Transitions that involve TaskView tasks.
+ */
+public class TaskViewTransitions implements Transitions.TransitionHandler {
+ private static final String TAG = "TaskViewTransitions";
+
+ private final ArrayList<TaskView> mTaskViews = new ArrayList<>();
+ private final ArrayList<PendingTransition> mPending = new ArrayList<>();
+ private final Transitions mTransitions;
+ private final boolean[] mRegistered = new boolean[]{ false };
+
+ /**
+ * TaskView makes heavy use of startTransition. Only one shell-initiated transition can be
+ * in-flight (collecting) at a time (because otherwise, the operations could get merged into
+ * a single transition). So, keep a queue here until we add a queue in server-side.
+ */
+ private static class PendingTransition {
+ final @WindowManager.TransitionType int mType;
+ final WindowContainerTransaction mWct;
+ final @NonNull TaskView mTaskView;
+ IBinder mClaimed;
+
+ PendingTransition(@WindowManager.TransitionType int type,
+ @Nullable WindowContainerTransaction wct, @NonNull TaskView taskView) {
+ mType = type;
+ mWct = wct;
+ mTaskView = taskView;
+ }
+ }
+
+ public TaskViewTransitions(Transitions transitions) {
+ mTransitions = transitions;
+ // Defer registration until the first TaskView because we want this to be the "first" in
+ // priority when handling requests.
+ // TODO(210041388): register here once we have an explicit ordering mechanism.
+ }
+
+ void addTaskView(TaskView tv) {
+ synchronized (mRegistered) {
+ if (!mRegistered[0]) {
+ mRegistered[0] = true;
+ mTransitions.addHandler(this);
+ }
+ }
+ mTaskViews.add(tv);
+ }
+
+ void removeTaskView(TaskView tv) {
+ mTaskViews.remove(tv);
+ // Note: Don't unregister handler since this is a singleton with lifetime bound to Shell
+ }
+
+ /**
+ * Looks through the pending transitions for one matching `taskView`.
+ * @param taskView the pending transition should be for this.
+ * @param closing When true, this only returns a pending transition of the close/hide type.
+ * Otherwise it selects open/show.
+ * @param latest When true, this will only check the most-recent pending transition for the
+ * specified taskView. If it doesn't match `closing`, this will return null even
+ * if there is a match earlier. The idea behind this is to check the state of
+ * the taskviews "as if all transitions already happened".
+ */
+ private PendingTransition findPending(TaskView taskView, boolean closing, boolean latest) {
+ for (int i = mPending.size() - 1; i >= 0; --i) {
+ if (mPending.get(i).mTaskView != taskView) continue;
+ if (Transitions.isClosingType(mPending.get(i).mType) == closing) {
+ return mPending.get(i);
+ }
+ if (latest) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private PendingTransition findPending(IBinder claimed) {
+ for (int i = 0; i < mPending.size(); ++i) {
+ if (mPending.get(i).mClaimed != claimed) continue;
+ return mPending.get(i);
+ }
+ return null;
+ }
+
+ /** @return whether there are pending transitions on TaskViews. */
+ public boolean hasPending() {
+ return !mPending.isEmpty();
+ }
+
+ @Override
+ public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+ @Nullable TransitionRequestInfo request) {
+ final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
+ if (triggerTask == null) {
+ return null;
+ }
+ final TaskView taskView = findTaskView(triggerTask);
+ if (taskView == null) return null;
+ // Opening types should all be initiated by shell
+ if (!Transitions.isClosingType(request.getType())) return null;
+ PendingTransition pending = findPending(taskView, true /* closing */, false /* latest */);
+ if (pending == null) {
+ pending = new PendingTransition(request.getType(), null, taskView);
+ }
+ if (pending.mClaimed != null) {
+ throw new IllegalStateException("Task is closing in 2 collecting transitions?"
+ + " This state doesn't make sense");
+ }
+ pending.mClaimed = transition;
+ return new WindowContainerTransaction();
+ }
+
+ private TaskView findTaskView(ActivityManager.RunningTaskInfo taskInfo) {
+ for (int i = 0; i < mTaskViews.size(); ++i) {
+ if (mTaskViews.get(i).getTaskInfo() == null) continue;
+ if (taskInfo.token.equals(mTaskViews.get(i).getTaskInfo().token)) {
+ return mTaskViews.get(i);
+ }
+ }
+ return null;
+ }
+
+ void startTaskView(WindowContainerTransaction wct, TaskView taskView) {
+ mPending.add(new PendingTransition(TRANSIT_OPEN, wct, taskView));
+ startNextTransition();
+ }
+
+ void setTaskViewVisible(TaskView taskView, boolean visible) {
+ PendingTransition pending = findPending(taskView, !visible, true /* latest */);
+ if (pending != null) {
+ // Already opening or creating a task, so no need to do anything here.
+ return;
+ }
+ if (taskView.getTaskInfo() == null) {
+ // Nothing to update, task is not yet available
+ return;
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setHidden(taskView.getTaskInfo().token, !visible /* hidden */);
+ pending = new PendingTransition(
+ visible ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK, wct, taskView);
+ mPending.add(pending);
+ startNextTransition();
+ // visibility is reported in transition.
+ }
+
+ private void startNextTransition() {
+ if (mPending.isEmpty()) return;
+ final PendingTransition pending = mPending.get(0);
+ if (pending.mClaimed != null) {
+ // Wait for this to start animating.
+ return;
+ }
+ pending.mClaimed = mTransitions.startTransition(pending.mType, pending.mWct, this);
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ PendingTransition pending = findPending(transition);
+ if (pending == null) return false;
+ mPending.remove(pending);
+ TaskView taskView = pending.mTaskView;
+ final ArrayList<TransitionInfo.Change> tasks = new ArrayList<>();
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ final TransitionInfo.Change chg = info.getChanges().get(i);
+ if (chg.getTaskInfo() == null) continue;
+ tasks.add(chg);
+ }
+ if (tasks.isEmpty()) {
+ Slog.e(TAG, "Got a TaskView transition with no task.");
+ return false;
+ }
+ WindowContainerTransaction wct = null;
+ for (int i = 0; i < tasks.size(); ++i) {
+ TransitionInfo.Change chg = tasks.get(i);
+ if (Transitions.isClosingType(chg.getMode())) {
+ final boolean isHide = chg.getMode() == TRANSIT_TO_BACK;
+ TaskView tv = findTaskView(chg.getTaskInfo());
+ if (tv == null) {
+ throw new IllegalStateException("TaskView transition is closing a "
+ + "non-taskview task ");
+ }
+ if (isHide) {
+ tv.prepareHideAnimation(finishTransaction);
+ } else {
+ tv.prepareCloseAnimation();
+ }
+ } else if (Transitions.isOpeningType(chg.getMode())) {
+ final boolean taskIsNew = chg.getMode() == TRANSIT_OPEN;
+ if (wct == null) wct = new WindowContainerTransaction();
+ TaskView tv = taskView;
+ if (!taskIsNew) {
+ tv = findTaskView(chg.getTaskInfo());
+ if (tv == null) {
+ throw new IllegalStateException("TaskView transition is showing a "
+ + "non-taskview task ");
+ }
+ }
+ tv.prepareOpenAnimation(taskIsNew, startTransaction, finishTransaction,
+ chg.getTaskInfo(), chg.getLeash(), wct);
+ } else {
+ throw new IllegalStateException("Claimed transition isn't an opening or closing"
+ + " type: " + chg.getMode());
+ }
+ }
+ // No animation, just show it immediately.
+ startTransaction.apply();
+ finishTransaction.apply();
+ finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ startNextTransition();
+ return true;
+ }
+}
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 ec59fad3e95b..f979f4d3b41f 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
@@ -80,6 +80,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
@@ -136,6 +137,7 @@ public class BubbleController {
private final TaskStackListenerImpl mTaskStackListener;
private final ShellTaskOrganizer mTaskOrganizer;
private final DisplayController mDisplayController;
+ private final TaskViewTransitions mTaskViewTransitions;
private final SyncTransactionQueue mSyncQueue;
// Used to post to main UI thread
@@ -212,6 +214,7 @@ public class BubbleController {
DisplayController displayController,
ShellExecutor mainExecutor,
Handler mainHandler,
+ TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
BubblePositioner positioner = new BubblePositioner(context, windowManager);
@@ -220,7 +223,7 @@ public class BubbleController {
new BubbleDataRepository(context, launcherApps, mainExecutor),
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
logger, taskStackListener, organizer, positioner, displayController, mainExecutor,
- mainHandler, syncQueue);
+ mainHandler, taskViewTransitions, syncQueue);
}
/**
@@ -243,6 +246,7 @@ public class BubbleController {
DisplayController displayController,
ShellExecutor mainExecutor,
Handler mainHandler,
+ TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
mContext = context;
mLauncherApps = launcherApps;
@@ -266,6 +270,7 @@ public class BubbleController {
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mBubbleIconFactory = new BubbleIconFactory(context);
mDisplayController = displayController;
+ mTaskViewTransitions = taskViewTransitions;
mSyncQueue = syncQueue;
}
@@ -570,6 +575,10 @@ public class BubbleController {
return mSyncQueue;
}
+ TaskViewTransitions getTaskViewTransitions() {
+ return mTaskViewTransitions;
+ }
+
/** Contains information to help position things on the screen. */
BubblePositioner getPositioner() {
return mBubblePositioner;
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 a87aad4261a6..af59062ba0f3 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
@@ -335,7 +335,7 @@ public class BubbleExpandedView extends LinearLayout {
mManageButton.setVisibility(GONE);
} else {
mTaskView = new TaskView(mContext, mController.getTaskOrganizer(),
- mController.getSyncTransactionQueue());
+ mController.getTaskViewTransitions(), mController.getSyncTransactionQueue());
mTaskView.setListener(mController.getMainExecutor(), mTaskViewListener);
mExpandedViewContainer.addView(mTaskView);
bringChildToFront(mTaskView);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 54ce6bb7acba..7bc8d23d81de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -36,6 +36,7 @@ import com.android.wm.shell.ShellInitImpl;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.TaskViewFactoryController;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.apppairs.AppPairsController;
@@ -463,6 +464,12 @@ public abstract class WMShellBaseModule {
animExecutor);
}
+ @WMSingleton
+ @Provides
+ static TaskViewTransitions provideTaskViewTransitions(Transitions transitions) {
+ return new TaskViewTransitions(transitions);
+ }
+
//
// Display areas
//
@@ -594,8 +601,10 @@ public abstract class WMShellBaseModule {
static TaskViewFactoryController provideTaskViewFactoryController(
ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor,
- SyncTransactionQueue syncQueue) {
- return new TaskViewFactoryController(shellTaskOrganizer, mainExecutor, syncQueue);
+ SyncTransactionQueue syncQueue,
+ TaskViewTransitions taskViewTransitions) {
+ return new TaskViewFactoryController(shellTaskOrganizer, mainExecutor, syncQueue,
+ taskViewTransitions);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index f562fd9cf1af..dff563589e5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -27,6 +27,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.bubbles.BubbleController;
@@ -108,11 +109,13 @@ public class WMShellModule {
DisplayController displayController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
+ TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
return BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, taskStackListener,
- uiEventLogger, organizer, displayController, mainExecutor, mainHandler, syncQueue);
+ uiEventLogger, organizer, displayController, mainExecutor, mainHandler,
+ taskViewTransitions, syncQueue);
}
//
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 1cbad155ba7b..03df92fd8477 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,12 +45,14 @@ import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SyncTransactionQueue.TransactionRunnable;
+import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
@@ -75,6 +79,8 @@ public class TaskViewTest extends ShellTestCase {
HandlerExecutor mExecutor;
@Mock
SyncTransactionQueue mSyncQueue;
+ @Mock
+ TaskViewTransitions mTaskViewTransitions;
SurfaceSession mSession;
SurfaceControl mLeash;
@@ -110,7 +116,7 @@ public class TaskViewTest extends ShellTestCase {
return null;
}).when(mSyncQueue).runInSync(any());
- mTaskView = new TaskView(mContext, mOrganizer, mSyncQueue);
+ mTaskView = new TaskView(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue);
mTaskView.setListener(mExecutor, mViewListener);
}
@@ -123,7 +129,7 @@ public class TaskViewTest extends ShellTestCase {
@Test
public void testSetPendingListener_throwsException() {
- TaskView taskView = new TaskView(mContext, mOrganizer, mSyncQueue);
+ TaskView taskView = new TaskView(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue);
taskView.setListener(mExecutor, mViewListener);
try {
taskView.setListener(mExecutor, mViewListener);
@@ -144,7 +150,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testOnTaskAppeared_noSurface() {
+ public void testOnTaskAppeared_noSurface_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
@@ -154,7 +161,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testOnTaskAppeared_withSurface() {
+ public void testOnTaskAppeared_withSurface_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
@@ -163,7 +171,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testSurfaceCreated_noTask() {
+ public void testSurfaceCreated_noTask_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
verify(mViewListener).onInitialized();
@@ -172,7 +181,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testSurfaceCreated_withTask() {
+ public void testSurfaceCreated_withTask_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
@@ -181,7 +191,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testSurfaceDestroyed_noTask() {
+ public void testSurfaceDestroyed_noTask_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
SurfaceHolder sh = mock(SurfaceHolder.class);
mTaskView.surfaceCreated(sh);
mTaskView.surfaceDestroyed(sh);
@@ -190,7 +201,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testSurfaceDestroyed_withTask() {
+ public void testSurfaceDestroyed_withTask_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
SurfaceHolder sh = mock(SurfaceHolder.class);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
mTaskView.surfaceCreated(sh);
@@ -201,7 +213,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testOnReleased() {
+ public void testOnReleased_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
mTaskView.release();
@@ -211,7 +224,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testOnTaskVanished() {
+ public void testOnTaskVanished_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
mTaskView.onTaskVanished(mTaskInfo);
@@ -220,7 +234,8 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testOnBackPressedOnTaskRoot() {
+ public void testOnBackPressedOnTaskRoot_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
mTaskView.onBackPressedOnTaskRoot(mTaskInfo);
@@ -228,17 +243,158 @@ public class TaskViewTest extends ShellTestCase {
}
@Test
- public void testSetOnBackPressedOnTaskRoot() {
+ public void testSetOnBackPressedOnTaskRoot_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(true));
}
@Test
- public void testUnsetOnBackPressedOnTaskRoot() {
+ public void testUnsetOnBackPressedOnTaskRoot_legacyTransitions() {
+ assumeFalse(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(true));
mTaskView.onTaskVanished(mTaskInfo);
verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(false));
}
+
+ @Test
+ public void testOnNewTask_noSurface() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+
+ verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
+ verify(mViewListener, never()).onInitialized();
+ // If there's no surface the task should be made invisible
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(false));
+ }
+
+ @Test
+ public void testSurfaceCreated_noTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ verify(mTaskViewTransitions, never()).setTaskViewVisible(any(), anyBoolean());
+
+ verify(mViewListener).onInitialized();
+ // No task, no visibility change
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testOnNewTask_withSurface() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+
+ verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testSurfaceCreated_withTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+
+ verify(mViewListener).onInitialized();
+ verify(mTaskViewTransitions).setTaskViewVisible(eq(mTaskView), eq(true));
+
+ mTaskView.prepareOpenAnimation(false /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(true));
+ }
+
+ @Test
+ public void testSurfaceDestroyed_noTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ SurfaceHolder sh = mock(SurfaceHolder.class);
+ mTaskView.surfaceCreated(sh);
+ mTaskView.surfaceDestroyed(sh);
+
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testSurfaceDestroyed_withTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ SurfaceHolder sh = mock(SurfaceHolder.class);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ mTaskView.surfaceCreated(sh);
+ reset(mViewListener);
+ mTaskView.surfaceDestroyed(sh);
+
+ verify(mTaskViewTransitions).setTaskViewVisible(eq(mTaskView), eq(false));
+
+ mTaskView.prepareHideAnimation(new SurfaceControl.Transaction());
+
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(false));
+ }
+
+ @Test
+ public void testOnReleased() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ mTaskView.release();
+
+ verify(mOrganizer).removeListener(eq(mTaskView));
+ verify(mViewListener).onReleased();
+ verify(mTaskViewTransitions).removeTaskView(eq(mTaskView));
+ }
+
+ @Test
+ public void testOnTaskVanished() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ mTaskView.prepareCloseAnimation();
+
+ verify(mViewListener).onTaskRemovalStarted(eq(mTaskInfo.taskId));
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ mTaskView.onBackPressedOnTaskRoot(mTaskInfo);
+
+ verify(mViewListener).onBackPressedOnTaskRoot(eq(mTaskInfo.taskId));
+ }
+
+ @Test
+ public void testSetOnBackPressedOnTaskRoot() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(true));
+ }
+
+ @Test
+ public void testUnsetOnBackPressedOnTaskRoot() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskView.prepareOpenAnimation(true /* newTask */, new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct);
+ verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(true));
+
+ mTaskView.prepareCloseAnimation();
+ verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(false));
+ }
}
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 c35d51ad629f..71ae5eb028a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -108,6 +108,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleData;
@@ -246,6 +247,8 @@ public class BubblesTest extends SysuiTestCase {
private ScreenOffAnimationController mScreenOffAnimationController;
@Mock
private AuthController mAuthController;
+ @Mock
+ private TaskViewTransitions mTaskViewTransitions;
private TestableBubblePositioner mPositioner;
@@ -344,6 +347,7 @@ public class BubblesTest extends SysuiTestCase {
mock(DisplayController.class),
syncExecutor,
mock(Handler.class),
+ mTaskViewTransitions,
mock(SyncTransactionQueue.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
spyOn(mBubbleController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index e2fce67e8b78..7b9e6a9efb3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -90,6 +90,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleData;
@@ -217,6 +218,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
private KeyguardStateController mKeyguardStateController;
@Mock
private ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock
+ private TaskViewTransitions mTaskViewTransitions;
private TestableBubblePositioner mPositioner;
@@ -306,6 +309,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mock(DisplayController.class),
syncExecutor,
mock(Handler.class),
+ mTaskViewTransitions,
mock(SyncTransactionQueue.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
spyOn(mBubbleController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 7b77cb0b5b30..80834c8130e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -23,6 +23,7 @@ import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleData;
@@ -56,11 +57,12 @@ public class TestableBubbleController extends BubbleController {
DisplayController displayController,
ShellExecutor shellMainExecutor,
Handler shellMainHandler,
+ TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
- shellMainExecutor, shellMainHandler, syncQueue);
+ shellMainExecutor, shellMainHandler, taskViewTransitions, syncQueue);
setInflateSynchronously(true);
initialize();
}