Loading services/core/java/com/android/server/wm/DisplayContent.java +41 −14 Original line number Diff line number Diff line Loading @@ -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(); } Loading @@ -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 Loading services/core/java/com/android/server/wm/WindowContainer.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()) { Loading services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +42 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; } } Loading
services/core/java/com/android/server/wm/DisplayContent.java +41 −14 Original line number Diff line number Diff line Loading @@ -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(); } Loading @@ -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 Loading
services/core/java/com/android/server/wm/WindowContainer.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()) { Loading
services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +42 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; } }