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/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 096541f..0a0530c9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,6 +23,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
@@ -47,6 +49,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -375,6 +378,45 @@
}
}
+ @Override
+ public List<RunningTaskInfo> getChildTasks(IWindowContainer parent) {
+ enforceStackPermission("getChildTasks()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ if (parent == null) {
+ throw new IllegalArgumentException("Can't get children of null parent");
+ }
+ final WindowContainer container = WindowContainer.fromBinder(parent.asBinder());
+ if (container == null) {
+ Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
+ return null;
+ }
+ // For now, only support returning children of persistent root tasks (of which the
+ // only current implementation is TaskTile).
+ if (!(container instanceof TaskTile)) {
+ Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
+ return null;
+ }
+ ArrayList<RunningTaskInfo> out = new ArrayList<>();
+ // Tiles aren't real parents, so we need to go through stacks on the display to
+ // ensure correct ordering.
+ final DisplayContent dc = container.getDisplayContent();
+ for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack as = dc.getStackAt(i);
+ if (as.getTile() == container) {
+ final RunningTaskInfo info = new RunningTaskInfo();
+ as.fillTaskInfo(info);
+ out.add(info);
+ }
+ }
+ return out;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private int sanitizeAndApplyChange(WindowContainer container,
WindowContainerTransaction.Change change) {
if (!(container instanceof Task)) {
@@ -405,6 +447,54 @@
return effects;
}
+ private int sanitizeAndApplyHierarchyOp(WindowContainer container,
+ WindowContainerTransaction.HierarchyOp hop) {
+ if (!(container instanceof Task)) {
+ throw new IllegalArgumentException("Invalid container in hierarchy op");
+ }
+ if (hop.isReparent()) {
+ // special case for tiles since they are "virtual" parents
+ if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
+ ActivityStack as = (ActivityStack) container;
+ TaskTile newParent = hop.getNewParent() == null ? null
+ : (TaskTile) WindowContainer.fromBinder(hop.getNewParent());
+ if (as.getTile() != newParent) {
+ if (as.getTile() != null) {
+ as.getTile().removeChild(as);
+ }
+ if (newParent != null) {
+ if (!as.affectedBySplitScreenResize()) {
+ return 0;
+ }
+ newParent.addChild(as, POSITION_TOP);
+ }
+ }
+ if (hop.getToTop()) {
+ as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+ } else {
+ as.getDisplay().positionStackAtBottom(as);
+ }
+ } else if (container instanceof Task) {
+ throw new RuntimeException("Reparenting leaf Tasks is not supported now.");
+ }
+ } else {
+ // Ugh, of course ActivityStack has its own special reorder logic...
+ if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
+ ActivityStack as = (ActivityStack) container;
+ if (hop.getToTop()) {
+ as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+ } else {
+ as.getDisplay().positionStackAtBottom(as);
+ }
+ } else {
+ container.getParent().positionChildAt(
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+ container, false /* includingParents */);
+ }
+ }
+ return TRANSACT_EFFECTS_LIFECYCLE;
+ }
+
private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
int windowMask, Configuration config) {
if ((container instanceof ActivityStack)
@@ -470,8 +560,7 @@
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
entries.next();
- final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
- entry.getKey()).getContainer();
+ final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
@@ -484,6 +573,13 @@
mBLASTSyncEngine.addToSyncSet(syncId, wc);
}
}
+ // Hierarchy changes
+ final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
+ for (int i = 0, n = hops.size(); i < n; ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+ final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+ effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ }
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(