diff options
3 files changed, 139 insertions, 56 deletions
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 25791c762e42..3dc672396c29 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -123,6 +123,10 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { private final RootWindowContainer.FindTaskResult mTmpFindTaskResult = new RootWindowContainer.FindTaskResult(); + // Indicates whether the Assistant should show on top of the Dream (respectively, above + // everything else on screen). Otherwise, it will be put under always-on-top stacks. + private final boolean mAssistantOnTopOfDream; + /** * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused * stack has been resumed. If stacks are changing position this will hold the old stack until @@ -148,6 +152,9 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { mDisplayContent = displayContent; mRootWindowContainer = service.mRoot; mAtmService = service.mAtmService; + + mAssistantOnTopOfDream = mWmService.mContext.getResources().getBoolean( + com.android.internal.R.bool.config_assistantOnTopOfDream); } /** @@ -327,55 +334,80 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } /** - * When stack is added or repositioned, find a proper position for it. - * This will make sure that pinned stack always stays on top. - * @param requestedPosition Position requested by caller. - * @param stack Stack to be added or positioned. - * @param adding Flag indicates whether we're adding a new stack or positioning an existing. - * @return The proper position for the stack. + * Assigns a priority number to stack types. This priority defines an order between the types + * of stacks that are added to the task display area. + * + * Higher priority number indicates that the stack should have a higher z-order. + * + * @return the priority of the stack */ - private int findPositionForStack(int requestedPosition, ActivityStack stack, - boolean adding) { - if (stack.isActivityTypeDream()) { - return POSITION_TOP; - } - - if (stack.inPinnedWindowingMode()) { - return POSITION_TOP; - } - - final int topChildPosition = mChildren.size() - 1; - int belowAlwaysOnTopPosition = POSITION_BOTTOM; - for (int i = topChildPosition; i >= 0; --i) { - // Since a stack could be repositioned while being one of the child, return - // current index if that's the same stack we are positioning and it is always on - // top. - final boolean sameStack = mChildren.get(i) == stack; - if ((sameStack && stack.isAlwaysOnTop()) - || (!sameStack && !mChildren.get(i).isAlwaysOnTop())) { - belowAlwaysOnTopPosition = i; + private int getPriority(ActivityStack stack) { + if (mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4; + if (stack.isActivityTypeDream()) return 3; + if (stack.inPinnedWindowingMode()) return 2; + if (stack.isAlwaysOnTop()) return 1; + return 0; + } + + private int findMinPositionForStack(ActivityStack stack) { + int minPosition = POSITION_BOTTOM; + for (int i = 0; i < mChildren.size(); ++i) { + if (getPriority(getStackAt(i)) < getPriority(stack)) { + minPosition = i; + } else { break; } } - // The max possible position we can insert the stack at. - int maxPosition = POSITION_TOP; - // The min possible position we can insert the stack at. - int minPosition = POSITION_BOTTOM; - if (stack.isAlwaysOnTop()) { - if (hasPinnedTask()) { - // Always-on-top stacks go below the pinned stack. - maxPosition = mChildren.indexOf(mRootPinnedTask) - 1; + // Since a stack could be repositioned while still being one of the children, we check + // if this always-on-top stack already exists and if so, set the minPosition to its + // previous position. + final int currentIndex = getIndexOf(stack); + if (currentIndex > minPosition) { + minPosition = currentIndex; } - // Always-on-top stacks need to be above all other stacks. - minPosition = belowAlwaysOnTopPosition - != POSITION_BOTTOM ? belowAlwaysOnTopPosition : topChildPosition; - } else { - // Other stacks need to be below the always-on-top stacks. - maxPosition = belowAlwaysOnTopPosition - != POSITION_BOTTOM ? belowAlwaysOnTopPosition : 0; } + return minPosition; + } + + private int findMaxPositionForStack(ActivityStack stack) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final ActivityStack curr = getStackAt(i); + // Since a stack could be repositioned while still being one of the children, we check + // if 'curr' is the same stack and skip it if so + final boolean sameStack = curr == stack; + if (getPriority(curr) <= getPriority(stack) && !sameStack) { + return i; + } + } + return 0; + } + + /** + * When stack is added or repositioned, find a proper position for it. + * + * The order is defined as: + * - Dream is on top of everything + * - PiP is directly below the Dream + * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above + * existing ones + * - other non-always-on-top stacks come directly below always-on-top stacks; new + * non-always-on-top stacks are added directly below always-on-top stacks and above existing + * non-always-on-top stacks + * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything + * (including the Dream); otherwise, it is a normal non-always-on-top stack + * + * @param requestedPosition Position requested by caller. + * @param stack Stack to be added or positioned. + * @param adding Flag indicates whether we're adding a new stack or positioning an existing. + * @return The proper position for the stack. + */ + private int findPositionForStack(int requestedPosition, ActivityStack stack, boolean adding) { + // The max possible position we can insert the stack at. + int maxPosition = findMaxPositionForStack(stack); + // The min possible position we can insert the stack at. + int minPosition = findMinPositionForStack(stack); // Cap the requested position to something reasonable for the previous position check // below. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 1debd8c9ffb1..e3bb1b6ca9f3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; @@ -270,6 +272,28 @@ public class ActivityDisplayTests extends ActivityTestsBase { anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM); assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1)); + + final ActivityStack dreamStack = taskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */); + assertEquals(taskDisplayArea, dreamStack.getDisplayArea()); + assertTrue(dreamStack.isAlwaysOnTop()); + topPosition = taskDisplayArea.getStackCount() - 1; + // Ensure dream shows above all activities, including PiP + assertEquals(dreamStack, taskDisplayArea.getTopStack()); + assertEquals(pinnedStack, taskDisplayArea.getStackAt(topPosition - 1)); + + final ActivityStack assistStack = taskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); + assertEquals(taskDisplayArea, assistStack.getDisplayArea()); + assertFalse(assistStack.isAlwaysOnTop()); + topPosition = taskDisplayArea.getStackCount() - 1; + + // Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream + // is false and on top of everything when true. + final boolean isAssistantOnTop = mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream); + assertEquals(assistStack, taskDisplayArea.getStackAt( + isAssistantOnTop ? topPosition : topPosition - 4)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 93ded1b6b2f3..6c209e496cf6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -471,23 +471,39 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, splitScreenSecondary2.getVisibility(null /* starting */)); - // Assistant stack shouldn't be visible behind translucent split-screen stack + // Assistant stack shouldn't be visible behind translucent split-screen stack, + // unless it is configured to show on top of everything. doReturn(false).when(assistantStack).isTranslucent(any()); doReturn(true).when(splitScreenPrimary).isTranslucent(any()); doReturn(true).when(splitScreenSecondary2).isTranslucent(any()); splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen"); splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen"); - assertFalse(assistantStack.shouldBeVisible(null /* starting */)); - assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); - assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); - assertEquals(STACK_VISIBILITY_INVISIBLE, - assistantStack.getVisibility(null /* starting */)); - assertEquals(STACK_VISIBILITY_VISIBLE, - splitScreenPrimary.getVisibility(null /* starting */)); - assertEquals(STACK_VISIBILITY_INVISIBLE, - splitScreenSecondary.getVisibility(null /* starting */)); - assertEquals(STACK_VISIBILITY_VISIBLE, - splitScreenSecondary2.getVisibility(null /* starting */)); + + if (isAssistantOnTop()) { + assertTrue(assistantStack.shouldBeVisible(null /* starting */)); + assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); + assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + assistantStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); + } else { + assertFalse(assistantStack.shouldBeVisible(null /* starting */)); + assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); + assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + assistantStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); + } } @Test @@ -927,9 +943,15 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary.moveToFront("testSplitScreenMoveToFront"); - assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); - assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); - assertFalse(assistantStack.shouldBeVisible(null /* starting */)); + if (isAssistantOnTop()) { + assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); + assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); + assertTrue(assistantStack.shouldBeVisible(null /* starting */)); + } else { + assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); + assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); + assertFalse(assistantStack.shouldBeVisible(null /* starting */)); + } } private ActivityStack createStandardStackForVisibilityTest(int windowingMode, @@ -1344,6 +1366,11 @@ public class ActivityStackTests extends ActivityTestsBase { anyBoolean()); } + private boolean isAssistantOnTop() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_assistantOnTopOfDream); + } + private void verifyShouldSleepActivities(boolean focusedStack, boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { final DisplayContent display = mock(DisplayContent.class); |