summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/WindowContainerTransaction.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java27
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) {