4/n Add fallback to default task display area

... for the cases when a particular task display area target is not
specified, and/or the logic applies only to the default/fallback
task area on the display.

Bug: 152116619
Test: WM CTS and unit tests
Change-Id: I209629baada05b0615ea2874f39a2b30a95b7565
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 77ef011..13e4d8b 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -127,6 +127,12 @@
      * the new stack becomes resumed after which it will be set to current focused stack.
      */
     ActivityStack mLastFocusedStack;
+    /**
+     * All of the stacks on this display. Order matters, topmost stack is in front of all other
+     * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
+     * changing the list should also call {@link #onStackOrderChanged()}.
+     */
+    private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
 
     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
         super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
@@ -336,9 +342,9 @@
             // Since a stack could be repositioned while being one of the child, return
             // current index if that's the same stack we are positioning and it is always on
             // top.
-            final boolean sameStack = mDisplayContent.getStacks().get(i) == stack;
+            final boolean sameStack = mChildren.get(i) == stack;
             if ((sameStack && stack.isAlwaysOnTop())
-                    || (!sameStack && !mDisplayContent.getStacks().get(i).isAlwaysOnTop())) {
+                    || (!sameStack && !mChildren.get(i).isAlwaysOnTop())) {
                 belowAlwaysOnTopPosition = i;
                 break;
             }
@@ -352,7 +358,7 @@
         if (stack.isAlwaysOnTop()) {
             if (hasPinnedTask()) {
                 // Always-on-top stacks go below the pinned stack.
-                maxPosition = mDisplayContent.getStacks().indexOf(mRootPinnedTask) - 1;
+                maxPosition = mChildren.indexOf(mRootPinnedTask) - 1;
             }
             // Always-on-top stacks need to be above all other stacks.
             minPosition = belowAlwaysOnTopPosition
@@ -375,7 +381,7 @@
         targetPosition = Math.min(targetPosition, maxPosition);
         targetPosition = Math.max(targetPosition, minPosition);
 
-        int prevPosition = mDisplayContent.getStacks().indexOf(stack);
+        int prevPosition = mChildren.indexOf(stack);
         // The positions we calculated above (maxPosition, minPosition) do not take into
         // consideration the following edge cases.
         // 1) We need to adjust the position depending on the value "adding".
@@ -471,7 +477,7 @@
 
     @Override
     int getOrientation(int candidate) {
-        if (mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+        if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
             // Apps and their containers are not allowed to specify an orientation while using
             // root tasks...except for the home stack if it is not resizable and currently
             // visible (top of) its root task.
@@ -637,7 +643,7 @@
             mPreferredTopFocusableStack = null;
         }
         mDisplayContent.releaseSelfIfNeeded();
-        mDisplayContent.onStackOrderChanged(stack);
+        onStackOrderChanged(stack);
     }
 
     void positionStackAt(int position, ActivityStack child, boolean includingParents) {
@@ -716,7 +722,7 @@
             }
         }
 
-        mDisplayContent.onStackOrderChanged(stack);
+        onStackOrderChanged(stack);
     }
 
     ActivityStack getStack(int rootTaskId) {
@@ -765,11 +771,11 @@
                 } else if (stack.getParent() != launchRootTask) {
                     stack.reparent(launchRootTask, position);
                 }
-            } else if (stack.getDisplay() != mDisplayContent || !stack.isRootTask()) {
+            } else if (stack.getDisplayArea() != this || !stack.isRootTask()) {
                 if (stack.getParent() == null) {
                     addStack(stack, position);
                 } else {
-                    stack.reparent(mDisplayContent, onTop);
+                    stack.reparent(this, onTop);
                 }
             }
             // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
@@ -832,7 +838,7 @@
             // Create stack on default display instead since this display can only contain 1 stack.
             // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
             // this goes away once ActivityView is no longer using virtual displays.
-            return mRootWindowContainer.getDefaultDisplay().mTaskContainers.createStack(
+            return mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
                     windowingMode, activityType, onTop, info, intent, createdByOrganizer);
         }
 
@@ -1551,6 +1557,16 @@
         return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
     }
 
+    /** Returns true if the stack in the windowing mode is visible. */
+    boolean isStackVisible(int windowingMode) {
+        final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
+        return stack != null && stack.isVisible();
+    }
+
+    void removeStack(ActivityStack stack) {
+        removeChild(stack);
+    }
+
     int getDisplayId() {
         return mDisplayContent.getDisplayId();
     }
@@ -1558,4 +1574,39 @@
     boolean isRemoved() {
         return mDisplayContent.isRemoved();
     }
+
+    /**
+     * Adds a listener to be notified whenever the stack order in the display changes. Currently
+     * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
+     * current animation when the system state changes.
+     */
+    void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
+        if (!mStackOrderChangedCallbacks.contains(listener)) {
+            mStackOrderChangedCallbacks.add(listener);
+        }
+    }
+
+    /**
+     * Removes a previously registered stack order change listener.
+     */
+    void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
+        mStackOrderChangedCallbacks.remove(listener);
+    }
+
+    /**
+     * Notifies of a stack order change
+     * @param stack The stack which triggered the order change
+     */
+    void onStackOrderChanged(ActivityStack stack) {
+        for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
+            mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
+        }
+    }
+
+    /**
+     * Callback for when the order of the stacks in the display changes.
+     */
+    interface OnStackOrderChangedListener {
+        void onStackOrderChanged(ActivityStack stack);
+    }
 }