Merge "Position stack at top when always on top flag is set"
This commit is contained in:
committed by
Android (Google) Code Review
commit
dd7b69d3c5
@@ -488,7 +488,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
|
||||
+ " mAppBounds=" + mAppBounds
|
||||
+ " mWindowingMode=" + windowingModeToString(mWindowingMode)
|
||||
+ " mActivityType=" + activityTypeToString(mActivityType)
|
||||
+ " mAlwaysOnTop=" + activityTypeToString(mAlwaysOnTop)
|
||||
+ " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@@ -652,4 +652,14 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
|
||||
}
|
||||
return String.valueOf(applicationType);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
|
||||
switch (alwaysOnTop) {
|
||||
case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
|
||||
case ALWAYS_ON_TOP_ON: return "on";
|
||||
case ALWAYS_ON_TOP_OFF: return "off";
|
||||
}
|
||||
return String.valueOf(alwaysOnTop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5279,6 +5279,20 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
}
|
||||
}
|
||||
|
||||
public void setAlwaysOnTop(boolean alwaysOnTop) {
|
||||
if (isAlwaysOnTop() == alwaysOnTop) {
|
||||
return;
|
||||
}
|
||||
super.setAlwaysOnTop(alwaysOnTop);
|
||||
final ActivityDisplay display = getDisplay();
|
||||
// positionChildAtTop() must be called even when always on top gets turned off because we
|
||||
// need to make sure that the stack is moved from among always on top windows to below other
|
||||
// always on top windows. Since the position the stack should be inserted into is calculated
|
||||
// properly in {@link ActivityDisplay#getTopInsertPosition()} in both cases, we can just
|
||||
// request that the stack is put at top here.
|
||||
display.positionChildAtTop(this);
|
||||
}
|
||||
|
||||
void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
|
||||
boolean setPause, String reason) {
|
||||
if (!moveToFront) {
|
||||
|
||||
@@ -3427,50 +3427,53 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
* @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;
|
||||
|
||||
if (stack.inPinnedWindowingMode()) {
|
||||
// Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
|
||||
// just return the candidate position.
|
||||
return requestedPosition;
|
||||
return POSITION_TOP;
|
||||
}
|
||||
|
||||
// We might call mChildren.get() with targetPosition below, but targetPosition might be
|
||||
// POSITION_TOP (INTEGER_MAX). We need to adjust the value to the actual index in the
|
||||
// array.
|
||||
int targetPosition = toTop ? topChildPosition : requestedPosition;
|
||||
// Note that the index we should return varies depending on the value of adding.
|
||||
// When we're adding a new stack the index is the current target position.
|
||||
// When we're positioning an existing stack the index is the position below the target
|
||||
// stack, because WindowContainer#positionAt() first removes element and then adds
|
||||
// it to specified place.
|
||||
if (toTop && adding) {
|
||||
final int topChildPosition = mChildren.size() - 1;
|
||||
int belowAlwaysOnTopPosition = POSITION_BOTTOM;
|
||||
for (int i = topChildPosition; i >= 0; --i) {
|
||||
if (getStacks().get(i) != stack && !getStacks().get(i).isAlwaysOnTop()) {
|
||||
belowAlwaysOnTopPosition = i;
|
||||
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 (hasPinnedStack()) {
|
||||
// Always-on-top stacks go below the pinned stack.
|
||||
maxPosition = getStacks().indexOf(mPinnedStack) - 1;
|
||||
}
|
||||
// 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 : topChildPosition;
|
||||
}
|
||||
|
||||
int targetPosition = requestedPosition;
|
||||
targetPosition = Math.min(targetPosition, maxPosition);
|
||||
targetPosition = Math.max(targetPosition, minPosition);
|
||||
|
||||
int prevPosition = getStacks().indexOf(stack);
|
||||
// The positions we calculated above (maxPosition, minPosition) do not take into
|
||||
// consideration the following edge cases.
|
||||
// 1) We need to adjust the position depending on the value "adding".
|
||||
// 2) When we are moving a stack to another position, we also need to adjust the
|
||||
// position depending on whether the stack is moving to a higher or lower position.
|
||||
if ((targetPosition != requestedPosition) &&
|
||||
(adding || targetPosition < prevPosition)) {
|
||||
targetPosition++;
|
||||
}
|
||||
|
||||
// Note we might have multiple always on top windows.
|
||||
while (targetPosition >= 0) {
|
||||
int adjustedTargetStackId = adding ? targetPosition - 1 : targetPosition;
|
||||
if (adjustedTargetStackId < 0 || adjustedTargetStackId > topChildPosition) {
|
||||
break;
|
||||
}
|
||||
TaskStack targetStack = mChildren.get(adjustedTargetStackId);
|
||||
if (!targetStack.isAlwaysOnTop()) {
|
||||
// We reached a stack that isn't always-on-top.
|
||||
break;
|
||||
}
|
||||
if (stack.isAlwaysOnTop() && !targetStack.inPinnedWindowingMode()) {
|
||||
// Always on-top non-pinned windowing mode stacks can go anywhere below pinned
|
||||
// stack.
|
||||
break;
|
||||
}
|
||||
// We go one level down, looking for the place on which the new stack can be put.
|
||||
targetPosition--;
|
||||
}
|
||||
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
|
||||
@@ -726,18 +726,33 @@ public class TaskStack extends WindowContainer<Task> implements
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newParentConfig) {
|
||||
final int prevWindowingMode = getWindowingMode();
|
||||
final boolean prevIsAlwaysOnTop = isAlwaysOnTop();
|
||||
super.onConfigurationChanged(newParentConfig);
|
||||
|
||||
// Only need to update surface size here since the super method will handle updating
|
||||
// surface position.
|
||||
updateSurfaceSize(getPendingTransaction());
|
||||
final int windowingMode = getWindowingMode();
|
||||
final boolean isAlwaysOnTop = isAlwaysOnTop();
|
||||
|
||||
if (mDisplayContent == null || prevWindowingMode == windowingMode) {
|
||||
if (mDisplayContent == null) {
|
||||
return;
|
||||
}
|
||||
mDisplayContent.onStackWindowingModeChanged(this);
|
||||
updateBoundsForWindowModeChange();
|
||||
|
||||
if (prevWindowingMode != windowingMode) {
|
||||
mDisplayContent.onStackWindowingModeChanged(this);
|
||||
updateBoundsForWindowModeChange();
|
||||
}
|
||||
|
||||
if (prevIsAlwaysOnTop != isAlwaysOnTop) {
|
||||
// positionStackAt(POSITION_TOP, this) must be called even when always on top gets
|
||||
// turned off because we need to make sure that the stack is moved from among always on
|
||||
// top windows to below other always on top windows. Since the position the stack should
|
||||
// be inserted into is calculated properly in
|
||||
// {@link DisplayContent#findPositionForStack()} in both cases, we can just request that
|
||||
// the stack is put at top here.
|
||||
mDisplayContent.positionStackAt(POSITION_TOP, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSurfaceBounds() {
|
||||
|
||||
@@ -246,6 +246,19 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
+ " is already a child of container=" + child.getParent().getName()
|
||||
+ " can't add to container=" + getName());
|
||||
}
|
||||
|
||||
if ((index < 0 && index != POSITION_BOTTOM)
|
||||
|| (index > mChildren.size() && index != POSITION_TOP)) {
|
||||
throw new IllegalArgumentException("addChild: invalid position=" + index
|
||||
+ ", children number=" + mChildren.size());
|
||||
}
|
||||
|
||||
if (index == POSITION_TOP) {
|
||||
index = mChildren.size();
|
||||
} else if (index == POSITION_BOTTOM) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
mChildren.add(index, child);
|
||||
onChildAdded(child);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.am;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
@@ -472,6 +473,42 @@ public class ActivityStackTests extends ActivityTestsBase {
|
||||
assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAlwaysOnTop() {
|
||||
final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
|
||||
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
|
||||
final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
|
||||
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
|
||||
assertTrue(mDefaultDisplay.getStackAbove(homeStack) == pinnedStack);
|
||||
|
||||
final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
|
||||
mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
|
||||
true /* onTop */);
|
||||
alwaysOnTopStack.setAlwaysOnTop(true);
|
||||
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
|
||||
// Ensure (non-pinned) always on top stack is put below pinned stack.
|
||||
assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack) == pinnedStack);
|
||||
|
||||
final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
|
||||
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
|
||||
true /* onTop */);
|
||||
// Ensure non always on top stack is put below always on top stacks.
|
||||
assertTrue(mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack) == alwaysOnTopStack);
|
||||
|
||||
final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
|
||||
mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
|
||||
true /* onTop */);
|
||||
alwaysOnTopStack2.setAlwaysOnTop(true);
|
||||
assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
|
||||
// Ensure newly created always on top stack is placed above other all always on top stacks.
|
||||
assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == pinnedStack);
|
||||
|
||||
alwaysOnTopStack2.setAlwaysOnTop(false);
|
||||
// Ensure, when always on top is turned off for a stack, the stack is put just below all
|
||||
// other always on top stacks.
|
||||
assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitScreenMoveToFront() throws Exception {
|
||||
final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
|
||||
|
||||
@@ -413,6 +413,14 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
|
||||
// existing other non-alwaysOnTop stacks.
|
||||
assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
|
||||
|
||||
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
|
||||
mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
|
||||
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
|
||||
topPosition = mDisplayContent.getStacks().size() - 1;
|
||||
// Ensure, when always on top is turned off for a stack, the stack is put just below all
|
||||
// other always on top stacks.
|
||||
assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -255,6 +255,33 @@ public class WindowContainerTests extends WindowTestsBase {
|
||||
assertNull(controller.mContainer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddChildByIndex() throws Exception {
|
||||
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
|
||||
final TestWindowContainer root = builder.setLayer(0).build();
|
||||
|
||||
final TestWindowContainer child = root.addChildWindow();
|
||||
|
||||
final TestWindowContainer child2 = builder.setLayer(1).build();
|
||||
final TestWindowContainer child3 = builder.setLayer(2).build();
|
||||
final TestWindowContainer child4 = builder.setLayer(3).build();
|
||||
|
||||
// Test adding at top.
|
||||
root.addChild(child2, POSITION_TOP);
|
||||
assertEquals(child2, root.getChildAt(root.getChildrenCount() - 1));
|
||||
|
||||
// Test adding at bottom.
|
||||
root.addChild(child3, POSITION_BOTTOM);
|
||||
assertEquals(child3, root.getChildAt(0));
|
||||
|
||||
// Test adding in the middle.
|
||||
root.addChild(child4, 1);
|
||||
assertEquals(child3, root.getChildAt(0));
|
||||
assertEquals(child4, root.getChildAt(1));
|
||||
assertEquals(child, root.getChildAt(2));
|
||||
assertEquals(child2, root.getChildAt(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPositionChildAt() throws Exception {
|
||||
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
|
||||
|
||||
Reference in New Issue
Block a user