Add hierarchy operations to container transaction
Also add a way to query for child containers of a container.
Combined, these provide enough flexibility to re-arrange
containers to system-ui. For now, it is locked-down a bit so
it only provides children of TaskTiles and can only reparent
ActivityStacks. Eventually, this can be expanded for nested
tasks or display areas.
Bug: 133381284
Test: Added TaskTileTest#testHierarchyTransaction
Change-Id: Id0e89a4e4b9352d9392349c4e1fe7d69b4f9f212
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
index bfc42ef..5d5956e 100644
--- a/core/java/android/app/ITaskOrganizerController.aidl
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -51,6 +51,9 @@
/** Deletes a persistent root task in WM */
boolean deleteRootTask(IWindowContainer task);
+ /** Gets direct child tasks (ordered from top-to-bottom) */
+ List<ActivityManager.RunningTaskInfo> getChildTasks(in IWindowContainer parent);
+
/** Get the root task which contains the current ime target */
IWindowContainer getImeTarget(int display);
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index 33f21f2..cf34b0b 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -16,6 +16,8 @@
package android.view;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -25,6 +27,8 @@
import android.os.Parcelable;
import android.util.ArrayMap;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
/**
@@ -36,10 +40,14 @@
public class WindowContainerTransaction implements Parcelable {
private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
+ // Flat list because re-order operations are order-dependent
+ private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
+
public WindowContainerTransaction() {}
protected WindowContainerTransaction(Parcel in) {
in.readMap(mChanges, null /* loader */);
+ in.readList(mHierarchyOps, null /* loader */);
}
private Change getOrCreateChange(IBinder token) {
@@ -97,10 +105,39 @@
return this;
}
+ /**
+ * Reparents a container into another one. The effect of a {@code null} parent can vary. For
+ * example, reparenting a stack to {@code null} will reparent it to its display.
+ *
+ * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
+ * the bottom.
+ */
+ public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
+ @Nullable IWindowContainer parent, boolean onTop) {
+ mHierarchyOps.add(new HierarchyOp(child.asBinder(),
+ parent == null ? null : parent.asBinder(), onTop));
+ return this;
+ }
+
+ /**
+ * Reorders a container within its parent.
+ *
+ * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
+ * the bottom.
+ */
+ public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
+ mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
+ return this;
+ }
+
public Map<IBinder, Change> getChanges() {
return mChanges;
}
+ public List<HierarchyOp> getHierarchyOps() {
+ return mHierarchyOps;
+ }
+
@Override
public String toString() {
return "WindowContainerTransaction { changes = " + mChanges + " }";
@@ -109,6 +146,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeMap(mChanges);
+ dest.writeList(mHierarchyOps);
}
@Override
@@ -249,4 +287,88 @@
}
};
}
+
+ /**
+ * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
+ * Changes because they must be executed in the same order that they are added.
+ */
+ public static class HierarchyOp implements Parcelable {
+ private final IBinder mContainer;
+
+ // If this is same as mContainer, then only change position, don't reparent.
+ private final IBinder mReparent;
+
+ // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
+ private final boolean mToTop;
+
+ public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
+ mContainer = container;
+ mReparent = reparent;
+ mToTop = toTop;
+ }
+
+ public HierarchyOp(@NonNull IBinder container, boolean toTop) {
+ mContainer = container;
+ mReparent = container;
+ mToTop = toTop;
+ }
+
+ protected HierarchyOp(Parcel in) {
+ mContainer = in.readStrongBinder();
+ mReparent = in.readStrongBinder();
+ mToTop = in.readBoolean();
+ }
+
+ public boolean isReparent() {
+ return mContainer != mReparent;
+ }
+
+ @Nullable
+ public IBinder getNewParent() {
+ return mReparent;
+ }
+
+ @NonNull
+ public IBinder getContainer() {
+ return mContainer;
+ }
+
+ public boolean getToTop() {
+ return mToTop;
+ }
+
+ @Override
+ public String toString() {
+ if (isReparent()) {
+ return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
+ + mReparent + "}";
+ } else {
+ return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mContainer);
+ dest.writeStrongBinder(mReparent);
+ dest.writeBoolean(mToTop);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
+ @Override
+ public HierarchyOp createFromParcel(Parcel in) {
+ return new HierarchyOp(in);
+ }
+
+ @Override
+ public HierarchyOp[] newArray(int size) {
+ return new HierarchyOp[size];
+ }
+ };
+ }
}