summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/WindowContainerTransaction.java115
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java71
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java43
3 files changed, 188 insertions, 41 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index a88a17283482..c8001198bdf6 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -486,7 +486,7 @@ public final class WindowContainerTransaction implements Parcelable {
}
/**
- * Sets to containers adjacent to each other. Containers below two visible adjacent roots will
+ * Sets two containers adjacent to each other. Containers below two visible adjacent roots will
* be made invisible. This currently only applies to TaskFragment containers created by
* organizer.
* @param root1 the first root.
@@ -495,9 +495,64 @@ public final class WindowContainerTransaction implements Parcelable {
@NonNull
public WindowContainerTransaction setAdjacentRoots(
@NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
- mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
- root1.asBinder(),
- root2.asBinder()));
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
+ root1.asBinder(),
+ root2.asBinder()));
+ return this;
+ }
+ return setAdjacentRootSet(root1, root2);
+ }
+
+ /**
+ * Sets multiple containers adjacent to each other. Containers below the visible adjacent roots
+ * will be made invisible. This currently only applies to Task containers created by organizer.
+ *
+ * To remove one container from the adjacent roots, one can call {@link #clearAdjacentRoots}
+ * with the target container.
+ * To remove all containers from the adjacent roots, one much call {@link #clearAdjacentRoots}
+ * on each container if there were more than two containers in the set.
+ *
+ * For non-Task TaskFragment, use {@link #setAdjacentTaskFragments} instead.
+ *
+ * @param roots the Tasks that should be adjacent to each other.
+ * @throws IllegalArgumentException if roots have size < 2.
+ * @hide // TODO(b/373709676) Rename to setAdjacentRoots and update CTS.
+ */
+ @NonNull
+ public WindowContainerTransaction setAdjacentRootSet(
+ @NonNull WindowContainerToken... roots) {
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ throw new IllegalArgumentException("allowMultipleAdjacentTaskFragments is not enabled."
+ + " Use #setAdjacentRoots instead.");
+ }
+ if (roots.length < 2) {
+ throw new IllegalArgumentException("setAdjacentRootSet must have size >= 2");
+ }
+ final IBinder[] rootTokens = new IBinder[roots.length];
+ for (int i = 0; i < roots.length; i++) {
+ rootTokens[i] = roots[i].asBinder();
+ }
+ mHierarchyOps.add(
+ new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
+ .setContainers(rootTokens)
+ .build());
+ return this;
+ }
+
+ /**
+ * Clears container adjacent.
+ * If {@link #setAdjacentRootSet} is called with more than 2 roots, calling this will only
+ * remove the given root from the adjacent set. The rest of roots will stay adjacent to each
+ * other.
+ *
+ * @param root the root container to clear the adjacent roots for.
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction clearAdjacentRoots(
+ @NonNull WindowContainerToken root) {
+ mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder()));
return this;
}
@@ -967,18 +1022,6 @@ public final class WindowContainerTransaction implements Parcelable {
}
/**
- * Clears container adjacent.
- * @param root the root container to clear the adjacent roots for.
- * @hide
- */
- @NonNull
- public WindowContainerTransaction clearAdjacentRoots(
- @NonNull WindowContainerToken root) {
- mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder()));
- return this;
- }
-
- /**
* Sets/removes the reparent leaf task flag for this {@code windowContainer}.
* When this is set, the server side will try to reparent the leaf task to task display area
* if there is an existing activity in history during the activity launch. This operation only
@@ -1520,6 +1563,9 @@ public final class WindowContainerTransaction implements Parcelable {
@Nullable
private IBinder mContainer;
+ @Nullable
+ private IBinder[] mContainers;
+
// If this is same as mContainer, then only change position, don't reparent.
@Nullable
private IBinder mReparent;
@@ -1704,6 +1750,7 @@ public final class WindowContainerTransaction implements Parcelable {
public HierarchyOp(@NonNull HierarchyOp copy) {
mType = copy.mType;
mContainer = copy.mContainer;
+ mContainers = copy.mContainers;
mBounds = copy.mBounds;
mIncludingParents = copy.mIncludingParents;
mReparent = copy.mReparent;
@@ -1729,6 +1776,7 @@ public final class WindowContainerTransaction implements Parcelable {
protected HierarchyOp(Parcel in) {
mType = in.readInt();
mContainer = in.readStrongBinder();
+ mContainers = in.createBinderArray();
mBounds = in.readTypedObject(Rect.CREATOR);
mIncludingParents = in.readBoolean();
mReparent = in.readStrongBinder();
@@ -1780,6 +1828,13 @@ public final class WindowContainerTransaction implements Parcelable {
}
@NonNull
+ public IBinder[] getContainers() {
+ return mContainers;
+ }
+
+ /** @deprecated b/373709676 replace with {@link #getContainers()}. */
+ @Deprecated
+ @NonNull
public IBinder getAdjacentRoot() {
return mReparent;
}
@@ -1869,7 +1924,7 @@ public final class WindowContainerTransaction implements Parcelable {
case HIERARCHY_OP_TYPE_REORDER: return "reorder";
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "childrenTasksReparent";
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "setLaunchRoot";
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoot";
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoots";
case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "launchTask";
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "setAdjacentFlagRoot";
case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
@@ -1883,7 +1938,7 @@ public final class WindowContainerTransaction implements Parcelable {
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop";
case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask";
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity";
- case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoot";
+ case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoots";
case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
return "setReparentLeafTaskIfRelaunch";
case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
@@ -1923,8 +1978,18 @@ public final class WindowContainerTransaction implements Parcelable {
sb.append(mContainer).append(" to ").append(mToTop ? "top" : "bottom");
break;
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
- sb.append("container=").append(mContainer)
- .append(" adjacentRoot=").append(mReparent);
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ for (IBinder container : mContainers) {
+ if (container == mContainers[0]) {
+ sb.append("adjacentRoots=").append(container);
+ } else {
+ sb.append(", ").append(container);
+ }
+ }
+ } else {
+ sb.append("container=").append(mContainer)
+ .append(" adjacentRoot=").append(mReparent);
+ }
break;
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
sb.append(mLaunchOptions);
@@ -1997,6 +2062,7 @@ public final class WindowContainerTransaction implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeStrongBinder(mContainer);
+ dest.writeBinderArray(mContainers);
dest.writeTypedObject(mBounds, flags);
dest.writeBoolean(mIncludingParents);
dest.writeStrongBinder(mReparent);
@@ -2044,6 +2110,9 @@ public final class WindowContainerTransaction implements Parcelable {
private IBinder mContainer;
@Nullable
+ private IBinder[] mContainers;
+
+ @Nullable
private IBinder mReparent;
@Nullable
@@ -2104,6 +2173,11 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
+ Builder setContainers(@Nullable IBinder[] containers) {
+ mContainers = containers;
+ return this;
+ }
+
Builder setReparentContainer(@Nullable IBinder reparentContainer) {
mReparent = reparentContainer;
return this;
@@ -2209,6 +2283,7 @@ public final class WindowContainerTransaction implements Parcelable {
HierarchyOp build() {
final HierarchyOp hierarchyOp = new HierarchyOp(mType);
hierarchyOp.mContainer = mContainer;
+ hierarchyOp.mContainers = mContainers;
hierarchyOp.mReparent = mReparent;
hierarchyOp.mWindowingModes = mWindowingModes != null
? Arrays.copyOf(mWindowingModes, mWindowingModes.length)
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3381ae08c6b0..5fb0787fa0dc 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -2201,31 +2201,60 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
private int setAdjacentRootsHierarchyOp(WindowContainerTransaction.HierarchyOp hop) {
- final WindowContainer wc1 = WindowContainer.fromBinder(hop.getContainer());
- if (wc1 == null || !wc1.isAttached()) {
- Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc1);
- return TRANSACT_EFFECTS_NONE;
- }
- final TaskFragment root1 = wc1.asTaskFragment();
- final WindowContainer wc2 = WindowContainer.fromBinder(hop.getAdjacentRoot());
- if (wc2 == null || !wc2.isAttached()) {
- Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc2);
- return TRANSACT_EFFECTS_NONE;
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ final WindowContainer wc1 = WindowContainer.fromBinder(hop.getContainer());
+ if (wc1 == null || !wc1.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc1);
+ return TRANSACT_EFFECTS_NONE;
+ }
+ final TaskFragment root1 = wc1.asTaskFragment();
+ final WindowContainer wc2 = WindowContainer.fromBinder(hop.getAdjacentRoot());
+ if (wc2 == null || !wc2.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc2);
+ return TRANSACT_EFFECTS_NONE;
+ }
+ final TaskFragment root2 = wc2.asTaskFragment();
+ if (!root1.mCreatedByOrganizer || !root2.mCreatedByOrganizer) {
+ throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
+ + " organizer root1=" + root1 + " root2=" + root2);
+ }
+ if (root1.isAdjacentTo(root2)) {
+ return TRANSACT_EFFECTS_NONE;
+ }
+ root1.setAdjacentTaskFragment(root2);
+ return TRANSACT_EFFECTS_LIFECYCLE;
}
- final TaskFragment root2 = wc2.asTaskFragment();
- if (!root1.mCreatedByOrganizer || !root2.mCreatedByOrganizer) {
- throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
- + " organizer root1=" + root1 + " root2=" + root2);
+
+ final IBinder[] containers = hop.getContainers();
+ final ArraySet<TaskFragment> adjacentRoots = new ArraySet<>();
+ for (IBinder container : containers) {
+ final WindowContainer wc = WindowContainer.fromBinder(container);
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
+ return TRANSACT_EFFECTS_NONE;
+ }
+ final Task root = wc.asTask();
+ if (root == null) {
+ // Only support Task. Use WCT#setAdjacentTaskFragments for non-Task TaskFragment.
+ throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not called with"
+ + " Task. wc=" + wc);
+ }
+ if (!root.mCreatedByOrganizer) {
+ throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
+ + " organizer root=" + root);
+ }
+ if (adjacentRoots.contains(root)) {
+ throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: called with same"
+ + " root twice=" + root);
+ }
+ adjacentRoots.add(root);
}
- if (root1.isAdjacentTo(root2)) {
+ final TaskFragment root0 = adjacentRoots.valueAt(0);
+ final TaskFragment.AdjacentSet adjacentSet = new TaskFragment.AdjacentSet(adjacentRoots);
+ if (adjacentSet.equals(root0.getAdjacentTaskFragments())) {
return TRANSACT_EFFECTS_NONE;
}
- if (Flags.allowMultipleAdjacentTaskFragments()) {
- // TODO(b/373709676): allow three roots.
- root1.setAdjacentTaskFragments(new TaskFragment.AdjacentSet(root1, root2));
- } else {
- root1.setAdjacentTaskFragment(root2);
- }
+ root0.setAdjacentTaskFragments(adjacentSet);
return TRANSACT_EFFECTS_LIFECYCLE;
}
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 410fa2879600..e1efed07fb97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -924,6 +924,49 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null);
}
+ @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
+ @Test
+ public void testSetAdjacentLaunchRootSet() {
+ final DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+
+ final Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ dc, WINDOWING_MODE_MULTI_WINDOW, null);
+ final RunningTaskInfo info1 = task1.getTaskInfo();
+ final Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ dc, WINDOWING_MODE_MULTI_WINDOW, null);
+ final RunningTaskInfo info2 = task2.getTaskInfo();
+ final Task task3 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ dc, WINDOWING_MODE_MULTI_WINDOW, null);
+ final RunningTaskInfo info3 = task3.getTaskInfo();
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setAdjacentRootSet(info1.token, info2.token, info3.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertTrue(task1.hasAdjacentTaskFragment());
+ assertTrue(task2.hasAdjacentTaskFragment());
+ assertTrue(task3.hasAdjacentTaskFragment());
+ assertTrue(task1.isAdjacentTo(task2));
+ assertTrue(task1.isAdjacentTo(task3));
+ assertTrue(task2.isAdjacentTo(task3));
+
+ wct = new WindowContainerTransaction();
+ wct.clearAdjacentRoots(info1.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertFalse(task1.hasAdjacentTaskFragment());
+ assertTrue(task2.hasAdjacentTaskFragment());
+ assertTrue(task3.hasAdjacentTaskFragment());
+ assertFalse(task1.isAdjacentTo(task2));
+ assertFalse(task1.isAdjacentTo(task3));
+ assertTrue(task2.isAdjacentTo(task3));
+
+ wct = new WindowContainerTransaction();
+ wct.clearAdjacentRoots(info2.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertFalse(task2.hasAdjacentTaskFragment());
+ assertFalse(task3.hasAdjacentTaskFragment());
+ assertFalse(task2.isAdjacentTo(task3));
+ }
+
@Test
public void testTileAddRemoveChild() {
final StubOrganizer listener = new StubOrganizer();