Defer always on top state when task gets maximized
This CL enables always on top to be restored/deferred when
stacks switch between freeform and fullscreen.
Bug: 110494387
Test: ActivityStackTests
Test: DisplayContentTests
Test: go/wm-smoke
Change-Id: Iccb9824f845dea4925fac5d5dcb5eeaab2acdfcd
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 562dfd6..5f9f4eb 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -167,8 +167,14 @@
mStacks.remove(stack);
final int insertPosition = getTopInsertPosition(stack, position);
mStacks.add(insertPosition, stack);
- mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
- insertPosition);
+ // Since positionChildAt() is called during the creation process of pinned stacks,
+ // ActivityStack#getWindowContainerController() can be null. In this special case,
+ // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
+ // we don't have to call WindowContainerController#positionChildAt() here.
+ if (stack.getWindowContainerController() != null) {
+ mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
+ insertPosition);
+ }
onStackOrderChanged();
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b0f1c45..bebaede 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -503,11 +503,21 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWindowingMode = getWindowingMode();
+ final boolean prevIsAlwaysOnTop = isAlwaysOnTop();
super.onConfigurationChanged(newParentConfig);
final ActivityDisplay display = getDisplay();
- if (display != null && prevWindowingMode != getWindowingMode()) {
+ if (display == null) {
+ return;
+ }
+ if (prevWindowingMode != getWindowingMode()) {
display.onStackWindowingModeChanged(this);
}
+ if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
+ // 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.positionChildAtTop(this);
+ }
}
@Override
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 4094716..6290751 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -507,6 +507,15 @@
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack);
+ alwaysOnTopStack2.setAlwaysOnTop(true);
+
+ // Ensure always on top state changes properly when windowing mode changes.
+ alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertFalse(alwaysOnTopStack2.isAlwaysOnTop());
+ assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack);
+ alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
+ assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == pinnedStack);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index ec068db..cd8e650 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -17,6 +17,8 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+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.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -384,7 +386,8 @@
*/
@Test
public void testAlwaysOnTopStackLocation() {
- final TaskStack alwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
+ final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
alwaysOnTopStack.setAlwaysOnTop(true);
mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack);
@@ -398,7 +401,8 @@
assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
assertEquals(pinnedStack, mDisplayContent.getTopStack());
- final TaskStack anotherAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
+ final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
@@ -407,7 +411,8 @@
// existing alwaysOnTop stack.
assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
- final TaskStack nonAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
+ final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
topPosition = mDisplayContent.getStacks().size() - 1;
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
@@ -417,10 +422,18 @@
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- topPosition = mDisplayContent.getStacks().size() - 1;
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
+ anotherAlwaysOnTopStack.setAlwaysOnTop(true);
+
+ // Ensure always on top state changes properly when windowing mode changes.
+ anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
+ assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
+ anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
+ assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
}
/**