Loading services/core/java/com/android/server/wm/TaskDisplayArea.java +73 −41 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); } /** Loading Loading @@ -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; break; } 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; } // The max possible position we can insert the stack at. int maxPosition = POSITION_TOP; // The min possible position we can insert the stack at. 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; } } 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. Loading services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +24 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +42 −15 Original line number Diff line number Diff line Loading @@ -471,12 +471,27 @@ 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"); 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 */)); Loading @@ -489,6 +504,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary2.getVisibility(null /* starting */)); } } @Test public void testGetVisibility_MultiLevel() { Loading Loading @@ -927,10 +943,16 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary.moveToFront("testSplitScreenMoveToFront"); 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, boolean translucent) { Loading Loading @@ -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); Loading Loading
services/core/java/com/android/server/wm/TaskDisplayArea.java +73 −41 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); } /** Loading Loading @@ -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; break; } 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; } // The max possible position we can insert the stack at. int maxPosition = POSITION_TOP; // The min possible position we can insert the stack at. 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; } } 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. Loading
services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +24 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading
services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +42 −15 Original line number Diff line number Diff line Loading @@ -471,12 +471,27 @@ 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"); 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 */)); Loading @@ -489,6 +504,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary2.getVisibility(null /* starting */)); } } @Test public void testGetVisibility_MultiLevel() { Loading Loading @@ -927,10 +943,16 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary.moveToFront("testSplitScreenMoveToFront"); 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, boolean translucent) { Loading Loading @@ -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); Loading