3/n Refactor TaskContainers to TaskDisplayArea

Renamed TaskContainers to TaskDisplayArea and added getDisplayArea()
method to WindowContainer that finds the first display area in the
hierarchy above the node. ActivityRecord and Task override it to
return the TaskDisplayArea class.

Bug: 152116619
Test: WM CTS and unit tests
Change-Id: I4525afbcd794848e1020213cdca04d89a646dd55
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 62ec936..ecafa69 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2079,6 +2079,12 @@
     }
 
     @Override
+    @Nullable
+    TaskDisplayArea getDisplayArea() {
+        return (TaskDisplayArea) super.getDisplayArea();
+    }
+
+    @Override
     boolean fillsParent() {
         return occludesParent();
     }
@@ -2232,8 +2238,8 @@
         boolean isKeyguardLocked = mAtmService.isKeyguardLocked();
         boolean isCurrentAppLocked =
                 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
-        final DisplayContent display = getDisplay();
-        boolean hasPinnedStack = display != null && display.hasPinnedTask();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        boolean hasPinnedStack = taskDisplayArea != null && taskDisplayArea.hasPinnedTask();
         // Don't return early if !isNotLocked, since we want to throw an exception if the activity
         // is in an incorrect state
         boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked;
@@ -2500,11 +2506,11 @@
                     // and focused application if needed.
                     stack.adjustFocusToNextFocusableStack("finish-top");
                 } else {
-                    // Only move the next stack to top in its display.
-                    final DisplayContent display = stack.getDisplay();
-                    next = display.topRunningActivity();
+                    // Only move the next stack to top in its task container.
+                    final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
+                    next = taskDisplayArea.topRunningActivity();
                     if (next != null) {
-                        display.mTaskContainers.positionStackAtTop(next.getRootTask(),
+                        taskDisplayArea.positionStackAtTop(next.getRootTask(),
                                 false /* includingParents */, "finish-display-top");
                     }
                 }
@@ -2634,7 +2640,7 @@
         // Note that if this finishing activity is floating task, we don't need to wait the
         // next activity resume and can destroy it directly.
         // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
-        final ActivityRecord next = getDisplay().topRunningActivity(
+        final ActivityRecord next = getDisplayArea().topRunningActivity(
                 true /* considerKeyguardState */);
         // isNextNotYetVisible is to check if the next activity is invisible, or it has been
         // requested to be invisible but its windows haven't reported as invisible.  If so, it
@@ -2673,13 +2679,13 @@
         mStackSupervisor.mStoppingActivities.remove(this);
 
         final ActivityStack stack = getRootTask();
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
         // TODO(b/137329632): Exclude current activity when looking for the next one with
         // DisplayContent#topRunningActivity().
-        final ActivityRecord next = display.topRunningActivity();
+        final ActivityRecord next = taskDisplayArea.topRunningActivity();
         final boolean isLastStackOverEmptyHome =
                 next == null && stack.isFocusedStackOnDisplay()
-                        && display.mTaskContainers.getOrCreateRootHomeTask() != null;
+                        && taskDisplayArea.getOrCreateRootHomeTask() != null;
         if (isLastStackOverEmptyHome) {
             // Don't destroy activity immediately if this is the last activity on the display and
             // the display contains home stack. Although there is no next activity at the moment,
@@ -4477,7 +4483,7 @@
         // case where this is the top activity in a pinned stack.
         final boolean isTop = this == stack.getTopNonFinishingActivity();
         final boolean isTopNotPinnedStack = stack.isAttached()
-                && stack.getDisplay().mTaskContainers.isTopNotPinnedStack(stack);
+                && stack.getDisplayArea().isTopNotPinnedStack(stack);
         final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
                 visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
 
@@ -5194,7 +5200,7 @@
         // The activity may have been requested to be invisible (another activity has been launched)
         // so there is no valid info. But if it is the current top activity (e.g. sleeping), the
         // invalid state is still reported to make sure the waiting result is notified.
-        if (validInfo || this == mDisplayContent.topRunningActivity()) {
+        if (validInfo || this == getDisplayArea().topRunningActivity()) {
             mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
                     windowsDrawnDelayMs, launchState);
             mStackSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 9815d6d..10b335e 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -24,9 +24,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -623,12 +621,13 @@
         // surface position.
         updateSurfaceSize(getPendingTransaction());
 
-        if (mDisplayContent == null) {
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        if (taskDisplayArea == null) {
             return;
         }
 
         if (prevWindowingMode != getWindowingMode()) {
-            mDisplayContent.onStackWindowingModeChanged(this);
+            taskDisplayArea.onStackWindowingModeChanged(this);
         }
 
         final DisplayContent display = getDisplay();
@@ -655,7 +654,7 @@
         }
 
         if (windowingModeChanged) {
-            display.onStackWindowingModeChanged(this);
+            taskDisplayArea.onStackWindowingModeChanged(this);
         }
         if (hasNewOverrideBounds) {
             if (inSplitScreenWindowingMode()) {
@@ -670,7 +669,7 @@
             // Since always on top is only on when the stack is freeform or pinned, the state
             // can be toggled when the windowing mode changes. We must make sure the stack is
             // placed properly when always on top state changes.
-            display.mTaskContainers.positionStackAtTop(this, false /* includingParents */);
+            taskDisplayArea.positionStackAtTop(this, false /* includingParents */);
         }
     }
 
@@ -730,7 +729,7 @@
             boolean creating) {
         final int currentMode = getWindowingMode();
         final int currentOverrideMode = getRequestedOverrideWindowingMode();
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
         final Task topTask = getTopMostTask();
         int windowingMode = preferredWindowingMode;
         if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
@@ -742,18 +741,17 @@
         // Need to make sure windowing mode is supported. If we in the process of creating the stack
         // no need to resolve the windowing mode again as it is already resolved to the right mode.
         if (!creating) {
-            windowingMode = display.mTaskContainers.validateWindowingMode(windowingMode,
+            windowingMode = taskDisplayArea.validateWindowingMode(windowingMode,
                     null /* ActivityRecord */, topTask, getActivityType());
         }
-        if (display.getRootSplitScreenPrimaryTask() == this
+        if (taskDisplayArea.getRootSplitScreenPrimaryTask() == this
                 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
             // Resolution to split-screen secondary for the primary split-screen stack means
             // we want to leave split-screen mode.
             windowingMode = mRestoreOverrideWindowingMode;
         }
 
-        final boolean alreadyInSplitScreenMode = display.mTaskContainers
-                .isSplitScreenModeActivated();
+        final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated();
 
         // Don't send non-resizeable notifications if the windowing mode changed was a side effect
         // of us entering split-screen mode.
@@ -770,7 +768,7 @@
                 // warning toast about it.
                 mAtmService.getTaskChangeNotificationController()
                         .notifyActivityDismissingDockedStack();
-                display.mTaskContainers.onSplitScreenModeDismissed();
+                taskDisplayArea.onSplitScreenModeDismissed();
             }
         }
 
@@ -862,7 +860,7 @@
                 // TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode
                 final boolean isRecentsComponentHome =
                         mAtmService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
-                final ActivityStack recentStack = display.mTaskContainers.getOrCreateStack(
+                final ActivityStack recentStack = taskDisplayArea.getOrCreateStack(
                         WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
                         isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS,
                         true /* onTop */);
@@ -1050,7 +1048,7 @@
             return;
         }
 
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
 
         if (inSplitScreenSecondaryWindowingMode()) {
             // If the stack is in split-screen secondary mode, we need to make sure we move the
@@ -1059,11 +1057,13 @@
             // cutting between them.
             // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
             final ActivityStack topFullScreenStack =
-                    display.mTaskContainers.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+                    taskDisplayArea.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
             if (topFullScreenStack != null) {
-                final ActivityStack primarySplitScreenStack = display.getRootSplitScreenPrimaryTask();
-                if (primarySplitScreenStack != null && display.getIndexOf(topFullScreenStack)
-                        > display.getIndexOf(primarySplitScreenStack)) {
+                final ActivityStack primarySplitScreenStack =
+                        taskDisplayArea.getRootSplitScreenPrimaryTask();
+                if (primarySplitScreenStack != null
+                        && taskDisplayArea.getIndexOf(topFullScreenStack)
+                            > taskDisplayArea.getIndexOf(primarySplitScreenStack)) {
                     primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
                 }
             }
@@ -1072,11 +1072,11 @@
         if (!isActivityTypeHome() && returnsToHomeStack()) {
             // Make sure the home stack is behind this stack since that is where we should return to
             // when this stack is no longer visible.
-            display.mTaskContainers.moveHomeStackToFront(reason + " returnToHome");
+            taskDisplayArea.moveHomeStackToFront(reason + " returnToHome");
         }
 
         if (isRootTask()) {
-            display.mTaskContainers.positionStackAtTop(this, false /* includingParents */, reason);
+            taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason);
         }
         if (task == null) {
             task = this;
@@ -1093,7 +1093,7 @@
             return;
         }
 
-        getDisplay().mTaskContainers.positionStackAtBottom(this, reason);
+        getDisplayArea().positionStackAtBottom(this, reason);
         if (task != null && task != this) {
             positionChildAtBottom(task);
         }
@@ -1451,7 +1451,7 @@
         // focus). Also if there is an active pinned stack - we always want to notify it about
         // task stack changes, because its positioning may depend on it.
         if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
-                || (getDisplay() != null && getDisplay().hasPinnedTask())) {
+                || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
             mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
         }
@@ -1459,9 +1459,9 @@
         mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
     }
 
-    boolean isTopStackOnDisplay() {
-        final DisplayContent display = getDisplay();
-        return display != null && display.mTaskContainers.isTopStack(this);
+    boolean isTopStackInDisplayArea() {
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        return taskDisplayArea != null && taskDisplayArea.isTopStack(this);
     }
 
     /**
@@ -1473,11 +1473,6 @@
         return display != null && this == display.getFocusedStack();
     }
 
-    boolean isTopActivityVisible() {
-        final ActivityRecord topActivity = getTopNonFinishingActivity();
-        return topActivity != null && topActivity.mVisibleRequested;
-    }
-
     /**
      * Returns true if the stack should be visible.
      *
@@ -1499,7 +1494,7 @@
             return STACK_VISIBILITY_INVISIBLE;
         }
 
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
         boolean gotSplitScreenStack = false;
         boolean gotOpaqueSplitScreenPrimary = false;
         boolean gotOpaqueSplitScreenSecondary = false;
@@ -1509,8 +1504,8 @@
         boolean shouldBeVisible = true;
         final int windowingMode = getWindowingMode();
         final boolean isAssistantType = isActivityTypeAssistant();
-        for (int i = display.getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack other = display.getStackAt(i);
+        for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack other = taskDisplayArea.getStackAt(i);
             final boolean hasRunningActivities = other.topRunningActivity() != null;
             if (other == this) {
                 // Should be visible if there is no other stack occluding it, unless it doesn't
@@ -1668,19 +1663,7 @@
      */
     boolean isTopSplitScreenStack() {
         return inSplitScreenWindowingMode()
-                && this == getDisplay().mTaskContainers
-                .getTopStackInWindowingMode(getWindowingMode());
-    }
-
-    /** @return True if the resizing of the primary-split-screen stack affects this stack size. */
-    boolean affectedBySplitScreenResize() {
-        if (!supportsSplitScreenWindowingMode()) {
-            return false;
-        }
-        final int windowingMode = getWindowingMode();
-        return windowingMode != WINDOWING_MODE_FREEFORM
-                && windowingMode != WINDOWING_MODE_PINNED
-                && windowingMode != WINDOWING_MODE_MULTI_WINDOW;
+                && this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode());
     }
 
     /**
@@ -1898,11 +1881,11 @@
         }
 
         next.delayedResume = false;
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
 
         // If the top activity is the resumed one, nothing to do.
         if (mResumedActivity == next && next.isState(RESUMED)
-                && display.mTaskContainers.allResumedActivitiesComplete()) {
+                && taskDisplayArea.allResumedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
@@ -1981,7 +1964,7 @@
         mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
 
         ActivityRecord lastResumed = null;
-        final ActivityStack lastFocusedStack = display.mTaskContainers.getLastFocusedStack();
+        final ActivityStack lastFocusedStack = taskDisplayArea.getLastFocusedStack();
         if (lastFocusedStack != null && lastFocusedStack != this) {
             // So, why aren't we using prev here??? See the param comment on the method. prev doesn't
             // represent the last resumed activity. However, the last focus stack does if it isn't null.
@@ -1995,7 +1978,7 @@
             }
         }
 
-        boolean pausing = display.mTaskContainers.pauseBackStacks(userLeaving, next);
+        boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next);
         if (mResumedActivity != null) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Pausing " + mResumedActivity);
@@ -2015,7 +1998,7 @@
                 // Since the start-process is asynchronous, if we already know the process of next
                 // activity isn't running, we can start the process earlier to save the time to wait
                 // for the current activity to be paused.
-                final boolean isTop = this == display.getFocusedStack();
+                final boolean isTop = this == taskDisplayArea.getFocusedStack();
                 mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                         isTop ? "pre-top-activity" : "pre-activity");
             }
@@ -2024,7 +2007,7 @@
             }
             return true;
         } else if (mResumedActivity == next && next.isState(RESUMED)
-                && display.mTaskContainers.allResumedActivitiesComplete()) {
+                && taskDisplayArea.allResumedActivitiesComplete()) {
             // It is possible for the activity to be resumed when we paused back stacks above if the
             // next activity doesn't have to wait for pause to complete.
             // So, nothing else to-do except:
@@ -2085,7 +2068,7 @@
         // that the previous one will be hidden soon.  This way it can know
         // to ignore it when computing the desired screen orientation.
         boolean anim = true;
-        final DisplayContent dc = display.mDisplayContent;
+        final DisplayContent dc = taskDisplayArea.mDisplayContent;
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
@@ -2261,7 +2244,7 @@
                 if (!next.hasBeenLaunched) {
                     next.hasBeenLaunched = true;
                 } else  if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null
-                        && lastFocusedStack.isTopStackOnDisplay()) {
+                        && lastFocusedStack.isTopStackInDisplayArea()) {
                     next.showStartingWindow(null /* prev */, false /* newTask */,
                             false /* taskSwitch */);
                 }
@@ -2544,7 +2527,7 @@
         if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
             // If we will be focusing on the home stack next and its current top activity isn't
             // visible, then use the move the home stack task to top to make the activity visible.
-            stack.getDisplay().mTaskContainers.moveHomeActivityToTop(reason);
+            stack.getDisplayArea().moveHomeActivityToTop(reason);
             return stack;
         }
 
@@ -2655,15 +2638,15 @@
 
     /** @return true if the stack behind this one is a standard activity type. */
     private boolean inFrontOfStandardStack() {
-        final DisplayContent display = getDisplay();
-        if (display == null) {
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        if (taskDisplayArea == null) {
             return false;
         }
-        final int index = display.getIndexOf(this);
+        final int index = taskDisplayArea.getIndexOf(this);
         if (index == 0) {
             return false;
         }
-        final ActivityStack stackBehind = display.getStackAt(index - 1);
+        final ActivityStack stackBehind = taskDisplayArea.getChildAt(index - 1);
         return stackBehind.isActivityTypeStandard();
     }
 
@@ -2830,7 +2813,7 @@
             AppTimeTracker timeTracker, boolean deferResume, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
-        final ActivityStack topStack = getDisplay().getTopStack();
+        final ActivityStack topStack = getDisplayArea().getTopStack();
         final ActivityRecord topActivity = topStack != null
                 ? topStack.getTopNonFinishingActivity() : null;
 
@@ -2933,7 +2916,7 @@
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (isTopStackOnDisplay() && mAtmService.mController != null) {
+        if (isTopStackInDisplayArea() && mAtmService.mController != null) {
             ActivityRecord next = topRunningActivity(null, tr.mTaskId);
             if (next == null) {
                 next = topRunningActivity(null, INVALID_TASK_ID);
@@ -2964,7 +2947,7 @@
             return true;
         }
 
-        ActivityRecord topActivity = getDisplay().topRunningActivity();
+        ActivityRecord topActivity = getDisplayArea().topRunningActivity();
         ActivityStack topStack = topActivity.getRootTask();
         if (topStack != null && topStack != this && topActivity.isState(RESUMED)) {
             // The new top activity is already resumed, so there's a good chance that nothing will
@@ -3306,7 +3289,7 @@
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
 
         boolean toTop = position >= getChildCount();
-        boolean includingParents = toTop || getDisplay().mTaskContainers.getNextFocusableStack(this,
+        boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this,
                 true /* ignoreCurrent */) == null;
         if (WindowManagerDebugConfig.DEBUG_STACK) {
             Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
@@ -3344,13 +3327,13 @@
             return;
         }
         super.setAlwaysOnTop(alwaysOnTop);
-        final DisplayContent display = getDisplay();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
         // positionChildAtTop() must be called even when always on top gets turned off because we
         // need to make sure that the stack is moved from among always on top windows to below other
         // always on top windows. Since the position the stack should be inserted into is calculated
         // properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just
         // request that the stack is put at top here.
-        display.mTaskContainers.positionStackAtTop(this, false /* includingParents */);
+        taskDisplayArea.positionStackAtTop(this, false /* includingParents */);
     }
 
     /** NOTE: Should only be called from {@link Task#reparent}. */
@@ -3395,7 +3378,7 @@
             final Task task = getBottomMostTask();
             setWindowingMode(WINDOWING_MODE_UNDEFINED);
 
-            getDisplay().mTaskContainers.positionStackAtTop(this, false /* includingParents */);
+            getDisplayArea().positionStackAtTop(this, false /* includingParents */);
 
             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
             MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
@@ -3515,7 +3498,7 @@
         // If there are other focusable stacks on the display, the z-order of the display should not
         // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
         // task to bottom, the next focusable stack on the same display should be focused.
-        final ActivityStack nextFocusableStack = getDisplay().mTaskContainers.getNextFocusableStack(
+        final ActivityStack nextFocusableStack = getDisplayArea().getNextFocusableStack(
                 child.getStack(), true /* ignoreCurrent */);
         positionChildAtBottom(child, nextFocusableStack == null /* includingParents */);
         child.updateTaskMovement(true);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index aed1d95..2c7ce91 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1788,7 +1788,7 @@
             if (prevStack != null) {
                 return prevStack;
             }
-            stack = stack.getDisplay().createStack(
+            stack = stack.getDisplayArea().createStack(
                     WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
         }
         return stack;
@@ -1878,7 +1878,7 @@
         mStoppingActivities.remove(r);
 
         final ActivityStack stack = r.getRootTask();
-        if (stack.getDisplay().mTaskContainers.allResumedActivitiesComplete()) {
+        if (stack.getDisplayArea().allResumedActivitiesComplete()) {
             mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
             // Make sure activity & window visibility should be identical
             // for all displays in this stage.
@@ -2242,7 +2242,7 @@
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
         final boolean inSplitScreenMode = actualStack != null
-                && actualStack.getDisplay().mTaskContainers.isSplitScreenModeActivated();
+                && actualStack.getDisplayArea().isSplitScreenModeActivated();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
                 && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
             return;
@@ -2289,14 +2289,14 @@
         if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
             // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
             // we need to move it to top of fullscreen stack, otherwise it will be covered.
-            final DisplayContent display = task.getStack().getDisplay();
-            if (display.mTaskContainers.isSplitScreenModeActivated()) {
+            final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
+            if (taskDisplayArea.isSplitScreenModeActivated()) {
                 // Display a warning toast that we tried to put an app that doesn't support
                 // split-screen in split-screen.
                 mService.getTaskChangeNotificationController()
                         .notifyActivityDismissingDockedStack();
-                display.mTaskContainers.onSplitScreenModeDismissed();
-                display.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+                taskDisplayArea.onSplitScreenModeDismissed();
+                taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
                         true /* notifyClients */);
             }
             return;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index da1c045..0ba1866 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1390,7 +1390,7 @@
             // The activity was already running so it wasn't started, but either brought to the
             // front or the new intent was delivered to it since it was already in front. Notify
             // anyone interested in this piece of information.
-            final ActivityStack homeStack = targetTask.getDisplayContent().getRootHomeTask();
+            final ActivityStack homeStack = targetTask.getDisplayArea().getRootHomeTask();
             final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
             mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
                     targetTask.getTaskInfo(), homeTaskVisible, clearedTask);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7e999c6..60ab556 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2357,7 +2357,7 @@
                 }
                 // Convert some windowing-mode changes into root-task reparents for split-screen.
                 if (stack.inSplitScreenWindowingMode()) {
-                    stack.getDisplay().mTaskContainers.onSplitScreenModeDismissed();
+                    stack.getDisplayArea().onSplitScreenModeDismissed();
 
                 } else {
                     stack.setWindowingMode(windowingMode);
@@ -2768,14 +2768,14 @@
     }
 
     void moveTaskToSplitScreenPrimaryTask(Task task, boolean toTop) {
-        final DisplayContent display = task.getDisplayContent();
-        final ActivityStack primarySplitTask = display.getRootSplitScreenPrimaryTask();
+        final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
+        final ActivityStack primarySplitTask = taskDisplayArea.getRootSplitScreenPrimaryTask();
         if (primarySplitTask == null) {
             throw new IllegalStateException("Can't enter split without associated organized task");
         }
 
         if (toTop) {
-            display.mTaskContainers.positionStackAt(POSITION_TOP, primarySplitTask,
+            taskDisplayArea.positionStackAt(POSITION_TOP, primarySplitTask,
                     false /* includingParents */);
         }
         WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -3245,8 +3245,8 @@
                 }
 
                 final ActivityStack stack = r.getRootTask();
-                final Task task = stack.getDisplay().mTaskContainers.createStack(
-                        stack.getWindowingMode(), stack.getActivityType(), !ON_TOP, ainfo, intent,
+                final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(),
+                        stack.getActivityType(), !ON_TOP, ainfo, intent,
                         false /* createdByOrganizer */);
 
                 if (!mRecentTasks.addToBottom(task)) {
@@ -3309,10 +3309,10 @@
                     throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
                 }
                 if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                    stack = stack.getDisplay().mTaskContainers.getOrCreateStack(
+                    stack = stack.getDisplayArea().getOrCreateStack(
                             WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
                 } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
-                    stack = stack.getDisplay().mTaskContainers.getOrCreateStack(
+                    stack = stack.getDisplayArea().getOrCreateStack(
                             WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP);
                 }
 
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 8cac487..fd70971 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -31,7 +31,6 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
 
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 import android.window.IDisplayAreaOrganizer;
@@ -227,6 +226,11 @@
         }
     }
 
+    @Override
+    DisplayArea getDisplayArea() {
+        return this;
+    }
+
     /**
      * Top-most DisplayArea under DisplayContent.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 3c083e1..9821573 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -48,19 +48,19 @@
      * @param content the display content for which the policy applies
      * @param root the root display area under which the policy operates
      * @param imeContainer the ime container that the policy must attach
-     * @param taskContainers the task container that the policy must attach
+     * @param taskDisplayArea the task container that the policy must attach
      *
      * @see #attachDisplayAreas()
      */
     protected DisplayAreaPolicy(WindowManagerService wmService,
             DisplayContent content, DisplayArea.Root root,
             DisplayArea<? extends WindowContainer> imeContainer,
-            DisplayArea<? extends ActivityStack> taskContainers) {
+            DisplayArea<? extends ActivityStack> taskDisplayArea) {
         mWmService = wmService;
         mContent = content;
         mRoot = root;
         mImeContainer = imeContainer;
-        mTaskContainers = taskContainers;
+        mTaskContainers = taskDisplayArea;
     }
 
     /**
@@ -86,9 +86,9 @@
         public DisplayAreaPolicy instantiate(WindowManagerService wmService,
                 DisplayContent content, DisplayArea.Root root,
                 DisplayArea<? extends WindowContainer> imeContainer,
-                TaskContainers taskContainers) {
+                TaskDisplayArea taskDisplayArea) {
             return new DisplayAreaPolicyBuilder()
-                    .build(wmService, content, root, imeContainer, taskContainers);
+                    .build(wmService, content, root, imeContainer, taskDisplayArea);
         }
     }
 
@@ -108,7 +108,7 @@
         DisplayAreaPolicy instantiate(WindowManagerService wmService,
                 DisplayContent content, DisplayArea.Root root,
                 DisplayArea<? extends WindowContainer> imeContainer,
-                TaskContainers taskContainers);
+                TaskDisplayArea taskDisplayArea);
 
         /**
          * Instantiate the device-specific {@link Provider}.
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 0c6e483..950df6f 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -201,8 +201,8 @@
 
         Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root,
                 DisplayArea<? extends WindowContainer> imeContainer,
-                DisplayArea<? extends ActivityStack> taskStacks, ArrayList<Feature> features) {
-            super(wmService, content, root, imeContainer, taskStacks);
+                DisplayArea<? extends ActivityStack> taskDisplayArea, ArrayList<Feature> features) {
+            super(wmService, content, root, imeContainer, taskDisplayArea);
             mFeatures = features;
             mAreas = new HashMap<>(features.size());
             for (int i = 0; i < mFeatures.size(); i++) {
@@ -320,9 +320,9 @@
     Result build(WindowManagerService wmService,
             DisplayContent content, DisplayArea.Root root,
             DisplayArea<? extends WindowContainer> imeContainer,
-            DisplayArea<? extends ActivityStack> taskContainers) {
+            DisplayArea<? extends ActivityStack> taskDisplayArea) {
 
-        return new Result(wmService, content, root, imeContainer, taskContainers, new ArrayList<>(
+        return new Result(wmService, content, root, imeContainer, taskDisplayArea, new ArrayList<>(
                 mFeatures));
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4a7edee..dd550a8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -110,7 +110,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -270,7 +269,7 @@
 
     /** The containers below are the only child containers {@link #mWindowContainers} can have. */
     // Contains all window containers that are related to apps (Activities)
-    final TaskContainers mTaskContainers = new TaskContainers(this, mWmService);
+    final TaskDisplayArea mTaskContainers = new TaskDisplayArea(this, mWmService);
 
     // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
     // on the IME target. We mainly have this container grouping so we can keep track of all the IME
@@ -608,25 +607,12 @@
      */
     private ActivityRecord mLastCompatModeActivity;
 
-    /**
-     * A focusable stack that is purposely to be positioned at the top. Although the stack may not
-     * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
-     * target stack properly when there are other focusable always-on-top stacks.
-     */
-    private ActivityStack mPreferredTopFocusableStack;
-
     // Used in updating the display size
     private Point mTmpDisplaySize = new Point();
 
     // Used in updating override configurations
     private final Configuration mTempConfig = new Configuration();
 
-    private final RootWindowContainer.FindTaskResult
-            mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
-
-    // When non-null, new tasks get put into this root task.
-    Task mLaunchRootTask = null;
-
     // Used in performing layout
     private boolean mTmpWindowsBehindIme;
 
@@ -2126,10 +2112,6 @@
         return mTaskContainers.getSplitScreenDividerAnchor();
     }
 
-    void onStackWindowingModeChanged(ActivityStack stack) {
-        mTaskContainers.onStackWindowingModeChanged(stack);
-    }
-
     /**
      * The value is only valid in the scope {@link #onRequestedOverrideConfigurationChanged} of the
      * changing hierarchy and the {@link #onConfigurationChanged} of its children.
@@ -2418,11 +2400,6 @@
         out.set(mDisplayFrames.mStable);
     }
 
-    void setStackOnDisplay(ActivityStack stack, int position) {
-        if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on displayId=" + mDisplayId);
-        mTaskContainers.addChild(stack, position);
-    }
-
     void moveStackToDisplay(ActivityStack stack, boolean onTop) {
         stack.reparent(mTaskContainers, onTop ? POSITION_TOP: POSITION_BOTTOM);
     }
@@ -2850,8 +2827,9 @@
         if (mLastFocus != mCurrentFocus) {
             pw.print("  mLastFocus="); pw.println(mLastFocus);
         }
-        if (mPreferredTopFocusableStack != null) {
-            pw.println(prefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+        if (mTaskContainers.mPreferredTopFocusableStack != null) {
+            pw.println(prefix + "mPreferredTopFocusableStack="
+                    + mTaskContainers.mPreferredTopFocusableStack);
         }
         if (mTaskContainers.mLastFocusedStack != null) {
             pw.println(prefix + "mLastFocusedStack=" + mTaskContainers.mLastFocusedStack);
@@ -5241,7 +5219,7 @@
         mRemoving = true;
         final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
         ActivityStack lastReparentedStack = null;
-        mPreferredTopFocusableStack = 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
@@ -5361,16 +5339,6 @@
         }
     }
 
-    /**
-     * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
-     *         already top-most.
-     */
-    ActivityStack getStackAbove(ActivityStack stack) {
-        final WindowContainer wc = stack.getParent();
-        final int index = wc.mChildren.indexOf(stack) + 1;
-        return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
-    }
-
     void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
             boolean preserveWindows, boolean notifyClients) {
         for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 12be9df..9b30103 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1399,8 +1399,9 @@
         }
 
         // Trim tasks that are in stacks that are behind the home stack
-        final DisplayContent display = stack.getDisplay();
-        return display.getIndexOf(stack) < display.getIndexOf(display.getRootHomeTask());
+        final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
+        return taskDisplayArea.getIndexOf(stack) < taskDisplayArea.getIndexOf(
+                taskDisplayArea.getRootHomeTask());
     }
 
     /** Remove the tasks that user may not be able to return. */
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 26b263e..08b0abf 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -30,6 +30,7 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
+import static com.android.server.wm.TaskDisplayArea.getStackAbove;
 
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
@@ -180,8 +181,8 @@
         ActivityRecord targetActivity = getTargetActivity(targetStack);
         final boolean hasExistingActivity = targetActivity != null;
         if (hasExistingActivity) {
-            final DisplayContent display = targetActivity.getDisplay();
-            mRestoreTargetBehindStack = display.getStackAbove(targetStack);
+            final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea();
+            mRestoreTargetBehindStack = getStackAbove(targetStack);
             if (mRestoreTargetBehindStack == null) {
                 notifyAnimationCancelBeforeStart(recentsAnimationRunner);
                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -210,7 +211,7 @@
                 // Move the recents activity into place for the animation if it is not top most
                 mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
-                        targetStack, mDefaultDisplay.getStackAbove(targetStack));
+                        targetStack, getStackAbove(targetStack));
 
                 // If there are multiple tasks in the target stack (ie. the home stack, with 3p
                 // and default launchers coexisting), then move the task to the top as a part of
@@ -229,7 +230,7 @@
                 targetActivity = getTargetActivity(targetStack);
                 mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
-                        targetStack, mDefaultDisplay.getStackAbove(targetStack));
+                        targetStack, getStackAbove(targetStack));
 
                 mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                 mWindowManager.executeAppTransition();
@@ -351,12 +352,11 @@
                         }
                     } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
                         // Restore the target stack to its previous position
-                        final DisplayContent display = targetActivity.getDisplay();
-                        display.mTaskContainers.moveStackBehindStack(targetStack,
+                        final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea();
+                        taskDisplayArea.moveStackBehindStack(targetStack,
                                 mRestoreTargetBehindStack);
                         if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
-                            final ActivityStack aboveTargetStack =
-                                    mDefaultDisplay.getStackAbove(targetStack);
+                            final ActivityStack aboveTargetStack = getStackAbove(targetStack);
                             if (mRestoreTargetBehindStack != null
                                     && aboveTargetStack != mRestoreTargetBehindStack) {
                                 ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 26eb36f..af783c5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2094,12 +2094,12 @@
             String reason) {
         mService.deferWindowLayout();
 
-        final DisplayContent display = r.getRootTask().getDisplay();
+        final TaskDisplayArea taskDisplayArea = r.getDisplayArea();
 
         try {
             final Task task = r.getTask();
 
-            final ActivityStack pinnedStack = display.getRootPinnedTask();
+            final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask();
             // This will change the pinned stack's windowing mode to its original mode, ensuring
             // we only have one stack that is in pinned mode.
             if (pinnedStack != null) {
@@ -2115,9 +2115,8 @@
             } else {
                 // In the case of multiple activities, we will create a new task for it and then
                 // move the PIP activity into the task.
-                stack = display.mTaskContainers.createStack(WINDOWING_MODE_PINNED,
-                        r.getActivityType(), ON_TOP, r.info, r.intent,
-                        false /* createdByOrganizer */);
+                stack = taskDisplayArea.createStack(WINDOWING_MODE_PINNED, r.getActivityType(),
+                        ON_TOP, r.info, r.intent, false /* createdByOrganizer */);
 
                 // There are multiple activities in the task and moving the top activity should
                 // reveal/leave the other activities in their original task.
@@ -2216,7 +2215,7 @@
         }
 
         boolean result = false;
-        if (targetStack != null && (targetStack.isTopStackOnDisplay()
+        if (targetStack != null && (targetStack.isTopStackInDisplayArea()
                 || getTopDisplayFocusedStack() == targetStack)) {
             result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
@@ -2342,16 +2341,16 @@
     }
 
     private ActivityManager.StackInfo getStackInfo(ActivityStack stack) {
-        final DisplayContent display = stack.getDisplayContent();
+        final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
         ActivityManager.StackInfo info = new ActivityManager.StackInfo();
         stack.getBounds(info.bounds);
-        info.displayId = display.mDisplayId;
+        info.displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId() : INVALID_DISPLAY;
         info.stackId = stack.mTaskId;
         info.stackToken = stack.mRemoteToken;
         info.userId = stack.mCurrentUser;
         info.visible = stack.shouldBeVisible(null);
         // A stack might be not attached to a display.
-        info.position = display != null ? display.getIndexOf(stack) : 0;
+        info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(stack) : 0;
         info.configuration.setTo(stack.getConfiguration());
 
         final int numTasks = stack.getDescendantTaskCount();
@@ -2507,16 +2506,16 @@
     }
 
     ActivityStack findStackBehind(ActivityStack stack) {
-        final DisplayContent display = stack.getDisplayContent();
-        if (display != null) {
-            for (int i = display.getStackCount() - 1; i >= 0; i--) {
-                if (display.getStackAt(i) == stack && i > 0) {
-                    return display.getStackAt(i - 1);
+        final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
+        if (taskDisplayArea != null) {
+            for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; i--) {
+                if (taskDisplayArea.getStackAt(i) == stack && i > 0) {
+                    return taskDisplayArea.getStackAt(i - 1);
                 }
             }
         }
         throw new IllegalStateException("Failed to find a stack behind stack=" + stack
-                + " in=" + display);
+                + " in=" + taskDisplayArea);
     }
 
     @Override
@@ -2799,7 +2798,7 @@
 
         // Give preference to the stack and display of the input task and activity if they match the
         // mode we want to launch into.
-        DisplayContent display = null;
+        TaskDisplayArea container = null;
         if (candidateTask != null) {
             stack = candidateTask.getStack();
         }
@@ -2809,11 +2808,11 @@
         int windowingMode = launchParams != null ? launchParams.mWindowingMode
                 : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
         if (stack != null) {
-            display = stack.getDisplay();
-            if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) {
+            container = stack.getDisplayArea();
+            if (container != null && canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
                 if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                    windowingMode = display.mTaskContainers.resolveWindowingMode(r, options,
-                            candidateTask, activityType);
+                    windowingMode = container.resolveWindowingMode(r, options, candidateTask,
+                            activityType);
                 }
                 // Always allow organized tasks that created by organizer since the activity type
                 // of an organized task is decided by the activity type of its top child, which
@@ -2822,7 +2821,7 @@
                     return stack;
                 }
                 if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
-                        && display.getRootSplitScreenPrimaryTask() == stack
+                        && container.getRootSplitScreenPrimaryTask() == stack
                         && candidateTask == stack.getTopMostTask()) {
                     // This is a special case when we try to launch an activity that is currently on
                     // top of split-screen primary stack, but is targeting split-screen secondary.
@@ -2834,16 +2833,16 @@
             }
         }
 
-        if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) {
-            display = getDefaultDisplay();
+        if (container == null
+                || !canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
+            container = getDefaultDisplay().mTaskContainers;
             if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                windowingMode = display.mTaskContainers.resolveWindowingMode(r, options,
-                        candidateTask, activityType);
+                windowingMode = container.resolveWindowingMode(r, options, candidateTask,
+                        activityType);
             }
         }
 
-        return display.mTaskContainers.getOrCreateStack(r, options, candidateTask, activityType,
-                onTop);
+        return container.getOrCreateStack(r, options, candidateTask, activityType, onTop);
     }
 
     /** @return true if activity record is null or can be launched on provided display. */
@@ -2986,18 +2985,18 @@
     ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus,
             boolean ignoreCurrent) {
         // First look for next focusable stack on the same display
-        DisplayContent preferredDisplay = currentFocus.getDisplay();
-        if (preferredDisplay == null) {
+        TaskDisplayArea preferredDisplayArea = currentFocus.getDisplayArea();
+        if (preferredDisplayArea == null) {
             // Stack is currently detached because it is being removed. Use the previous display it
             // was on.
-            preferredDisplay = getDisplayContent(currentFocus.mPrevDisplayId);
+            preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId).mTaskContainers;
         }
-        final ActivityStack preferredFocusableStack = preferredDisplay.mTaskContainers
-                .getNextFocusableStack(currentFocus, ignoreCurrent);
+        final ActivityStack preferredFocusableStack = preferredDisplayArea.getNextFocusableStack(
+                currentFocus, ignoreCurrent);
         if (preferredFocusableStack != null) {
             return preferredFocusableStack;
         }
-        if (preferredDisplay.supportsSystemDecorations()) {
+        if (preferredDisplayArea.mDisplayContent.supportsSystemDecorations()) {
             // Stop looking for focusable stack on other displays because the preferred display
             // supports system decorations. Home activity would be launched on the same display if
             // no focusable stack found.
@@ -3007,7 +3006,7 @@
         // Now look through all displays
         for (int i = getChildCount() - 1; i >= 0; --i) {
             final DisplayContent display = getChildAt(i);
-            if (display == preferredDisplay) {
+            if (display == preferredDisplayArea.mDisplayContent) {
                 // We've already checked this one
                 continue;
             }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 10be11a..9f5126e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -825,7 +825,7 @@
             // In some cases the focused stack isn't the front stack. E.g. pinned stack.
             // Whenever we are moving the top activity from the front stack we want to make sure to
             // move the stack to the front.
-            final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
+            final boolean wasFront = r != null && sourceStack.isTopStackInDisplayArea()
                     && (sourceStack.topRunningActivity() == r);
 
             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
@@ -1386,7 +1386,7 @@
         // A rootable task that is now being added to be the child of an organized task. Making
         // sure the stack references is keep updated.
         if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
-            mDisplayContent.mTaskContainers.addStackReferenceIfNeeded((ActivityStack) child);
+            getDisplayArea().addStackReferenceIfNeeded((ActivityStack) child);
         }
 
         // Make sure the list of display UID whitelists is updated
@@ -1432,7 +1432,7 @@
         // A rootable child task that is now being removed from an organized task. Making sure
         // the stack references is keep updated.
         if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
-            mDisplayContent.mTaskContainers.removeStackReferenceIfNeeded((ActivityStack) child);
+            getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) child);
         }
         removeChild(child, "removeChild");
     }
@@ -3068,8 +3068,14 @@
     }
 
     public boolean isAttached() {
-        final DisplayContent display = getDisplayContent();
-        return display != null && !display.isRemoved();
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        return taskDisplayArea != null && !taskDisplayArea.isRemoved();
+    }
+
+    @Override
+    @Nullable
+    TaskDisplayArea getDisplayArea() {
+        return (TaskDisplayArea) super.getDisplayArea();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskContainers.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
similarity index 97%
rename from services/core/java/com/android/server/wm/TaskContainers.java
rename to services/core/java/com/android/server/wm/TaskDisplayArea.java
index 540bc9b..a5ae721 100644
--- a/services/core/java/com/android/server/wm/TaskContainers.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -43,6 +43,7 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.RootWindowContainer.TAG_STATES;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.Nullable;
@@ -66,11 +67,10 @@
 import java.util.List;
 
 /**
- * Window container class that contains all containers on this display relating to Apps.
- * I.e Activities.
+ * {@link DisplayArea} that represents a section of a screen that contains app window containers.
  */
-final class TaskContainers extends DisplayArea<ActivityStack> {
-    private DisplayContent mDisplayContent;
+final class TaskDisplayArea extends DisplayArea<ActivityStack> {
+    DisplayContent mDisplayContent;
     /**
      * A control placed at the appropriate level for transitions to occur.
      */
@@ -109,14 +109,14 @@
     private RootWindowContainer mRootWindowContainer;
 
     // When non-null, new tasks get put into this root task.
-    private Task mLaunchRootTask = null;
+    Task mLaunchRootTask = null;
 
     /**
      * A focusable stack that is purposely to be positioned at the top. Although the stack may not
      * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
      * target stack properly when there are other focusable always-on-top stacks.
      */
-    private ActivityStack mPreferredTopFocusableStack;
+    ActivityStack mPreferredTopFocusableStack;
 
     private final RootWindowContainer.FindTaskResult
             mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
@@ -128,7 +128,7 @@
      */
     ActivityStack mLastFocusedStack;
 
-    TaskContainers(DisplayContent displayContent, WindowManagerService service) {
+    TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
         super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
         mDisplayContent = displayContent;
         mRootWindowContainer = service.mRoot;
@@ -350,7 +350,7 @@
         int minPosition = POSITION_BOTTOM;
 
         if (stack.isAlwaysOnTop()) {
-            if (mDisplayContent.hasPinnedTask()) {
+            if (hasPinnedTask()) {
                 // Always-on-top stacks go below the pinned stack.
                 maxPosition = mDisplayContent.getStacks().indexOf(mRootPinnedTask) - 1;
             }
@@ -623,7 +623,8 @@
     }
 
     void addStack(ActivityStack stack, int position) {
-        mDisplayContent.setStackOnDisplay(stack, position);
+        if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on taskDisplayArea=" + this);
+        addChild(stack, position);
         positionStackAt(stack, position);
     }
 
@@ -1334,6 +1335,10 @@
         return false;
     }
 
+    ActivityRecord topRunningActivity() {
+        return topRunningActivity(false /* considerKeyguardState */);
+    }
+
     /**
      * Returns the top running activity in the focused stack. In the case the focused stack has no
      * such activity, the next focusable stack on this display is returned.
@@ -1446,7 +1451,7 @@
         }
 
         final PooledPredicate p = PooledLambda.obtainPredicate(
-                TaskContainers::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+                TaskDisplayArea::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
                 userId);
         final ActivityRecord r = homeStack.getActivity(p);
         p.recycle();
@@ -1530,4 +1535,26 @@
             parent.positionChildAt(position, stack, false /* includingParents */);
         }
     }
+
+    boolean hasPinnedTask() {
+        return getRootPinnedTask() != null;
+    }
+
+    /**
+     * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
+     *         already top-most.
+     */
+    static ActivityStack getStackAbove(ActivityStack stack) {
+        final WindowContainer wc = stack.getParent();
+        final int index = wc.mChildren.indexOf(stack) + 1;
+        return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
+    }
+
+    int getDisplayId() {
+        return mDisplayContent.getDisplayId();
+    }
+
+    boolean isRemoved() {
+        return mDisplayContent.isRemoved();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8e95ca7..189fe31 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -392,25 +392,26 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
-                if (display == null) {
+                TaskDisplayArea taskDisplayArea =
+                        mService.mRootWindowContainer.getDisplayContent(displayId).mTaskContainers;
+                if (taskDisplayArea == null) {
                     return;
                 }
                 Task task = token == null
                         ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
                 if (task == null) {
-                    display.mLaunchRootTask = null;
+                    taskDisplayArea.mLaunchRootTask = null;
                     return;
                 }
                 if (!task.mCreatedByOrganizer) {
                     throw new IllegalArgumentException("Attempt to set task not created by "
                             + "organizer as launch root task=" + task);
                 }
-                if (task.getDisplayContent() != display) {
+                if (task.getDisplayArea() != taskDisplayArea) {
                     throw new RuntimeException("Can't set launch root for display " + displayId
                             + " to task on display " + task.getDisplayContent().getDisplayId());
                 }
-                display.mLaunchRootTask = task;
+                taskDisplayArea.mLaunchRootTask = task;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ae0b685..98585a9 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -68,7 +68,6 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
-import android.window.IWindowContainer;
 import android.view.MagnificationSpec;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
@@ -77,6 +76,7 @@
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 import android.view.animation.Animation;
+import android.window.IWindowContainer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
@@ -728,6 +728,13 @@
         return mDisplayContent;
     }
 
+    /** Get the first node of type {@link DisplayArea} above or at this node. */
+    @Nullable
+    DisplayArea getDisplayArea() {
+        WindowContainer parent = getParent();
+        return parent != null ? parent.getDisplayArea() : null;
+    }
+
     void setWaitingForDrawnIfResizingChanged() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 6ef5ed6..14c9429 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -249,10 +249,10 @@
                     final ActivityStack rootTask =
                             (ActivityStack) (newParent != null ? newParent : task.getRootTask());
                     if (hop.getToTop()) {
-                        as.getDisplay().mTaskContainers.positionStackAtTop(rootTask,
+                        as.getDisplayArea().positionStackAtTop(rootTask,
                                 false /* includingParents */);
                     } else {
-                        as.getDisplay().mTaskContainers.positionStackAtBottom(rootTask);
+                        as.getDisplayArea().positionStackAtBottom(rootTask);
                     }
                 }
             } else {
@@ -262,9 +262,9 @@
             // Ugh, of course ActivityStack has its own special reorder logic...
             if (task.isRootTask()) {
                 if (hop.getToTop()) {
-                    dc.mTaskContainers.positionStackAtTop(as, false /* includingParents */);
+                    as.getDisplayArea().positionStackAtTop(as, false /* includingParents */);
                 } else {
-                    dc.mTaskContainers.positionStackAtBottom(as);
+                    as.getDisplayArea().positionStackAtBottom(as);
                 }
             } else {
                 task.getParent().positionChildAt(