diff options
20 files changed, 211 insertions, 111 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 599487d68965..edf860665fb6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2375,7 +2375,7 @@ package android.window { public class TaskOrganizer extends android.window.WindowOrganizer { ctor public TaskOrganizer(); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void createRootTask(int, int, @Nullable android.os.IBinder); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.window.WindowContainerToken getImeTarget(int); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index f1a67767cbe6..5caf3057c840 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -241,6 +241,7 @@ public class TaskInfo { /** @hide */ public void addLaunchCookie(IBinder cookie) { + if (cookie == null || launchCookies.contains(cookie)) return; launchCookies.add(cookie); } diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl index 3a84c1f98ce6..4a43a438b69d 100644 --- a/core/java/android/window/ITaskOrganizerController.aidl +++ b/core/java/android/window/ITaskOrganizerController.aidl @@ -40,7 +40,7 @@ interface ITaskOrganizerController { void unregisterTaskOrganizer(ITaskOrganizer organizer); /** Creates a persistent root task in WM for a particular windowing-mode. */ - ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode); + void createRootTask(int displayId, int windowingMode, IBinder launchCookie); /** Deletes a persistent root task in WM */ boolean deleteRootTask(in WindowContainerToken task); diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 6c739bed35a4..ad48a9f9f776 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.ActivityManager; +import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; @@ -101,12 +102,18 @@ public class TaskOrganizer extends WindowOrganizer { @BinderThread public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} - /** Creates a persistent root task in WM for a particular windowing-mode. */ + /** + * Creates a persistent root task in WM for a particular windowing-mode. + * @param displayId The display to create the root task on. + * @param windowingMode Windowing mode to put the root task in. + * @param launchCookie Launch cookie to associate with the task so that is can be identified + * when the {@link ITaskOrganizer#onTaskAppeared} callback is called. + */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) { + public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) { try { - return mTaskOrganizerController.createRootTask(displayId, windowingMode); + mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index a430dcdda247..e51bf5e4e1f6 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2923,6 +2923,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/TaskDisplayArea.java" }, + "1396893178": { + "message": "createRootTask unknown displayId=%d", + "level": "ERROR", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "1401295262": { "message": "Mode default, asking user", "level": "WARN", diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json index 358d440686dd..a4e69de97299 100644 --- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json +++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json @@ -37,6 +37,18 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" }, + "-1325223370": { + "message": "Task appeared taskId=%d listener=%s", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "-1312360667": { + "message": "createRootTask() displayId=%d winMode=%d listener=%s", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, "-1006733970": { "message": "Display added: %d", "level": "VERBOSE", @@ -61,6 +73,12 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/LetterboxTaskListener.java" }, + "-842742255": { + "message": "%s onTaskAppeared unknown taskId=%d winMode=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java" + }, "-712674749": { "message": "Clip description: %s", "level": "VERBOSE", @@ -73,11 +91,11 @@ "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java" }, - "-460572385": { - "message": "Task appeared taskId=%d", + "-679492476": { + "message": "%s onTaskAppeared Primary taskId=%d", "level": "VERBOSE", "group": "WM_SHELL_TASK_ORG", - "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + "at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java" }, "-191422040": { "message": "Transition animations finished, notifying core %s", @@ -85,6 +103,12 @@ "group": "WM_SHELL_TRANSITIONS", "at": "com\/android\/wm\/shell\/Transitions.java" }, + "154313206": { + "message": "%s onTaskAppeared Secondary taskId=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java" + }, "157713005": { "message": "Task info changed taskId=%d", "level": "VERBOSE", @@ -162,6 +186,12 @@ "level": "VERBOSE", "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java" + }, + "2135461748": { + "message": "%s onTaskAppeared Supported", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java" } }, "groups": { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 5234fa0df77f..d4ff275d426d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -20,8 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; @@ -29,6 +27,7 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG import android.annotation.IntDef; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration.WindowingMode; +import android.os.Binder; import android.os.IBinder; import android.util.ArrayMap; import android.util.Log; @@ -63,15 +62,13 @@ public class ShellTaskOrganizer extends TaskOrganizer { 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_SPLIT_SCREEN = -5; - public static final int TASK_LISTENER_TYPE_LETTERBOX = -6; + public static final int TASK_LISTENER_TYPE_LETTERBOX = -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_SPLIT_SCREEN, TASK_LISTENER_TYPE_LETTERBOX, }) public @interface TaskListenerType {} @@ -139,6 +136,14 @@ public class ShellTaskOrganizer extends TaskOrganizer { } } + public void createRootTask(int displayId, int windowingMode, TaskListener listener) { + ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s", + displayId, windowingMode, listener.toString()); + final IBinder cookie = new Binder(); + setPendingLaunchCookieListener(cookie, listener); + super.createRootTask(displayId, windowingMode, cookie); + } + /** * Adds a listener for a specific task id. */ @@ -238,10 +243,10 @@ public class ShellTaskOrganizer extends TaskOrganizer { private void onTaskAppeared(TaskAppearedInfo info) { final int taskId = info.getTaskInfo().taskId; - ProtoLog.v(WM_SHELL_TASK_ORG, "Task appeared taskId=%d", taskId); mTasks.put(taskId, info); final TaskListener listener = getTaskListener(info.getTaskInfo(), true /*removeLaunchCookieIfNeeded*/); + ProtoLog.v(WM_SHELL_TASK_ORG, "Task appeared taskId=%d listener=%s", taskId, listener); if (listener != null) { listener.onTaskAppeared(info.getTaskInfo(), info.getLeash()); } @@ -336,7 +341,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { } @WindowingMode - private static int getWindowingMode(RunningTaskInfo taskInfo) { + public static int getWindowingMode(RunningTaskInfo taskInfo) { return taskInfo.configuration.windowConfiguration.getWindowingMode(); } @@ -350,9 +355,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { : TASK_LISTENER_TYPE_FULLSCREEN; case WINDOWING_MODE_MULTI_WINDOW: return TASK_LISTENER_TYPE_MULTI_WINDOW; - case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: - return TASK_LISTENER_TYPE_SPLIT_SCREEN; case WINDOWING_MODE_PINNED: return TASK_LISTENER_TYPE_PIP; case WINDOWING_MODE_FREEFORM: @@ -370,8 +372,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { return "TASK_LISTENER_TYPE_LETTERBOX"; case TASK_LISTENER_TYPE_MULTI_WINDOW: return "TASK_LISTENER_TYPE_MULTI_WINDOW"; - case TASK_LISTENER_TYPE_SPLIT_SCREEN: - return "TASK_LISTENER_TYPE_SPLIT_SCREEN"; case TASK_LISTENER_TYPE_PIP: return "TASK_LISTENER_TYPE_PIP"; case TASK_LISTENER_TYPE_UNDEFINED: diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java index ff617ed466d1..eb82357f2dea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java @@ -40,7 +40,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private static final float ADJUSTED_NONFOCUS_DIM = 0.3f; - private final SplitScreenTaskOrganizer mSplits; + private final SplitScreenTaskListener mSplits; private final TransactionPool mTransactionPool; private final Handler mHandler; private final TaskOrganizer mTaskOrganizer; @@ -92,7 +92,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private boolean mPausedTargetAdjusted = false; private boolean mAdjustedWhileHidden = false; - DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler, + DividerImeController(SplitScreenTaskListener splits, TransactionPool pool, Handler handler, TaskOrganizer taskOrganizer) { mSplits = splits; mTransactionPool = pool; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java index 2b14e8bf88d6..c6496ad6246f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java @@ -155,7 +155,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mAdjustedForIme; private DividerState mState; - private SplitScreenTaskOrganizer mTiles; + private SplitScreenTaskListener mTiles; boolean mFirstLayout = true; int mDividerPositionX; int mDividerPositionY; @@ -354,7 +354,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, void injectDependencies(SplitScreenController splitScreenController, DividerWindowManager windowManager, DividerState dividerState, - DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl, + DividerCallbacks callback, SplitScreenTaskListener tiles, SplitDisplayLayout sdl, DividerImeController imeController, WindowManagerProxy wmProxy) { mSplitScreenController = splitScreenController; mWindowManager = windowManager; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java index 3c0f93906795..7d5e1a84a38d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java @@ -47,7 +47,7 @@ public class SplitDisplayLayout { private static final int DIVIDER_WIDTH_INACTIVE_DP = 4; - SplitScreenTaskOrganizer mTiles; + SplitScreenTaskListener mTiles; DisplayLayout mDisplayLayout; Context mContext; @@ -62,7 +62,7 @@ public class SplitDisplayLayout { Rect mAdjustedPrimary = null; Rect mAdjustedSecondary = null; - public SplitDisplayLayout(Context ctx, DisplayLayout dl, SplitScreenTaskOrganizer taskTiles) { + public SplitDisplayLayout(Context ctx, DisplayLayout dl, SplitScreenTaskListener taskTiles) { mTiles = taskTiles; mDisplayLayout = dl; mContext = ctx; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 43e4d62baaf6..69d428a3ae1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -75,7 +75,7 @@ public class SplitScreenController implements SplitScreen, private final DividerState mDividerState = new DividerState(); private final ForcedResizableInfoActivityController mForcedResizableController; private final Handler mHandler; - private final SplitScreenTaskOrganizer mSplits; + private final SplitScreenTaskListener mSplits; private final SystemWindows mSystemWindows; final TransactionPool mTransactionPool; private final WindowManagerProxy mWindowManagerProxy; @@ -117,7 +117,7 @@ public class SplitScreenController implements SplitScreen, mTransactionPool = transactionPool; mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer); mTaskOrganizer = shellTaskOrganizer; - mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer); + mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer); mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler, shellTaskOrganizer); mRotationController = @@ -164,6 +164,14 @@ public class SplitScreenController implements SplitScreen, // Don't initialize the divider or anything until we get the default display. } + void onSplitScreenSupported() { + // Set starting tile bounds based on middle target + final WindowContainerTransaction tct = new WindowContainerTransaction(); + int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; + mSplitLayout.resizeSplits(midPos, tct); + mTaskOrganizer.applyTransaction(tct); + } + @Override public boolean isSplitScreenSupported() { return mSplits.isSplitScreenSupported(); @@ -196,11 +204,6 @@ public class SplitScreenController implements SplitScreen, } try { mSplits.init(); - // Set starting tile bounds based on middle target - final WindowContainerTransaction tct = new WindowContainerTransaction(); - int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - mSplitLayout.resizeSplits(midPos, tct); - mTaskOrganizer.applyTransaction(tct); } catch (Exception e) { Slog.e(TAG, "Failed to register docked stack listener", e); removeDivider(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java index f763d6d714c4..191a317452e3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java @@ -23,25 +23,24 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_SPLIT_SCREEN; -import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; +import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode; +import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import android.app.ActivityManager.RunningTaskInfo; import android.graphics.Rect; -import android.os.RemoteException; import android.util.Log; -import android.view.Display; import android.view.SurfaceControl; import android.view.SurfaceSession; import androidx.annotation.NonNull; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import java.io.PrintWriter; -class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { - private static final String TAG = "SplitScreenTaskOrg"; +class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { + private static final String TAG = "SplitScreenTaskListener"; private static final boolean DEBUG = SplitScreenController.DEBUG; private final ShellTaskOrganizer mTaskOrganizer; @@ -58,20 +57,19 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { final SurfaceSession mSurfaceSession = new SurfaceSession(); - SplitScreenTaskOrganizer(SplitScreenController splitScreenController, + SplitScreenTaskListener(SplitScreenController splitScreenController, ShellTaskOrganizer shellTaskOrganizer) { mSplitScreenController = splitScreenController; mTaskOrganizer = shellTaskOrganizer; - mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_SPLIT_SCREEN); } - void init() throws RemoteException { + void init() { synchronized (this) { try { - mPrimary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mSecondary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + mTaskOrganizer.createRootTask( + DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, this); + mTaskOrganizer.createRootTask( + DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, this); } catch (Exception e) { // teardown to prevent callbacks mTaskOrganizer.removeListener(this); @@ -95,19 +93,26 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { synchronized (this) { - if (mPrimary == null || mSecondary == null) { - Log.w(TAG, "Received onTaskAppeared before creating root tasks " + taskInfo); - return; - } - - if (taskInfo.token.equals(mPrimary.token)) { + final int winMode = getWindowingMode(taskInfo); + if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + ProtoLog.v(WM_SHELL_TASK_ORG, + "%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId); + mPrimary = taskInfo; mPrimarySurface = leash; - } else if (taskInfo.token.equals(mSecondary.token)) { + } else if (winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + ProtoLog.v(WM_SHELL_TASK_ORG, + "%s onTaskAppeared Secondary taskId=%d", TAG, taskInfo.taskId); + mSecondary = taskInfo; mSecondarySurface = leash; + } else { + ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared unknown taskId=%d winMode=%d", + TAG, taskInfo.taskId, winMode); } if (!mSplitScreenSupported && mPrimarySurface != null && mSecondarySurface != null) { mSplitScreenSupported = true; + mSplitScreenController.onSplitScreenSupported(); + ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG); // Initialize dim surfaces: mPrimaryDim = new SurfaceControl.Builder(mSurfaceSession) @@ -240,10 +245,13 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { final String innerPrefix = prefix + " "; final String childPrefix = innerPrefix + " "; pw.println(prefix + this); + pw.println(innerPrefix + "mSplitScreenSupported=" + mSplitScreenSupported); + if (mPrimary != null) pw.println(innerPrefix + "mPrimary.taskId=" + mPrimary.taskId); + if (mSecondary != null) pw.println(innerPrefix + "mSecondary.taskId=" + mSecondary.taskId); } @Override public String toString() { - return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_SPLIT_SCREEN); + return TAG; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java index 47e7c99d2268..c51bbeb7b6c2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java @@ -88,7 +88,7 @@ class WindowManagerProxy { mTaskOrganizer = taskOrganizer; } - void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout, + void dismissOrMaximizeDocked(final SplitScreenTaskListener tiles, SplitDisplayLayout layout, final boolean dismissOrMaximize) { mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize)); } @@ -189,7 +189,7 @@ class WindowManagerProxy { * * @return whether the home stack is resizable */ - boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) { + boolean applyEnterSplit(SplitScreenTaskListener tiles, SplitDisplayLayout layout) { // Set launchtile first so that any stack created after // getAllRootTaskInfos and before reparent (even if unlikely) are placed // correctly. @@ -242,7 +242,7 @@ class WindowManagerProxy { * split (thus resulting in the top of the secondary split becoming * fullscreen. {@code false} resolves the other way. */ - void applyDismissSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout, + void applyDismissSplit(SplitScreenTaskListener tiles, SplitDisplayLayout layout, boolean dismissOrMaximize) { // Set launch root first so that any task created after getChildContainers and // before reparent (pretty unlikely) are put into fullscreen. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ca4982f44a41..67eb482df140 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -795,6 +795,10 @@ class Task extends WindowContainer<WindowContainer> { */ boolean mTaskAppearedSent; + // If the sending of the task appear signal should be deferred until this flag is set back to + // false. + private boolean mDeferTaskAppear; + /** * This task was created by the task organizer which has the following implementations. * <ul> @@ -807,14 +811,20 @@ class Task extends WindowContainer<WindowContainer> { @VisibleForTesting boolean mCreatedByOrganizer; + // Tracking cookie for the creation of this task. + IBinder mLaunchCookie; + /** * Don't use constructor directly. Use {@link TaskDisplayArea#createStackUnchecked()} instead. */ - Task(ActivityTaskManagerService atmService, int id, int activityType, - ActivityInfo info, Intent intent, boolean createdByOrganizer) { + Task(ActivityTaskManagerService atmService, int id, int activityType, ActivityInfo info, + Intent intent, boolean createdByOrganizer, boolean deferTaskAppear, + IBinder launchCookie) { this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, null /*taskDescription*/, null /*stack*/); mCreatedByOrganizer = createdByOrganizer; + mLaunchCookie = launchCookie; + mDeferTaskAppear = deferTaskAppear; setActivityType(activityType); } @@ -4088,6 +4098,7 @@ class Task extends WindowContainer<WindowContainer> { info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; + info.addLaunchCookie(mLaunchCookie); forAllActivities(r -> { info.addLaunchCookie(r.mLaunchCookie); }); @@ -4857,6 +4868,13 @@ class Task extends WindowContainer<WindowContainer> { return mHasBeenVisible; } + void setDeferTaskAppear(boolean deferTaskAppear) { + mDeferTaskAppear = deferTaskAppear; + if (!mDeferTaskAppear) { + sendTaskAppeared(); + } + } + /** In the case that these conditions are true, we want to send the Task to the organizer: * 1. An organizer has been set * 2. The Task was created by the organizer @@ -4871,6 +4889,10 @@ class Task extends WindowContainer<WindowContainer> { return false; } + if (mDeferTaskAppear) { + return false; + } + if (mCreatedByOrganizer) { return true; } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 9392666fbf54..68cb3173cfd7 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -50,6 +50,7 @@ import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.os.IBinder; import android.os.UserHandle; import android.util.IntArray; import android.util.Slog; @@ -996,6 +997,13 @@ final class TaskDisplayArea extends DisplayArea<Task> { false /* createdByOrganizer */); } + Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, + Intent intent, boolean createdByOrganizer) { + return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */, + false /* createdByOrganizer */ , false /* deferTaskAppear */, + null /* launchCookie */); + } + /** * Creates a stack matching the input windowing mode and activity type on this display. * @@ -1013,10 +1021,14 @@ final class TaskDisplayArea extends DisplayArea<Task> { * @param intent The intent that started this task. * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false} * otherwise. + * @param deferTaskAppear @{code true} if the task appeared signal should be deferred. + * @param launchCookie Launch cookie used for tracking/association of the task we are + * creating. * @return The newly created stack. */ Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, - Intent intent, boolean createdByOrganizer) { + Intent intent, boolean createdByOrganizer, boolean deferTaskAppear, + IBinder launchCookie) { if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) { // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants // anything else should be passing it in anyways...except for the task organizer. @@ -1048,7 +1060,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { final int stackId = getNextStackId(); return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent, - createdByOrganizer); + createdByOrganizer, deferTaskAppear, launchCookie); } /** @return the root task to create the next task in. */ @@ -1078,8 +1090,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { } @VisibleForTesting - Task createStackUnchecked(int windowingMode, int activityType, int stackId, - boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) { + Task createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop, + ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear, + IBinder launchCookie) { if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) { throw new IllegalArgumentException("Stack with windowing mode cannot with non standard " + "activity type."); @@ -1097,7 +1110,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { } final Task stack = new Task(mAtmService, stackId, activityType, - info, intent, createdByOrganizer); + info, intent, createdByOrganizer, deferTaskAppear, launchCookie); if (launchRootTask != null) { launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM); if (onTop) { diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 5f86c2f60db7..a70efbcf5500 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -156,9 +156,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) { - if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { - // Skip if the task has not yet received taskAppeared(), except for tasks created - // by the organizer that don't receive that signal + if (!task.mTaskAppearedSent) { + // Skip if the task has not yet received taskAppeared(). return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId); @@ -179,9 +178,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { void onBackPressedOnTaskRoot(Task task) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d", task.mTaskId); - if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { - // Skip if the task has not yet received taskAppeared(), except for tasks created - // by the organizer that don't receive that signal + if (!task.mTaskAppearedSent) { + // Skip if the task has not yet received taskAppeared(). return; } if (!task.isOrganized()) { @@ -402,30 +400,39 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } @Override - public RunningTaskInfo createRootTask(int displayId, int windowingMode) { + public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) { enforceStackPermission("createRootTask()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId); if (display == null) { - return null; + ProtoLog.e(WM_DEBUG_WINDOW_ORGANIZER, + "createRootTask unknown displayId=%d", displayId); + return; } - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d", - displayId, windowingMode); - final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode, - ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(), - true /* createdByOrganizer */); - RunningTaskInfo out = task.getTaskInfo(); - mLastSentTaskInfos.put(task, out); - return out; + createRootTask(display, windowingMode, launchCookie); } } finally { Binder.restoreCallingIdentity(origId); } } + @VisibleForTesting + Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d", + display.mDisplayId, windowingMode); + // We want to defer the task appear signal until the task is fully created and attached to + // to the hierarchy so that the complete starting configuration is in the task info we send + // over to the organizer. + final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode, + ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(), + true /* createdByOrganizer */, true /* deferTaskAppear */, launchCookie); + task.setDeferTaskAppear(false /* deferTaskAppear */); + return task; + } + @Override public boolean deleteRootTask(WindowContainerToken token) { enforceStackPermission("deleteRootTask()"); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index caf8a720e26c..b6323313dd27 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -245,9 +245,8 @@ public class ActivityStackTests extends WindowTestsBase { .setStack(rootHomeTask) .setCreateTask(true) .build(); - final Task secondaryStack = (Task) WindowContainer.fromBinder( - mAtm.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(), - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder()); + final Task secondaryStack = mAtm.mTaskOrganizerController.createRootTask( + rootHomeTask.getDisplayContent(), WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null); rootHomeTask.reparent(secondaryStack, POSITION_TOP); assertEquals(secondaryStack, rootHomeTask.getParent()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index e47881917b2c..3720e520b1b9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -1022,7 +1022,7 @@ public class ActivityStarterTests extends WindowTestsBase { assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse(); // Move activity to split-screen-primary stack and make sure it has the focus. - TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayId()); + TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent()); top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM); top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent"); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 7a1f65a3b62c..b4480aea3ce4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -479,21 +479,22 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testCreateDeleteRootTasks() { - RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - Display.DEFAULT_DISPLAY, - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); + + Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + dc, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null); + RunningTaskInfo info1 = task1.getTaskInfo(); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, info1.configuration.windowConfiguration.getWindowingMode()); assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); - RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - Display.DEFAULT_DISPLAY, - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + dc, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null); + RunningTaskInfo info2 = task2.getTaskInfo(); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, info2.configuration.windowConfiguration.getWindowingMode()); assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType); - DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); List<Task> infos = getTasksCreatedByOrganizer(dc); assertEquals(2, infos.size()); @@ -521,8 +522,9 @@ public class WindowOrganizerTests extends WindowTestsBase { } }; mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); - RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null); + RunningTaskInfo info1 = task.getTaskInfo(); final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent); @@ -579,8 +581,9 @@ public class WindowOrganizerTests extends WindowTestsBase { } }; mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); - RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null); + RunningTaskInfo info1 = task.getTaskInfo(); lastReportedTiles.clear(); called[0] = false; @@ -640,10 +643,13 @@ public class WindowOrganizerTests extends WindowTestsBase { } }; mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); - RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( - mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + + Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null); + RunningTaskInfo info1 = task1.getTaskInfo(); + Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null); + RunningTaskInfo info2 = task2.getTaskInfo(); final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks( mDisplayContent.mDisplayId, null /* activityTypes */).size(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 1eb7cbed02c8..62f04a1c830a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -973,8 +973,9 @@ class WindowTestsBase extends SystemServiceTestsBase { final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextStackId(); if (mParentTask == null) { task = mTaskDisplayArea.createStackUnchecked( - mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, - mIntent, false /* createdByOrganizer */); + mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, mIntent, + false /* createdByOrganizer */, false /* deferTaskAppear */, + null /* launchCookie */); } else { task = new Task(mSupervisor.mService, taskId, mActivityInfo, mIntent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, @@ -1016,20 +1017,17 @@ class WindowTestsBase extends SystemServiceTestsBase { // moves everything to secondary. Most tests expect this since sysui usually does it. boolean mMoveToSecondaryOnEnter = true; int mDisplayId; - TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { + TestSplitOrganizer(ActivityTaskManagerService service, DisplayContent display) { mService = service; - mDisplayId = displayId; + mDisplayId = display.mDisplayId; mService.mTaskOrganizerController.registerTaskOrganizer(this); - WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( - displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; - mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); - WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( - displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; - mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); + mPrimary = mService.mTaskOrganizerController.createRootTask( + display, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null); + mSecondary = mService.mTaskOrganizerController.createRootTask( + display, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);; } TestSplitOrganizer(ActivityTaskManagerService service) { - this(service, - service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId); + this(service, service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay()); } public void setMoveToSecondaryOnEnter(boolean move) { mMoveToSecondaryOnEnter = move; |