Merge "Split window decor lifecycle to a TransitionObserver" into tm-qpr-dev
This commit is contained in:
@@ -55,6 +55,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
|
|||||||
import com.android.wm.shell.freeform.FreeformComponents;
|
import com.android.wm.shell.freeform.FreeformComponents;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
|
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.fullscreen.FullscreenTaskListener;
|
||||||
import com.android.wm.shell.onehanded.OneHandedController;
|
import com.android.wm.shell.onehanded.OneHandedController;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
@@ -207,8 +208,10 @@ public abstract class WMShellModule {
|
|||||||
@DynamicOverride
|
@DynamicOverride
|
||||||
static FreeformComponents provideFreeformComponents(
|
static FreeformComponents provideFreeformComponents(
|
||||||
FreeformTaskListener<?> taskListener,
|
FreeformTaskListener<?> taskListener,
|
||||||
FreeformTaskTransitionHandler transitionHandler) {
|
FreeformTaskTransitionHandler transitionHandler,
|
||||||
return new FreeformComponents(taskListener, Optional.of(transitionHandler));
|
FreeformTaskTransitionObserver transitionObserver) {
|
||||||
|
return new FreeformComponents(
|
||||||
|
taskListener, Optional.of(transitionHandler), Optional.of(transitionObserver));
|
||||||
}
|
}
|
||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
@@ -230,19 +233,22 @@ public abstract class WMShellModule {
|
|||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
|
static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
|
||||||
|
ShellInit shellInit,
|
||||||
|
Transitions transitions,
|
||||||
|
WindowDecorViewModel<?> windowDecorViewModel) {
|
||||||
|
return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
static FreeformTaskTransitionObserver provideFreeformTaskTransitionObserver(
|
||||||
Context context,
|
Context context,
|
||||||
ShellInit shellInit,
|
ShellInit shellInit,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
WindowDecorViewModel<?> windowDecorViewModel,
|
|
||||||
FullscreenTaskListener<?> fullscreenTaskListener,
|
FullscreenTaskListener<?> fullscreenTaskListener,
|
||||||
FreeformTaskListener<?> freeformTaskListener) {
|
FreeformTaskListener<?> freeformTaskListener) {
|
||||||
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
|
return new FreeformTaskTransitionObserver(
|
||||||
// override for this controller from the base module
|
context, shellInit, transitions, fullscreenTaskListener, freeformTaskListener);
|
||||||
ShellInit init = FreeformComponents.isFreeformEnabled(context)
|
|
||||||
? shellInit
|
|
||||||
: null;
|
|
||||||
return new FreeformTaskTransitionHandler(init, transitions,
|
|
||||||
windowDecorViewModel, fullscreenTaskListener, freeformTaskListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -33,16 +33,19 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public class FreeformComponents {
|
public class FreeformComponents {
|
||||||
public final ShellTaskOrganizer.TaskListener mTaskListener;
|
public final ShellTaskOrganizer.TaskListener mTaskListener;
|
||||||
public final Optional<Transitions.TransitionHandler> mTaskTransitionHandler;
|
public final Optional<Transitions.TransitionHandler> mTransitionHandler;
|
||||||
|
public final Optional<Transitions.TransitionObserver> mTransitionObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance with the given components.
|
* Creates an instance with the given components.
|
||||||
*/
|
*/
|
||||||
public FreeformComponents(
|
public FreeformComponents(
|
||||||
ShellTaskOrganizer.TaskListener taskListener,
|
ShellTaskOrganizer.TaskListener taskListener,
|
||||||
Optional<Transitions.TransitionHandler> taskTransitionHandler) {
|
Optional<Transitions.TransitionHandler> transitionHandler,
|
||||||
|
Optional<Transitions.TransitionObserver> transitionObserver) {
|
||||||
mTaskListener = taskListener;
|
mTaskListener = taskListener;
|
||||||
mTaskTransitionHandler = taskTransitionHandler;
|
mTransitionHandler = transitionHandler;
|
||||||
|
mTransitionObserver = transitionObserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.WindowConfiguration;
|
import android.app.WindowConfiguration;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.window.TransitionInfo;
|
import android.window.TransitionInfo;
|
||||||
@@ -32,7 +31,6 @@ import android.window.WindowContainerTransaction;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
|
||||||
import com.android.wm.shell.sysui.ShellInit;
|
import com.android.wm.shell.sysui.ShellInit;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
|
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
|
||||||
@@ -41,17 +39,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link Transitions.TransitionHandler} that handles freeform task launches, closes,
|
* The {@link Transitions.TransitionHandler} that handles freeform task maximizing and restoring
|
||||||
* maximizing and restoring transitions. It also reports transitions so that window decorations can
|
* transitions.
|
||||||
* be a part of transitions.
|
|
||||||
*/
|
*/
|
||||||
public class FreeformTaskTransitionHandler
|
public class FreeformTaskTransitionHandler
|
||||||
implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
|
implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
|
||||||
private static final String TAG = "FreeformTH";
|
|
||||||
|
|
||||||
private final Transitions mTransitions;
|
private final Transitions mTransitions;
|
||||||
private final FreeformTaskListener<?> mFreeformTaskListener;
|
|
||||||
private final FullscreenTaskListener<?> mFullscreenTaskListener;
|
|
||||||
private final WindowDecorViewModel<?> mWindowDecorViewModel;
|
private final WindowDecorViewModel<?> mWindowDecorViewModel;
|
||||||
|
|
||||||
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
|
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
|
||||||
@@ -59,21 +53,16 @@ public class FreeformTaskTransitionHandler
|
|||||||
public FreeformTaskTransitionHandler(
|
public FreeformTaskTransitionHandler(
|
||||||
ShellInit shellInit,
|
ShellInit shellInit,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
WindowDecorViewModel<?> windowDecorViewModel,
|
WindowDecorViewModel<?> windowDecorViewModel) {
|
||||||
FullscreenTaskListener<?> fullscreenTaskListener,
|
|
||||||
FreeformTaskListener<?> freeformTaskListener) {
|
|
||||||
mTransitions = transitions;
|
mTransitions = transitions;
|
||||||
mFullscreenTaskListener = fullscreenTaskListener;
|
|
||||||
mFreeformTaskListener = freeformTaskListener;
|
|
||||||
mWindowDecorViewModel = windowDecorViewModel;
|
mWindowDecorViewModel = windowDecorViewModel;
|
||||||
if (shellInit != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
shellInit.addInitCallback(this::onInit, this);
|
shellInit.addInitCallback(this::onInit, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInit() {
|
private void onInit() {
|
||||||
mWindowDecorViewModel.setFreeformTaskTransitionStarter(this);
|
mWindowDecorViewModel.setFreeformTaskTransitionStarter(this);
|
||||||
mTransitions.addHandler(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,13 +90,13 @@ public class FreeformTaskTransitionHandler
|
|||||||
mPendingTransitionTokens.add(mTransitions.startTransition(type, wct, this));
|
mPendingTransitionTokens.add(mTransitions.startTransition(type, wct, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
||||||
@NonNull SurfaceControl.Transaction startT,
|
@NonNull SurfaceControl.Transaction startT,
|
||||||
@NonNull SurfaceControl.Transaction finishT,
|
@NonNull SurfaceControl.Transaction finishT,
|
||||||
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
||||||
boolean transitionHandled = false;
|
boolean transitionHandled = false;
|
||||||
final ArrayList<AutoCloseable> windowDecorsInCloseTransitions = new ArrayList<>();
|
|
||||||
for (TransitionInfo.Change change : info.getChanges()) {
|
for (TransitionInfo.Change change : info.getChanges()) {
|
||||||
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
|
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -119,22 +108,13 @@ public class FreeformTaskTransitionHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (change.getMode()) {
|
switch (change.getMode()) {
|
||||||
case WindowManager.TRANSIT_OPEN:
|
|
||||||
transitionHandled |= startOpenTransition(change, startT, finishT);
|
|
||||||
break;
|
|
||||||
case WindowManager.TRANSIT_CLOSE:
|
|
||||||
transitionHandled |= startCloseTransition(
|
|
||||||
change, windowDecorsInCloseTransitions, startT, finishT);
|
|
||||||
break;
|
|
||||||
case WindowManager.TRANSIT_CHANGE:
|
case WindowManager.TRANSIT_CHANGE:
|
||||||
transitionHandled |= startChangeTransition(
|
transitionHandled |= startChangeTransition(
|
||||||
transition, info.getType(), change, startT, finishT);
|
transition, info.getType(), change);
|
||||||
break;
|
break;
|
||||||
case WindowManager.TRANSIT_TO_BACK:
|
case WindowManager.TRANSIT_TO_BACK:
|
||||||
transitionHandled |= startMinimizeTransition(transition);
|
transitionHandled |= startMinimizeTransition(transition);
|
||||||
break;
|
break;
|
||||||
case WindowManager.TRANSIT_TO_FRONT:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,139 +126,43 @@ public class FreeformTaskTransitionHandler
|
|||||||
|
|
||||||
startT.apply();
|
startT.apply();
|
||||||
mTransitions.getMainExecutor().execute(
|
mTransitions.getMainExecutor().execute(
|
||||||
() -> finishTransition(windowDecorsInCloseTransitions, finishCallback));
|
() -> finishCallback.onTransitionFinished(null, null));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean startOpenTransition(
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intercepted transition to manage the window decorations. Let other handlers animate.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean startCloseTransition(
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
// Intercepted transition to manage the window decorations. Let other handlers animate.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean startMinimizeTransition(IBinder transition) {
|
|
||||||
if (!mPendingTransitionTokens.contains(transition)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean startChangeTransition(
|
private boolean startChangeTransition(
|
||||||
IBinder transition,
|
IBinder transition,
|
||||||
int type,
|
int type,
|
||||||
TransitionInfo.Change change,
|
TransitionInfo.Change change) {
|
||||||
SurfaceControl.Transaction startT,
|
|
||||||
SurfaceControl.Transaction finishT) {
|
|
||||||
AutoCloseable windowDecor = null;
|
|
||||||
|
|
||||||
if (!mPendingTransitionTokens.contains(transition)) {
|
if (!mPendingTransitionTokens.contains(transition)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
boolean adopted = false;
|
|
||||||
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
|
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
|
||||||
if (type == Transitions.TRANSIT_MAXIMIZE
|
if (type == Transitions.TRANSIT_MAXIMIZE
|
||||||
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
|
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
|
||||||
|
// TODO: Add maximize animations
|
||||||
handled = true;
|
handled = true;
|
||||||
windowDecor = mFreeformTaskListener.giveWindowDecoration(
|
|
||||||
change.getTaskInfo(), startT, finishT);
|
|
||||||
adopted = mFullscreenTaskListener.adoptWindowDecoration(change,
|
|
||||||
startT, finishT, windowDecor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE
|
if (type == Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE
|
||||||
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
|
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
|
||||||
|
// TODO: Add restore animations
|
||||||
handled = true;
|
handled = true;
|
||||||
windowDecor = mFullscreenTaskListener.giveWindowDecoration(
|
|
||||||
change.getTaskInfo(), startT, finishT);
|
|
||||||
adopted = mFreeformTaskListener.adoptWindowDecoration(change,
|
|
||||||
startT, finishT, windowDecor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!adopted) {
|
|
||||||
releaseWindowDecor(windowDecor);
|
|
||||||
}
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishTransition(
|
private boolean startMinimizeTransition(IBinder transition) {
|
||||||
ArrayList<AutoCloseable> windowDecorsInCloseTransitions,
|
return mPendingTransitionTokens.contains(transition);
|
||||||
Transitions.TransitionFinishCallback finishCallback) {
|
|
||||||
for (AutoCloseable windowDecor : windowDecorsInCloseTransitions) {
|
|
||||||
releaseWindowDecor(windowDecor);
|
|
||||||
}
|
|
||||||
mFreeformTaskListener.onTaskTransitionFinished();
|
|
||||||
mFullscreenTaskListener.onTaskTransitionFinished();
|
|
||||||
finishCallback.onTransitionFinished(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void releaseWindowDecor(AutoCloseable windowDecor) {
|
|
||||||
if (windowDecor == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
windowDecor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Failed to release window decoration.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
||||||
@NonNull TransitionRequestInfo request) {
|
@NonNull TransitionRequestInfo request) {
|
||||||
final ActivityManager.RunningTaskInfo taskInfo = request.getTriggerTask();
|
|
||||||
if (taskInfo == null || taskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
switch (request.getType()) {
|
|
||||||
case WindowManager.TRANSIT_OPEN:
|
|
||||||
case WindowManager.TRANSIT_CLOSE:
|
|
||||||
case WindowManager.TRANSIT_TO_FRONT:
|
|
||||||
case WindowManager.TRANSIT_TO_BACK:
|
|
||||||
return new WindowContainerTransaction();
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.wm.shell.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;
|
||||||
|
|
||||||
|
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 java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Transitions.TransitionHandler} that handles freeform task launches, closes,
|
||||||
|
* maximizing and restoring transitions. It also reports transitions so that window decorations can
|
||||||
|
* 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 Map<IBinder, List<AutoCloseable>> mTransitionToWindowDecors = new HashMap<>();
|
||||||
|
|
||||||
|
public FreeformTaskTransitionObserver(
|
||||||
|
Context context,
|
||||||
|
ShellInit shellInit,
|
||||||
|
Transitions transitions,
|
||||||
|
FullscreenTaskListener<?> fullscreenTaskListener,
|
||||||
|
FreeformTaskListener<?> freeformTaskListener) {
|
||||||
|
mTransitions = transitions;
|
||||||
|
mFreeformTaskListener = freeformTaskListener;
|
||||||
|
mFullscreenTaskListener = fullscreenTaskListener;
|
||||||
|
if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
|
||||||
|
shellInit.addInitCallback(this::onInit, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void onInit() {
|
||||||
|
mTransitions.registerObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransitionReady(
|
||||||
|
@NonNull IBinder transition,
|
||||||
|
@NonNull TransitionInfo info,
|
||||||
|
@NonNull SurfaceControl.Transaction startT,
|
||||||
|
@NonNull SurfaceControl.Transaction finishT) {
|
||||||
|
final ArrayList<AutoCloseable> windowDecors = new ArrayList<>();
|
||||||
|
for (TransitionInfo.Change change : info.getChanges()) {
|
||||||
|
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
|
||||||
|
if (taskInfo == null || taskInfo.taskId == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (change.getMode()) {
|
||||||
|
case WindowManager.TRANSIT_OPEN:
|
||||||
|
onOpenTransitionReady(change, startT, finishT);
|
||||||
|
break;
|
||||||
|
case WindowManager.TRANSIT_CLOSE: {
|
||||||
|
onCloseTransitionReady(change, windowDecors, startT, finishT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WindowManager.TRANSIT_CHANGE:
|
||||||
|
onChangeTransitionReady(info.getType(), change, startT, finishT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!windowDecors.isEmpty()) {
|
||||||
|
mTransitionToWindowDecors.put(transition, windowDecors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (type == Transitions.TRANSIT_MAXIMIZE
|
||||||
|
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
|
||||||
|
windowDecor = mFreeformTaskListener.giveWindowDecoration(
|
||||||
|
change.getTaskInfo(), startT, finishT);
|
||||||
|
adopted = mFullscreenTaskListener.adoptWindowDecoration(
|
||||||
|
change, startT, finishT, windowDecor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE
|
||||||
|
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
|
||||||
|
windowDecor = mFullscreenTaskListener.giveWindowDecoration(
|
||||||
|
change.getTaskInfo(), startT, finishT);
|
||||||
|
adopted = mFreeformTaskListener.adoptWindowDecoration(
|
||||||
|
change, startT, finishT, windowDecor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adopted) {
|
||||||
|
releaseWindowDecor(windowDecor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransitionStarting(@NonNull IBinder transition) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
|
||||||
|
final List<AutoCloseable> windowDecorsOfMerged = mTransitionToWindowDecors.get(merged);
|
||||||
|
if (windowDecorsOfMerged == 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);
|
||||||
|
|
||||||
|
final List<AutoCloseable> windowDecorsOfPlaying = mTransitionToWindowDecors.get(playing);
|
||||||
|
if (windowDecorsOfPlaying != null) {
|
||||||
|
windowDecorsOfPlaying.addAll(windowDecorsOfMerged);
|
||||||
|
} else {
|
||||||
|
mTransitionToWindowDecors.put(playing, windowDecorsOfMerged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {
|
||||||
|
final List<AutoCloseable> windowDecors = mTransitionToWindowDecors.getOrDefault(
|
||||||
|
transition, Collections.emptyList());
|
||||||
|
mTransitionToWindowDecors.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.wm.shell.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;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.window.IWindowContainerToken;
|
||||||
|
import android.window.TransitionInfo;
|
||||||
|
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 org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of {@link FreeformTaskTransitionObserver}
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
public class FreeformTaskTransitionObserverTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ShellInit mShellInit;
|
||||||
|
@Mock
|
||||||
|
private Transitions mTransitions;
|
||||||
|
@Mock
|
||||||
|
private FullscreenTaskListener<?> mFullscreenTaskListener;
|
||||||
|
@Mock
|
||||||
|
private FreeformTaskListener<?> mFreeformTaskListener;
|
||||||
|
|
||||||
|
private FreeformTaskTransitionObserver mTransitionObserver;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
PackageManager pm = mock(PackageManager.class);
|
||||||
|
doReturn(true).when(pm).hasSystemFeature(
|
||||||
|
PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
|
||||||
|
final Context context = mock(Context.class);
|
||||||
|
doReturn(pm).when(context).getPackageManager();
|
||||||
|
|
||||||
|
mTransitionObserver = new FreeformTaskTransitionObserver(
|
||||||
|
context, mShellInit, mTransitions, mFullscreenTaskListener, mFreeformTaskListener);
|
||||||
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
|
final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
|
||||||
|
Runnable.class);
|
||||||
|
verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
|
||||||
|
same(mTransitionObserver));
|
||||||
|
initRunnableCaptor.getValue().run();
|
||||||
|
} else {
|
||||||
|
mTransitionObserver.onInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegistersObserverAtInit() {
|
||||||
|
verify(mTransitions).registerObserver(same(mTransitionObserver));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatesWindowDecorOnOpenTransition_freeform() {
|
||||||
|
final TransitionInfo.Change change =
|
||||||
|
createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 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(mFreeformTaskListener).createWindowDecoration(change, startT, finishT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObtainsWindowDecorOnCloseTransition_freeform() {
|
||||||
|
final TransitionInfo.Change change =
|
||||||
|
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
final TransitionInfo info = new TransitionInfo(TRANSIT_CLOSE, 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(mFreeformTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesntCloseWindowDecorDuringCloseTransition() throws Exception {
|
||||||
|
final TransitionInfo.Change change =
|
||||||
|
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosesWindowDecorAfterCloseTransition() throws Exception {
|
||||||
|
final TransitionInfo.Change change =
|
||||||
|
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
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);
|
||||||
|
mTransitionObserver.onTransitionFinished(transition, false);
|
||||||
|
|
||||||
|
verify(windowDecor).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosesMergedWindowDecorationAfterTransitionFinishes() throws Exception {
|
||||||
|
// The playing transition
|
||||||
|
final TransitionInfo.Change change1 =
|
||||||
|
createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
final TransitionInfo info1 = new TransitionInfo(TRANSIT_OPEN, 0);
|
||||||
|
info1.addChange(change1);
|
||||||
|
|
||||||
|
final IBinder transition1 = mock(IBinder.class);
|
||||||
|
final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
|
||||||
|
final SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
|
||||||
|
mTransitionObserver.onTransitionReady(transition1, info1, startT1, finishT1);
|
||||||
|
mTransitionObserver.onTransitionStarting(transition1);
|
||||||
|
|
||||||
|
// The merged transition
|
||||||
|
final TransitionInfo.Change change2 =
|
||||||
|
createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM);
|
||||||
|
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);
|
||||||
|
mTransitionObserver.onTransitionReady(transition2, info2, startT2, finishT2);
|
||||||
|
mTransitionObserver.onTransitionMerged(transition2, transition1);
|
||||||
|
|
||||||
|
mTransitionObserver.onTransitionFinished(transition1, false);
|
||||||
|
|
||||||
|
verify(windowDecor2).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosesAllWindowDecorsOnTransitionMergeAfterCloseTransitions() throws Exception {
|
||||||
|
// The playing transition
|
||||||
|
final TransitionInfo.Change change1 =
|
||||||
|
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
|
||||||
|
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);
|
||||||
|
mTransitionObserver.onTransitionReady(transition1, info1, startT1, finishT1);
|
||||||
|
mTransitionObserver.onTransitionStarting(transition1);
|
||||||
|
|
||||||
|
// The merged transition
|
||||||
|
final TransitionInfo.Change change2 =
|
||||||
|
createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM);
|
||||||
|
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);
|
||||||
|
mTransitionObserver.onTransitionReady(transition2, info2, startT2, finishT2);
|
||||||
|
mTransitionObserver.onTransitionMerged(transition2, transition1);
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransitionInfo.Change createChange(int mode, int taskId, int windowingMode) {
|
||||||
|
final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
|
||||||
|
taskInfo.taskId = taskId;
|
||||||
|
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
|
||||||
|
|
||||||
|
final TransitionInfo.Change change = new TransitionInfo.Change(
|
||||||
|
new WindowContainerToken(mock(IWindowContainerToken.class)),
|
||||||
|
mock(SurfaceControl.class));
|
||||||
|
change.setMode(mode);
|
||||||
|
change.setTaskInfo(taskInfo);
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user