diff options
author | 2021-10-15 05:46:13 +0000 | |
---|---|---|
committer | 2021-10-15 05:46:13 +0000 | |
commit | be0c2bdc92b269ee7ba358acb83ca77652531a46 (patch) | |
tree | c610c58fdc1c71218a9923ea879d6298c5f9f590 | |
parent | 5b73d12920cee715209f62dfc72f76ba3b29cd48 (diff) | |
parent | 62c6c83f571e2e002bbf3aa76e5770ec94eba326 (diff) |
Merge "Make split screen only reparent top task" into sc-v2-dev
7 files changed, 95 insertions, 38 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 9d6488d7aa14..bbf813891387 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -295,7 +295,7 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Reparent's all children tasks of {@param currentParent} in the specified + * Reparent's all children tasks or the top task of {@param currentParent} in the specified * {@param windowingMode} and {@param activityType} to {@param newParent} in their current * z-order. * @@ -306,21 +306,46 @@ public final class WindowContainerTransaction implements Parcelable { * @param activityTypes of the tasks to reparent. * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to * the bottom. + * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes + * and activityTypes. + * @hide */ @NonNull public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, - @Nullable int[] activityTypes, boolean onTop) { + @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) { mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent( currentParent != null ? currentParent.asBinder() : null, newParent != null ? newParent.asBinder() : null, windowingModes, activityTypes, - onTop)); + onTop, + reparentTopOnly)); return this; } /** + * Reparent's all children tasks of {@param currentParent} in the specified + * {@param windowingMode} and {@param activityType} to {@param newParent} in their current + * z-order. + * + * @param currentParent of the tasks to perform the operation no. + * {@code null} will perform the operation on the display. + * @param newParent for the tasks. {@code null} will perform the operation on the display. + * @param windowingModes of the tasks to reparent. + * @param activityTypes of the tasks to reparent. + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + */ + @NonNull + public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, + @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, + @Nullable int[] activityTypes, boolean onTop) { + return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop, + false /* reparentTopOnly */); + } + + /** * Sets whether a container should be the launch root for the specified windowing mode and * activity type. This currently only applies to Task containers created by organizer. */ @@ -948,6 +973,8 @@ public final class WindowContainerTransaction implements Parcelable { // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. private boolean mToTop; + private boolean mReparentTopOnly; + @Nullable private int[] mWindowingModes; @@ -985,13 +1012,15 @@ public final class WindowContainerTransaction implements Parcelable { } public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent, - IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop) { + IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, + boolean reparentTopOnly) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT) .setContainer(currentParent) .setReparentContainer(newParent) .setWindowingModes(windowingModes) .setActivityTypes(activityTypes) .setToTop(onTop) + .setReparentTopOnly(reparentTopOnly) .build(); } @@ -1040,6 +1069,7 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = copy.mContainer; mReparent = copy.mReparent; mToTop = copy.mToTop; + mReparentTopOnly = copy.mReparentTopOnly; mWindowingModes = copy.mWindowingModes; mActivityTypes = copy.mActivityTypes; mLaunchOptions = copy.mLaunchOptions; @@ -1053,6 +1083,7 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = in.readStrongBinder(); mReparent = in.readStrongBinder(); mToTop = in.readBoolean(); + mReparentTopOnly = in.readBoolean(); mWindowingModes = in.createIntArray(); mActivityTypes = in.createIntArray(); mLaunchOptions = in.readBundle(); @@ -1093,6 +1124,10 @@ public final class WindowContainerTransaction implements Parcelable { return mToTop; } + public boolean getReparentTopOnly() { + return mReparentTopOnly; + } + public int[] getWindowingModes() { return mWindowingModes; } @@ -1126,12 +1161,13 @@ public final class WindowContainerTransaction implements Parcelable { switch (mType) { case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "{ChildrenTasksReparent: from=" + mContainer + " to=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + " mReparentTopOnly=" + mReparentTopOnly + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "{SetLaunchRoot: container=" + mContainer - + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_REPARENT: return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ") + mReparent + "}"; @@ -1163,8 +1199,9 @@ public final class WindowContainerTransaction implements Parcelable { + " adjacentContainer=" + mReparent + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; } } @@ -1174,6 +1211,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeStrongBinder(mContainer); dest.writeStrongBinder(mReparent); dest.writeBoolean(mToTop); + dest.writeBoolean(mReparentTopOnly); dest.writeIntArray(mWindowingModes); dest.writeIntArray(mActivityTypes); dest.writeBundle(mLaunchOptions); @@ -1211,6 +1249,8 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mToTop; + private boolean mReparentTopOnly; + @Nullable private int[] mWindowingModes; @@ -1248,6 +1288,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setReparentTopOnly(boolean reparentTopOnly) { + mReparentTopOnly = reparentTopOnly; + return this; + } + Builder setWindowingModes(@Nullable int[] windowingModes) { mWindowingModes = windowingModes; return this; @@ -1290,6 +1335,7 @@ public final class WindowContainerTransaction implements Parcelable { ? Arrays.copyOf(mActivityTypes, mActivityTypes.length) : null; hierarchyOp.mToTop = mToTop; + hierarchyOp.mReparentTopOnly = mReparentTopOnly; hierarchyOp.mLaunchOptions = mLaunchOptions; hierarchyOp.mActivityIntent = mActivityIntent; hierarchyOp.mPendingIntent = mPendingIntent; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index 7f82ebde77af..a47a15287dda 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -49,25 +49,24 @@ class MainStage extends StageTaskListener { return mIsActive; } - void activate(Rect rootBounds, WindowContainerTransaction wct) { + void activate(Rect rootBounds, WindowContainerTransaction wct, boolean includingTopTask) { if (mIsActive) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setBounds(rootToken, rootBounds) .setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW) - .setLaunchRoot( - rootToken, - CONTROLLED_WINDOWING_MODES, - CONTROLLED_ACTIVITY_TYPES) - .reparentTasks( - null /* currentParent */, - rootToken, - CONTROLLED_WINDOWING_MODES, - CONTROLLED_ACTIVITY_TYPES, - true /* onTop */) // Moving the root task to top after the child tasks were re-parented , or the root // task cannot be visible and focused. .reorder(rootToken, true /* onTop */); + if (includingTopTask) { + wct.reparentTasks( + null /* currentParent */, + rootToken, + CONTROLLED_WINDOWING_MODES, + CONTROLLED_ACTIVITY_TYPES, + true /* onTop */, + true /* reparentTopOnly */); + } mIsActive = true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 414b4e48efdd..3e74ad38f1f1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -263,7 +263,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @SplitPosition int sideStagePosition) { final WindowContainerTransaction wct = new WindowContainerTransaction(); setSideStagePosition(sideStagePosition, wct); - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, true /* reparent */); mSideStage.addTask(task, getSideStageBounds(), wct); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(null /* layout */, t)); @@ -299,7 +299,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots @@ -368,7 +368,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots @@ -756,7 +756,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else if (isSideStage) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // Make sure the main stage is active. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, true /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); mTaskOrganizer.applyTransaction(wct); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java index 12b547a765be..2bcc45e2587d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java @@ -62,7 +62,8 @@ public class MainStageTests { @Test public void testActiveDeactivate() { - mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct); + mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct, + true /* reparent */); assertThat(mMainStage.isActive()).isTrue(); mMainStage.deactivate(mWct); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index be103863a0f2..05496b059030 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -316,7 +316,8 @@ public class SplitTransitionTests extends ShellTestCase { mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), mock(Transitions.TransitionFinishCallback.class)); - mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction()); + mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction(), + true /* includingTopTask */); } private boolean containsSplitExit(@NonNull WindowContainerTransaction wct) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index a39d331ca884..aeb2849b49b3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -18,9 +18,11 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.Display.DEFAULT_DISPLAY; + import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -111,7 +113,8 @@ public class StageCoordinatorTests extends ShellTestCase { mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT); - verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class)); + verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class), + eq(true /* includingTopTask */)); verify(mSideStage).addTask(eq(task), any(Rect.class), any(WindowContainerTransaction.class)); } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 54ce5fc6bbec..6288ab5de888 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -83,7 +83,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.Function; /** * Server side implementation for the interface for organizing windows @@ -893,24 +893,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // We want to collect the tasks first before re-parenting to avoid array shifting on us. final ArrayList<Task> tasksToReparent = new ArrayList<>(); - currentParent.forAllTasks((Consumer<Task>) (task) -> { + currentParent.forAllTasks((Function<Task, Boolean>) task -> { Slog.i(TAG, " Processing task=" + task); - if (task.mCreatedByOrganizer - || task.getParent() != finalCurrentParent) { + final boolean reparent; + if (task.mCreatedByOrganizer || task.getParent() != finalCurrentParent) { // We only care about non-organized task that are direct children of the thing we // are reparenting from. - return; + return false; } if (newParentInMultiWindow && !task.supportsMultiWindowInDisplayArea(newParentTda)) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp non-resizeable task to multi window," + " task=" + task); - return; + return false; + } + if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType()) + || !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { + return false; } - if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) return; - if (!ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) return; - tasksToReparent.add(task); - }, !hop.getToTop()); + if (hop.getToTop()) { + tasksToReparent.add(0, task); + } else { + tasksToReparent.add(task); + } + return hop.getReparentTopOnly() && tasksToReparent.size() == 1; + }); final int count = tasksToReparent.size(); for (int i = 0; i < count; ++i) { |