diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ff841b147d9c4..d86c4dab54fb0 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= 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 984cf55de0e72..c9bf4fa55efda 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 implements Comparable= 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 746310217c389..24893a142b204 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; + } }