summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java46
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java73
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java59
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java3
7 files changed, 160 insertions, 34 deletions
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index aa5a2e091130..af2220933dae 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -291,7 +291,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
<T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
boolean onTop) {
- final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
+ // First preference is the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ // Validate that our desired windowingMode will work under the current conditions.
+ // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
+ // it's display's windowing mode.
+ windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
return getOrCreateStack(windowingMode, activityType, onTop);
}
@@ -303,7 +309,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
* Creates a stack matching the input windowing mode and activity type on this display.
* @param windowingMode The windowing mode the stack should be created in. If
* {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
- * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
+ * inherit it's parent's windowing mode.
* @param activityType The activityType the stack should be created in. If
* {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
* be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
@@ -549,7 +555,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
- otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN, false /* animate */,
+ otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
false /* showRecents */, false /* enteringSplitScreenMode */,
true /* deferEnsuringVisibility */);
}
@@ -610,10 +616,14 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
return false;
}
+ final int displayWindowingMode = getWindowingMode();
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
return supportsSplitScreen
- && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
+ && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
+ // Freeform windows and split-screen windows don't mix well, so prevent
+ // split windowing modes on freeform displays.
+ && displayWindowingMode != WINDOWING_MODE_FREEFORM;
}
if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
@@ -626,6 +636,16 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
return true;
}
+ /**
+ * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
+ * display with the provided parameters.
+ *
+ * @param r The ActivityRecord in question.
+ * @param options Options to start with.
+ * @param task The task within-which the activity would start.
+ * @param activityType The type of activity to start.
+ * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
+ */
int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable TaskRecord task, int activityType) {
@@ -647,7 +667,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
windowingMode = getWindowingMode();
}
}
- return validateWindowingMode(windowingMode, r, task, activityType);
+ windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
+ return windowingMode != WINDOWING_MODE_UNDEFINED
+ ? windowingMode : WINDOWING_MODE_FULLSCREEN;
}
/**
@@ -684,23 +706,21 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
if (!inSplitScreenMode
&& windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
- // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
+ // Switch to the display's windowing mode if we are not in split-screen mode and we are
// trying to launch in split-screen secondary.
- windowingMode = WINDOWING_MODE_FULLSCREEN;
- } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_UNDEFINED)
&& supportsSplitScreen) {
windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
if (windowingMode != WINDOWING_MODE_UNDEFINED
&& isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
- supportsFreeform, supportsPip, activityType)) {
+ supportsFreeform, supportsPip, activityType)) {
return windowingMode;
}
- // Try to use the display's windowing mode otherwise fallback to fullscreen.
- windowingMode = getWindowingMode();
- return windowingMode != WINDOWING_MODE_UNDEFINED
- ? windowingMode : WINDOWING_MODE_FULLSCREEN;
+ return WINDOWING_MODE_UNDEFINED;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 355d890f1bd1..1209bde535e9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -347,6 +347,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
/** The attached Display's unique identifier, or -1 if detached */
int mDisplayId;
+ /** Stores the override windowing-mode from before a transient mode change (eg. split) */
+ private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
+
private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
private final Rect mTmpRect2 = new Rect();
@@ -531,16 +534,48 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */);
}
+ /**
+ * A transient windowing mode is one which activities enter into temporarily. Examples of this
+ * are Split window modes and pip. Non-transient modes are modes that displays can adopt.
+ *
+ * @param windowingMode the windowingMode to test for transient-ness.
+ * @return {@code true} if the windowing mode is transient, {@code false} otherwise.
+ */
+ private static boolean isTransientWindowingMode(int windowingMode) {
+ // TODO(b/114842032): add PIP if/when it uses mode transitions instead of task reparenting
+ return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ }
+
+ /**
+ * Specialization of {@link #setWindowingMode(int)} for this subclass.
+ *
+ * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending
+ * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the
+ * previous non-transient mode if this stack is currently in a transient mode.
+ * @param animate Can be used to prevent animation.
+ * @param showRecents Controls whether recents is shown on the other side of a split while
+ * entering split mode.
+ * @param enteringSplitScreenMode {@code true} if entering split mode.
+ * @param deferEnsuringVisibility Whether visibility updates are deferred. This is set when
+ * many operations (which can effect visibility) are being performed in bulk.
+ */
void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
boolean enteringSplitScreenMode, boolean deferEnsuringVisibility) {
final boolean creating = mWindowContainerController == null;
final int currentMode = getWindowingMode();
+ final int currentOverrideMode = getOverrideWindowingMode();
final ActivityDisplay display = getDisplay();
final TaskRecord topTask = topTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
- mTmpOptions.setLaunchWindowingMode(preferredWindowingMode);
-
int windowingMode = preferredWindowingMode;
+ if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
+ && isTransientWindowingMode(currentMode)) {
+ // Leaving a transient mode. Interpret UNDEFINED as "restore"
+ windowingMode = mRestoreOverrideWindowingMode;
+ }
+ mTmpOptions.setLaunchWindowingMode(windowingMode);
+
// 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) {
@@ -550,8 +585,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (splitScreenStack == this
&& windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
// Resolution to split-screen secondary for the primary split-screen stack means
- // we want to go fullscreen.
- windowingMode = WINDOWING_MODE_FULLSCREEN;
+ // we want to leave split-screen mode.
+ windowingMode = mRestoreOverrideWindowingMode;
}
final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
@@ -570,21 +605,33 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// doesn't support split-screen mode, go ahead an dismiss split-screen and display a
// warning toast about it.
mService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack();
- display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN,
+ display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_UNDEFINED,
false /* animate */, false /* showRecents */,
false /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */);
}
}
if (currentMode == windowingMode) {
- // You are already in the window mode silly...
+ // You are already in the window mode, so we can skip most of the work below. However,
+ // it's possible that we have inherited the current windowing mode from a parent. So,
+ // fulfill this method's contract by setting the override mode directly.
+ getOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
return;
}
final WindowManagerService wm = mService.mWindowManager;
final ActivityRecord topActivity = getTopActivity();
- if (sendNonResizeableNotification && windowingMode != WINDOWING_MODE_FULLSCREEN
+ // For now, assume that the Stack's windowing mode is what will actually be used
+ // by it's activities. In the future, there may be situations where this doesn't
+ // happen; so at that point, this message will need to handle that.
+ int likelyResolvedMode = windowingMode;
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ final ConfigurationContainer parent = getParent();
+ likelyResolvedMode = parent != null ? parent.getWindowingMode()
+ : WINDOWING_MODE_FULLSCREEN;
+ }
+ if (sendNonResizeableNotification && likelyResolvedMode != WINDOWING_MODE_FULLSCREEN
&& topActivity != null && topActivity.isNonResizableOrForcedResizable()
&& !topActivity.noDisplay) {
// Inform the user that they are starting an app that may not work correctly in
@@ -625,6 +672,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
+ " while there is already one isn't currently supported");
//return;
}
+ if (isTransientWindowingMode(windowingMode) && !isTransientWindowingMode(currentMode)) {
+ mRestoreOverrideWindowingMode = currentOverrideMode;
+ }
mTmpRect2.setEmpty();
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
@@ -674,13 +724,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// display, so they should be considered compatible.
activityType = ACTIVITY_TYPE_STANDARD;
}
- final ActivityDisplay display = getDisplay();
- if (display != null && activityType == ACTIVITY_TYPE_STANDARD
- && windowingMode == WINDOWING_MODE_UNDEFINED) {
- // Standard activity types will mostly take on the windowing mode of the display if one
- // isn't specified, so look-up a compatible stack based on the display's windowing mode.
- windowingMode = display.getWindowingMode();
- }
return super.isCompatible(windowingMode, activityType);
}
@@ -1085,7 +1128,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* behind the home stack. Exit split screen in this case.
*/
if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ setWindowingMode(WINDOWING_MODE_UNDEFINED);
}
getDisplay().positionChildAtBottom(this);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1ffdc6738c1d..869be482ad77 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2817,8 +2817,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
- resizeStackLocked(otherStack, null, null, null, PRESERVE_WINDOWS,
- true /* allowResizeInDockedMode */, DEFER_RESUME);
+ otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
}
// Also disable docked stack resizing since we have manually adjusted the
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 7eadcb307028..212844ab85ce 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -3338,7 +3338,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index f2ce63c23cb6..64553a8c7ade 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -29,6 +29,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.windowingModeToString;
+
import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
@@ -295,6 +296,10 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return mFullConfiguration.windowConfiguration.getWindowingMode();
}
+ public int getOverrideWindowingMode() {
+ return mOverrideConfiguration.windowConfiguration.getWindowingMode();
+ }
+
/** Sets the windowing mode for the configuration container. */
public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
mTmpConfig.setTo(getOverrideConfiguration());
@@ -513,7 +518,8 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
final String childPrefix = prefix + " ";
pw.println(getName()
+ " type=" + activityTypeToString(getActivityType())
- + " mode=" + windowingModeToString(getWindowingMode()));
+ + " mode=" + windowingModeToString(getWindowingMode())
+ + " override-mode=" + windowingModeToString(getOverrideWindowingMode()));
for (int i = getChildCount() - 1; i >= 0; --i) {
final E cc = getChildAt(i);
pw.print(childPrefix + "#" + i + " ");
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 59b08909bb76..22de662138fe 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -24,6 +24,7 @@ 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_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
@@ -73,7 +74,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mService = createActivityTaskManagerService();
mSupervisor = mService.mStackSupervisor;
mDefaultDisplay = mService.mStackSupervisor.getDefaultDisplay();
- mStack = mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
}
@@ -140,7 +141,7 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
- public void testPrimarySplitScreenToFullscreenWhenMovedToBack() throws Exception {
+ public void testPrimarySplitScreenRestoresWhenMovedToBack() throws Exception {
// Create primary splitscreen stack. This will create secondary stacks and places the
// existing fullscreen stack on the bottom.
final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
@@ -158,6 +159,60 @@ public class ActivityStackTests extends ActivityTestsBase {
// Ensure no longer in splitscreen.
assertEquals(primarySplitScreen.getWindowingMode(), WINDOWING_MODE_FULLSCREEN);
+
+ // Ensure that the override mode is restored to undefined
+ assertEquals(primarySplitScreen.getOverrideWindowingMode(), WINDOWING_MODE_UNDEFINED);
+ }
+
+ @Test
+ public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() throws Exception {
+ // This time, start with a fullscreen activitystack
+ final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+
+ // Assert windowing mode.
+ assertEquals(primarySplitScreen.getWindowingMode(), WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+
+ // Move primary to back.
+ primarySplitScreen.moveToBack("testPrimarySplitScreenToFullscreenWhenMovedToBack",
+ null /* task */);
+
+ // Assert that stack is at the bottom.
+ assertEquals(mDefaultDisplay.getIndexOf(primarySplitScreen), 0);
+
+ // Ensure that the override mode is restored to what it was (fullscreen)
+ assertEquals(primarySplitScreen.getOverrideWindowingMode(), WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testStackInheritsDisplayWindowingMode() throws Exception {
+ final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
+ assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode());
+
+ mDefaultDisplay.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(WINDOWING_MODE_FREEFORM, primarySplitScreen.getWindowingMode());
+ assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode());
+ }
+
+ @Test
+ public void testStackOverridesDisplayWindowingMode() throws Exception {
+ final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
+ assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode());
+
+ primarySplitScreen.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ // setting windowing mode should still work even though resolved mode is already fullscreen
+ assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getOverrideWindowingMode());
+
+ mDefaultDisplay.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index aef5537badeb..bb8e5c555481 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -520,6 +520,9 @@ public class ActivityTestsBase {
private final ActivityStackSupervisor mSupervisor;
TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
super(supervisor, displayId);
+ // Normally this comes from display-properties as exposed by WM. Without that, just
+ // hard-code to FULLSCREEN for tests.
+ setWindowingMode(WINDOWING_MODE_FULLSCREEN);
mSupervisor = supervisor;
}