From 048e2661ee4e76c1358ea77a9050619f0b960471 Mon Sep 17 00:00:00 2001 From: Kazuki Takise Date: Wed, 27 Jun 2018 17:05:11 +0900 Subject: [PATCH] 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 --- .../java/android/app/WindowConfiguration.java | 3 ++- .../android/server/am/ActivityDisplay.java | 10 +++++++-- .../com/android/server/am/ActivityStack.java | 12 ++++++++++- .../android/server/am/ActivityStackTests.java | 9 ++++++++ .../server/wm/DisplayContentTests.java | 21 +++++++++++++++---- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index aea767ecb3f0d..e6fb5dc02ce32 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -575,7 +575,8 @@ public class WindowConfiguration implements Parcelable, Comparable 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 b0f1c45327cf8..bebaede0d4827 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 @@ class ActivityStack extends ConfigurationContai @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 4094716f8f3bb..6290751576b27 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 @@ public class ActivityStackTests extends ActivityTestsBase { // 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 ec068dbcd755e..cd8e650406d22 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 @@ public class DisplayContentTests extends WindowTestsBase { */ @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 @@ public class DisplayContentTests extends WindowTestsBase { 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 @@ public class DisplayContentTests extends WindowTestsBase { // 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 @@ public class DisplayContentTests extends WindowTestsBase { 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)); } /**