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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c1c8440..a66741c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7411,7 +7411,17 @@
      */
     boolean isResumedActivityOnDisplay() {
         final DisplayContent display = getDisplay();
-        return display != null && this == display.mTaskContainers.getResumedActivity();
+        if (display == null) {
+            return false;
+        }
+        for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+            final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
+            if (resumedActivity != null) {
+                return resumedActivity == this;
+            }
+        }
+        return false;
     }
 
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index a446720..f5eba96 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1119,8 +1119,8 @@
 
     @Override
     public boolean isAttached() {
-        final DisplayContent display = getDisplay();
-        return display != null && !display.isRemoved();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        return taskDisplayArea != null && !taskDisplayArea.isRemoved();
     }
 
     // TODO: Should each user have there own stacks?
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 8af8624..02601ff 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -385,15 +385,15 @@
     private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
             new MoveTaskToFullscreenHelper();
     private class MoveTaskToFullscreenHelper {
-        private DisplayContent mToDisplay;
+        private TaskDisplayArea mToDisplayArea;
         private boolean mOnTop;
         private Task mTopTask;
         private boolean mSchedulePictureInPictureModeChange;
 
-        void process(ActivityStack fromStack, DisplayContent toDisplay, boolean onTop,
+        void process(ActivityStack fromStack, TaskDisplayArea toDisplayArea, boolean onTop,
                 boolean schedulePictureInPictureModeChange) {
             mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
-            mToDisplay = toDisplay;
+            mToDisplayArea = toDisplayArea;
             mOnTop = onTop;
             mTopTask = fromStack.getTopMostTask();
 
@@ -401,7 +401,7 @@
                     MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class));
             fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */);
             c.recycle();
-            mToDisplay = null;
+            mToDisplayArea = null;
             mTopTask = null;
         }
 
@@ -411,19 +411,18 @@
                     task.getActivityType())) {
                 final ActivityStack stack = (ActivityStack) task;
                 stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-                if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
-                    stack.reparent(mToDisplay.getDefaultTaskDisplayArea(), mOnTop);
+                if (mToDisplayArea.getDisplayId() != stack.getDisplayId()) {
+                    stack.reparent(mToDisplayArea, mOnTop);
                 } else if (mOnTop) {
-                    mToDisplay.mTaskContainers.positionStackAtTop(stack,
-                            false /* includingParents */);
+                    mToDisplayArea.positionStackAtTop(stack, false /* includingParents */);
                 } else {
-                    mToDisplay.mTaskContainers.positionStackAtBottom(stack);
+                    mToDisplayArea.positionStackAtBottom(stack);
                 }
                 return;
             }
 
-            final ActivityStack toStack = mToDisplay.mTaskContainers.getOrCreateStack(
-                    null, mTmpOptions, task, task.getActivityType(), mOnTop);
+            final ActivityStack toStack = mToDisplayArea.getOrCreateStack(null, mTmpOptions, task,
+                    task.getActivityType(), mOnTop);
             if (task == toStack) {
                 // The task was reused as the root task.
                 return;
@@ -1418,7 +1417,7 @@
                     mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP);
 
             if (stack != currentStack) {
-                moveHomeStackToFrontIfNeeded(flags, stack.getDisplay(), reason);
+                moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
                 task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
                         reason);
                 currentStack = stack;
@@ -1437,7 +1436,7 @@
         }
 
         if (!reparented) {
-            moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplay(), reason);
+            moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
         }
 
         final ActivityRecord r = task.getTopNonFinishingActivity();
@@ -1451,15 +1450,16 @@
                 currentStack, forceNonResizeable);
     }
 
-    private void moveHomeStackToFrontIfNeeded(int flags, DisplayContent display, String reason) {
-        final ActivityStack focusedStack = display.getFocusedStack();
+    private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea,
+            String reason) {
+        final ActivityStack focusedStack = taskDisplayArea.getFocusedStack();
 
-        if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+        if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
                 && (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0)
                 || (focusedStack != null && focusedStack.isActivityTypeRecents())) {
-            // We move home stack to front when we are on a fullscreen display and caller has
+            // We move home stack to front when we are on a fullscreen display area and caller has
             // requested the home activity to move with it. Or the previous stack is recents.
-            display.mTaskContainers.moveHomeStackToFront(reason);
+            taskDisplayArea.moveHomeStackToFront(reason);
         }
     }
 
@@ -1511,15 +1511,15 @@
         mService.deferWindowLayout();
         try {
             final int windowingMode = fromStack.getWindowingMode();
-            final DisplayContent toDisplay =
-                    mRootWindowContainer.getDisplayContent(toDisplayId);
+            final TaskDisplayArea toDisplayArea = mRootWindowContainer
+                    .getDisplayContent(toDisplayId).getDefaultTaskDisplayArea();
 
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 // We are moving all tasks from the docked stack to the fullscreen stack,
                 // which is dismissing the docked stack, so resize all other stacks to
                 // fullscreen here already so we don't end up with resize trashing.
-                for (int i = toDisplay.getStackCount() - 1; i >= 0; --i) {
-                    final ActivityStack otherStack = toDisplay.getStackAt(i);
+                for (int i = toDisplayArea.getStackCount() - 1; i >= 0; --i) {
+                    final ActivityStack otherStack = toDisplayArea.getStackAt(i);
                     if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                         continue;
                     }
@@ -1535,7 +1535,7 @@
             if (fromStack.hasChild()) {
                 mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
                 mMoveTaskToFullscreenHelper.process(
-                        fromStack, toDisplay, onTop, schedulePictureInPictureModeChange);
+                        fromStack, toDisplayArea, onTop, schedulePictureInPictureModeChange);
             }
 
             mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
@@ -1546,6 +1546,7 @@
     }
 
     void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) {
+        // TODO(b/153089193): Support moving within the same task display area
         mWindowManager.inSurfaceTransaction(() ->
                 moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop));
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 0a0049d..d777f3f 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -189,9 +189,10 @@
         mSupervisor.beginDeferResume();
         final ActivityStack homeStack;
         try {
+            // TODO(multi-display-area): Support starting home in a task display area
             // Make sure home stack exist on display.
-            homeStack = display.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN,
-                    ACTIVITY_TYPE_HOME, ON_TOP);
+            homeStack = display.getDefaultTaskDisplayArea().getOrCreateStack(
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         } finally {
             mSupervisor.endDeferResume();
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 85517a4..7931cd5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2060,20 +2060,53 @@
      * activity type. Null is no compatible stack on the display.
      */
     ActivityStack getStack(int windowingMode, int activityType) {
-        return mTaskContainers.getStack(windowingMode, activityType);
+        for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx)
+                    .getStack(windowingMode, activityType);
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
+    protected int getTaskDisplayAreaCount() {
+        // TODO(multi-display-area): Report actual display area count
+        return 1;
+    }
+
+    protected TaskDisplayArea getTaskDisplayAreaAt(int index) {
+        // TODO(multi-display-area): Report actual display area values
+        return mTaskContainers;
+    }
+
+    ActivityStack getStack(int rootTaskId) {
+        for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx).getStack(rootTaskId);
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
     }
 
     protected int getStackCount() {
-        return mTaskContainers.mChildren.size();
-    }
-
-    protected ActivityStack getStackAt(int index) {
-        return mTaskContainers.mChildren.get(index);
+        int totalStackCount = 0;
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            totalStackCount += getTaskDisplayAreaAt(i).getStackCount();
+        }
+        return totalStackCount;
     }
 
     @VisibleForTesting
     ActivityStack getTopStack() {
-        return mTaskContainers.getTopStack();
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getTaskDisplayAreaAt(i).getTopStack();
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
     }
 
     /**
@@ -2449,7 +2482,7 @@
             final PooledConsumer c = PooledLambda.obtainConsumer(
                     DisplayContent::processTaskForTouchExcludeRegion, this,
                     PooledLambda.__(Task.class), focusedTask, delta);
-            mTaskContainers.forAllTasks(c);
+            forAllTasks(c);
             c.recycle();
 
             // If we removed the focused task above, add it back and only leave its
@@ -2630,9 +2663,8 @@
     }
 
     void prepareFreezingTaskBounds() {
-        for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mTaskContainers.getChildAt(stackNdx);
-            stack.prepareFreezingTaskBounds();
+        for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            getTaskDisplayAreaAt(tdaNdx).prepareFreezingTaskBounds();
         }
     }
 
@@ -2738,8 +2770,8 @@
         final ActivityStack focusedStack = getFocusedStack();
         if (focusedStack != null) {
             proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId());
-            final ActivityRecord focusedActivity = focusedStack.getDisplay().mTaskContainers
-                    .getResumedActivity();
+            final ActivityRecord focusedActivity = focusedStack.getDisplayArea()
+                    .getFocusedActivity();
             if (focusedActivity != null) {
                 focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
             }
@@ -2797,13 +2829,6 @@
         if (mLastFocus != mCurrentFocus) {
             pw.print("  mLastFocus="); pw.println(mLastFocus);
         }
-        if (mTaskContainers.mPreferredTopFocusableStack != null) {
-            pw.println(prefix + "mPreferredTopFocusableStack="
-                    + mTaskContainers.mPreferredTopFocusableStack);
-        }
-        if (mTaskContainers.mLastFocusedStack != null) {
-            pw.println(prefix + "mLastFocusedStack=" + mTaskContainers.mLastFocusedStack);
-        }
         if (mLosingFocus.size() > 0) {
             pw.println();
             pw.println("  Windows losing focus:");
@@ -2837,10 +2862,9 @@
         }
 
         pw.println();
-        pw.println(prefix + "Application tokens in top down Z order:");
-        for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mTaskContainers.getChildAt(stackNdx);
-            stack.dump(pw, prefix + "  ", dumpAll);
+        pw.println(prefix + "Task display areas in top down Z order:");
+        for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            getTaskDisplayAreaAt(tdaNdx).dump(pw, prefix + "  ", dumpAll);
         }
 
         pw.println();
@@ -4002,7 +4026,9 @@
         }
 
         // Initialize state of exiting applications.
-        mTaskContainers.setExitingTokensHasVisible(hasVisible);
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).setExitingTokensHasVisible(hasVisible);
+        }
     }
 
     void removeExistingTokensIfPossible() {
@@ -4014,7 +4040,9 @@
         }
 
         // Time to remove any exiting applications?
-        mTaskContainers.removeExistingAppTokensIfPossible();
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).removeExistingAppTokensIfPossible();
+        }
     }
 
     @Override
@@ -4475,7 +4503,9 @@
     }
 
     void assignStackOrdering() {
-        mTaskContainers.assignStackOrdering(getPendingTransaction());
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).assignStackOrdering(getPendingTransaction());
+        }
     }
 
     /**
@@ -5002,13 +5032,15 @@
                 || windowingMode == WINDOWING_MODE_MULTI_WINDOW);
     }
 
-    ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
-        return mTaskContainers.createStack(windowingMode, activityType, onTop, null /* info */,
-                null /* intent */, false /* createdByOrganizer */);
-    }
-
+    @Nullable
     ActivityStack getFocusedStack() {
-        return mTaskContainers.getFocusedStack();
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getTaskDisplayAreaAt(i).getFocusedStack();
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
     }
 
     /**
@@ -5016,11 +5048,15 @@
      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
      */
     void removeStacksInWindowingModes(int... windowingModes) {
-        mTaskContainers.removeStacksInWindowingModes(windowingModes);
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).removeStacksInWindowingModes(windowingModes);
+        }
     }
 
     void removeStacksWithActivityTypes(int... activityTypes) {
-        mTaskContainers.removeStacksWithActivityTypes(activityTypes);
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).removeStacksWithActivityTypes(activityTypes);
+        }
     }
 
     ActivityRecord topRunningActivity() {
@@ -5037,7 +5073,14 @@
      * @return The top running activity. {@code null} if none is available.
      */
     ActivityRecord topRunningActivity(boolean considerKeyguardState) {
-        return mTaskContainers.topRunningActivity(considerKeyguardState);
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            final ActivityRecord activity = getTaskDisplayAreaAt(i)
+                    .topRunningActivity(considerKeyguardState);
+            if (activity != null) {
+                return activity;
+            }
+        }
+        return null;
     }
 
     boolean updateDisplayOverrideConfigurationLocked() {
@@ -5149,7 +5192,7 @@
         // The display may be about to rotate seamlessly, and the animation of closing apps may
         // still animate in old rotation. So make sure the outdated animation won't show on the
         // rotated display.
-        mTaskContainers.forAllActivities(a -> {
+        forAllActivities(a -> {
             if (a.nowVisible && a != mFixedRotationLaunchingApp
                     && a.getWindowConfiguration().getRotation() != newRotation) {
                 final WindowContainer<?> w = a.getAnimatingContainer();
@@ -5210,40 +5253,17 @@
 
     void remove() {
         mRemoving = true;
-        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
         ActivityStack lastReparentedStack = null;
-        mTaskContainers.mPreferredTopFocusableStack = null;
 
-        // Stacks could be reparented from the removed display to other display. While
-        // reparenting the last stack of the removed display, the remove display is ready to be
-        // released (no more ActivityStack). But, we cannot release it at that moment or the
-        // related WindowContainer will also be removed. So, we set display as removed after
-        // reparenting stack finished.
-        final TaskDisplayArea toTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         mRootWindowContainer.mStackSupervisor.beginDeferResume();
         try {
-            int numStacks = getStackCount();
-            // Keep the order from bottom to top.
-            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 = toTaskDisplayArea.isSplitScreenModeActivated()
-                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                            : WINDOWING_MODE_UNDEFINED;
-                    stack.reparent(toTaskDisplayArea, true /* onTop */);
-                    stack.setWindowingMode(windowingMode);
-                    lastReparentedStack = stack;
+            int numTaskContainers = getTaskDisplayAreaCount();
+            for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+                final ActivityStack lastReparentedStackFromArea = getTaskDisplayAreaAt(tdaNdx)
+                        .remove();
+                if (lastReparentedStackFromArea != null) {
+                    lastReparentedStack = lastReparentedStackFromArea;
                 }
-                // Stacks may be removed from this display. Ensure each stack will be processed and
-                // the loop will end.
-                stackNdx -= numStacks - getStackCount();
-                numStacks = getStackCount();
             }
         } finally {
             mRootWindowContainer.mStackSupervisor.endDeferResume();
@@ -5270,12 +5290,27 @@
             return;
         }
 
-        final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
-        if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
-            // Release this display if an empty home stack is the only thing left.
-            // Since it is the last stack, this display will be released along with the stack
-            // removal.
-            stack.removeIfPossible();
+        // Check if all task display areas have only the empty home stacks left.
+        boolean onlyEmptyHomeStacksLeft = true;
+        for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final TaskDisplayArea taskDisplayArea = getTaskDisplayAreaAt(tdaNdx);
+            if (taskDisplayArea.getStackCount() != 1) {
+                onlyEmptyHomeStacksLeft = false;
+                break;
+            }
+            final ActivityStack stack = taskDisplayArea.getStackAt(0);
+            if (!stack.isActivityTypeHome() || stack.hasChild()) {
+                onlyEmptyHomeStacksLeft = false;
+                break;
+            }
+        }
+        if (onlyEmptyHomeStacksLeft) {
+            // Release this display if only empty home stack(s) are left. This display will be
+            // released along with the stack(s) removal.
+            for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final ActivityStack s = getTaskDisplayAreaAt(tdaNdx).getStackAt(0);
+                s.removeIfPossible();
+            }
         } else if (getTopStack() == null) {
             removeIfPossible();
             mRootWindowContainer.mStackSupervisor
@@ -5334,10 +5369,9 @@
 
     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);
+        for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+            getTaskDisplayAreaAt(i).ensureActivitiesVisible(starting, configChanges,
+                    preserveWindows, notifyClients);
         }
     }
 
@@ -5350,13 +5384,18 @@
     }
 
     void setDisplayToSingleTaskInstance() {
-        final int childCount = getStackCount();
-        if (childCount > 1) {
+        final int taskDisplayAreaCount = getTaskDisplayAreaCount();
+        if (taskDisplayAreaCount > 1) {
+            throw new IllegalArgumentException(
+                    "Display already has multiple task display areas. display=" + this);
+        }
+        final int stackCount = getDefaultTaskDisplayArea().getStackCount();
+        if (stackCount > 1) {
             throw new IllegalArgumentException("Display already has multiple stacks. display="
                     + this);
         }
-        if (childCount > 0) {
-            final ActivityStack stack = getStackAt(0);
+        if (stackCount > 0) {
+            final ActivityStack stack = getDefaultTaskDisplayArea().getStackAt(0);
             if (stack.getChildCount() > 1) {
                 throw new IllegalArgumentException("Display stack already has multiple tasks."
                         + " display=" + this + " stack=" + stack);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 264da9f..caaa173 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -3247,7 +3247,7 @@
         final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
                 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
         final boolean inSplitScreen =
-                mService.mRoot.getDefaultDisplay().mTaskContainers.isSplitScreenModeActivated();
+                mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
         if (inSplitScreen) {
             mService.getStackBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
                     mDockedStackBounds);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 57a54d0..f672394 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -529,11 +529,14 @@
          * occlusion state.
          */
         private ActivityStack getStackForControllingOccluding(DisplayContent display) {
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                if (stack != null && stack.isFocusableAndVisible()
-                        && !stack.inPinnedWindowingMode()) {
-                    return stack;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    if (stack != null && stack.isFocusableAndVisible()
+                            && !stack.inPinnedWindowingMode()) {
+                        return stack;
+                    }
                 }
             }
             return null;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 84229f0..6fda117 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -340,7 +340,7 @@
 
         // Make leashes for each of the visible/target tasks and add it to the recents animation to
         // be started
-        // TODO(multi-display-area): Support Recents on multiple task display areas
+        // TODO(b/153090560): Support Recents on multiple task display areas
         final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea()
                 .getVisibleTasks();
         final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea()
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2eeda4d..e1ef76f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1643,7 +1643,9 @@
             displayId = DEFAULT_DISPLAY;
         }
 
-        final ActivityRecord r = getDisplayContent(displayId).mTaskContainers.getHomeActivity();
+        // TODO(multi-display-area): Resume home on the right task container
+        final ActivityRecord r = getDisplayContent(displayId).getDefaultTaskDisplayArea()
+                .getHomeActivity();
         final String myReason = reason + " resumeHomeActivity";
 
         // Only resume home activity if isn't finishing.
@@ -1800,19 +1802,23 @@
         final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
         final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
         // Traverse all displays.
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final DisplayContent display = getChildAt(i);
-            // Traverse all stacks on a display.
-            for (int j = display.getStackCount() - 1; j >= 0; --j) {
-                final ActivityStack stack = display.getStackAt(j);
-                // Get top activity from a visible stack and add it to the list.
-                if (stack.shouldBeVisible(null /* starting */)) {
-                    final ActivityRecord top = stack.getTopNonFinishingActivity();
-                    if (top != null) {
-                        if (stack == topFocusedStack) {
-                            topActivityTokens.add(0, top.appToken);
-                        } else {
-                            topActivityTokens.add(top.appToken);
+        for (int dNdx = getChildCount() - 1; dNdx >= 0; dNdx--) {
+            final DisplayContent display = getChildAt(dNdx);
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea =
+                        display.getTaskDisplayAreaAt(tdaNdx);
+                // Traverse all stacks on a display area.
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    // Get top activity from a visible stack and add it to the list.
+                    if (stack.shouldBeVisible(null /* starting */)) {
+                        final ActivityRecord top = stack.getTopNonFinishingActivity();
+                        if (top != null) {
+                            if (stack == topFocusedStack) {
+                                topActivityTokens.add(0, top.appToken);
+                            } else {
+                                topActivityTokens.add(top.appToken);
+                            }
                         }
                     }
                 }
@@ -1844,10 +1850,13 @@
         // focus order.
         for (int i = getChildCount() - 1; i >= 0; --i) {
             final DisplayContent display = getChildAt(i);
-            final ActivityRecord resumedActivityOnDisplay = display.mTaskContainers
-                    .getResumedActivity();
-            if (resumedActivityOnDisplay != null) {
-                return resumedActivityOnDisplay;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                final ActivityRecord resumedActivityOnTaskContainer = taskDisplayArea
+                        .getFocusedActivity();
+                if (resumedActivityOnTaskContainer != null) {
+                    return resumedActivityOnTaskContainer;
+                }
             }
         }
         return null;
@@ -1867,16 +1876,19 @@
         WindowProcessController fgApp = null;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                if (isTopDisplayFocusedStack(stack)) {
-                    final ActivityRecord resumedActivity = stack.getResumedActivity();
-                    if (resumedActivity != null) {
-                        fgApp = resumedActivity.app;
-                    } else if (stack.mPausingActivity != null) {
-                        fgApp = stack.mPausingActivity.app;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    if (isTopDisplayFocusedStack(stack)) {
+                        final ActivityRecord resumedActivity = stack.getResumedActivity();
+                        if (resumedActivity != null) {
+                            fgApp = resumedActivity.app;
+                        } else if (stack.mPausingActivity != null) {
+                            fgApp = stack.mPausingActivity.app;
+                        }
+                        break;
                     }
-                    break;
                 }
             }
         }
@@ -1992,9 +2004,12 @@
         mStackSupervisor.mStartingUsers.add(uss);
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                stack.switchUser(userId);
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    stack.switchUser(userId);
+                }
             }
         }
 
@@ -2196,13 +2211,17 @@
         ActivityStack focusedStack = getTopDisplayFocusedStack();
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            // It is possible that request to finish activity might also remove its task and stack,
-            // so we need to be careful with indexes in the loop and check child count every time.
-            for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                final Task t = stack.finishTopCrashedActivityLocked(app, reason);
-                if (stack == focusedStack || finishedTask == null) {
-                    finishedTask = t;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                // It is possible that request to finish activity might also remove its task and
+                // stack, so we need to be careful with indexes in the loop and check child count
+                // every time.
+                for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+                    final Task t = stack.finishTopCrashedActivityLocked(app, reason);
+                    if (stack == focusedStack || finishedTask == null) {
+                        finishedTask = t;
+                    }
                 }
             }
         }
@@ -2229,26 +2248,29 @@
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             boolean resumedOnDisplay = false;
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                final ActivityRecord topRunningActivity = stack.topRunningActivity();
-                if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
-                    continue;
-                }
-                if (stack == targetStack) {
-                    // Simply update the result for targetStack because the targetStack had
-                    // already resumed in above. We don't want to resume it again, especially in
-                    // some cases, it would cause a second launch failure if app process was dead.
-                    resumedOnDisplay |= result;
-                    continue;
-                }
-                if (display.mTaskContainers.isTopStack(stack)
-                        && topRunningActivity.isState(RESUMED)) {
-                    // Kick off any lingering app transitions form the MoveTaskToFront operation,
-                    // but only consider the top task and stack on that display.
-                    stack.executeAppTransition(targetOptions);
-                } else {
-                    resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    final ActivityRecord topRunningActivity = stack.topRunningActivity();
+                    if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
+                        continue;
+                    }
+                    if (stack == targetStack) {
+                        // Simply update the result for targetStack because the targetStack had
+                        // already resumed in above. We don't want to resume it again, especially in
+                        // some cases, it would cause a second launch failure if app process was
+                        // dead.
+                        resumedOnDisplay |= result;
+                        continue;
+                    }
+                    if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
+                        // Kick off any lingering app transitions form the MoveTaskToFront
+                        // operation, but only consider the top task and stack on that display.
+                        stack.executeAppTransition(targetOptions);
+                    } else {
+                        resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+                    }
                 }
             }
             if (!resumedOnDisplay) {
@@ -2284,32 +2306,37 @@
             }
 
             // Set the sleeping state of the stacks on the display.
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                if (displayShouldSleep) {
-                    stack.goToSleepIfPossible(false /* shuttingDown */);
-                } else {
-                    // When the display which can only contain one task turns on, start a special
-                    // transition. {@link AppTransitionController#handleAppTransitionReady} later
-                    // picks up the transition, and schedules
-                    // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
-                    // triggered after contents are drawn on the display.
-                    if (display.isSingleTaskInstance()) {
-                        display.mDisplayContent.prepareAppTransition(
-                                TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
-                    }
-                    stack.awakeFromSleepingLocked();
-                    if (display.isSingleTaskInstance()) {
-                        display.executeAppTransition();
-                    }
-                    if (stack.isFocusedStackOnDisplay()
-                            && !mStackSupervisor.getKeyguardController()
-                            .isKeyguardOrAodShowing(display.mDisplayId)) {
-                        // If the keyguard is unlocked - resume immediately.
-                        // It is possible that the display will not be awake at the time we
-                        // process the keyguard going away, which can happen before the sleep token
-                        // is released. As a result, it is important we resume the activity here.
-                        resumeFocusedStacksTopActivities();
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    if (displayShouldSleep) {
+                        stack.goToSleepIfPossible(false /* shuttingDown */);
+                    } else {
+                        // When the display which can only contain one task turns on, start a
+                        // special transition.
+                        // {@link AppTransitionController#handleAppTransitionReady} later picks up
+                        // the transition, and schedules
+                        // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
+                        // triggered after contents are drawn on the display.
+                        if (display.isSingleTaskInstance()) {
+                            display.mDisplayContent.prepareAppTransition(
+                                    TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+                        }
+                        stack.awakeFromSleepingLocked();
+                        if (display.isSingleTaskInstance()) {
+                            display.executeAppTransition();
+                        }
+                        if (stack.isFocusedStackOnDisplay()
+                                && !mStackSupervisor.getKeyguardController()
+                                .isKeyguardOrAodShowing(display.mDisplayId)) {
+                            // If the keyguard is unlocked - resume immediately.
+                            // It is possible that the display will not be awake at the time we
+                            // process the keyguard going away, which can happen before the sleep
+                            // token is released. As a result, it is important we resume the
+                            // activity here.
+                            resumeFocusedStacksTopActivities();
+                        }
                     }
                 }
             }
@@ -2318,7 +2345,7 @@
 
     protected ActivityStack getStack(int stackId) {
         for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i).mTaskContainers.getStack(stackId);
+            final ActivityStack stack = getChildAt(i).getStack(stackId);
             if (stack != null) {
                 return stack;
             }
@@ -2414,9 +2441,12 @@
         if (displayId == INVALID_DISPLAY) {
             for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
                 final DisplayContent display = getChildAt(displayNdx);
-                for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = display.getStackAt(stackNdx);
-                    list.add(getStackInfo(stack));
+                for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                    final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                    for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                        final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                        list.add(getStackInfo(stack));
+                    }
                 }
             }
             return list;
@@ -2425,9 +2455,12 @@
         if (display == null) {
             return list;
         }
-        for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = display.getStackAt(stackNdx);
-            list.add(getStackInfo(stack));
+        for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+            for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                list.add(getStackInfo(stack));
+            }
         }
         return list;
     }
@@ -2646,19 +2679,21 @@
         boolean allSleep = true;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                // Stacks and activities could be removed while putting activities to sleep if
-                // the app process was gone. This prevents us getting exception by accessing an
-                // invalid stack index.
-                if (stackNdx >= display.getStackCount()) {
-                    continue;
-                }
-
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                if (allowDelay) {
-                    allSleep &= stack.goToSleepIfPossible(shuttingDown);
-                } else {
-                    stack.goToSleep();
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    // Stacks and activities could be removed while putting activities to sleep if
+                    // the app process was gone. This prevents us getting exception by accessing an
+                    // invalid stack index.
+                    if (sNdx >= taskDisplayArea.getStackCount()) {
+                        continue;
+                    }
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    if (allowDelay) {
+                        allSleep &= stack.goToSleepIfPossible(shuttingDown);
+                    } else {
+                        stack.goToSleep();
+                    }
                 }
             }
         }
@@ -2910,14 +2945,17 @@
             windowingMode = options != null ? options.getLaunchWindowingMode()
                     : r.getWindowingMode();
         }
-        windowingMode = displayContent.mTaskContainers.validateWindowingMode(windowingMode, r,
-                candidateTask, r.getActivityType());
 
         // Return the topmost valid stack on the display.
-        for (int i = displayContent.getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = displayContent.getStackAt(i);
-            if (isValidLaunchStack(stack, r, windowingMode)) {
-                return stack;
+        for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+            final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+            final int validatedWindowingMode = taskDisplayArea
+                    .validateWindowingMode(windowingMode, r, candidateTask, r.getActivityType());
+            for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                if (isValidLaunchStack(stack, r, validatedWindowingMode)) {
+                    return stack;
+                }
             }
         }
 
@@ -3034,9 +3072,12 @@
         boolean hasVisibleActivities = false;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                hasVisibleActivities |= stack.handleAppDied(app);
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    hasVisibleActivities |= stack.handleAppDied(app);
+                }
             }
         }
         return hasVisibleActivities;
@@ -3147,10 +3188,14 @@
     void finishVoiceTask(IVoiceInteractionSession session) {
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            final int numStacks = display.getStackCount();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                stack.finishVoiceTask(session);
+            int numTaskContainers = display.getTaskDisplayAreaCount();
+            for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                final int numStacks = display.getStackCount();
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+                    stack.finishVoiceTask(session);
+                }
             }
         }
     }
@@ -3214,14 +3259,17 @@
         boolean foundResumed = false;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                final ActivityRecord r = stack.getResumedActivity();
-                if (r != null) {
-                    if (!r.nowVisible) {
-                        return false;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    final ActivityRecord r = stack.getResumedActivity();
+                    if (r != null) {
+                        if (!r.nowVisible) {
+                            return false;
+                        }
+                        foundResumed = true;
                     }
-                    foundResumed = true;
                 }
             }
         }
@@ -3232,16 +3280,19 @@
         boolean pausing = true;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                final ActivityRecord r = stack.mPausingActivity;
-                if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
-                    if (DEBUG_STATES) {
-                        Slog.d(TAG_STATES,
-                                "allPausedActivitiesComplete: r=" + r + " state=" + r.getState());
-                        pausing = false;
-                    } else {
-                        return false;
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    final ActivityRecord r = stack.mPausingActivity;
+                    if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
+                        if (DEBUG_STATES) {
+                            Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
+                                    + " state=" + r.getState());
+                            pausing = false;
+                        } else {
+                            return false;
+                        }
                     }
                 }
             }
@@ -3297,9 +3348,11 @@
     void cancelInitializingActivities() {
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                stack.cancelInitializingActivities();
+            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    taskDisplayArea.getStackAt(sNdx).cancelInitializingActivities();
+                }
             }
         }
     }
@@ -3402,20 +3455,23 @@
         }
 
         if (!sendHint) { // targetActivity != null
-            // Send power hint when the activity's process is different than the current resumed
-            // activity on all displays, or if there are no resumed activities in the system.
+            // Send power hint when the activity's process is different than the current top resumed
+            // activity on all display areas, or if there are no resumed activities in the system.
             boolean noResumedActivities = true;
             boolean allFocusedProcessesDiffer = true;
             for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
-                final DisplayContent displayContent = getChildAt(displayNdx);
-                final ActivityRecord resumedActivity = displayContent.mTaskContainers
-                        .getResumedActivity();
-                final WindowProcessController resumedActivityProcess =
-                        resumedActivity == null ? null : resumedActivity.app;
+                final DisplayContent dc = getChildAt(displayNdx);
+                for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                    final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+                    final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
+                    final WindowProcessController resumedActivityProcess =
+                            resumedActivity == null ? null : resumedActivity.app;
 
-                noResumedActivities &= resumedActivityProcess == null;
-                if (resumedActivityProcess != null) {
-                    allFocusedProcessesDiffer &= !resumedActivityProcess.equals(targetActivity.app);
+                    noResumedActivities &= resumedActivityProcess == null;
+                    if (resumedActivityProcess != null) {
+                        allFocusedProcessesDiffer &= !resumedActivityProcess.equals(
+                                targetActivity.app);
+                    }
                 }
             }
             sendHint = noResumedActivities || allFocusedProcessesDiffer;
@@ -3462,10 +3518,13 @@
             int numDisplays = getChildCount();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent display = getChildAt(displayNdx);
-                for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = display.getStackAt(stackNdx);
-                    if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
-                        activities.addAll(stack.getDumpActivitiesLocked(name));
+                for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                    final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+                    for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                        final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                        if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
+                            activities.addAll(stack.getDumpActivitiesLocked(name));
+                        }
                     }
                 }
             }
@@ -3505,14 +3564,21 @@
             DisplayContent displayContent = getChildAt(displayNdx);
             pw.print("Display #"); pw.print(displayContent.mDisplayId);
             pw.println(" (activities from top to bottom):");
-            for (int stackNdx = displayContent.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = displayContent.getStackAt(stackNdx);
-                pw.println();
-                printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
-                needSep = printed;
+            for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                    pw.println();
+                    printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
+                    needSep = printed;
+                }
             }
-            printThisActivity(pw, displayContent.mTaskContainers.getResumedActivity(), dumpPackage,
-                    needSep, " ResumedActivity:");
+            pw.println(" (resumed activities in task display areas from top to bottom):");
+            for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+                printThisActivity(pw, taskDisplayArea.getFocusedActivity(), dumpPackage, needSep,
+                        "   ResumedActivity:");
+            }
         }
 
         printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, "  ",
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);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index e6757e1..da4401a 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -705,14 +705,19 @@
     private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
             @NonNull Rect inOutBounds) {
         final List<Rect> taskBoundsToCheck = new ArrayList<>();
-        for (int i = 0; i < display.getStackCount(); ++i) {
-            final ActivityStack stack = display.getStackAt(i);
-            if (!stack.inFreeformWindowingMode()) {
-                continue;
-            }
+        int numTaskContainers = display.getTaskDisplayAreaCount();
+        for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+            final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+            int numStacks = taskDisplayArea.getStackCount();
+            for (int sNdx = 0; sNdx < numStacks; ++sNdx) {
+                final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+                if (!stack.inFreeformWindowingMode()) {
+                    continue;
+                }
 
-            for (int j = 0; j < stack.getChildCount(); ++j) {
-                taskBoundsToCheck.add(stack.getChildAt(j).getBounds());
+                for (int j = 0; j < stack.getChildCount(); ++j) {
+                    taskBoundsToCheck.add(stack.getChildAt(j).getBounds());
+                }
             }
         }
         adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9ffd8d2..2bbf8db 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -395,26 +395,27 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                TaskDisplayArea taskDisplayArea =
-                        mService.mRootWindowContainer.getDisplayContent(displayId).mTaskContainers;
-                if (taskDisplayArea == null) {
+                TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer
+                        .getDisplayContent(displayId).getDefaultTaskDisplayArea();
+                if (defaultTaskDisplayArea == null) {
                     return;
                 }
                 Task task = token == null
                         ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
                 if (task == null) {
-                    taskDisplayArea.mLaunchRootTask = null;
+                    defaultTaskDisplayArea.mLaunchRootTask = null;
                     return;
                 }
                 if (!task.mCreatedByOrganizer) {
                     throw new IllegalArgumentException("Attempt to set task not created by "
                             + "organizer as launch root task=" + task);
                 }
-                if (task.getDisplayArea() != taskDisplayArea) {
+                if (task.getDisplayArea() == null
+                        || task.getDisplayArea().getDisplayId() != displayId) {
                     throw new RuntimeException("Can't set launch root for display " + displayId
                             + " to task on display " + task.getDisplayContent().getDisplayId());
                 }
-                taskDisplayArea.mLaunchRootTask = task;
+                task.getDisplayArea().mLaunchRootTask = task;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -475,13 +476,16 @@
                     throw new IllegalArgumentException("Display " + displayId + " doesn't exist");
                 }
                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
-                for (int i = dc.getStackCount() - 1; i >= 0; --i) {
-                    final Task task = dc.getStackAt(i);
-                    if (activityTypes != null
-                            && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
-                        continue;
+                for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+                    final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+                    for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                        final Task task = taskDisplayArea.getStackAt(sNdx);
+                        if (activityTypes != null
+                                && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
+                            continue;
+                        }
+                        out.add(task.getTaskInfo());
                     }
-                    out.add(task.getTaskInfo());
                 }
                 return out;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 687af64..3cbb85b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7318,7 +7318,7 @@
 
         @Override
         public boolean isStackVisibleLw(int windowingMode) {
-            // TODO(multi-display-area): Support multiple task display areas & displays
+            // TODO(b/153090332): Support multiple task display areas & displays
             final TaskDisplayArea tc = mRoot.getDefaultTaskDisplayArea();
             return tc.isStackVisible(windowingMode);
         }