diff options
3 files changed, 84 insertions, 17 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ff841b147d9c..d86c4dab54fb 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2498,19 +2498,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void addChild(TaskStack stack, boolean toTop) { - int addIndex = toTop ? mChildren.size() : 0; - - if (toTop - && mService.isStackVisibleLocked(PINNED_STACK_ID) - && stack.mStackId != PINNED_STACK_ID) { - // The pinned stack is always the top most stack (always-on-top) when it is visible. - // So, stack is moved just below the pinned stack. - addIndex--; - TaskStack topStack = mChildren.get(addIndex); - if (topStack.mStackId != PINNED_STACK_ID) { - throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); - } - } + final int addIndex = findPositionForStack(toTop ? mChildren.size() : 0, stack, + true /* adding */); addChild(stack, addIndex); setLayoutNeeded(); } @@ -2528,7 +2517,45 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } - super.positionChildAt(position, child, includingParents); + final int targetPosition = findPositionForStack(position, child, false /* adding */); + super.positionChildAt(targetPosition, child, includingParents); + + setLayoutNeeded(); + } + + /** + * 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. + */ + private int findPositionForStack(int requestedPosition, TaskStack stack, boolean adding) { + final int topChildPosition = mChildren.size() - 1; + boolean toTop = requestedPosition == POSITION_TOP; + toTop |= adding ? requestedPosition >= topChildPosition + 1 + : requestedPosition >= topChildPosition; + int targetPosition = requestedPosition; + + if (toTop + && mService.isStackVisibleLocked(PINNED_STACK_ID) + && stack.mStackId != PINNED_STACK_ID) { + // The pinned stack is always the top most stack (always-on-top) when it is visible. + TaskStack topStack = mChildren.get(topChildPosition); + if (topStack.mStackId != PINNED_STACK_ID) { + throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); + } + + // So, stack is moved just below the pinned stack. + // When we're adding a new stack the target is the current pinned stack position. + // When we're positioning an existing stack the target is the position below pinned + // stack, because WindowContainer#positionAt() first removes element and then adds it + // to specified place. + targetPosition = adding ? topChildPosition : topChildPosition - 1; + } + + return targetPosition; } @Override diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 984cf55de0e7..c9bf4fa55efd 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -434,7 +434,7 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon // TODO: Will this be more correct if it checks the visibility of its parents? // It depends...For example, Tasks and Stacks are only visible if there children are visible // but, WindowState are not visible if there parent are not visible. Maybe have the - // container specify which direction to treverse for for visibility? + // container specify which direction to traverse for visibility? for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer wc = mChildren.get(i); if (wc.isVisible()) { diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java index 746310217c38..24893a142b20 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java @@ -47,14 +47,15 @@ public class TaskStackContainersTests extends WindowTestsBase { // Test that always-on-top stack can't be moved to position other than top. final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent); final TaskStack stack2 = createTaskStackOnDisplay(sDisplayContent); - sDisplayContent.addStackToDisplay(PINNED_STACK_ID, true); - final TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID); + final TaskStack pinnedStack = addPinnedStack(); final WindowContainer taskStackContainer = stack1.getParent(); final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1); final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2); final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack); + assertGreaterThan(pinnedStackPos, stack2Pos); + assertGreaterThan(stack2Pos, stack1Pos); taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, pinnedStack, false); assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1); @@ -66,4 +67,43 @@ public class TaskStackContainersTests extends WindowTestsBase { assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2); assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack); } + @Test + public void testStackPositionBelowPinnedStack() throws Exception { + // Test that no stack can be above pinned stack. + final TaskStack pinnedStack = addPinnedStack(); + final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent); + + final WindowContainer taskStackContainer = stack1.getParent(); + + final int stackPos = taskStackContainer.mChildren.indexOf(stack1); + final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack); + assertGreaterThan(pinnedStackPos, stackPos); + + taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false); + assertEquals(taskStackContainer.mChildren.get(stackPos), stack1); + assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack); + + taskStackContainer.positionChildAt(taskStackContainer.mChildren.size() - 1, stack1, false); + assertEquals(taskStackContainer.mChildren.get(stackPos), stack1); + assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack); + } + + private TaskStack addPinnedStack() { + TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID); + if (pinnedStack == null) { + sDisplayContent.addStackToDisplay(PINNED_STACK_ID, true); + pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID); + } + + if (!pinnedStack.isVisible()) { + // Stack should contain visible app window to be considered visible. + final Task pinnedTask = createTaskInStack(pinnedStack, 0 /* userId */); + assertFalse(pinnedStack.isVisible()); + final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent); + pinnedTask.addChild(pinnedApp, 0 /* addPos */); + assertTrue(pinnedStack.isVisible()); + } + + return pinnedStack; + } } |