Simplified ActivityStack.shouldBeVisible()

The method can now be simplified since we have a stack per task so
if a stack should be visible is now a question of if it is occluded
by another stack.

Also,
- Fixed an issue where the windowing mode of the primary split-screen
stack was changing to split-screen-secondary instead of fullscreen
when we are exiting split-screen mode because we are not allowed to
to create fullscreen stack when there is a primary split-screen stack. We
now clear the reference to the primary split-screen stack when exiting
split-screen mode.
- Re-worked windowing mode resolution to be inside ActivityDisplay
object since the determination of the windowing mode is dependant on the
display.

Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests
Test: Existing tests pass.
Test: go/wm-smoke
Bug: 64146578
Fixes: 67914671
Change-Id: I7e8cfe49fbf6a5836ded022bb11adcde58ae689c
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c15b5e2..7a4a0d4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -110,7 +110,6 @@
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.WaitResult;
-import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -223,13 +222,6 @@
     // at the top of its container (e.g. stack).
     static final boolean ON_TOP = true;
 
-    // Used to indicate that an objects (e.g. task) removal from its container
-    // (e.g. stack) is due to it moving to another container.
-    static final boolean MOVING = true;
-
-    // Force the focus to change to the stack we are moving a task to..
-    static final boolean FORCE_FOCUS = true;
-
     // Don't execute any calls to resume.
     static final boolean DEFER_RESUME = true;
 
@@ -405,6 +397,7 @@
      * object each time.
      */
     private final Rect tempRect = new Rect();
+    private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
 
     // The default minimal size that will be used if the activity doesn't specify its minimal size.
     // It will be calculated when the default display gets added.
@@ -2186,89 +2179,6 @@
         return null;
     }
 
-    /**
-     * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
-     * @param windowingMode The windowing mode we are checking support for.
-     * @param supportsMultiWindow If we should consider support for multi-window mode in general.
-     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
-     * @param supportsFreeform If we should consider support for freeform multi-window.
-     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
-     * @param activityType The activity type under consideration.
-     * @return true if the windowing mode is supported.
-     */
-    boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
-            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
-            int activityType) {
-
-        if (windowingMode == WINDOWING_MODE_UNDEFINED
-                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            return true;
-        }
-        if (!supportsMultiWindow) {
-            return false;
-        }
-
-        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-            return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
-                    windowingMode, activityType);
-        }
-
-        if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
-            return false;
-        }
-
-        if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
-            return false;
-        }
-        return true;
-    }
-
-    private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable TaskRecord task, int activityType) {
-
-        // First preference if the windowing mode in the activity options if set.
-        int windowingMode = (options != null)
-                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
-        // If windowing mode is unset, then next preference is the candidate task, then the
-        // activity record.
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            if (task != null) {
-                windowingMode = task.getWindowingMode();
-            }
-            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
-                windowingMode = r.getWindowingMode();
-            }
-        }
-
-        // Make sure the windowing mode we are trying to use makes sense for what is supported.
-        boolean supportsMultiWindow = mService.mSupportsMultiWindow;
-        boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
-        boolean supportsFreeform = mService.mSupportsFreeformWindowManagement;
-        boolean supportsPip = mService.mSupportsPictureInPicture;
-        if (supportsMultiWindow) {
-            if (task != null) {
-                supportsMultiWindow = task.isResizeable();
-                supportsSplitScreen = task.supportsSplitScreenWindowingMode();
-                // TODO: Do we need to check for freeform and Pip support here?
-            } else if (r != null) {
-                supportsMultiWindow = r.isResizeable();
-                supportsSplitScreen = r.supportsSplitScreenWindowingMode();
-                supportsFreeform = r.supportsFreeform();
-                supportsPip = r.supportsPictureInPicture();
-            }
-        }
-
-        if (windowingMode != WINDOWING_MODE_UNDEFINED
-                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
-                supportsFreeform, supportsPip, activityType)) {
-            return windowingMode;
-        }
-        // Return root/systems windowing mode
-        return getWindowingMode();
-    }
-
     int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
             @Nullable TaskRecord task) {
         // Preference is given to the activity type for the activity then the task since the type
@@ -2329,7 +2239,6 @@
         }
 
         final int activityType = resolveActivityType(r, options, candidateTask);
-        int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
         T stack = null;
 
         // Next preference for stack goes to the display Id set in the activity options or the
@@ -2347,7 +2256,7 @@
             }
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
             if (display != null) {
-                stack = display.getOrCreateStack(windowingMode, activityType, onTop);
+                stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
                 if (stack != null) {
                     return stack;
                 }
@@ -2365,10 +2274,14 @@
             stack = r.getStack();
         }
         if (stack != null) {
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return stack;
-            }
             display = stack.getDisplay();
+            if (display != null) {
+                final int windowingMode =
+                        display.resolveWindowingMode(r, options, candidateTask, activityType);
+                if (stack.isCompatible(windowingMode, activityType)) {
+                    return stack;
+                }
+            }
         }
 
         if (display == null
@@ -2379,7 +2292,7 @@
             display = getDefaultDisplay();
         }
 
-        return display.getOrCreateStack(windowingMode, activityType, onTop);
+        return display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
     }
 
     /**
@@ -2596,6 +2509,8 @@
             final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId);
 
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                // Tell the display we are exiting split-screen mode.
+                toDisplay.onExitingSplitScreenMode();
                 // 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.
@@ -2625,35 +2540,34 @@
             final ArrayList<TaskRecord> tasks = fromStack.getAllTasks();
 
             if (!tasks.isEmpty()) {
+                mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
                 final int size = tasks.size();
-                final ActivityStack fullscreenStack = toDisplay.getOrCreateStack(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop);
+                for (int i = 0; i < size; ++i) {
+                    final TaskRecord task = tasks.get(i);
+                    final ActivityStack toStack = toDisplay.getOrCreateStack(
+                                null, mTmpOptions, task, task.getActivityType(), onTop);
 
-                if (onTop) {
-                    final int returnToType =
-                            toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
-                    for (int i = 0; i < size; i++) {
-                        final TaskRecord task = tasks.get(i);
+                    if (onTop) {
+                        final int returnToType =
+                                toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
                         final boolean isTopTask = i == (size - 1);
                         if (inPinnedWindowingMode) {
-                            // Update the return-to to reflect where the pinned stack task was moved
-                            // from so that we retain the stack that was previously visible if the
-                            // pinned stack is recreated. See moveActivityToPinnedStackLocked().
+                            // Update the return-to to reflect where the pinned stack task was
+                            // moved from so that we retain the stack that was previously
+                            // visible if the pinned stack is recreated.
+                            // See moveActivityToPinnedStackLocked().
                             task.setTaskToReturnTo(returnToType);
                         }
                         // Defer resume until all the tasks have been moved to the fullscreen stack
-                        task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
+                        task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
                                 isTopTask /* animate */, DEFER_RESUME,
                                 schedulePictureInPictureModeChange,
                                 "moveTasksToFullscreenStack - onTop");
-                    }
-                } else {
-                    for (int i = 0; i < size; i++) {
-                        final TaskRecord task = tasks.get(i);
+                    } else {
                         // Position the tasks in the fullscreen stack in order at the bottom of the
                         // stack. Also defer resume until all the tasks have been moved to the
                         // fullscreen stack.
-                        task.reparent(fullscreenStack, i /* position */,
+                        task.reparent(toStack, ON_TOP,
                                 REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME,
                                 schedulePictureInPictureModeChange,
                                 "moveTasksToFullscreenStack - NOT_onTop");
@@ -3080,23 +2994,16 @@
                     + " task=" + task);
         }
 
-        // We don't allow moving a unresizeable task to the docked stack since the docked stack is
-        // used for split-screen mode and will cause things like the docked divider to show up. We
-        // instead leave the task in its current stack or move it to the fullscreen stack if it
-        // isn't currently in a stack.
+        // Leave the task in its current stack or a fullscreen stack if it isn't resizeable and the
+        // preferred stack is in multi-window mode.
         if (inMultiWindowMode && !task.isResizeable()) {
-            Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack."
-                    + " Moving to stackId=" + stackId + " instead.");
-            // Temporarily disable resizeablility of the task as we don't want it to be resized if,
-            // for example, a docked stack is created which will lead to the stack we are moving
-            // from being resized and and its resizeable tasks being resized.
-            try {
-                task.mTemporarilyUnresizable = true;
-                stack = stack.getDisplay().createStack(
-                        WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
-            } finally {
-                task.mTemporarilyUnresizable = false;
+            Slog.w(TAG, "Can not move unresizeable task=" + task + " to multi-window stack=" + stack
+                    + " Moving to a fullscreen stack instead.");
+            if (prevStack != null) {
+                return prevStack;
             }
+            stack = stack.getDisplay().createStack(
+                    WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
         }
         return stack;
     }
@@ -4287,9 +4194,9 @@
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
         final boolean inSplitScreenMode = actualStack != null
-                && actualStack.inSplitScreenWindowingMode();
+                && actualStack.getDisplay().hasSplitScreenPrimaryStack();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
-                && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
+                && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
             return;
         }