Merge "Add a minimal FreeformTaskListener" into sc-v2-dev am: 7e23f324dd

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

Change-Id: I51add5776a23fe63978771aaa8a885b619289890
This commit is contained in:
Garfield Tan
2021-08-06 16:44:04 +00:00
committed by Automerger Merge Worker
9 changed files with 195 additions and 32 deletions

View File

@@ -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

View File

@@ -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:

View File

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

View File

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

View File

@@ -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
//

View File

@@ -4600,7 +4600,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;
}

View File

@@ -307,7 +307,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

View File

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

View File

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