Merge "Make split screen only reparent top task" into sc-v2-dev
This commit is contained in:
@@ -294,6 +294,36 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
* @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, boolean reparentTopOnly) {
|
||||
mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
|
||||
currentParent != null ? currentParent.asBinder() : null,
|
||||
newParent != null ? newParent.asBinder() : null,
|
||||
windowingModes,
|
||||
activityTypes,
|
||||
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
|
||||
@@ -311,13 +341,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
|
||||
@Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
|
||||
@Nullable int[] activityTypes, boolean onTop) {
|
||||
mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
|
||||
currentParent != null ? currentParent.asBinder() : null,
|
||||
newParent != null ? newParent.asBinder() : null,
|
||||
windowingModes,
|
||||
activityTypes,
|
||||
onTop));
|
||||
return this;
|
||||
return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop,
|
||||
false /* reparentTopOnly */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user