From 73166e71d0c9e681cc03b13febd67928da292003 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Mon, 3 Oct 2022 09:48:41 -0700 Subject: [PATCH] Put window decors at one place There are some juggling between task listeners and the transition observer of window decors because they are hosts together with its corresponding task states. This change can remove those juggling by putting all of them at one place. Bug: 250622579 Test: atest WMShellUnitTests Change-Id: Ic1db1633a5e79e2bcea5885b8fc2f345fa05fb1e --- .../wm/shell/dagger/WMShellBaseModule.java | 12 +- .../wm/shell/dagger/WMShellModule.java | 18 +- .../shell/freeform/FreeformTaskListener.java | 174 ++-------------- .../FreeformTaskTransitionHandler.java | 4 +- .../FreeformTaskTransitionObserver.java | 133 +++---------- .../fullscreen/FullscreenTaskListener.java | 188 ++---------------- .../CaptionWindowDecorViewModel.java | 44 ++-- .../windowdecor/WindowDecorViewModel.java | 31 +-- .../FreeformTaskTransitionObserverTest.java | 91 ++------- 9 files changed, 131 insertions(+), 564 deletions(-) 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 353014264990b..6645e7828aea0 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 @@ -289,17 +289,17 @@ public abstract class WMShellBaseModule { // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} @BindsOptionalOf @DynamicOverride - abstract FullscreenTaskListener optionalFullscreenTaskListener(); + abstract FullscreenTaskListener optionalFullscreenTaskListener(); @WMSingleton @Provides - static FullscreenTaskListener provideFullscreenTaskListener( - @DynamicOverride Optional> fullscreenTaskListener, + static FullscreenTaskListener provideFullscreenTaskListener( + @DynamicOverride Optional fullscreenTaskListener, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Optional recentTasksOptional, - Optional> windowDecorViewModelOptional) { + Optional windowDecorViewModelOptional) { if (fullscreenTaskListener.isPresent()) { return fullscreenTaskListener.get(); } else { @@ -313,7 +313,7 @@ public abstract class WMShellBaseModule { // @BindsOptionalOf - abstract WindowDecorViewModel optionalWindowDecorViewModel(); + abstract WindowDecorViewModel optionalWindowDecorViewModel(); // // Unfold transition @@ -765,7 +765,7 @@ public abstract class WMShellBaseModule { Optional splitScreenOptional, Optional pipOptional, Optional pipTouchHandlerOptional, - FullscreenTaskListener fullscreenTaskListener, + FullscreenTaskListener fullscreenTaskListener, Optional unfoldAnimationController, Optional unfoldTransitionHandler, Optional freeformComponents, 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 47b665970d283..461d7dcf30ad3 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 @@ -55,7 +55,6 @@ import com.android.wm.shell.freeform.FreeformComponents; import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.freeform.FreeformTaskTransitionHandler; import com.android.wm.shell.freeform.FreeformTaskTransitionObserver; -import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; @@ -183,7 +182,7 @@ public abstract class WMShellModule { @WMSingleton @Provides - static WindowDecorViewModel provideWindowDecorViewModel( + static WindowDecorViewModel provideWindowDecorViewModel( Context context, @ShellMainThread Handler mainHandler, @ShellMainThread Choreographer mainChoreographer, @@ -209,7 +208,7 @@ public abstract class WMShellModule { @Provides @DynamicOverride static FreeformComponents provideFreeformComponents( - FreeformTaskListener taskListener, + FreeformTaskListener taskListener, FreeformTaskTransitionHandler transitionHandler, FreeformTaskTransitionObserver transitionObserver) { return new FreeformComponents( @@ -218,18 +217,18 @@ public abstract class WMShellModule { @WMSingleton @Provides - static FreeformTaskListener provideFreeformTaskListener( + static FreeformTaskListener provideFreeformTaskListener( Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Optional desktopModeTaskRepository, - WindowDecorViewModel windowDecorViewModel) { + WindowDecorViewModel windowDecorViewModel) { // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic // override for this controller from the base module ShellInit init = FreeformComponents.isFreeformEnabled(context) ? shellInit : null; - return new FreeformTaskListener<>(init, shellTaskOrganizer, desktopModeTaskRepository, + return new FreeformTaskListener(init, shellTaskOrganizer, desktopModeTaskRepository, windowDecorViewModel); } @@ -238,7 +237,7 @@ public abstract class WMShellModule { static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler( ShellInit shellInit, Transitions transitions, - WindowDecorViewModel windowDecorViewModel) { + WindowDecorViewModel windowDecorViewModel) { return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel); } @@ -248,10 +247,9 @@ public abstract class WMShellModule { Context context, ShellInit shellInit, Transitions transitions, - FullscreenTaskListener fullscreenTaskListener, - FreeformTaskListener freeformTaskListener) { + WindowDecorViewModel windowDecorViewModel) { return new FreeformTaskTransitionObserver( - context, shellInit, transitions, fullscreenTaskListener, freeformTaskListener); + context, shellInit, transitions, windowDecorViewModel); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index e2d5a499d1e11..f82a34621262b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -19,12 +19,8 @@ package com.android.wm.shell.freeform; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM; import android.app.ActivityManager.RunningTaskInfo; -import android.util.Log; import android.util.SparseArray; import android.view.SurfaceControl; -import android.window.TransitionInfo; - -import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; @@ -41,31 +37,26 @@ import java.util.Optional; /** * {@link ShellTaskOrganizer.TaskListener} for {@link * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}. - * - * @param the type of window decoration instance */ -public class FreeformTaskListener - implements ShellTaskOrganizer.TaskListener { +public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FreeformTaskListener"; private final ShellTaskOrganizer mShellTaskOrganizer; private final Optional mDesktopModeTaskRepository; - private final WindowDecorViewModel mWindowDecorationViewModel; + private final WindowDecorViewModel mWindowDecorationViewModel; - private final SparseArray> mTasks = new SparseArray<>(); - private final SparseArray mWindowDecorOfVanishedTasks = new SparseArray<>(); + private final SparseArray mTasks = new SparseArray<>(); - private static class State { + private static class State { RunningTaskInfo mTaskInfo; SurfaceControl mLeash; - T mWindowDecoration; } public FreeformTaskListener( ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Optional desktopModeTaskRepository, - WindowDecorViewModel windowDecorationViewModel) { + WindowDecorViewModel windowDecorationViewModel) { mShellTaskOrganizer = shellTaskOrganizer; mWindowDecorationViewModel = windowDecorationViewModel; mDesktopModeTaskRepository = desktopModeTaskRepository; @@ -80,13 +71,18 @@ public class FreeformTaskListener @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { + if (mTasks.get(taskInfo.taskId) != null) { + throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId); + } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d", taskInfo.taskId); - final State state = createOrUpdateTaskState(taskInfo, leash); + final State state = new State(); + state.mTaskInfo = taskInfo; + state.mLeash = leash; + mTasks.put(taskInfo.taskId, state); if (!Transitions.ENABLE_SHELL_TRANSITIONS) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - state.mWindowDecoration = - mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t); + mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t); t.apply(); } @@ -97,28 +93,8 @@ public class FreeformTaskListener } } - private State createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) { - State state = mTasks.get(taskInfo.taskId); - if (state != null) { - updateTaskInfo(taskInfo); - return state; - } - - state = new State<>(); - state.mTaskInfo = taskInfo; - state.mLeash = leash; - mTasks.put(taskInfo.taskId, state); - - return state; - } - @Override public void onTaskVanished(RunningTaskInfo taskInfo) { - final State state = mTasks.get(taskInfo.taskId); - if (state == null) { - // This is possible if the transition happens before this method. - return; - } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d", taskInfo.taskId); mTasks.remove(taskInfo.taskId); @@ -129,26 +105,18 @@ public class FreeformTaskListener mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(taskInfo.taskId)); } - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - // Save window decorations of closing tasks so that we can hand them over to the - // transition system if this method happens before the transition. In case where the - // transition didn't happen, it'd be cleared when the next transition finished. - if (state.mWindowDecoration != null) { - mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration); - } - return; + if (!Transitions.ENABLE_SHELL_TRANSITIONS) { + mWindowDecorationViewModel.destroyWindowDecoration(taskInfo); } - releaseWindowDecor(state.mWindowDecoration); } @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { - final State state = updateTaskInfo(taskInfo); + final State state = mTasks.get(taskInfo.taskId); + state.mTaskInfo = taskInfo; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d", taskInfo.taskId); - if (state.mWindowDecoration != null) { - mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration); - } + mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo); if (DesktopModeStatus.IS_SUPPORTED) { if (taskInfo.isVisible) { @@ -159,15 +127,6 @@ public class FreeformTaskListener } } - private State updateTaskInfo(RunningTaskInfo taskInfo) { - final State state = mTasks.get(taskInfo.taskId); - if (state == null) { - throw new RuntimeException("Task info changed before appearing: #" + taskInfo.taskId); - } - state.mTaskInfo = taskInfo; - return state; - } - @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { b.setParent(findTaskSurface(taskId)); @@ -186,103 +145,6 @@ public class FreeformTaskListener return mTasks.get(taskId).mLeash; } - /** - * Creates a window decoration for a transition. - * - * @param change the change of this task transition that needs to have the task layer as the - * leash - * @return {@code true} if it creates the window decoration; {@code false} otherwise - */ - boolean createWindowDecoration( - TransitionInfo.Change change, - SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT) { - final State state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash()); - if (state.mWindowDecoration != null) { - return false; - } - state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration( - state.mTaskInfo, state.mLeash, startT, finishT); - return true; - } - - /** - * Gives out the ownership of the task's window decoration. The given task is leaving (of has - * left) this task listener. This is the transition system asking for the ownership. - * - * @param taskInfo the maximizing task - * @return the window decor of the maximizing task if any - */ - T giveWindowDecoration( - RunningTaskInfo taskInfo, - SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT) { - T windowDecor; - final State state = mTasks.get(taskInfo.taskId); - if (state != null) { - windowDecor = state.mWindowDecoration; - state.mWindowDecoration = null; - } else { - windowDecor = - mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId); - } - if (windowDecor == null) { - return null; - } - mWindowDecorationViewModel.setupWindowDecorationForTransition( - taskInfo, startT, finishT, windowDecor); - return windowDecor; - } - - /** - * Adopt the incoming window decoration and lets the window decoration prepare for a transition. - * - * @param change the change of this task transition that needs to have the task layer as the - * leash - * @param startT the start transaction of this transition - * @param finishT the finish transaction of this transition - * @param windowDecor the window decoration to adopt - * @return {@code true} if it adopts the window decoration; {@code false} otherwise - */ - boolean adoptWindowDecoration( - TransitionInfo.Change change, - SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT, - @Nullable AutoCloseable windowDecor) { - final State state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash()); - state.mWindowDecoration = mWindowDecorationViewModel.adoptWindowDecoration(windowDecor); - if (state.mWindowDecoration != null) { - mWindowDecorationViewModel.setupWindowDecorationForTransition( - state.mTaskInfo, startT, finishT, state.mWindowDecoration); - return true; - } else { - state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration( - state.mTaskInfo, state.mLeash, startT, finishT); - return false; - } - } - - void onTaskTransitionFinished() { - if (mWindowDecorOfVanishedTasks.size() == 0) { - return; - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, - "Clearing window decors of vanished tasks. There could be visual defects " - + "if any of them is used later in transitions."); - for (int i = 0; i < mWindowDecorOfVanishedTasks.size(); ++i) { - releaseWindowDecor(mWindowDecorOfVanishedTasks.valueAt(i)); - } - mWindowDecorOfVanishedTasks.clear(); - } - - private void releaseWindowDecor(T windowDecor) { - try { - windowDecor.close(); - } catch (Exception e) { - Log.e(TAG, "Failed to release window decoration.", e); - } - } - @Override public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index fd4c85fad77fa..04fc79acadbdd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -46,14 +46,14 @@ public class FreeformTaskTransitionHandler implements Transitions.TransitionHandler, FreeformTaskTransitionStarter { private final Transitions mTransitions; - private final WindowDecorViewModel mWindowDecorViewModel; + private final WindowDecorViewModel mWindowDecorViewModel; private final List mPendingTransitionTokens = new ArrayList<>(); public FreeformTaskTransitionHandler( ShellInit shellInit, Transitions transitions, - WindowDecorViewModel windowDecorViewModel) { + WindowDecorViewModel windowDecorViewModel) { mTransitions = transitions; mWindowDecorViewModel = windowDecorViewModel; if (Transitions.ENABLE_SHELL_TRANSITIONS) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java index 17d60671e9644..f4888fbb2bb97 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java @@ -16,13 +16,9 @@ package com.android.wm.shell.freeform; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; - import android.app.ActivityManager; import android.content.Context; import android.os.IBinder; -import android.util.Log; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; @@ -31,9 +27,9 @@ import android.window.WindowContainerToken; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; +import com.android.wm.shell.windowdecor.WindowDecorViewModel; import java.util.ArrayList; import java.util.Collections; @@ -47,23 +43,19 @@ import java.util.Map; * be a part of transitions. */ public class FreeformTaskTransitionObserver implements Transitions.TransitionObserver { - private static final String TAG = "FreeformTO"; - private final Transitions mTransitions; - private final FreeformTaskListener mFreeformTaskListener; - private final FullscreenTaskListener mFullscreenTaskListener; + private final WindowDecorViewModel mWindowDecorViewModel; - private final Map> mTransitionToWindowDecors = new HashMap<>(); + private final Map> mTransitionToTaskInfo = + new HashMap<>(); public FreeformTaskTransitionObserver( Context context, ShellInit shellInit, Transitions transitions, - FullscreenTaskListener fullscreenTaskListener, - FreeformTaskListener freeformTaskListener) { + WindowDecorViewModel windowDecorViewModel) { mTransitions = transitions; - mFreeformTaskListener = freeformTaskListener; - mFullscreenTaskListener = fullscreenTaskListener; + mWindowDecorViewModel = windowDecorViewModel; if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) { shellInit.addInitCallback(this::onInit, this); } @@ -80,7 +72,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT) { - final ArrayList windowDecors = new ArrayList<>(); + final ArrayList taskInfoList = new ArrayList<>(); final ArrayList taskParents = new ArrayList<>(); for (TransitionInfo.Change change : info.getChanges()) { if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) { @@ -110,92 +102,40 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs onOpenTransitionReady(change, startT, finishT); break; case WindowManager.TRANSIT_CLOSE: { - onCloseTransitionReady(change, windowDecors, startT, finishT); + taskInfoList.add(change.getTaskInfo()); + onCloseTransitionReady(change, startT, finishT); break; } case WindowManager.TRANSIT_CHANGE: - onChangeTransitionReady(info.getType(), change, startT, finishT); + onChangeTransitionReady(change, startT, finishT); break; } } - if (!windowDecors.isEmpty()) { - mTransitionToWindowDecors.put(transition, windowDecors); - } + mTransitionToTaskInfo.put(transition, taskInfoList); } private void onOpenTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - switch (change.getTaskInfo().getWindowingMode()){ - case WINDOWING_MODE_FREEFORM: - mFreeformTaskListener.createWindowDecoration(change, startT, finishT); - break; - case WINDOWING_MODE_FULLSCREEN: - mFullscreenTaskListener.createWindowDecoration(change, startT, finishT); - break; - } + mWindowDecorViewModel.createWindowDecoration( + change.getTaskInfo(), change.getLeash(), startT, finishT); } private void onCloseTransitionReady( TransitionInfo.Change change, - ArrayList windowDecors, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - final AutoCloseable windowDecor; - switch (change.getTaskInfo().getWindowingMode()) { - case WINDOWING_MODE_FREEFORM: - windowDecor = mFreeformTaskListener.giveWindowDecoration(change.getTaskInfo(), - startT, finishT); - break; - case WINDOWING_MODE_FULLSCREEN: - windowDecor = mFullscreenTaskListener.giveWindowDecoration(change.getTaskInfo(), - startT, finishT); - break; - default: - windowDecor = null; - } - if (windowDecor != null) { - windowDecors.add(windowDecor); - } + mWindowDecorViewModel.setupWindowDecorationForTransition( + change.getTaskInfo(), startT, finishT); } private void onChangeTransitionReady( - int type, TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - AutoCloseable windowDecor = null; - - boolean adopted = false; - final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { - windowDecor = mFreeformTaskListener.giveWindowDecoration( - change.getTaskInfo(), startT, finishT); - if (windowDecor != null) { - adopted = mFullscreenTaskListener.adoptWindowDecoration( - change, startT, finishT, windowDecor); - } else { - // will return false if it already has the window decor. - adopted = mFullscreenTaskListener.createWindowDecoration(change, startT, finishT); - } - } - - if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { - windowDecor = mFullscreenTaskListener.giveWindowDecoration( - change.getTaskInfo(), startT, finishT); - if (windowDecor != null) { - adopted = mFreeformTaskListener.adoptWindowDecoration( - change, startT, finishT, windowDecor); - } else { - // will return false if it already has the window decor. - adopted = mFreeformTaskListener.createWindowDecoration(change, startT, finishT); - } - } - - if (!adopted) { - releaseWindowDecor(windowDecor); - } + mWindowDecorViewModel.setupWindowDecorationForTransition( + change.getTaskInfo(), startT, finishT); } @Override @@ -203,43 +143,32 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs @Override public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) { - final List windowDecorsOfMerged = mTransitionToWindowDecors.get(merged); - if (windowDecorsOfMerged == null) { + final List infoOfMerged = + mTransitionToTaskInfo.get(merged); + if (infoOfMerged == null) { // We are adding window decorations of the merged transition to them of the playing // transition so if there is none of them there is nothing to do. return; } - mTransitionToWindowDecors.remove(merged); + mTransitionToTaskInfo.remove(merged); - final List windowDecorsOfPlaying = mTransitionToWindowDecors.get(playing); - if (windowDecorsOfPlaying != null) { - windowDecorsOfPlaying.addAll(windowDecorsOfMerged); + final List infoOfPlaying = + mTransitionToTaskInfo.get(playing); + if (infoOfPlaying != null) { + infoOfPlaying.addAll(infoOfMerged); } else { - mTransitionToWindowDecors.put(playing, windowDecorsOfMerged); + mTransitionToTaskInfo.put(playing, infoOfMerged); } } @Override public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) { - final List windowDecors = mTransitionToWindowDecors.getOrDefault( - transition, Collections.emptyList()); - mTransitionToWindowDecors.remove(transition); + final List taskInfo = + mTransitionToTaskInfo.getOrDefault(transition, Collections.emptyList()); + mTransitionToTaskInfo.remove(transition); - for (AutoCloseable windowDecor : windowDecors) { - releaseWindowDecor(windowDecor); - } - mFullscreenTaskListener.onTaskTransitionFinished(); - mFreeformTaskListener.onTaskTransitionFinished(); - } - - private static void releaseWindowDecor(AutoCloseable windowDecor) { - if (windowDecor == null) { - return; - } - try { - windowDecor.close(); - } catch (Exception e) { - Log.e(TAG, "Failed to release window decoration.", e); + for (int i = 0; i < taskInfo.size(); ++i) { + mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i)); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java index 76e296bb8c610..75a4091c7d782 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java @@ -22,13 +22,10 @@ import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.graphics.Point; -import android.util.Log; import android.util.SparseArray; import android.view.SurfaceControl; -import android.window.TransitionInfo; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; @@ -46,23 +43,20 @@ import java.util.Optional; * Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}. * @param the type of window decoration instance */ -public class FullscreenTaskListener - implements ShellTaskOrganizer.TaskListener { +public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FullscreenTaskListener"; private final ShellTaskOrganizer mShellTaskOrganizer; - private final SparseArray> mTasks = new SparseArray<>(); - private final SparseArray mWindowDecorOfVanishedTasks = new SparseArray<>(); + private final SparseArray mTasks = new SparseArray<>(); - private static class State { + private static class State { RunningTaskInfo mTaskInfo; SurfaceControl mLeash; - T mWindowDecoration; } private final SyncTransactionQueue mSyncQueue; private final Optional mRecentTasksOptional; - private final Optional> mWindowDecorViewModelOptional; + private final Optional mWindowDecorViewModelOptional; /** * This constructor is used by downstream products. */ @@ -75,7 +69,7 @@ public class FullscreenTaskListener ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Optional recentTasksOptional, - Optional> windowDecorViewModelOptional) { + Optional windowDecorViewModelOptional) { mShellTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; mRecentTasksOptional = recentTasksOptional; @@ -98,21 +92,21 @@ public class FullscreenTaskListener ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d", taskInfo.taskId); final Point positionInParent = taskInfo.positionInParent; - final State state = new State(); + final State state = new State(); state.mLeash = leash; state.mTaskInfo = taskInfo; mTasks.put(taskInfo.taskId, state); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; updateRecentsForVisibleFullscreenTask(taskInfo); + boolean createdWindowDecor = false; if (mWindowDecorViewModelOptional.isPresent()) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - state.mWindowDecoration = - mWindowDecorViewModelOptional.get().createWindowDecoration(taskInfo, - leash, t, t); + createdWindowDecor = mWindowDecorViewModelOptional.get() + .createWindowDecoration(taskInfo, leash, t, t); t.apply(); } - if (state.mWindowDecoration == null) { + if (!createdWindowDecor) { mSyncQueue.runInSync(t -> { // Reset several properties back to fullscreen (PiP, for example, leaves all these // properties in a bad state). @@ -127,12 +121,11 @@ public class FullscreenTaskListener @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { - final State state = mTasks.get(taskInfo.taskId); + final State state = mTasks.get(taskInfo.taskId); final Point oldPositionInParent = state.mTaskInfo.positionInParent; state.mTaskInfo = taskInfo; - if (state.mWindowDecoration != null) { - mWindowDecorViewModelOptional.get().onTaskInfoChanged( - state.mTaskInfo, state.mWindowDecoration); + if (mWindowDecorViewModelOptional.isPresent()) { + mWindowDecorViewModelOptional.get().onTaskInfoChanged(state.mTaskInfo); } if (Transitions.ENABLE_SHELL_TRANSITIONS) return; updateRecentsForVisibleFullscreenTask(taskInfo); @@ -147,160 +140,13 @@ public class FullscreenTaskListener @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { - final State state = mTasks.get(taskInfo.taskId); - if (state == null) { - // This is possible if the transition happens before this method. - return; - } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d", taskInfo.taskId); mTasks.remove(taskInfo.taskId); - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - // Save window decorations of closing tasks so that we can hand them over to the - // transition system if this method happens before the transition. In case where the - // transition didn't happen, it'd be cleared when the next transition finished. - if (state.mWindowDecoration != null) { - mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration); - } - return; - } - releaseWindowDecor(state.mWindowDecoration); - } - - /** - * Creates a window decoration for a transition. - * - * @param change the change of this task transition that needs to have the task layer as the - * leash - * @return {@code true} if a decoration was actually created. - */ - public boolean createWindowDecoration(TransitionInfo.Change change, - SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - final State state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash()); - if (!mWindowDecorViewModelOptional.isPresent()) return false; - if (state.mWindowDecoration != null) { - // Already has a decoration. - return false; - } - T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration( - state.mTaskInfo, state.mLeash, startT, finishT); - if (newWindowDecor != null) { - state.mWindowDecoration = newWindowDecor; - return true; - } - return false; - } - - /** - * Adopt the incoming window decoration and lets the window decoration prepare for a transition. - * - * @param change the change of this task transition that needs to have the task layer as the - * leash - * @param startT the start transaction of this transition - * @param finishT the finish transaction of this transition - * @param windowDecor the window decoration to adopt - * @return {@code true} if it adopts the window decoration; {@code false} otherwise - */ - public boolean adoptWindowDecoration( - TransitionInfo.Change change, - SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT, - @Nullable AutoCloseable windowDecor) { - if (!mWindowDecorViewModelOptional.isPresent()) { - return false; - } - final State state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash()); - state.mWindowDecoration = mWindowDecorViewModelOptional.get().adoptWindowDecoration( - windowDecor); - if (state.mWindowDecoration != null) { - mWindowDecorViewModelOptional.get().setupWindowDecorationForTransition( - state.mTaskInfo, startT, finishT, state.mWindowDecoration); - return true; - } else { - T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration( - state.mTaskInfo, state.mLeash, startT, finishT); - if (newWindowDecor != null) { - state.mWindowDecoration = newWindowDecor; - } - return false; - } - } - - /** - * Clear window decors of vanished tasks. - */ - public void onTaskTransitionFinished() { - if (mWindowDecorOfVanishedTasks.size() == 0) { - return; - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, - "Clearing window decors of vanished tasks. There could be visual defects " - + "if any of them is used later in transitions."); - for (int i = 0; i < mWindowDecorOfVanishedTasks.size(); ++i) { - releaseWindowDecor(mWindowDecorOfVanishedTasks.valueAt(i)); - } - mWindowDecorOfVanishedTasks.clear(); - } - - /** - * Gives out the ownership of the task's window decoration. The given task is leaving (of has - * left) this task listener. This is the transition system asking for the ownership. - * - * @param taskInfo the maximizing task - * @return the window decor of the maximizing task if any - */ - public T giveWindowDecoration( - ActivityManager.RunningTaskInfo taskInfo, - SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT) { - T windowDecor; - final State state = mTasks.get(taskInfo.taskId); - if (state != null) { - windowDecor = state.mWindowDecoration; - state.mWindowDecoration = null; - } else { - windowDecor = - mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId); - } - if (mWindowDecorViewModelOptional.isPresent() && windowDecor != null) { - mWindowDecorViewModelOptional.get().setupWindowDecorationForTransition( - taskInfo, startT, finishT, windowDecor); - } - - return windowDecor; - } - - private State createOrUpdateTaskState(ActivityManager.RunningTaskInfo taskInfo, - SurfaceControl leash) { - State state = mTasks.get(taskInfo.taskId); - if (state != null) { - updateTaskInfo(taskInfo); - return state; - } - - state = new State(); - state.mTaskInfo = taskInfo; - state.mLeash = leash; - mTasks.put(taskInfo.taskId, state); - - return state; - } - - private State updateTaskInfo(ActivityManager.RunningTaskInfo taskInfo) { - final State state = mTasks.get(taskInfo.taskId); - state.mTaskInfo = taskInfo; - return state; - } - - private void releaseWindowDecor(T windowDecor) { - if (windowDecor == null) { - return; - } - try { - windowDecor.close(); - } catch (Exception e) { - Log.e(TAG, "Failed to release window decoration.", e); + if (Transitions.ENABLE_SHELL_TRANSITIONS) return; + if (mWindowDecorViewModelOptional.isPresent()) { + mWindowDecorViewModelOptional.get().destroyWindowDecoration(taskInfo); } } @@ -342,6 +188,4 @@ public class FullscreenTaskListener public String toString() { return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN); } - - } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 9e49b51e15048..3df33f346e844 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -26,6 +26,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; import android.os.Handler; +import android.util.SparseArray; import android.view.Choreographer; import android.view.MotionEvent; import android.view.SurfaceControl; @@ -46,7 +47,7 @@ import com.android.wm.shell.transition.Transitions; * View model for the window decoration with a caption and shadows. Works with * {@link CaptionWindowDecoration}. */ -public class CaptionWindowDecorViewModel implements WindowDecorViewModel { +public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final ActivityTaskManager mActivityTaskManager; private final ShellTaskOrganizer mTaskOrganizer; private final Context mContext; @@ -57,6 +58,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel mWindowDecorByTaskId = new SparseArray<>(); + public CaptionWindowDecorViewModel( Context context, Handler mainHandler, @@ -81,12 +84,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel The actual decoration type */ -public interface WindowDecorViewModel { +public interface WindowDecorViewModel { /** * Sets the transition starter that starts freeform task transitions. @@ -50,29 +46,19 @@ public interface WindowDecorViewModel { * @param finishT the finish transaction to restore states after the transition * @return the window decoration object */ - @Nullable T createWindowDecoration( + boolean createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT); - /** - * Adopts the window decoration if possible. - * May be {@code null} if a window decor is not needed or the given one is incompatible. - * - * @param windowDecor the potential window decoration to adopt - * @return the window decoration if it can be adopted, or {@code null} otherwise. - */ - @Nullable T adoptWindowDecoration(@Nullable AutoCloseable windowDecor); - /** * Notifies a task info update on the given task, with the window decoration created previously * for this task by {@link #createWindowDecoration}. * * @param taskInfo the new task info of the task - * @param windowDecoration the window decoration created for the task */ - void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo, T windowDecoration); + void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo); /** * Notifies a transition is about to start about the given task to give the window decoration a @@ -80,11 +66,16 @@ public interface WindowDecorViewModel { * * @param startT the start transaction to be applied before the transition * @param finishT the finish transaction to restore states after the transition - * @param windowDecoration the window decoration created for the task */ void setupWindowDecorationForTransition( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, - SurfaceControl.Transaction finishT, - T windowDecoration); + SurfaceControl.Transaction finishT); + + /** + * Destroys the window decoration of the give task. + * + * @param taskInfo the info of the task + */ + void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java index 0fd5cb081ea9f..7068a84c30560 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java @@ -17,17 +17,10 @@ package com.android.wm.shell.freeform; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; -import static com.android.wm.shell.transition.Transitions.TRANSIT_MAXIMIZE; -import static com.android.wm.shell.transition.Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE; - -import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; @@ -44,9 +37,9 @@ import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; -import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; +import com.android.wm.shell.windowdecor.WindowDecorViewModel; import org.junit.Before; import org.junit.Test; @@ -65,9 +58,7 @@ public class FreeformTaskTransitionObserverTest { @Mock private Transitions mTransitions; @Mock - private FullscreenTaskListener mFullscreenTaskListener; - @Mock - private FreeformTaskListener mFreeformTaskListener; + private WindowDecorViewModel mWindowDecorViewModel; private FreeformTaskTransitionObserver mTransitionObserver; @@ -82,7 +73,7 @@ public class FreeformTaskTransitionObserverTest { doReturn(pm).when(context).getPackageManager(); mTransitionObserver = new FreeformTaskTransitionObserver( - context, mShellInit, mTransitions, mFullscreenTaskListener, mFreeformTaskListener); + context, mShellInit, mTransitions, mWindowDecorViewModel); if (Transitions.ENABLE_SHELL_TRANSITIONS) { final ArgumentCaptor initRunnableCaptor = ArgumentCaptor.forClass( Runnable.class); @@ -112,11 +103,12 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mFreeformTaskListener).createWindowDecoration(change, startT, finishT); + verify(mWindowDecorViewModel).createWindowDecoration( + change.getTaskInfo(), change.getLeash(), startT, finishT); } @Test - public void testObtainsWindowDecorOnCloseTransition_freeform() { + public void testPreparesWindowDecorOnCloseTransition_freeform() { final TransitionInfo.Change change = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); final TransitionInfo info = new TransitionInfo(TRANSIT_CLOSE, 0); @@ -128,7 +120,8 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mFreeformTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT); + verify(mWindowDecorViewModel).setupWindowDecorationForTransition( + change.getTaskInfo(), startT, finishT); } @Test @@ -138,17 +131,13 @@ public class FreeformTaskTransitionObserverTest { final TransitionInfo info = new TransitionInfo(TRANSIT_CLOSE, 0); info.addChange(change); - final AutoCloseable windowDecor = mock(AutoCloseable.class); - doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration( - eq(change.getTaskInfo()), any(), any()); - final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(windowDecor, never()).close(); + verify(mWindowDecorViewModel, never()).destroyWindowDecoration(change.getTaskInfo()); } @Test @@ -159,8 +148,6 @@ public class FreeformTaskTransitionObserverTest { info.addChange(change); final AutoCloseable windowDecor = mock(AutoCloseable.class); - doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration( - eq(change.getTaskInfo()), any(), any()); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -169,7 +156,7 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionStarting(transition); mTransitionObserver.onTransitionFinished(transition, false); - verify(windowDecor).close(); + verify(mWindowDecorViewModel).destroyWindowDecoration(change.getTaskInfo()); } @Test @@ -192,10 +179,6 @@ public class FreeformTaskTransitionObserverTest { final TransitionInfo info2 = new TransitionInfo(TRANSIT_CLOSE, 0); info2.addChange(change2); - final AutoCloseable windowDecor2 = mock(AutoCloseable.class); - doReturn(windowDecor2).when(mFreeformTaskListener).giveWindowDecoration( - eq(change2.getTaskInfo()), any(), any()); - final IBinder transition2 = mock(IBinder.class); final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class); @@ -204,7 +187,7 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionFinished(transition1, false); - verify(windowDecor2).close(); + verify(mWindowDecorViewModel).destroyWindowDecoration(change2.getTaskInfo()); } @Test @@ -215,10 +198,6 @@ public class FreeformTaskTransitionObserverTest { final TransitionInfo info1 = new TransitionInfo(TRANSIT_CLOSE, 0); info1.addChange(change1); - final AutoCloseable windowDecor1 = mock(AutoCloseable.class); - doReturn(windowDecor1).when(mFreeformTaskListener).giveWindowDecoration( - eq(change1.getTaskInfo()), any(), any()); - final IBinder transition1 = mock(IBinder.class); final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class); @@ -231,10 +210,6 @@ public class FreeformTaskTransitionObserverTest { final TransitionInfo info2 = new TransitionInfo(TRANSIT_CLOSE, 0); info2.addChange(change2); - final AutoCloseable windowDecor2 = mock(AutoCloseable.class); - doReturn(windowDecor2).when(mFreeformTaskListener).giveWindowDecoration( - eq(change2.getTaskInfo()), any(), any()); - final IBinder transition2 = mock(IBinder.class); final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class); @@ -243,48 +218,8 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionFinished(transition1, false); - verify(windowDecor1).close(); - verify(windowDecor2).close(); - } - - @Test - public void testTransfersWindowDecorOnMaximize() { - final TransitionInfo.Change change = - createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN); - final TransitionInfo info = new TransitionInfo(TRANSIT_MAXIMIZE, 0); - info.addChange(change); - - final AutoCloseable windowDecor = mock(AutoCloseable.class); - doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration( - eq(change.getTaskInfo()), any(), any()); - - final IBinder transition = mock(IBinder.class); - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - mTransitionObserver.onTransitionReady(transition, info, startT, finishT); - mTransitionObserver.onTransitionStarting(transition); - - verify(mFreeformTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT); - verify(mFullscreenTaskListener).adoptWindowDecoration( - eq(change), same(startT), same(finishT), any()); - } - - @Test - public void testTransfersWindowDecorOnRestoreFromMaximize() { - final TransitionInfo.Change change = - createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfo(TRANSIT_RESTORE_FROM_MAXIMIZE, 0); - info.addChange(change); - - final IBinder transition = mock(IBinder.class); - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - mTransitionObserver.onTransitionReady(transition, info, startT, finishT); - mTransitionObserver.onTransitionStarting(transition); - - verify(mFullscreenTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT); - verify(mFreeformTaskListener).adoptWindowDecoration( - eq(change), same(startT), same(finishT), any()); + verify(mWindowDecorViewModel).destroyWindowDecoration(change1.getTaskInfo()); + verify(mWindowDecorViewModel).destroyWindowDecoration(change2.getTaskInfo()); } private static TransitionInfo.Change createChange(int mode, int taskId, int windowingMode) {