Merge "Add FreeformTaskTransitionHandler" into tm-qpr-dev am: 3f2c081a30

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19224057

Change-Id: Ie17cd9184f05209837683adeba4bf9f268fdddb4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2022-07-28 23:55:56 +00:00
committed by Automerger Merge Worker
14 changed files with 630 additions and 100 deletions

View File

@@ -29,8 +29,6 @@ import com.android.internal.logging.UiEventLogger;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootDisplayAreaOrganizer; import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.TaskViewFactoryController; import com.android.wm.shell.TaskViewFactoryController;
@@ -59,7 +57,7 @@ import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController; import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
@@ -78,7 +76,9 @@ import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.startingsurface.StartingWindowController;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm; import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.sysui.ShellInterface; import com.android.wm.shell.sysui.ShellInterface;
import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.transition.Transitions;
@@ -339,15 +339,15 @@ public abstract class WMShellBaseModule {
// Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride}
@BindsOptionalOf @BindsOptionalOf
@DynamicOverride @DynamicOverride
abstract FreeformTaskListener<?> optionalFreeformTaskListener(); abstract FreeformComponents optionalFreeformComponents();
@WMSingleton @WMSingleton
@Provides @Provides
static Optional<FreeformTaskListener<?>> provideFreeformTaskListener( static Optional<FreeformComponents> provideFreeformTaskListener(
@DynamicOverride Optional<FreeformTaskListener<?>> freeformTaskListener, @DynamicOverride Optional<FreeformComponents> freeformComponents,
Context context) { Context context) {
if (FreeformTaskListener.isFreeformEnabled(context)) { if (FreeformComponents.isFreeformEnabled(context)) {
return freeformTaskListener; return freeformComponents;
} }
return Optional.empty(); return Optional.empty();
} }
@@ -636,7 +636,7 @@ public abstract class WMShellBaseModule {
FullscreenTaskListener fullscreenTaskListener, FullscreenTaskListener fullscreenTaskListener,
Optional<UnfoldAnimationController> unfoldAnimationController, Optional<UnfoldAnimationController> unfoldAnimationController,
Optional<UnfoldTransitionHandler> unfoldTransitionHandler, Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
Optional<FreeformTaskListener<?>> freeformTaskListener, Optional<FreeformComponents> freeformComponents,
Optional<RecentTasksController> recentTasksOptional, Optional<RecentTasksController> recentTasksOptional,
Optional<ActivityEmbeddingController> activityEmbeddingOptional, Optional<ActivityEmbeddingController> activityEmbeddingOptional,
Transitions transitions, Transitions transitions,
@@ -655,7 +655,7 @@ public abstract class WMShellBaseModule {
fullscreenTaskListener, fullscreenTaskListener,
unfoldAnimationController, unfoldAnimationController,
unfoldTransitionHandler, unfoldTransitionHandler,
freeformTaskListener, freeformComponents,
recentTasksOptional, recentTasksOptional,
activityEmbeddingOptional, activityEmbeddingOptional,
transitions, transitions,

View File

@@ -49,7 +49,9 @@ import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellBackgroundThread; import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropController;
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.onehanded.OneHandedController; import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAnimationController;
@@ -194,10 +196,27 @@ public abstract class WMShellModule {
@WMSingleton @WMSingleton
@Provides @Provides
@DynamicOverride @DynamicOverride
static FreeformComponents provideFreeformComponents(
FreeformTaskListener<?> taskListener,
FreeformTaskTransitionHandler transitionHandler) {
return new FreeformComponents(taskListener, Optional.of(transitionHandler));
}
@WMSingleton
@Provides
static FreeformTaskListener<?> provideFreeformTaskListener( static FreeformTaskListener<?> provideFreeformTaskListener(
WindowDecorViewModel<?> windowDecorViewModel) {
return new FreeformTaskListener<>(windowDecorViewModel);
}
@WMSingleton
@Provides
static FreeformTaskTransitionHandler provideTaskTransitionHandler(
Transitions transitions,
WindowDecorViewModel<?> windowDecorViewModel, WindowDecorViewModel<?> windowDecorViewModel,
SyncTransactionQueue syncQueue) { FreeformTaskListener<?> freeformTaskListener) {
return new FreeformTaskListener<>(windowDecorViewModel, syncQueue); return new FreeformTaskTransitionHandler(transitions, windowDecorViewModel,
freeformTaskListener);
} }
// //

View File

@@ -0,0 +1,56 @@
/*
* 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.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.content.Context;
import android.provider.Settings;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
/**
* Class that holds freeform related classes. It serves as the single injection point of
* all freeform classes to avoid leaking implementation details to the base Dagger module.
*/
public class FreeformComponents {
public final ShellTaskOrganizer.TaskListener mTaskListener;
public final Optional<Transitions.TransitionHandler> mTaskTransitionHandler;
/**
* Creates an instance with the given components.
*/
public FreeformComponents(
ShellTaskOrganizer.TaskListener taskListener,
Optional<Transitions.TransitionHandler> taskTransitionHandler) {
mTaskListener = taskListener;
mTaskTransitionHandler = taskTransitionHandler;
}
/**
* Returns if this device supports freeform.
*/
public static boolean isFreeformEnabled(Context context) {
return context.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
|| Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
}
}

View File

@@ -16,20 +16,18 @@
package com.android.wm.shell.freeform; package com.android.wm.shell.freeform;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context; import android.util.Log;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.window.TransitionInfo;
import androidx.annotation.Nullable;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel; import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -45,9 +43,9 @@ public class FreeformTaskListener<T extends AutoCloseable>
private static final String TAG = "FreeformTaskListener"; private static final String TAG = "FreeformTaskListener";
private final WindowDecorViewModel<T> mWindowDecorationViewModel; private final WindowDecorViewModel<T> mWindowDecorationViewModel;
private final SyncTransactionQueue mSyncQueue;
private final SparseArray<State<T>> mTasks = new SparseArray<>(); private final SparseArray<State<T>> mTasks = new SparseArray<>();
private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
private static class State<T extends AutoCloseable> { private static class State<T extends AutoCloseable> {
RunningTaskInfo mTaskInfo; RunningTaskInfo mTaskInfo;
@@ -55,58 +53,79 @@ public class FreeformTaskListener<T extends AutoCloseable>
T mWindowDecoration; T mWindowDecoration;
} }
public FreeformTaskListener( public FreeformTaskListener(WindowDecorViewModel<T> windowDecorationViewModel) {
WindowDecorViewModel<T> windowDecorationViewModel,
SyncTransactionQueue syncQueue) {
mWindowDecorationViewModel = windowDecorationViewModel; mWindowDecorationViewModel = windowDecorationViewModel;
mSyncQueue = syncQueue;
} }
@Override @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
if (mTasks.get(taskInfo.taskId) != null) {
throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d", ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d",
taskInfo.taskId); taskInfo.taskId);
final State<T> state = new State<>(); final State<T> state = createOrUpdateTaskState(taskInfo, leash);
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
state.mWindowDecoration =
mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
t.apply();
}
}
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.mTaskInfo = taskInfo;
state.mLeash = leash; state.mLeash = leash;
state.mWindowDecoration =
mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash);
mTasks.put(taskInfo.taskId, state); mTasks.put(taskInfo.taskId, state);
return state;
} }
@Override @Override
public void onTaskVanished(RunningTaskInfo taskInfo) { public void onTaskVanished(RunningTaskInfo taskInfo) {
State<T> state = mTasks.get(taskInfo.taskId); final State<T> state = mTasks.get(taskInfo.taskId);
if (state == null) { if (state == null) {
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); // This is possible if the transition happens before this method.
return; return;
} }
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d", ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
taskInfo.taskId); taskInfo.taskId);
mTasks.remove(taskInfo.taskId); mTasks.remove(taskInfo.taskId);
try { if (Transitions.ENABLE_SHELL_TRANSITIONS) {
state.mWindowDecoration.close(); // Save window decorations of closing tasks so that we can hand them over to the
} catch (Exception e) { // transition system if this method happens before the transition. In case where the
Slog.e(TAG, "Failed to release window decoration.", e); // 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);
} }
@Override @Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) { public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
State<T> state = mTasks.get(taskInfo.taskId); final State<T> state = updateTaskInfo(taskInfo);
if (state == null) {
throw new RuntimeException(
"Task info changed before appearing: #" + taskInfo.taskId);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d", ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
taskInfo.taskId); taskInfo.taskId);
state.mTaskInfo = taskInfo; if (state.mWindowDecoration != null) {
mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration); mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
} }
}
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 @Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
@@ -126,6 +145,93 @@ public class FreeformTaskListener<T extends AutoCloseable>
return mTasks.get(taskId).mLeash; 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 adopts the window decoration; {@code false} otherwise
*/
void createWindowDecoration(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
state.mTaskInfo, state.mLeash, startT, finishT);
}
/**
* 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 = mWindowDecorOfVanishedTasks.get(taskInfo.taskId);
mWindowDecorOfVanishedTasks.remove(taskInfo.taskId);
final State<T> state = mTasks.get(taskInfo.taskId);
if (state != null) {
windowDecor = windowDecor == null ? state.mWindowDecoration : windowDecor;
state.mWindowDecoration = 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;
}
Log.w(TAG, "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 @Override
public void dump(PrintWriter pw, String prefix) { public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " "; final String innerPrefix = prefix + " ";
@@ -137,16 +243,4 @@ public class FreeformTaskListener<T extends AutoCloseable>
public String toString() { public String toString() {
return TAG; return TAG;
} }
/**
* Checks if freeform support is enabled in system.
*
* @param context context used to check settings and package manager.
* @return {@code true} if freeform is enabled, {@code false} if not.
*/
public static boolean isFreeformEnabled(Context context) {
return context.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
|| Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
}
} }

View File

@@ -0,0 +1,234 @@
/*
* 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.app.WindowConfiguration;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.util.ArrayList;
import java.util.List;
/**
* 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 FreeformTaskTransitionHandler
implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
private static final String TAG = "FreeformTH";
private final Transitions mTransitions;
private final FreeformTaskListener<?> mFreeformTaskListener;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
public FreeformTaskTransitionHandler(
Transitions transitions,
WindowDecorViewModel<?> windowDecorViewModel,
FreeformTaskListener<?> freeformTaskListener) {
mTransitions = transitions;
mFreeformTaskListener = freeformTaskListener;
windowDecorViewModel.setFreeformTaskTransitionStarter(this);
}
@Override
public void startWindowingModeTransition(
int targetWindowingMode, WindowContainerTransaction wct) {
final int type;
switch (targetWindowingMode) {
case WINDOWING_MODE_FULLSCREEN:
type = Transitions.TRANSIT_MAXIMIZE;
break;
case WINDOWING_MODE_FREEFORM:
type = Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE;
break;
default:
throw new IllegalArgumentException("Unexpected target windowing mode "
+ WindowConfiguration.windowingModeToString(targetWindowingMode));
}
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startT,
@NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
boolean transitionHandled = false;
final ArrayList<AutoCloseable> windowDecorsInCloseTransitions = 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:
transitionHandled |= startOpenTransition(change, startT, finishT);
break;
case WindowManager.TRANSIT_CLOSE:
transitionHandled |= startCloseTransition(
change, windowDecorsInCloseTransitions, startT, finishT);
break;
case WindowManager.TRANSIT_CHANGE:
transitionHandled |= startChangeTransition(
transition, info.getType(), change, startT, finishT);
break;
case WindowManager.TRANSIT_TO_BACK:
case WindowManager.TRANSIT_TO_FRONT:
transitionHandled = true;
break;
}
}
mPendingTransitionTokens.remove(transition);
if (!transitionHandled) {
return false;
}
startT.apply();
mTransitions.getMainExecutor().execute(
() -> finishTransition(windowDecorsInCloseTransitions, finishCallback));
return true;
}
private boolean startOpenTransition(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
if (change.getTaskInfo().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
return false;
}
mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
return true;
}
private boolean startCloseTransition(
TransitionInfo.Change change,
ArrayList<AutoCloseable> windowDecors,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
if (change.getTaskInfo().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
return false;
}
final AutoCloseable windowDecor =
mFreeformTaskListener.giveWindowDecoration(change.getTaskInfo(), startT, finishT);
if (windowDecor != null) {
windowDecors.add(windowDecor);
}
return true;
}
private boolean startChangeTransition(
IBinder transition,
int type,
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
AutoCloseable windowDecor = null;
if (!mPendingTransitionTokens.contains(transition)) {
return false;
}
boolean handled = false;
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (type == Transitions.TRANSIT_MAXIMIZE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
handled = true;
windowDecor = mFreeformTaskListener.giveWindowDecoration(
change.getTaskInfo(), startT, finishT);
// TODO(b/235638450): Let fullscreen task listener adopt the window decor.
}
if (type == Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
handled = true;
// TODO(b/235638450): Let fullscreen task listener transfer the window decor.
mFreeformTaskListener.adoptWindowDecoration(change, startT, finishT, windowDecor);
}
releaseWindowDecor(windowDecor);
return handled;
}
private void finishTransition(
ArrayList<AutoCloseable> windowDecorsInCloseTransitions,
Transitions.TransitionFinishCallback finishCallback) {
for (AutoCloseable windowDecor : windowDecorsInCloseTransitions) {
releaseWindowDecor(windowDecor);
}
mFreeformTaskListener.onTaskTransitionFinished();
// TODO(b/235638450): Dispatch it to fullscreen task listener.
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
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo taskInfo = request.getTriggerTask();
if (taskInfo == null || taskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
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;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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 android.window.WindowContainerTransaction;
/**
* The interface around {@link FreeformTaskTransitionHandler} for task listeners to start freeform
* task transitions.
*/
public interface FreeformTaskTransitionStarter {
/**
* Starts a windowing mode transition.
*
* @param targetWindowingMode the target windowing mode
* @param wct the {@link WindowContainerTransaction} that changes the windowing mode
*/
void startWindowingModeTransition(int targetWindowingMode, WindowContainerTransaction wct);
}

View File

@@ -34,7 +34,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -68,7 +68,7 @@ public class ShellInit {
private final FullscreenTaskListener mFullscreenTaskListener; private final FullscreenTaskListener mFullscreenTaskListener;
private final Optional<UnfoldAnimationController> mUnfoldController; private final Optional<UnfoldAnimationController> mUnfoldController;
private final Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler; private final Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
private final Optional<FreeformTaskListener<?>> mFreeformTaskListenerOptional; private final Optional<FreeformComponents> mFreeformComponentsOptional;
private final ShellExecutor mMainExecutor; private final ShellExecutor mMainExecutor;
private final Transitions mTransitions; private final Transitions mTransitions;
private final StartingWindowController mStartingWindow; private final StartingWindowController mStartingWindow;
@@ -93,7 +93,7 @@ public class ShellInit {
FullscreenTaskListener fullscreenTaskListener, FullscreenTaskListener fullscreenTaskListener,
Optional<UnfoldAnimationController> unfoldAnimationController, Optional<UnfoldAnimationController> unfoldAnimationController,
Optional<UnfoldTransitionHandler> unfoldTransitionHandler, Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
Optional<FreeformTaskListener<?>> freeformTaskListenerOptional, Optional<FreeformComponents> freeformComponentsOptional,
Optional<RecentTasksController> recentTasks, Optional<RecentTasksController> recentTasks,
Optional<ActivityEmbeddingController> activityEmbeddingOptional, Optional<ActivityEmbeddingController> activityEmbeddingOptional,
Transitions transitions, Transitions transitions,
@@ -111,7 +111,7 @@ public class ShellInit {
mPipTouchHandlerOptional = pipTouchHandlerOptional; mPipTouchHandlerOptional = pipTouchHandlerOptional;
mUnfoldController = unfoldAnimationController; mUnfoldController = unfoldAnimationController;
mUnfoldTransitionHandler = unfoldTransitionHandler; mUnfoldTransitionHandler = unfoldTransitionHandler;
mFreeformTaskListenerOptional = freeformTaskListenerOptional; mFreeformComponentsOptional = freeformComponentsOptional;
mRecentTasks = recentTasks; mRecentTasks = recentTasks;
mActivityEmbeddingOptional = activityEmbeddingOptional; mActivityEmbeddingOptional = activityEmbeddingOptional;
mTransitions = transitions; mTransitions = transitions;
@@ -143,6 +143,8 @@ public class ShellInit {
mTransitions.register(mShellTaskOrganizer); mTransitions.register(mShellTaskOrganizer);
mActivityEmbeddingOptional.ifPresent(ActivityEmbeddingController::init); mActivityEmbeddingOptional.ifPresent(ActivityEmbeddingController::init);
mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init); mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init);
mFreeformComponentsOptional.flatMap(f -> f.mTaskTransitionHandler)
.ifPresent(mTransitions::addHandler);
if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) { if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions, final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
mPipTouchHandlerOptional.get().getTransitionHandler(), mPipTouchHandlerOptional.get().getTransitionHandler(),
@@ -158,9 +160,9 @@ public class ShellInit {
mPipTouchHandlerOptional.ifPresent((handler) -> handler.init()); mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
// Initialize optional freeform // Initialize optional freeform
mFreeformTaskListenerOptional.ifPresent(f -> mFreeformComponentsOptional.ifPresent(f ->
mShellTaskOrganizer.addListenerForType( mShellTaskOrganizer.addListenerForType(
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM)); f.mTaskListener, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
mUnfoldController.ifPresent(UnfoldAnimationController::init); mUnfoldController.ifPresent(UnfoldAnimationController::init);
mRecentTasks.ifPresent(RecentTasksController::init); mRecentTasks.ifPresent(RecentTasksController::init);

View File

@@ -98,6 +98,12 @@ public class Transitions implements RemoteCallable<Transitions> {
/** Transition type for dismissing split-screen. */ /** Transition type for dismissing split-screen. */
public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 7; public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 7;
/** Transition type for freeform to maximize transition. */
public static final int TRANSIT_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 8;
/** Transition type for maximize to freeform transition. */
public static final int TRANSIT_RESTORE_FROM_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 9;
private final WindowOrganizer mOrganizer; private final WindowOrganizer mOrganizer;
private final Context mContext; private final Context mContext;
private final ShellExecutor mMainExecutor; private final ShellExecutor mMainExecutor;

View File

@@ -36,6 +36,8 @@ import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.transition.Transitions;
/** /**
* View model for the window decoration with a caption and shadows. Works with * View model for the window decoration with a caption and shadows. Works with
@@ -50,6 +52,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
private final DisplayController mDisplayController; private final DisplayController mDisplayController;
private final SyncTransactionQueue mSyncQueue; private final SyncTransactionQueue mSyncQueue;
private FreeformTaskTransitionStarter mTransitionStarter;
public CaptionWindowDecorViewModel( public CaptionWindowDecorViewModel(
Context context, Context context,
Handler mainHandler, Handler mainHandler,
@@ -66,9 +70,17 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
mSyncQueue = syncQueue; mSyncQueue = syncQueue;
} }
@Override
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
mTransitionStarter = transitionStarter;
}
@Override @Override
public CaptionWindowDecoration createWindowDecoration( public CaptionWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface) { ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration( final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
mContext, mContext,
mDisplayController, mDisplayController,
@@ -83,18 +95,39 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
new CaptionTouchEventListener(taskInfo, taskPositioner); new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragResizeCallback(taskPositioner); windowDecoration.setDragResizeCallback(taskPositioner);
onTaskInfoChanged(taskInfo, windowDecoration); setupWindowDecorationForTransition(taskInfo, startT, finishT, windowDecoration);
setupCaptionColor(taskInfo, windowDecoration);
return windowDecoration; return windowDecoration;
} }
@Override
public CaptionWindowDecoration adoptWindowDecoration(AutoCloseable windowDecor) {
return (windowDecor instanceof CaptionWindowDecoration)
? (CaptionWindowDecoration) windowDecor
: null;
}
@Override @Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) { public void onTaskInfoChanged(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
decoration.relayout(taskInfo); decoration.relayout(taskInfo);
setupCaptionColor(taskInfo, decoration);
}
private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
int statusBarColor = taskInfo.taskDescription.getStatusBarColor(); int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
decoration.setCaptionColor(statusBarColor); decoration.setCaptionColor(statusBarColor);
} }
@Override
public void setupWindowDecorationForTransition(
RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT,
CaptionWindowDecoration decoration) {
decoration.relayout(taskInfo, startT, finishT);
}
private class CaptionTouchEventListener implements private class CaptionTouchEventListener implements
View.OnClickListener, View.OnTouchListener { View.OnClickListener, View.OnTouchListener {
@@ -105,7 +138,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
private int mDragPointerId = -1; private int mDragPointerId = -1;
private CaptionTouchEventListener( private CaptionTouchEventListener(
RunningTaskInfo taskInfo, DragResizeCallback dragResizeCallback) { RunningTaskInfo taskInfo,
DragResizeCallback dragResizeCallback) {
mTaskId = taskInfo.taskId; mTaskId = taskInfo.taskId;
mTaskToken = taskInfo.token; mTaskToken = taskInfo.token;
mDragResizeCallback = dragResizeCallback; mDragResizeCallback = dragResizeCallback;
@@ -113,7 +147,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
@Override @Override
public void onClick(View v) { public void onClick(View v) {
int id = v.getId(); final int id = v.getId();
if (id == R.id.close_window) { if (id == R.id.close_window) {
mActivityTaskManager.removeTask(mTaskId); mActivityTaskManager.removeTask(mTaskId);
} else if (id == R.id.maximize_window) { } else if (id == R.id.maximize_window) {
@@ -129,9 +163,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) { if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
wct.setBounds(mTaskToken, null); wct.setBounds(mTaskToken, null);
} }
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitionStarter.startWindowingModeTransition(targetWindowingMode, wct);
} else {
mSyncQueue.queue(wct); mSyncQueue.queue(wct);
} }
} }
}
@Override @Override
public boolean onTouch(View v, MotionEvent e) { public boolean onTouch(View v, MotionEvent e) {

View File

@@ -101,6 +101,16 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
@Override @Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) { void relayout(ActivityManager.RunningTaskInfo taskInfo) {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
relayout(taskInfo, t, t);
mSyncQueue.runInSync(transaction -> {
transaction.merge(t);
t.close();
});
}
void relayout(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
final int shadowRadiusDp = taskInfo.isFocused final int shadowRadiusDp = taskInfo.isFocused
? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP; ? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP;
final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode() final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode()
@@ -110,18 +120,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
WindowDecorLinearLayout oldRootView = mResult.mRootView; WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
relayout(taskInfo, R.layout.caption_window_decoration, oldRootView, relayout(taskInfo, R.layout.caption_window_decoration, oldRootView,
DECOR_CAPTION_HEIGHT_IN_DIP, outset, shadowRadiusDp, t, wct, mResult); DECOR_CAPTION_HEIGHT_IN_DIP, outset, shadowRadiusDp, startT, finishT, wct, mResult);
taskInfo = null; // Clear it just in case we use it accidentally taskInfo = null; // Clear it just in case we use it accidentally
mSyncQueue.runInSync(transaction -> {
transaction.merge(t);
t.close();
mTaskOrganizer.applyTransaction(wct); mTaskOrganizer.applyTransaction(wct);
});
if (mResult.mRootView == null) { if (mResult.mRootView == null) {
// This means something blocks the window decor from showing, e.g. the task is hidden. // This means something blocks the window decor from showing, e.g. the task is hidden.

View File

@@ -19,6 +19,10 @@ package com.android.wm.shell.windowdecor;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import androidx.annotation.Nullable;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
/** /**
* The interface used by some {@link com.android.wm.shell.ShellTaskOrganizer.TaskListener} to help * The interface used by some {@link com.android.wm.shell.ShellTaskOrganizer.TaskListener} to help
* customize {@link WindowDecoration}. Its implementations are responsible to interpret user's * customize {@link WindowDecoration}. Its implementations are responsible to interpret user's
@@ -29,14 +33,35 @@ import android.view.SurfaceControl;
*/ */
public interface WindowDecorViewModel<T extends AutoCloseable> { public interface WindowDecorViewModel<T extends AutoCloseable> {
/**
* Sets the transition starter that starts freeform task transitions.
*
* @param transitionStarter the transition starter that starts freeform task transitions
*/
void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
/** /**
* Creates a window decoration for the given task. * Creates a window decoration for the given task.
* *
* @param taskInfo the initial task info of the task * @param taskInfo the initial task info of the task
* @param taskSurface the surface of the task * @param taskSurface the surface of the task
* @param startT the start transaction to be applied before the transition
* @param finishT the finish transaction to restore states after the transition
* @return the window decoration object * @return the window decoration object
*/ */
T createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface); T createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT);
/**
* Adopts the window decoration if possible.
*
* @param windowDecor the potential window decoration to adopt
* @return the window decoration if it can be adopted, or {@code null} otherwise.
*/
T adoptWindowDecoration(@Nullable AutoCloseable windowDecor);
/** /**
* Notifies a task info update on the given task, with the window decoration created previously * Notifies a task info update on the given task, with the window decoration created previously
@@ -46,4 +71,18 @@ public interface WindowDecorViewModel<T extends AutoCloseable> {
* @param windowDecoration the window decoration created for the task * @param windowDecoration the window decoration created for the task
*/ */
void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo, T windowDecoration); void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo, T windowDecoration);
/**
* Notifies a transition is about to start about the given task to give the window decoration a
* chance to prepare for this transition.
*
* @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);
} }

View File

@@ -140,8 +140,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
abstract void relayout(RunningTaskInfo taskInfo); abstract void relayout(RunningTaskInfo taskInfo);
void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp, void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction t, Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT,
WindowContainerTransaction wct, RelayoutResult<T> outResult) { SurfaceControl.Transaction finishT, WindowContainerTransaction wct,
RelayoutResult<T> outResult) {
outResult.reset(); outResult.reset();
final Configuration oldTaskConfig = mTaskInfo.getConfiguration(); final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
@@ -151,7 +152,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
if (!mTaskInfo.isVisible) { if (!mTaskInfo.isVisible) {
releaseViews(); releaseViews();
t.hide(mTaskSurface); finishT.hide(mTaskSurface);
return; return;
} }
@@ -192,7 +193,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
.setParent(mTaskSurface) .setParent(mTaskSurface)
.build(); .build();
t.setTrustedOverlay(mDecorationContainerSurface, true); startT.setTrustedOverlay(mDecorationContainerSurface, true);
} }
final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
@@ -205,7 +206,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
outResult.mHeight = taskBounds.height() outResult.mHeight = taskBounds.height()
+ (int) (outsetsDp.bottom * outResult.mDensity) + (int) (outsetsDp.bottom * outResult.mDensity)
- decorContainerOffsetY; - decorContainerOffsetY;
t.setPosition(mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY) startT.setPosition(
mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY)
.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
.setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1) .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1)
.show(mDecorationContainerSurface); .show(mDecorationContainerSurface);
@@ -225,7 +227,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
t.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height())
.setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setShadowRadius(mTaskBackgroundSurface, shadowRadius)
.setColor(mTaskBackgroundSurface, mTmpColor); .setColor(mTaskBackgroundSurface, mTmpColor);
@@ -264,9 +266,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
decorContainerOffsetY, decorContainerOffsetY,
outResult.mWidth + decorContainerOffsetX, outResult.mWidth + decorContainerOffsetX,
outResult.mHeight + decorContainerOffsetY); outResult.mHeight + decorContainerOffsetY);
t.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) startT.show(mTaskSurface);
.setCrop(mTaskSurface, mTaskSurfaceCrop) finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
.show(mTaskSurface); .setCrop(mTaskSurface, mTaskSurfaceCrop);
} }
/** /**

View File

@@ -31,7 +31,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -71,7 +71,7 @@ public class ShellInitTest extends ShellTestCase {
@Mock private FullscreenTaskListener mFullscreenTaskListener; @Mock private FullscreenTaskListener mFullscreenTaskListener;
@Mock private Optional<UnfoldAnimationController> mUnfoldAnimationController; @Mock private Optional<UnfoldAnimationController> mUnfoldAnimationController;
@Mock private Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler; @Mock private Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
@Mock private Optional<FreeformTaskListener<?>> mFreeformTaskListenerOptional; @Mock private Optional<FreeformComponents> mFreeformComponentsOptional;
@Mock private Optional<RecentTasksController> mRecentTasks; @Mock private Optional<RecentTasksController> mRecentTasks;
@Mock private Optional<ActivityEmbeddingController> mActivityEmbeddingController; @Mock private Optional<ActivityEmbeddingController> mActivityEmbeddingController;
@Mock private Transitions mTransitions; @Mock private Transitions mTransitions;
@@ -87,7 +87,7 @@ public class ShellInitTest extends ShellTestCase {
mDisplayInsetsController, mDragAndDropController, mShellTaskOrganizer, mDisplayInsetsController, mDragAndDropController, mShellTaskOrganizer,
mKidsModeTaskOrganizer, mBubblesOptional, mSplitScreenOptional, mKidsModeTaskOrganizer, mBubblesOptional, mSplitScreenOptional,
mPipTouchHandlerOptional, mFullscreenTaskListener, mUnfoldAnimationController, mPipTouchHandlerOptional, mFullscreenTaskListener, mUnfoldAnimationController,
mUnfoldTransitionHandler, mFreeformTaskListenerOptional, mRecentTasks, mUnfoldTransitionHandler, mFreeformComponentsOptional, mRecentTasks,
mActivityEmbeddingController, mTransitions, mStartingWindow, mMainExecutor); mActivityEmbeddingController, mTransitions, mStartingWindow, mMainExecutor);
} }

View File

@@ -98,11 +98,13 @@ public class WindowDecorationTests extends ShellTestCase {
private WindowContainerTransaction mMockWindowContainerTransaction; private WindowContainerTransaction mMockWindowContainerTransaction;
private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>(); private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
private SurfaceControl.Transaction mMockSurfaceControlTransaction; private SurfaceControl.Transaction mMockSurfaceControlStartT;
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
@Before @Before
public void setUp() { public void setUp() {
mMockSurfaceControlTransaction = createMockSurfaceControlTransaction(); mMockSurfaceControlStartT = createMockSurfaceControlTransaction();
mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
.create(any(), any(), any(), anyBoolean()); .create(any(), any(), any(), anyBoolean());
@@ -149,7 +151,7 @@ public class WindowDecorationTests extends ShellTestCase {
verify(mMockSurfaceControlViewHostFactory, never()) verify(mMockSurfaceControlViewHostFactory, never())
.create(any(), any(), any(), anyBoolean()); .create(any(), any(), any(), anyBoolean());
verify(mMockSurfaceControlTransaction).hide(taskSurface); verify(mMockSurfaceControlFinishT).hide(taskSurface);
assertNull(mRelayoutResult.mRootView); assertNull(mRelayoutResult.mRootView);
} }
@@ -192,16 +194,16 @@ public class WindowDecorationTests extends ShellTestCase {
verify(decorContainerSurfaceBuilder).setParent(taskSurface); verify(decorContainerSurfaceBuilder).setParent(taskSurface);
verify(decorContainerSurfaceBuilder).setContainerLayer(); verify(decorContainerSurfaceBuilder).setContainerLayer();
verify(mMockSurfaceControlTransaction).setTrustedOverlay(decorContainerSurface, true); verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
verify(mMockSurfaceControlTransaction).setPosition(decorContainerSurface, -20, -40); verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40);
verify(mMockSurfaceControlTransaction).setWindowCrop(decorContainerSurface, 380, 220); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220);
verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); verify(taskBackgroundSurfaceBuilder).setParent(taskSurface);
verify(taskBackgroundSurfaceBuilder).setEffectLayer(); verify(taskBackgroundSurfaceBuilder).setEffectLayer();
verify(mMockSurfaceControlTransaction).setWindowCrop(taskBackgroundSurface, 300, 100); verify(mMockSurfaceControlStartT).setWindowCrop(taskBackgroundSurface, 300, 100);
verify(mMockSurfaceControlTransaction) verify(mMockSurfaceControlStartT)
.setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f}); .setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f});
verify(mMockSurfaceControlTransaction).setShadowRadius(taskBackgroundSurface, 10); verify(mMockSurfaceControlStartT).setShadowRadius(taskBackgroundSurface, 10);
verify(mMockSurfaceControlViewHostFactory) verify(mMockSurfaceControlViewHostFactory)
.create(any(), eq(defaultDisplay), any(), anyBoolean()); .create(any(), eq(defaultDisplay), any(), anyBoolean());
@@ -218,11 +220,11 @@ public class WindowDecorationTests extends ShellTestCase {
new int[] { InsetsState.ITYPE_CAPTION_BAR }); new int[] { InsetsState.ITYPE_CAPTION_BAR });
} }
verify(mMockSurfaceControlTransaction) verify(mMockSurfaceControlFinishT)
.setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y);
verify(mMockSurfaceControlTransaction) verify(mMockSurfaceControlFinishT)
.setCrop(taskSurface, new Rect(-20, -40, 360, 180)); .setCrop(taskSurface, new Rect(-20, -40, 360, 180));
verify(mMockSurfaceControlTransaction) verify(mMockSurfaceControlStartT)
.show(taskSurface); .show(taskSurface);
assertEquals(380, mRelayoutResult.mWidth); assertEquals(380, mRelayoutResult.mWidth);
@@ -319,8 +321,8 @@ public class WindowDecorationTests extends ShellTestCase {
@Override @Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) { void relayout(ActivityManager.RunningTaskInfo taskInfo) {
relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP, relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlTransaction, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
mMockWindowContainerTransaction, mRelayoutResult); mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult);
} }
} }
} }