Merge "Add FreeformTaskTransitionHandler" into tm-qpr-dev am: 3f2c081a30 am: dd4fc8f5d8
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19224057 Change-Id: I0f62ed136594ac01a2ddfba40d185de0f6f87235 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -29,8 +29,6 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.wm.shell.RootDisplayAreaOrganizer;
|
||||
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.TaskViewFactory;
|
||||
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.DisplayAreaHelperController;
|
||||
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.hidedisplaycutout.HideDisplayCutoutController;
|
||||
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.StartingWindowTypeAlgorithm;
|
||||
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.ShellInit;
|
||||
import com.android.wm.shell.sysui.ShellInterface;
|
||||
import com.android.wm.shell.transition.ShellTransitions;
|
||||
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}
|
||||
@BindsOptionalOf
|
||||
@DynamicOverride
|
||||
abstract FreeformTaskListener<?> optionalFreeformTaskListener();
|
||||
abstract FreeformComponents optionalFreeformComponents();
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<FreeformTaskListener<?>> provideFreeformTaskListener(
|
||||
@DynamicOverride Optional<FreeformTaskListener<?>> freeformTaskListener,
|
||||
static Optional<FreeformComponents> provideFreeformTaskListener(
|
||||
@DynamicOverride Optional<FreeformComponents> freeformComponents,
|
||||
Context context) {
|
||||
if (FreeformTaskListener.isFreeformEnabled(context)) {
|
||||
return freeformTaskListener;
|
||||
if (FreeformComponents.isFreeformEnabled(context)) {
|
||||
return freeformComponents;
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -636,7 +636,7 @@ public abstract class WMShellBaseModule {
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<UnfoldAnimationController> unfoldAnimationController,
|
||||
Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
|
||||
Optional<FreeformTaskListener<?>> freeformTaskListener,
|
||||
Optional<FreeformComponents> freeformComponents,
|
||||
Optional<RecentTasksController> recentTasksOptional,
|
||||
Optional<ActivityEmbeddingController> activityEmbeddingOptional,
|
||||
Transitions transitions,
|
||||
@@ -655,7 +655,7 @@ public abstract class WMShellBaseModule {
|
||||
fullscreenTaskListener,
|
||||
unfoldAnimationController,
|
||||
unfoldTransitionHandler,
|
||||
freeformTaskListener,
|
||||
freeformComponents,
|
||||
recentTasksOptional,
|
||||
activityEmbeddingOptional,
|
||||
transitions,
|
||||
|
||||
@@ -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.ShellMainThread;
|
||||
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.FreeformTaskTransitionHandler;
|
||||
import com.android.wm.shell.onehanded.OneHandedController;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
@@ -194,10 +196,27 @@ public abstract class WMShellModule {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
@DynamicOverride
|
||||
static FreeformComponents provideFreeformComponents(
|
||||
FreeformTaskListener<?> taskListener,
|
||||
FreeformTaskTransitionHandler transitionHandler) {
|
||||
return new FreeformComponents(taskListener, Optional.of(transitionHandler));
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static FreeformTaskListener<?> provideFreeformTaskListener(
|
||||
WindowDecorViewModel<?> windowDecorViewModel) {
|
||||
return new FreeformTaskListener<>(windowDecorViewModel);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static FreeformTaskTransitionHandler provideTaskTransitionHandler(
|
||||
Transitions transitions,
|
||||
WindowDecorViewModel<?> windowDecorViewModel,
|
||||
SyncTransactionQueue syncQueue) {
|
||||
return new FreeformTaskListener<>(windowDecorViewModel, syncQueue);
|
||||
FreeformTaskListener<?> freeformTaskListener) {
|
||||
return new FreeformTaskTransitionHandler(transitions, windowDecorViewModel,
|
||||
freeformTaskListener);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -16,20 +16,18 @@
|
||||
|
||||
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.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.TransitionInfo;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -45,9 +43,9 @@ public class FreeformTaskListener<T extends AutoCloseable>
|
||||
private static final String TAG = "FreeformTaskListener";
|
||||
|
||||
private final WindowDecorViewModel<T> mWindowDecorationViewModel;
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
|
||||
private final SparseArray<State<T>> mTasks = new SparseArray<>();
|
||||
private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
|
||||
|
||||
private static class State<T extends AutoCloseable> {
|
||||
RunningTaskInfo mTaskInfo;
|
||||
@@ -55,57 +53,78 @@ public class FreeformTaskListener<T extends AutoCloseable>
|
||||
T mWindowDecoration;
|
||||
}
|
||||
|
||||
public FreeformTaskListener(
|
||||
WindowDecorViewModel<T> windowDecorationViewModel,
|
||||
SyncTransactionQueue syncQueue) {
|
||||
public FreeformTaskListener(WindowDecorViewModel<T> windowDecorationViewModel) {
|
||||
mWindowDecorationViewModel = windowDecorationViewModel;
|
||||
mSyncQueue = syncQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
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",
|
||||
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.mLeash = leash;
|
||||
state.mWindowDecoration =
|
||||
mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash);
|
||||
mTasks.put(taskInfo.taskId, state);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskVanished(RunningTaskInfo taskInfo) {
|
||||
State<T> state = mTasks.get(taskInfo.taskId);
|
||||
final State<T> state = mTasks.get(taskInfo.taskId);
|
||||
if (state == null) {
|
||||
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
|
||||
// This is possible if the transition happens before this method.
|
||||
return;
|
||||
}
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
|
||||
taskInfo.taskId);
|
||||
mTasks.remove(taskInfo.taskId);
|
||||
|
||||
try {
|
||||
state.mWindowDecoration.close();
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Failed to release window decoration.", e);
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
// Save window decorations of closing tasks so that we can hand them over to the
|
||||
// transition system if this method happens before the transition. In case where the
|
||||
// transition didn't happen, it'd be cleared when the next transition finished.
|
||||
if (state.mWindowDecoration != null) {
|
||||
mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration);
|
||||
}
|
||||
return;
|
||||
}
|
||||
releaseWindowDecor(state.mWindowDecoration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
|
||||
State<T> state = mTasks.get(taskInfo.taskId);
|
||||
if (state == null) {
|
||||
throw new RuntimeException(
|
||||
"Task info changed before appearing: #" + taskInfo.taskId);
|
||||
}
|
||||
final State<T> state = updateTaskInfo(taskInfo);
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
|
||||
taskInfo.taskId);
|
||||
if (state.mWindowDecoration != null) {
|
||||
mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,6 +145,93 @@ public class FreeformTaskListener<T extends AutoCloseable>
|
||||
return mTasks.get(taskId).mLeash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a window decoration for a transition.
|
||||
*
|
||||
* @param change the change of this task transition that needs to have the task layer as the
|
||||
* leash
|
||||
* @return {@code true} if it 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
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
@@ -137,16 +243,4 @@ public class FreeformTaskListener<T extends AutoCloseable>
|
||||
public String toString() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
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.kidsmode.KidsModeTaskOrganizer;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
@@ -68,7 +68,7 @@ public class ShellInit {
|
||||
private final FullscreenTaskListener mFullscreenTaskListener;
|
||||
private final Optional<UnfoldAnimationController> mUnfoldController;
|
||||
private final Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
|
||||
private final Optional<FreeformTaskListener<?>> mFreeformTaskListenerOptional;
|
||||
private final Optional<FreeformComponents> mFreeformComponentsOptional;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final Transitions mTransitions;
|
||||
private final StartingWindowController mStartingWindow;
|
||||
@@ -93,7 +93,7 @@ public class ShellInit {
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<UnfoldAnimationController> unfoldAnimationController,
|
||||
Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
|
||||
Optional<FreeformTaskListener<?>> freeformTaskListenerOptional,
|
||||
Optional<FreeformComponents> freeformComponentsOptional,
|
||||
Optional<RecentTasksController> recentTasks,
|
||||
Optional<ActivityEmbeddingController> activityEmbeddingOptional,
|
||||
Transitions transitions,
|
||||
@@ -111,7 +111,7 @@ public class ShellInit {
|
||||
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
||||
mUnfoldController = unfoldAnimationController;
|
||||
mUnfoldTransitionHandler = unfoldTransitionHandler;
|
||||
mFreeformTaskListenerOptional = freeformTaskListenerOptional;
|
||||
mFreeformComponentsOptional = freeformComponentsOptional;
|
||||
mRecentTasks = recentTasks;
|
||||
mActivityEmbeddingOptional = activityEmbeddingOptional;
|
||||
mTransitions = transitions;
|
||||
@@ -143,6 +143,8 @@ public class ShellInit {
|
||||
mTransitions.register(mShellTaskOrganizer);
|
||||
mActivityEmbeddingOptional.ifPresent(ActivityEmbeddingController::init);
|
||||
mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init);
|
||||
mFreeformComponentsOptional.flatMap(f -> f.mTaskTransitionHandler)
|
||||
.ifPresent(mTransitions::addHandler);
|
||||
if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
|
||||
final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
|
||||
mPipTouchHandlerOptional.get().getTransitionHandler(),
|
||||
@@ -158,9 +160,9 @@ public class ShellInit {
|
||||
mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
|
||||
|
||||
// Initialize optional freeform
|
||||
mFreeformTaskListenerOptional.ifPresent(f ->
|
||||
mFreeformComponentsOptional.ifPresent(f ->
|
||||
mShellTaskOrganizer.addListenerForType(
|
||||
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
||||
f.mTaskListener, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
||||
|
||||
mUnfoldController.ifPresent(UnfoldAnimationController::init);
|
||||
mRecentTasks.ifPresent(RecentTasksController::init);
|
||||
|
||||
@@ -98,6 +98,12 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
/** Transition type for dismissing split-screen. */
|
||||
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 Context mContext;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
|
||||
@@ -36,6 +36,8 @@ import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
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
|
||||
@@ -50,6 +52,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
private final DisplayController mDisplayController;
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
|
||||
private FreeformTaskTransitionStarter mTransitionStarter;
|
||||
|
||||
public CaptionWindowDecorViewModel(
|
||||
Context context,
|
||||
Handler mainHandler,
|
||||
@@ -66,9 +70,17 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
mSyncQueue = syncQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
|
||||
mTransitionStarter = transitionStarter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptionWindowDecoration createWindowDecoration(
|
||||
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface) {
|
||||
ActivityManager.RunningTaskInfo taskInfo,
|
||||
SurfaceControl taskSurface,
|
||||
SurfaceControl.Transaction startT,
|
||||
SurfaceControl.Transaction finishT) {
|
||||
final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
|
||||
mContext,
|
||||
mDisplayController,
|
||||
@@ -83,18 +95,39 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
new CaptionTouchEventListener(taskInfo, taskPositioner);
|
||||
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
||||
windowDecoration.setDragResizeCallback(taskPositioner);
|
||||
onTaskInfoChanged(taskInfo, windowDecoration);
|
||||
setupWindowDecorationForTransition(taskInfo, startT, finishT, windowDecoration);
|
||||
setupCaptionColor(taskInfo, windowDecoration);
|
||||
return windowDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptionWindowDecoration adoptWindowDecoration(AutoCloseable windowDecor) {
|
||||
return (windowDecor instanceof CaptionWindowDecoration)
|
||||
? (CaptionWindowDecoration) windowDecor
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskInfoChanged(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
|
||||
decoration.relayout(taskInfo);
|
||||
|
||||
setupCaptionColor(taskInfo, decoration);
|
||||
}
|
||||
|
||||
private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
|
||||
int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
|
||||
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
|
||||
View.OnClickListener, View.OnTouchListener {
|
||||
|
||||
@@ -105,7 +138,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
private int mDragPointerId = -1;
|
||||
|
||||
private CaptionTouchEventListener(
|
||||
RunningTaskInfo taskInfo, DragResizeCallback dragResizeCallback) {
|
||||
RunningTaskInfo taskInfo,
|
||||
DragResizeCallback dragResizeCallback) {
|
||||
mTaskId = taskInfo.taskId;
|
||||
mTaskToken = taskInfo.token;
|
||||
mDragResizeCallback = dragResizeCallback;
|
||||
@@ -113,7 +147,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
final int id = v.getId();
|
||||
if (id == R.id.close_window) {
|
||||
mActivityTaskManager.removeTask(mTaskId);
|
||||
} else if (id == R.id.maximize_window) {
|
||||
@@ -129,7 +163,11 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption
|
||||
if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
|
||||
wct.setBounds(mTaskToken, null);
|
||||
}
|
||||
mSyncQueue.queue(wct);
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
mTransitionStarter.startWindowingModeTransition(targetWindowingMode, wct);
|
||||
} else {
|
||||
mSyncQueue.queue(wct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,16 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
||||
|
||||
@Override
|
||||
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
|
||||
? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP;
|
||||
final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode()
|
||||
@@ -110,18 +120,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
||||
|
||||
WindowDecorLinearLayout oldRootView = mResult.mRootView;
|
||||
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
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
|
||||
|
||||
mSyncQueue.runInSync(transaction -> {
|
||||
transaction.merge(t);
|
||||
t.close();
|
||||
|
||||
mTaskOrganizer.applyTransaction(wct);
|
||||
});
|
||||
mTaskOrganizer.applyTransaction(wct);
|
||||
|
||||
if (mResult.mRootView == null) {
|
||||
// This means something blocks the window decor from showing, e.g. the task is hidden.
|
||||
|
||||
@@ -19,6 +19,10 @@ package com.android.wm.shell.windowdecor;
|
||||
import android.app.ActivityManager;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -29,14 +33,35 @@ import android.view.SurfaceControl;
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param taskInfo the initial task info 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
|
||||
*/
|
||||
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
|
||||
@@ -46,4 +71,18 @@ public interface WindowDecorViewModel<T extends AutoCloseable> {
|
||||
* @param windowDecoration the window decoration created for the task
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -140,8 +140,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
abstract void relayout(RunningTaskInfo taskInfo);
|
||||
|
||||
void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
|
||||
Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction t,
|
||||
WindowContainerTransaction wct, RelayoutResult<T> outResult) {
|
||||
Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT,
|
||||
SurfaceControl.Transaction finishT, WindowContainerTransaction wct,
|
||||
RelayoutResult<T> outResult) {
|
||||
outResult.reset();
|
||||
|
||||
final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
|
||||
@@ -151,7 +152,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
|
||||
if (!mTaskInfo.isVisible) {
|
||||
releaseViews();
|
||||
t.hide(mTaskSurface);
|
||||
finishT.hide(mTaskSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
.setParent(mTaskSurface)
|
||||
.build();
|
||||
|
||||
t.setTrustedOverlay(mDecorationContainerSurface, true);
|
||||
startT.setTrustedOverlay(mDecorationContainerSurface, true);
|
||||
}
|
||||
|
||||
final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
|
||||
@@ -205,7 +206,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
outResult.mHeight = taskBounds.height()
|
||||
+ (int) (outsetsDp.bottom * outResult.mDensity)
|
||||
- decorContainerOffsetY;
|
||||
t.setPosition(mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY)
|
||||
startT.setPosition(
|
||||
mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY)
|
||||
.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
|
||||
.setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1)
|
||||
.show(mDecorationContainerSurface);
|
||||
@@ -225,7 +227,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
|
||||
mTmpColor[1] = (float) Color.green(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)
|
||||
.setColor(mTaskBackgroundSurface, mTmpColor);
|
||||
|
||||
@@ -264,9 +266,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
||||
decorContainerOffsetY,
|
||||
outResult.mWidth + decorContainerOffsetX,
|
||||
outResult.mHeight + decorContainerOffsetY);
|
||||
t.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
|
||||
.setCrop(mTaskSurface, mTaskSurfaceCrop)
|
||||
.show(mTaskSurface);
|
||||
startT.show(mTaskSurface);
|
||||
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
|
||||
.setCrop(mTaskSurface, mTaskSurfaceCrop);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
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.kidsmode.KidsModeTaskOrganizer;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
@@ -71,7 +71,7 @@ public class ShellInitTest extends ShellTestCase {
|
||||
@Mock private FullscreenTaskListener mFullscreenTaskListener;
|
||||
@Mock private Optional<UnfoldAnimationController> mUnfoldAnimationController;
|
||||
@Mock private Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
|
||||
@Mock private Optional<FreeformTaskListener<?>> mFreeformTaskListenerOptional;
|
||||
@Mock private Optional<FreeformComponents> mFreeformComponentsOptional;
|
||||
@Mock private Optional<RecentTasksController> mRecentTasks;
|
||||
@Mock private Optional<ActivityEmbeddingController> mActivityEmbeddingController;
|
||||
@Mock private Transitions mTransitions;
|
||||
@@ -87,7 +87,7 @@ public class ShellInitTest extends ShellTestCase {
|
||||
mDisplayInsetsController, mDragAndDropController, mShellTaskOrganizer,
|
||||
mKidsModeTaskOrganizer, mBubblesOptional, mSplitScreenOptional,
|
||||
mPipTouchHandlerOptional, mFullscreenTaskListener, mUnfoldAnimationController,
|
||||
mUnfoldTransitionHandler, mFreeformTaskListenerOptional, mRecentTasks,
|
||||
mUnfoldTransitionHandler, mFreeformComponentsOptional, mRecentTasks,
|
||||
mActivityEmbeddingController, mTransitions, mStartingWindow, mMainExecutor);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,11 +98,13 @@ public class WindowDecorationTests extends ShellTestCase {
|
||||
private WindowContainerTransaction mMockWindowContainerTransaction;
|
||||
|
||||
private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
|
||||
private SurfaceControl.Transaction mMockSurfaceControlTransaction;
|
||||
private SurfaceControl.Transaction mMockSurfaceControlStartT;
|
||||
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMockSurfaceControlTransaction = createMockSurfaceControlTransaction();
|
||||
mMockSurfaceControlStartT = createMockSurfaceControlTransaction();
|
||||
mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
|
||||
|
||||
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
|
||||
.create(any(), any(), any(), anyBoolean());
|
||||
@@ -149,7 +151,7 @@ public class WindowDecorationTests extends ShellTestCase {
|
||||
verify(mMockSurfaceControlViewHostFactory, never())
|
||||
.create(any(), any(), any(), anyBoolean());
|
||||
|
||||
verify(mMockSurfaceControlTransaction).hide(taskSurface);
|
||||
verify(mMockSurfaceControlFinishT).hide(taskSurface);
|
||||
|
||||
assertNull(mRelayoutResult.mRootView);
|
||||
}
|
||||
@@ -192,16 +194,16 @@ public class WindowDecorationTests extends ShellTestCase {
|
||||
|
||||
verify(decorContainerSurfaceBuilder).setParent(taskSurface);
|
||||
verify(decorContainerSurfaceBuilder).setContainerLayer();
|
||||
verify(mMockSurfaceControlTransaction).setTrustedOverlay(decorContainerSurface, true);
|
||||
verify(mMockSurfaceControlTransaction).setPosition(decorContainerSurface, -20, -40);
|
||||
verify(mMockSurfaceControlTransaction).setWindowCrop(decorContainerSurface, 380, 220);
|
||||
verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
|
||||
verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40);
|
||||
verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220);
|
||||
|
||||
verify(taskBackgroundSurfaceBuilder).setParent(taskSurface);
|
||||
verify(taskBackgroundSurfaceBuilder).setEffectLayer();
|
||||
verify(mMockSurfaceControlTransaction).setWindowCrop(taskBackgroundSurface, 300, 100);
|
||||
verify(mMockSurfaceControlTransaction)
|
||||
verify(mMockSurfaceControlStartT).setWindowCrop(taskBackgroundSurface, 300, 100);
|
||||
verify(mMockSurfaceControlStartT)
|
||||
.setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f});
|
||||
verify(mMockSurfaceControlTransaction).setShadowRadius(taskBackgroundSurface, 10);
|
||||
verify(mMockSurfaceControlStartT).setShadowRadius(taskBackgroundSurface, 10);
|
||||
|
||||
verify(mMockSurfaceControlViewHostFactory)
|
||||
.create(any(), eq(defaultDisplay), any(), anyBoolean());
|
||||
@@ -218,11 +220,11 @@ public class WindowDecorationTests extends ShellTestCase {
|
||||
new int[] { InsetsState.ITYPE_CAPTION_BAR });
|
||||
}
|
||||
|
||||
verify(mMockSurfaceControlTransaction)
|
||||
verify(mMockSurfaceControlFinishT)
|
||||
.setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y);
|
||||
verify(mMockSurfaceControlTransaction)
|
||||
verify(mMockSurfaceControlFinishT)
|
||||
.setCrop(taskSurface, new Rect(-20, -40, 360, 180));
|
||||
verify(mMockSurfaceControlTransaction)
|
||||
verify(mMockSurfaceControlStartT)
|
||||
.show(taskSurface);
|
||||
|
||||
assertEquals(380, mRelayoutResult.mWidth);
|
||||
@@ -319,8 +321,8 @@ public class WindowDecorationTests extends ShellTestCase {
|
||||
@Override
|
||||
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
|
||||
mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlTransaction,
|
||||
mMockWindowContainerTransaction, mRelayoutResult);
|
||||
mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
|
||||
mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user