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
This commit is contained in:
Garfield Tan
2022-10-03 09:48:41 -07:00
parent ddc26a33f8
commit 73166e71d0
9 changed files with 131 additions and 564 deletions

View File

@@ -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<?>> fullscreenTaskListener,
static FullscreenTaskListener provideFullscreenTaskListener(
@DynamicOverride Optional<FullscreenTaskListener> fullscreenTaskListener,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue,
Optional<RecentTasksController> recentTasksOptional,
Optional<WindowDecorViewModel<?>> windowDecorViewModelOptional) {
Optional<WindowDecorViewModel> 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<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener<?> fullscreenTaskListener,
FullscreenTaskListener fullscreenTaskListener,
Optional<UnfoldAnimationController> unfoldAnimationController,
Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
Optional<FreeformComponents> freeformComponents,

View File

@@ -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> 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);
}
//

View File

@@ -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 <T> the type of window decoration instance
*/
public class FreeformTaskListener<T extends AutoCloseable>
implements ShellTaskOrganizer.TaskListener {
public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "FreeformTaskListener";
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
private final WindowDecorViewModel<T> mWindowDecorationViewModel;
private final WindowDecorViewModel mWindowDecorationViewModel;
private final SparseArray<State<T>> mTasks = new SparseArray<>();
private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
private final SparseArray<State> mTasks = new SparseArray<>();
private static class State<T extends AutoCloseable> {
private static class State {
RunningTaskInfo mTaskInfo;
SurfaceControl mLeash;
T mWindowDecoration;
}
public FreeformTaskListener(
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
WindowDecorViewModel<T> windowDecorationViewModel) {
WindowDecorViewModel windowDecorationViewModel) {
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
mDesktopModeTaskRepository = desktopModeTaskRepository;
@@ -80,13 +71,18 @@ public class FreeformTaskListener<T extends AutoCloseable>
@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<T> 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<T extends AutoCloseable>
}
}
private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
State<T> 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<T> 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<T extends AutoCloseable>
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<T> 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<T extends AutoCloseable>
}
}
private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
final State<T> 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<T extends AutoCloseable>
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<T> 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<T> 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<T> 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 + " ";

View File

@@ -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<IBinder> mPendingTransitionTokens = new ArrayList<>();
public FreeformTaskTransitionHandler(
ShellInit shellInit,
Transitions transitions,
WindowDecorViewModel<?> windowDecorViewModel) {
WindowDecorViewModel windowDecorViewModel) {
mTransitions = transitions;
mWindowDecorViewModel = windowDecorViewModel;
if (Transitions.ENABLE_SHELL_TRANSITIONS) {

View File

@@ -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<IBinder, List<AutoCloseable>> mTransitionToWindowDecors = new HashMap<>();
private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> 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<AutoCloseable> windowDecors = new ArrayList<>();
final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
final ArrayList<WindowContainerToken> 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<AutoCloseable> 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<AutoCloseable> windowDecorsOfMerged = mTransitionToWindowDecors.get(merged);
if (windowDecorsOfMerged == null) {
final List<ActivityManager.RunningTaskInfo> 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<AutoCloseable> windowDecorsOfPlaying = mTransitionToWindowDecors.get(playing);
if (windowDecorsOfPlaying != null) {
windowDecorsOfPlaying.addAll(windowDecorsOfMerged);
final List<ActivityManager.RunningTaskInfo> 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<AutoCloseable> windowDecors = mTransitionToWindowDecors.getOrDefault(
transition, Collections.emptyList());
mTransitionToWindowDecors.remove(transition);
final List<ActivityManager.RunningTaskInfo> 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));
}
}
}

View File

@@ -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 <T> the type of window decoration instance
*/
public class FullscreenTaskListener<T extends AutoCloseable>
implements ShellTaskOrganizer.TaskListener {
public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "FullscreenTaskListener";
private final ShellTaskOrganizer mShellTaskOrganizer;
private final SparseArray<State<T>> mTasks = new SparseArray<>();
private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
private final SparseArray<State> mTasks = new SparseArray<>();
private static class State<T extends AutoCloseable> {
private static class State {
RunningTaskInfo mTaskInfo;
SurfaceControl mLeash;
T mWindowDecoration;
}
private final SyncTransactionQueue mSyncQueue;
private final Optional<RecentTasksController> mRecentTasksOptional;
private final Optional<WindowDecorViewModel<T>> mWindowDecorViewModelOptional;
private final Optional<WindowDecorViewModel> mWindowDecorViewModelOptional;
/**
* This constructor is used by downstream products.
*/
@@ -75,7 +69,7 @@ public class FullscreenTaskListener<T extends AutoCloseable>
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue,
Optional<RecentTasksController> recentTasksOptional,
Optional<WindowDecorViewModel<T>> windowDecorViewModelOptional) {
Optional<WindowDecorViewModel> windowDecorViewModelOptional) {
mShellTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
mRecentTasksOptional = recentTasksOptional;
@@ -98,21 +92,21 @@ public class FullscreenTaskListener<T extends AutoCloseable>
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
taskInfo.taskId);
final Point positionInParent = taskInfo.positionInParent;
final State<T> 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<T extends AutoCloseable>
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
final State<T> 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<T extends AutoCloseable>
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
final State<T> 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<T> 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<T> 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<T> 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<T> createOrUpdateTaskState(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl leash) {
State<T> state = mTasks.get(taskInfo.taskId);
if (state != null) {
updateTaskInfo(taskInfo);
return state;
}
state = new State<T>();
state.mTaskInfo = taskInfo;
state.mLeash = leash;
mTasks.put(taskInfo.taskId, state);
return state;
}
private State<T> updateTaskInfo(ActivityManager.RunningTaskInfo taskInfo) {
final State<T> 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<T extends AutoCloseable>
public String toString() {
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
}
}

View File

@@ -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<CaptionWindowDecoration> {
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<Caption
private FreeformTaskTransitionStarter mTransitionStarter;
private DesktopModeController mDesktopModeController;
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
public CaptionWindowDecorViewModel(
Context context,
Handler mainHandler,
@@ -81,12 +84,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
}
@Override
public CaptionWindowDecoration createWindowDecoration(
public boolean createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
if (!shouldShowWindowDecor(taskInfo)) return null;
if (!shouldShowWindowDecor(taskInfo)) return false;
final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
mContext,
mDisplayController,
@@ -96,30 +99,24 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
mMainHandler,
mMainChoreographer,
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration);
CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragResizeCallback(taskPositioner);
setupWindowDecorationForTransition(taskInfo, startT, finishT, windowDecoration);
setupWindowDecorationForTransition(taskInfo, startT, finishT);
setupCaptionColor(taskInfo, windowDecoration);
return windowDecoration;
return true;
}
@Override
public CaptionWindowDecoration adoptWindowDecoration(AutoCloseable windowDecor) {
if (!(windowDecor instanceof CaptionWindowDecoration)) return null;
final CaptionWindowDecoration captionWindowDecor = (CaptionWindowDecoration) windowDecor;
if (!shouldShowWindowDecor(captionWindowDecor.mTaskInfo)) {
return null;
}
return captionWindowDecor;
}
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return;
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
decoration.relayout(taskInfo);
setupCaptionColor(taskInfo, decoration);
}
@@ -132,11 +129,22 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
public void setupWindowDecorationForTransition(
RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT,
CaptionWindowDecoration decoration) {
SurfaceControl.Transaction finishT) {
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return;
decoration.relayout(taskInfo, startT, finishT);
}
@Override
public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
final CaptionWindowDecoration decoration =
mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
if (decoration == null) return;
decoration.close();
}
private class CaptionTouchEventListener implements
View.OnClickListener, View.OnTouchListener {

View File

@@ -19,8 +19,6 @@ package com.android.wm.shell.windowdecor;
import android.app.ActivityManager;
import android.view.SurfaceControl;
import androidx.annotation.Nullable;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
/**
@@ -28,10 +26,8 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
* customize {@link WindowDecoration}. Its implementations are responsible to interpret user's
* interactions with UI widgets in window decorations and send corresponding requests to system
* servers.
*
* @param <T> The actual decoration type
*/
public interface WindowDecorViewModel<T extends AutoCloseable> {
public interface WindowDecorViewModel {
/**
* Sets the transition starter that starts freeform task transitions.
@@ -50,29 +46,19 @@ public interface WindowDecorViewModel<T extends AutoCloseable> {
* @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<T extends AutoCloseable> {
*
* @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);
}

View File

@@ -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<Runnable> 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) {