Introducing split-screen windowing modes.

WINDOWING_MODE_SPLIT_SCREEN_PRIMARY is what used to be the docked
windowing mode and is used to indicated the primary container
dirving the split-screen windowing mode.
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY is the windowing mode of any
container to the side/adjacent to the primary split-screen container.
For example, any container that was in fullscreen mode and that should
now be adjacent to the primary split-screen container will.

Test: go/wm-smoke
Test: WM Unit tests via TreeHugger
Change-Id: Idc8560073c613c708cb40ba8449641a6be11d9f1
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index aae98a6..0c8321d 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -6,10 +6,12 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_DOCKED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
@@ -111,31 +113,34 @@
         }
         mLastLogTimeSecs = now;
 
-        ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
-        if (stack != null && stack.shouldBeVisible(null) != STACK_INVISIBLE) {
-            mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
+        mWindowState = WINDOW_STATE_INVALID;
+        ActivityStack stack = mSupervisor.getFocusedStack();
+        if (stack.isActivityTypeAssistant()) {
+            mWindowState = WINDOW_STATE_ASSISTANT;
             return;
         }
-        mWindowState = WINDOW_STATE_INVALID;
-        stack = mSupervisor.getFocusedStack();
+
         int windowingMode = stack.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_PINNED) {
             stack = mSupervisor.findStackBehind(stack);
             windowingMode = stack.getWindowingMode();
         }
-        if (StackId.isHomeOrRecentsStack(stack.mStackId)
-                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            mWindowState = WINDOW_STATE_STANDARD;
-        } else if (windowingMode == WINDOWING_MODE_DOCKED) {
-            Slog.wtf(TAG, "Docked stack shouldn't be the focused stack, because it reported not"
-                    + " being visible.");
-            mWindowState = WINDOW_STATE_INVALID;
-        } else if (windowingMode == WINDOWING_MODE_FREEFORM) {
-            mWindowState = WINDOW_STATE_FREEFORM;
-        } else if (stack.mStackId == ASSISTANT_STACK_ID) {
-            mWindowState = WINDOW_STATE_ASSISTANT;
-        } else if (StackId.isStaticStack(stack.mStackId)) {
-            throw new IllegalStateException("Unknown stack=" + stack);
+        switch (windowingMode) {
+            case WINDOWING_MODE_FULLSCREEN:
+                mWindowState = WINDOW_STATE_STANDARD;
+                break;
+            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+            case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
+                mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
+                break;
+            case WINDOW_STATE_FREEFORM:
+                mWindowState = WINDOW_STATE_FREEFORM;
+                break;
+            default:
+                if (windowingMode != WINDOWING_MODE_UNDEFINED) {
+                    throw new IllegalStateException("Unknown windowing mode for stack=" + stack
+                            + " windowingMode=" + windowingMode);
+                }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 84bf18a0..7ade512 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -482,7 +482,8 @@
     // TODO: Not needed once we are no longer using stack ids as the override config. can be passed
     // in.
     private void updateOverrideConfiguration() {
-        final int windowingMode = getWindowingModeForStackId(mStackId);
+        final int windowingMode = getWindowingModeForStackId(
+                mStackId, mStackSupervisor.getStack(DOCKED_STACK_ID) != null);
         if (windowingMode != WINDOWING_MODE_UNDEFINED) {
             setWindowingMode(windowingMode);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e4a2273..fe28956 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -36,6 +36,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
@@ -2279,15 +2281,6 @@
         return null;
     }
 
-    /**
-     * Returns if a stack should be treated as if it's docked. Returns true if the stack is
-     * the docked stack itself, or if it's side-by-side to the docked stack.
-     */
-    boolean isStackDockedInEffect(int stackId) {
-        return stackId == DOCKED_STACK_ID ||
-                (StackId.isResizeableByDockedStack(stackId) && getStack(DOCKED_STACK_ID) != null);
-    }
-
     void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
             boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) {
         if (stackId == DOCKED_STACK_ID) {
@@ -2301,9 +2294,9 @@
             return;
         }
 
+        final boolean splitScreenActive = getStack(DOCKED_STACK_ID) != null;
         if (!allowResizeInDockedMode
-                && !stack.getWindowConfiguration().tasksAreFloating()
-                && getStack(DOCKED_STACK_ID) != null) {
+                && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) {
             // If the docked stack exists, don't resize non-floating stacks independently of the
             // size computed from the docked stack size (otherwise they will be out of sync)
             return;
@@ -2312,6 +2305,16 @@
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
         mWindowManager.deferSurfaceLayout();
         try {
+            if (stack.supportSplitScreenWindowingMode()) {
+                if (bounds == null && stack.inSplitScreenWindowingMode()) {
+                    // null bounds = fullscreen windowing mode...at least for now.
+                    stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+                } else if (splitScreenActive) {
+                    // If we are in split-screen mode and this stack support split-screen, then
+                    // it should be split-screen secondary mode. i.e. adjacent to the docked stack.
+                    stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                }
+            }
             stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds);
             if (!deferResume) {
                 stack.ensureVisibleActivitiesConfigurationLocked(
@@ -2323,14 +2326,14 @@
         }
     }
 
-    void deferUpdateBounds(int stackId) {
+    private void deferUpdateBounds(int stackId) {
         final ActivityStack stack = getStack(stackId);
         if (stack != null) {
             stack.deferUpdateBounds();
         }
     }
 
-    void continueUpdateBounds(int stackId) {
+    private void continueUpdateBounds(int stackId) {
         final ActivityStack stack = getStack(stackId);
         if (stack != null) {
             stack.continueUpdateBounds();
@@ -2365,13 +2368,15 @@
                 // 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 = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    if (StackId.isResizeableByDockedStack(i)) {
-                        ActivityStack otherStack = getStack(i);
-                        if (otherStack != null) {
-                            resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS,
-                                    true /* allowResizeInDockedMode */, DEFER_RESUME);
-                        }
+                    final ActivityStack otherStack = getStack(i);
+                    if (otherStack == null) {
+                        continue;
                     }
+                    if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
+                        continue;
+                    }
+                    resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS,
+                            true /* allowResizeInDockedMode */, DEFER_RESUME);
                 }
 
                 // Also disable docked stack resizing since we have manually adjusted the
@@ -2485,18 +2490,24 @@
                 // screen controls and is also the same for all stacks.
                 final Rect otherTaskRect = new Rect();
                 for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    final ActivityStack current = getStack(i);
-                    if (current != null && StackId.isResizeableByDockedStack(i)) {
-                        current.getStackDockedModeBounds(
-                                tempOtherTaskBounds /* currentTempTaskBounds */,
-                                tempRect /* outStackBounds */,
-                                otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */);
-
-                        resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null,
-                                !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
-                                tempOtherTaskInsetBounds, preserveWindows,
-                                true /* allowResizeInDockedMode */, deferResume);
+                    if (i == DOCKED_STACK_ID) {
+                        continue;
                     }
+                    final ActivityStack current = getStack(i);
+                    if (current == null || !current.supportSplitScreenWindowingMode()) {
+                        continue;
+                    }
+                    // Need to set windowing mode here before we try to get the dock bounds.
+                    current.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                    current.getStackDockedModeBounds(
+                            tempOtherTaskBounds /* currentTempTaskBounds */,
+                            tempRect /* outStackBounds */,
+                            otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */);
+
+                    resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null,
+                            !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
+                            tempOtherTaskInsetBounds, preserveWindows,
+                            true /* allowResizeInDockedMode */, deferResume);
                 }
             }
             if (!deferResume) {
@@ -4023,7 +4034,10 @@
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
                 || StackId.isDynamicStack(preferredStackId);
-        if (((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
+        final ActivityStack actualStack = getStack(actualStackId);
+        final boolean inSplitScreenMode = actualStack != null
+                && actualStack.inSplitScreenWindowingMode();
+        if (((!inSplitScreenMode && preferredStackId != DOCKED_STACK_ID)
                 && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
             return;
         }
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index cbf4fc0..7051a73 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -21,6 +21,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.activityTypeToString;
 
 import android.app.WindowConfiguration;
@@ -145,6 +147,33 @@
         onOverrideConfigurationChanged(mTmpConfig);
     }
 
+    /** Returns true if this container is currently in split-screen windowing mode. */
+    public boolean inSplitScreenWindowingMode() {
+        @WindowConfiguration.WindowingMode int windowingMode =
+                mFullConfiguration.windowConfiguration.getWindowingMode();
+
+        return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+    }
+
+    /** Returns true if this container is currently in split-screen secondary windowing mode. */
+    public boolean inSplitScreenSecondaryWindowingMode() {
+        @WindowConfiguration.WindowingMode int windowingMode =
+                mFullConfiguration.windowConfiguration.getWindowingMode();
+
+        return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+    }
+
+    /**
+     * Returns true if this container can be put in either
+     * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
+     * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
+     * its current state.
+     */
+    public boolean supportSplitScreenWindowingMode() {
+        return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
+    }
+
     /** Returns the activity type associated with the the configuration container. */
     /*@WindowConfiguration.ActivityType*/
     public int getActivityType() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e9f8457..55b6c91 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -421,9 +421,9 @@
 
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
-        final DisplayContent displayContent = mStack.getDisplayContent();
+        final DisplayContent displayContent = getDisplayContent();
         return mFillsParent
-                || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
+                || !inSplitScreenSecondaryWindowingMode()
                 || displayContent == null
                 || displayContent.getDockedStackIgnoringVisibility() != null;
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6ec7565..4664dcb 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -289,7 +289,7 @@
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
         if (mFillsParent
-                || !StackId.isResizeableByDockedStack(mStackId)
+                || !inSplitScreenSecondaryWindowingMode()
                 || mDisplayContent == null
                 || mDisplayContent.getDockedStackLocked() != null) {
             return true;
@@ -684,7 +684,7 @@
         Rect bounds = null;
         final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
         if (mStackId == DOCKED_STACK_ID
-                || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
+                || (dockedStack != null && inSplitScreenSecondaryWindowingMode()
                         && !dockedStack.fillsParent())) {
             // The existence of a docked stack affects the size of other static stack created since
             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
@@ -756,8 +756,7 @@
             return;
         }
 
-        if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
-                || mDisplayContent == null) {
+        if (!inSplitScreenWindowingMode() || mDisplayContent == null) {
             outStackBounds.set(mBounds);
             return;
         }
@@ -1324,8 +1323,8 @@
         return getDockSide(mBounds);
     }
 
-    int getDockSide(Rect bounds) {
-        if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
+    private int getDockSide(Rect bounds) {
+        if (!inSplitScreenWindowingMode()) {
             return DOCKED_INVALID;
         }
         if (mDisplayContent == null) {
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 5d1083e..857b13d 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -101,7 +101,7 @@
             mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
                     w.mWinAnimator.mAnimLayer);
         }
-        if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
+        if (w.getAppToken() != null && w.inSplitScreenSecondaryWindowingMode()) {
             mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
                     w.mWinAnimator.mAnimLayer);
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 5f1c011..29bbe6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -54,7 +54,7 @@
         super.setUp();
         final Configuration overrideConfig = new Configuration();
         overrideConfig.windowConfiguration.setWindowingMode(
-                getWindowingModeForStackId(PINNED_STACK_ID));
+                getWindowingModeForStackId(PINNED_STACK_ID, false /* inSplitScreenMode */));
         mPinnedStack = new StackWindowController(PINNED_STACK_ID, null,
                 mDisplayContent.getDisplayId(), true /* onTop */, new Rect(), sWm).mContainer;
         mPinnedStack.onOverrideConfigurationChanged(overrideConfig);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 817f2b4..3df13ab 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -240,7 +240,7 @@
     StackWindowController createStackControllerOnStackOnDisplay(int stackId, DisplayContent dc) {
         final Configuration overrideConfig = new Configuration();
         overrideConfig.windowConfiguration.setWindowingMode(
-                getWindowingModeForStackId(stackId));
+                getWindowingModeForStackId(stackId, false /* inSplitScreenMode */));
         final StackWindowController controller = new StackWindowController(stackId, null,
                 dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
         controller.onOverrideConfigurationChanged(overrideConfig);