5/n Add support for multiple task display areas

Replaces the references to DisplayContent#mTaskContainers field with
iteration over all child task containers where necessary.

This does not change the behavior for the regular non-foldable
devices, since they would normally have only one task display area,
so iterating throught the list is logically equivalent to referencing
it directly.

Bug: 152116619
Test: WM CTS and unit tests
Change-Id: Ibc1b18ad4c06236e944abd49089672105506ec2c
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 13e4d8b..8e45dc3 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -63,6 +63,7 @@
 import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.protolog.common.ProtoLog;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -134,6 +135,12 @@
      */
     private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
 
+    /**
+     * The task display area is removed from the system and we are just waiting for all activities
+     * on it to be finished before removing this object.
+     */
+    private boolean mRemoved;
+
     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
         super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
         mDisplayContent = displayContent;
@@ -986,7 +993,7 @@
         return candidate;
     }
 
-    ActivityRecord getResumedActivity() {
+    ActivityRecord getFocusedActivity() {
         final ActivityStack focusedStack = getFocusedStack();
         if (focusedStack == null) {
             return null;
@@ -1572,7 +1579,7 @@
     }
 
     boolean isRemoved() {
-        return mDisplayContent.isRemoved();
+        return mRemoved;
     }
 
     /**
@@ -1609,4 +1616,82 @@
     interface OnStackOrderChangedListener {
         void onStackOrderChanged(ActivityStack stack);
     }
+
+    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+                    notifyClients);
+        }
+    }
+
+    void prepareFreezingTaskBounds() {
+        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getChildAt(stackNdx);
+            stack.prepareFreezingTaskBounds();
+        }
+    }
+
+    /**
+     * Removes the stacks in the node applying the content removal node from the display.
+     * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
+     */
+    ActivityStack remove() {
+        mPreferredTopFocusableStack = null;
+        // TODO(b/153090332): Allow setting content removal mode per task display area
+        final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
+        final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+        ActivityStack lastReparentedStack = null;
+
+        // Stacks could be reparented from the removed display area to other display area. After
+        // reparenting the last stack of the removed display area, the display area becomes ready to
+        // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
+        // related WindowContainer will also be removed. So, we set display area as removed after
+        // reparenting stack finished.
+        // Keep the order from bottom to top.
+        int numStacks = getStackCount();
+        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            // Always finish non-standard type stacks.
+            if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+                stack.finishAllActivitiesImmediately();
+            } else {
+                // If default display is in split-window mode, set windowing mode of the
+                // stack to split-screen secondary. Otherwise, set the windowing mode to
+                // undefined by default to let stack inherited the windowing mode from the
+                // new display.
+                final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
+                        ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                        : WINDOWING_MODE_UNDEFINED;
+                stack.reparent(toDisplayArea, true /* onTop */);
+                stack.setWindowingMode(windowingMode);
+                lastReparentedStack = stack;
+            }
+            // Stacks may be removed from this display. Ensure each stack will be processed
+            // and the loop will end.
+            stackNdx -= numStacks - getStackCount();
+            numStacks = getStackCount();
+        }
+        mRemoved = true;
+
+        return lastReparentedStack;
+    }
+
+
+    @Override
+    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        pw.println(prefix + "TaskDisplayArea " + getName());
+        if (mPreferredTopFocusableStack != null) {
+            pw.println(prefix + "  mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+        }
+        if (mLastFocusedStack != null) {
+            pw.println(prefix + "  mLastFocusedStack=" + mLastFocusedStack);
+        }
+        pw.println(prefix + "  Application tokens in top down Z order:");
+        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getChildAt(stackNdx);
+            stack.dump(pw, prefix + "    ", dumpAll);
+        }
+    }
 }