Merge "Add a minimal FreeformTaskListener" into sc-v2-dev am: 7e23f324dd am: 4140b2ee39
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15475655 Change-Id: Ic28799314d8643279c620a41702cb6c6f41471ae
This commit is contained in:
@@ -24,6 +24,7 @@ import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
@@ -47,6 +48,7 @@ public class ShellInitImpl {
|
||||
private final Optional<AppPairsController> mAppPairsOptional;
|
||||
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
|
||||
private final FullscreenTaskListener mFullscreenTaskListener;
|
||||
private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final Transitions mTransitions;
|
||||
private final StartingWindowController mStartingWindow;
|
||||
@@ -62,6 +64,7 @@ public class ShellInitImpl {
|
||||
Optional<AppPairsController> appPairsOptional,
|
||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
||||
Transitions transitions,
|
||||
StartingWindowController startingWindow,
|
||||
ShellExecutor mainExecutor) {
|
||||
@@ -74,6 +77,7 @@ public class ShellInitImpl {
|
||||
mAppPairsOptional = appPairsOptional;
|
||||
mFullscreenTaskListener = fullscreenTaskListener;
|
||||
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
||||
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
|
||||
mTransitions = transitions;
|
||||
mMainExecutor = mainExecutor;
|
||||
mStartingWindow = startingWindow;
|
||||
@@ -108,6 +112,11 @@ public class ShellInitImpl {
|
||||
// controller instead of the feature interface, can just initialize the touch handler if
|
||||
// needed
|
||||
mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
|
||||
|
||||
// Initialize optional freeform
|
||||
mFreeformTaskListenerOptional.ifPresent(f ->
|
||||
mShellTaskOrganizer.addListenerForType(
|
||||
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
||||
}
|
||||
|
||||
@ExternalThread
|
||||
|
||||
@@ -71,12 +71,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
||||
public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2;
|
||||
public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
|
||||
public static final int TASK_LISTENER_TYPE_PIP = -4;
|
||||
public static final int TASK_LISTENER_TYPE_FREEFORM = -5;
|
||||
|
||||
@IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
|
||||
TASK_LISTENER_TYPE_UNDEFINED,
|
||||
TASK_LISTENER_TYPE_FULLSCREEN,
|
||||
TASK_LISTENER_TYPE_MULTI_WINDOW,
|
||||
TASK_LISTENER_TYPE_PIP,
|
||||
TASK_LISTENER_TYPE_FREEFORM,
|
||||
})
|
||||
public @interface TaskListenerType {}
|
||||
|
||||
@@ -572,6 +574,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
||||
case WINDOWING_MODE_PINNED:
|
||||
return TASK_LISTENER_TYPE_PIP;
|
||||
case WINDOWING_MODE_FREEFORM:
|
||||
return TASK_LISTENER_TYPE_FREEFORM;
|
||||
case WINDOWING_MODE_UNDEFINED:
|
||||
default:
|
||||
return TASK_LISTENER_TYPE_UNDEFINED;
|
||||
@@ -586,6 +589,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
||||
return "TASK_LISTENER_TYPE_MULTI_WINDOW";
|
||||
case TASK_LISTENER_TYPE_PIP:
|
||||
return "TASK_LISTENER_TYPE_PIP";
|
||||
case TASK_LISTENER_TYPE_FREEFORM:
|
||||
return "TASK_LISTENER_TYPE_FREEFORM";
|
||||
case TASK_LISTENER_TYPE_UNDEFINED:
|
||||
return "TASK_LISTENER_TYPE_UNDEFINED";
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
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 java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* {@link ShellTaskOrganizer.TaskListener} for {@link
|
||||
* ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}.
|
||||
*/
|
||||
public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
private static final String TAG = "FreeformTaskListener";
|
||||
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
|
||||
private final SparseArray<State> mTasks = new SparseArray<>();
|
||||
|
||||
private static class State {
|
||||
RunningTaskInfo mTaskInfo;
|
||||
SurfaceControl mLeash;
|
||||
}
|
||||
|
||||
public FreeformTaskListener(SyncTransactionQueue syncQueue) {
|
||||
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 state = new State();
|
||||
state.mTaskInfo = taskInfo;
|
||||
state.mLeash = leash;
|
||||
mTasks.put(taskInfo.taskId, state);
|
||||
|
||||
final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
|
||||
mSyncQueue.runInSync(t -> {
|
||||
Point taskPosition = taskInfo.positionInParent;
|
||||
t.setPosition(leash, taskPosition.x, taskPosition.y)
|
||||
.setWindowCrop(leash, taskBounds.width(), taskBounds.height())
|
||||
.show(leash);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskVanished(RunningTaskInfo taskInfo) {
|
||||
State state = mTasks.get(taskInfo.taskId);
|
||||
if (state == null) {
|
||||
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
|
||||
return;
|
||||
}
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
|
||||
taskInfo.taskId);
|
||||
mTasks.remove(taskInfo.taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
|
||||
State state = mTasks.get(taskInfo.taskId);
|
||||
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",
|
||||
taskInfo.taskId);
|
||||
state.mTaskInfo = taskInfo;
|
||||
|
||||
final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
|
||||
final SurfaceControl leash = state.mLeash;
|
||||
mSyncQueue.runInSync(t -> {
|
||||
Point taskPosition = taskInfo.positionInParent;
|
||||
t.setPosition(leash, taskPosition.x, taskPosition.y)
|
||||
.setWindowCrop(leash, taskBounds.width(), taskBounds.height())
|
||||
.show(leash);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.println(prefix + this);
|
||||
pw.println(innerPrefix + mTasks.size() + " tasks");
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link FreeformTaskListener} if freeform is enabled.
|
||||
*/
|
||||
public static FreeformTaskListener create(Context context,
|
||||
SyncTransactionQueue syncQueue) {
|
||||
if (!isFreeformEnabled(context)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FreeformTaskListener(syncQueue);
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ import com.android.wm.shell.common.annotations.ShellAnimationThread;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
||||
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
@@ -212,6 +213,13 @@ public abstract class WMShellBaseModule {
|
||||
return new FullscreenTaskListener(syncQueue);
|
||||
}
|
||||
|
||||
//
|
||||
// Freeform (optional feature)
|
||||
//
|
||||
|
||||
@BindsOptionalOf
|
||||
abstract Optional<FreeformTaskListener> optionalFreeformTaskListener();
|
||||
|
||||
//
|
||||
// Hide display cutout
|
||||
//
|
||||
@@ -453,6 +461,7 @@ public abstract class WMShellBaseModule {
|
||||
Optional<AppPairsController> appPairsOptional,
|
||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
||||
Transitions transitions,
|
||||
StartingWindowController startingWindow,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
@@ -465,6 +474,7 @@ public abstract class WMShellBaseModule {
|
||||
appPairsOptional,
|
||||
pipTouchHandlerOptional,
|
||||
fullscreenTaskListener,
|
||||
freeformTaskListener,
|
||||
transitions,
|
||||
startingWindow,
|
||||
mainExecutor);
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
import com.android.wm.shell.onehanded.OneHandedController;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
@@ -88,6 +89,18 @@ public class WMShellModule {
|
||||
transactionPool);
|
||||
}
|
||||
|
||||
//
|
||||
// Freeform
|
||||
//
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<FreeformTaskListener> provideFreeformTaskListener(
|
||||
Context context,
|
||||
SyncTransactionQueue syncQueue) {
|
||||
return Optional.ofNullable(FreeformTaskListener.create(context, syncQueue));
|
||||
}
|
||||
|
||||
//
|
||||
// Split/multiwindow
|
||||
//
|
||||
|
||||
@@ -4586,7 +4586,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
return true;
|
||||
}
|
||||
|
||||
if (task.isOrganized()) {
|
||||
// TODO(b/165794880): Freeform task organizer doesn't support drag-resize yet. Remove
|
||||
// the special case when it does.
|
||||
if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -306,7 +306,10 @@ final class InputMonitor {
|
||||
boolean useSurfaceCrop = false;
|
||||
final Task task = w.getTask();
|
||||
if (task != null) {
|
||||
if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
|
||||
// TODO(b/165794636): Remove the special case for freeform window once drag resizing is
|
||||
// handled by WM shell.
|
||||
if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
|
||||
&& !task.inFreeformWindowingMode()) {
|
||||
// If the window is in a TaskManaged by a TaskOrganizer then most cropping will
|
||||
// be applied using the SurfaceControl hierarchy from the Organizer. This means
|
||||
// we need to make sure that these changes in crop are reflected in the input
|
||||
|
||||
@@ -4174,8 +4174,7 @@ class Task extends TaskFragment {
|
||||
}
|
||||
|
||||
private boolean canBeOrganized() {
|
||||
if (mForceNotOrganized || !mAtmService.mTaskOrganizerController
|
||||
.isSupportedWindowingMode(getWindowingMode())) {
|
||||
if (mForceNotOrganized) {
|
||||
return false;
|
||||
}
|
||||
// All root tasks can be organized
|
||||
@@ -4332,7 +4331,7 @@ class Task extends TaskFragment {
|
||||
|
||||
final int windowingMode = getWindowingMode();
|
||||
final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController;
|
||||
final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
|
||||
final ITaskOrganizer organizer = controller.getTaskOrganizer();
|
||||
if (!forceUpdate && mTaskOrganizer == organizer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
|
||||
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
|
||||
@@ -67,14 +64,6 @@ import java.util.function.Consumer;
|
||||
class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
private static final String TAG = "TaskOrganizerController";
|
||||
|
||||
// The set of modes that are currently supports
|
||||
// TODO: Remove once the task organizer can support all modes
|
||||
@VisibleForTesting
|
||||
static final int[] UNSUPPORTED_WINDOWING_MODES = {
|
||||
WINDOWING_MODE_UNDEFINED,
|
||||
WINDOWING_MODE_FREEFORM
|
||||
};
|
||||
|
||||
private class DeathRecipient implements IBinder.DeathRecipient {
|
||||
ITaskOrganizer mTaskOrganizer;
|
||||
|
||||
@@ -373,11 +362,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
|
||||
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
|
||||
mService.mRootWindowContainer.forAllTasks((task) -> {
|
||||
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES,
|
||||
task.getWindowingMode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean returnTask = !task.mCreatedByOrganizer;
|
||||
task.updateTaskOrganizerState(true /* forceUpdate */,
|
||||
returnTask /* skipTaskAppeared */);
|
||||
@@ -433,14 +417,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
/**
|
||||
* @return the task organizer key for a given windowing mode.
|
||||
*/
|
||||
ITaskOrganizer getTaskOrganizer(int windowingMode) {
|
||||
return isSupportedWindowingMode(windowingMode)
|
||||
? mTaskOrganizers.peekLast()
|
||||
: null;
|
||||
}
|
||||
|
||||
boolean isSupportedWindowingMode(int winMode) {
|
||||
return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
|
||||
ITaskOrganizer getTaskOrganizer() {
|
||||
return mTaskOrganizers.peekLast();
|
||||
}
|
||||
|
||||
// Capture the animation surface control for activity's main window
|
||||
@@ -993,9 +971,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
for (int k = 0; k < tasks.size(); k++) {
|
||||
final Task task = tasks.get(k);
|
||||
final int mode = task.getWindowingMode();
|
||||
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, mode)) {
|
||||
continue;
|
||||
}
|
||||
pw.println(innerPrefix + " ("
|
||||
+ WindowConfiguration.windowingModeToString(mode) + ") " + task);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user