Loading core/java/android/app/WindowConfiguration.java +47 −4 Original line number Diff line number Diff line Loading @@ -59,6 +59,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** The current windowing mode of the configuration. */ private @WindowingMode int mWindowingMode; private int mFlags; /** Indicates that this window should always be on top of the other windows. */ private static final int PFLAG_ALWAYS_ON_TOP = 1 << 0; /** Windowing mode is currently not defined. */ public static final int WINDOWING_MODE_UNDEFINED = 0; /** Occupies the full area of the screen or the parent container. */ Loading Loading @@ -136,13 +141,16 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** Bit that indicates that the {@link #mActivityType} changed. * @hide */ public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3; /** Bit that indicates that the {@link #mFlags} changed. * @hide */ public static final int WINDOW_CONFIG_FLAGS = 1 << 4; /** @hide */ @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = { WINDOW_CONFIG_BOUNDS, WINDOW_CONFIG_APP_BOUNDS, WINDOW_CONFIG_WINDOWING_MODE, WINDOW_CONFIG_ACTIVITY_TYPE WINDOW_CONFIG_ACTIVITY_TYPE, WINDOW_CONFIG_FLAGS }) public @interface WindowConfig {} Loading @@ -168,6 +176,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu dest.writeParcelable(mAppBounds, flags); dest.writeInt(mWindowingMode); dest.writeInt(mActivityType); dest.writeInt(mFlags); } private void readFromParcel(Parcel source) { Loading @@ -175,6 +184,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu mAppBounds = source.readParcelable(Rect.class.getClassLoader()); mWindowingMode = source.readInt(); mActivityType = source.readInt(); mFlags = source.readInt(); } @Override Loading Loading @@ -222,6 +232,23 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setAppBounds(rect.left, rect.top, rect.right, rect.bottom); } private void setFlags(int flags) { mFlags = flags; } /** * Sets whether this window should be always on top. * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false} * @hide */ public void setAlwaysOnTop(boolean alwaysOnTop) { if (alwaysOnTop) { mFlags |= PFLAG_ALWAYS_ON_TOP; } else { mFlags &= ~PFLAG_ALWAYS_ON_TOP; } } /** * @see #setAppBounds(Rect) * @see #getAppBounds() Loading Loading @@ -281,6 +308,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setAppBounds(other.mAppBounds); setWindowingMode(other.mWindowingMode); setActivityType(other.mActivityType); setFlags(other.mFlags); } /** Set this object to completely undefined. Loading @@ -295,6 +323,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setBounds(null); setWindowingMode(WINDOWING_MODE_UNDEFINED); setActivityType(ACTIVITY_TYPE_UNDEFINED); setFlags(0); } /** Loading @@ -312,6 +341,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changed |= WINDOW_CONFIG_BOUNDS; setBounds(delta.mBounds); } if (delta.mFlags != mFlags) { changed |= WINDOW_CONFIG_FLAGS; setFlags(delta.mFlags); } if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) { changed |= WINDOW_CONFIG_APP_BOUNDS; setAppBounds(delta.mAppBounds); Loading Loading @@ -347,6 +380,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changes |= WINDOW_CONFIG_BOUNDS; } if (mFlags != other.mFlags) { changes |= WINDOW_CONFIG_FLAGS; } // Make sure that one of the values is not null and that they are not equal. if ((compareUndefined || other.mAppBounds != null) && mAppBounds != other.mAppBounds Loading Loading @@ -399,6 +436,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu n = mActivityType - that.mActivityType; if (n != 0) return n; n = mFlags - that.mFlags; if (n != 0) return n; // if (n != 0) return n; return n; } Loading @@ -425,6 +465,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu result = 31 * result + mWindowingMode; result = 31 * result + mActivityType; result = 31 * result + mFlags; return result; } Loading @@ -434,7 +475,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu return "{ mBounds=" + mBounds + " mAppBounds=" + mAppBounds + " mWindowingMode=" + windowingModeToString(mWindowingMode) + " mActivityType=" + activityTypeToString(mActivityType) + "}"; + " mActivityType=" + activityTypeToString(mActivityType) + " mFlags=0x" + Integer.toHexString(mFlags) + "}"; } /** Loading Loading @@ -520,7 +563,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu * @hide */ public boolean isAlwaysOnTop() { return mWindowingMode == WINDOWING_MODE_PINNED; return mWindowingMode == WINDOWING_MODE_PINNED || (mFlags & PFLAG_ALWAYS_ON_TOP) != 0; } /** Loading services/core/java/com/android/server/am/ActivityDisplay.java +15 −5 Original line number Diff line number Diff line Loading @@ -173,12 +173,22 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> private int getTopInsertPosition(ActivityStack stack, int candidatePosition) { int position = mStacks.size(); if (position > 0) { final ActivityStack topStack = mStacks.get(position - 1); if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) { // If the top stack is always on top, we move this stack just below it. position--; 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 Math.min(position, candidatePosition); } while (position > 0) { final ActivityStack targetStack = mStacks.get(position - 1); 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; } position--; } return Math.min(position, candidatePosition); } Loading services/core/java/com/android/server/wm/ConfigurationContainer.java +13 −1 Original line number Diff line number Diff line Loading @@ -302,6 +302,18 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { onOverrideConfigurationChanged(mTmpConfig); } /** Sets the always on top flag for this configuration container. * When you call this function, make sure that the following functions are called as well to * keep proper z-order. * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)}; * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)}; * */ public void setAlwaysOnTop(boolean alwaysOnTop) { mTmpConfig.setTo(getOverrideConfiguration()); mTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop); onOverrideConfigurationChanged(mTmpConfig); } /** * Returns true if this container is currently in multi-window mode. I.e. sharing the screen * with another activity. Loading Loading @@ -513,7 +525,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return toString(); } boolean isAlwaysOnTop() { public boolean isAlwaysOnTop() { return mFullConfiguration.windowConfiguration.isAlwaysOnTop(); } Loading services/core/java/com/android/server/wm/DisplayContent.java +41 −13 Original line number Diff line number Diff line Loading @@ -1565,6 +1565,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mTaskStackContainers.getStack(windowingMode, activityType); } @VisibleForTesting WindowList<TaskStack> getStacks() { return mTaskStackContainers.mChildren; } @VisibleForTesting TaskStack getTopStack() { return mTaskStackContainers.getTopStack(); Loading Loading @@ -3426,21 +3431,44 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo boolean toTop = requestedPosition == POSITION_TOP; toTop |= adding ? requestedPosition >= topChildPosition + 1 : requestedPosition >= topChildPosition; int targetPosition = requestedPosition; if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED && hasPinnedStack()) { // The pinned stack is always the top most stack (always-on-top) when it is present. TaskStack topStack = mChildren.get(topChildPosition); if (topStack.getWindowingMode() != WINDOWING_MODE_PINNED) { throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); 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; } // 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 // 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. targetPosition = adding ? topChildPosition : topChildPosition - 1; if (toTop && adding) { 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; Loading services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +24 −9 Original line number Diff line number Diff line Loading @@ -380,21 +380,36 @@ public class DisplayContentTests extends WindowTestsBase { } /** * This test enforces that the pinned stack is always kept as the top stack. * This test enforces that alwaysOnTop stack is placed at proper position. */ @Test public void testPinnedStackLocation() { public void testAlwaysOnTopStackLocation() { final TaskStack alwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); alwaysOnTopStack.setAlwaysOnTop(true); mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack); assertTrue(alwaysOnTopStack.isAlwaysOnTop()); assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack()); final TaskStack pinnedStack = createStackControllerOnStackOnDisplay( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; // Ensure that the pinned stack is the top stack assertEquals(pinnedStack, mDisplayContent.getPinnedStack()); assertEquals(pinnedStack, mDisplayContent.getTopStack()); // By default, this should try to create a new stack on top final TaskStack otherStack = createTaskStackOnDisplay(mDisplayContent); // Ensure that the other stack is on the display. assertEquals(mDisplayContent, otherStack.getDisplayContent()); // Ensure that the pinned stack is still on top assertEquals(pinnedStack, mDisplayContent.getTopStack()); final TaskStack anotherAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); anotherAlwaysOnTopStack.setAlwaysOnTop(true); mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack); assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); int topPosition = mDisplayContent.getStacks().size() - 1; // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the // existing alwaysOnTop stack. assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1)); final TaskStack nonAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent()); topPosition = mDisplayContent.getStacks().size() - 1; // 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)); } /** Loading Loading
core/java/android/app/WindowConfiguration.java +47 −4 Original line number Diff line number Diff line Loading @@ -59,6 +59,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** The current windowing mode of the configuration. */ private @WindowingMode int mWindowingMode; private int mFlags; /** Indicates that this window should always be on top of the other windows. */ private static final int PFLAG_ALWAYS_ON_TOP = 1 << 0; /** Windowing mode is currently not defined. */ public static final int WINDOWING_MODE_UNDEFINED = 0; /** Occupies the full area of the screen or the parent container. */ Loading Loading @@ -136,13 +141,16 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** Bit that indicates that the {@link #mActivityType} changed. * @hide */ public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3; /** Bit that indicates that the {@link #mFlags} changed. * @hide */ public static final int WINDOW_CONFIG_FLAGS = 1 << 4; /** @hide */ @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = { WINDOW_CONFIG_BOUNDS, WINDOW_CONFIG_APP_BOUNDS, WINDOW_CONFIG_WINDOWING_MODE, WINDOW_CONFIG_ACTIVITY_TYPE WINDOW_CONFIG_ACTIVITY_TYPE, WINDOW_CONFIG_FLAGS }) public @interface WindowConfig {} Loading @@ -168,6 +176,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu dest.writeParcelable(mAppBounds, flags); dest.writeInt(mWindowingMode); dest.writeInt(mActivityType); dest.writeInt(mFlags); } private void readFromParcel(Parcel source) { Loading @@ -175,6 +184,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu mAppBounds = source.readParcelable(Rect.class.getClassLoader()); mWindowingMode = source.readInt(); mActivityType = source.readInt(); mFlags = source.readInt(); } @Override Loading Loading @@ -222,6 +232,23 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setAppBounds(rect.left, rect.top, rect.right, rect.bottom); } private void setFlags(int flags) { mFlags = flags; } /** * Sets whether this window should be always on top. * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false} * @hide */ public void setAlwaysOnTop(boolean alwaysOnTop) { if (alwaysOnTop) { mFlags |= PFLAG_ALWAYS_ON_TOP; } else { mFlags &= ~PFLAG_ALWAYS_ON_TOP; } } /** * @see #setAppBounds(Rect) * @see #getAppBounds() Loading Loading @@ -281,6 +308,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setAppBounds(other.mAppBounds); setWindowingMode(other.mWindowingMode); setActivityType(other.mActivityType); setFlags(other.mFlags); } /** Set this object to completely undefined. Loading @@ -295,6 +323,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setBounds(null); setWindowingMode(WINDOWING_MODE_UNDEFINED); setActivityType(ACTIVITY_TYPE_UNDEFINED); setFlags(0); } /** Loading @@ -312,6 +341,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changed |= WINDOW_CONFIG_BOUNDS; setBounds(delta.mBounds); } if (delta.mFlags != mFlags) { changed |= WINDOW_CONFIG_FLAGS; setFlags(delta.mFlags); } if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) { changed |= WINDOW_CONFIG_APP_BOUNDS; setAppBounds(delta.mAppBounds); Loading Loading @@ -347,6 +380,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changes |= WINDOW_CONFIG_BOUNDS; } if (mFlags != other.mFlags) { changes |= WINDOW_CONFIG_FLAGS; } // Make sure that one of the values is not null and that they are not equal. if ((compareUndefined || other.mAppBounds != null) && mAppBounds != other.mAppBounds Loading Loading @@ -399,6 +436,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu n = mActivityType - that.mActivityType; if (n != 0) return n; n = mFlags - that.mFlags; if (n != 0) return n; // if (n != 0) return n; return n; } Loading @@ -425,6 +465,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu result = 31 * result + mWindowingMode; result = 31 * result + mActivityType; result = 31 * result + mFlags; return result; } Loading @@ -434,7 +475,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu return "{ mBounds=" + mBounds + " mAppBounds=" + mAppBounds + " mWindowingMode=" + windowingModeToString(mWindowingMode) + " mActivityType=" + activityTypeToString(mActivityType) + "}"; + " mActivityType=" + activityTypeToString(mActivityType) + " mFlags=0x" + Integer.toHexString(mFlags) + "}"; } /** Loading Loading @@ -520,7 +563,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu * @hide */ public boolean isAlwaysOnTop() { return mWindowingMode == WINDOWING_MODE_PINNED; return mWindowingMode == WINDOWING_MODE_PINNED || (mFlags & PFLAG_ALWAYS_ON_TOP) != 0; } /** Loading
services/core/java/com/android/server/am/ActivityDisplay.java +15 −5 Original line number Diff line number Diff line Loading @@ -173,12 +173,22 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> private int getTopInsertPosition(ActivityStack stack, int candidatePosition) { int position = mStacks.size(); if (position > 0) { final ActivityStack topStack = mStacks.get(position - 1); if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) { // If the top stack is always on top, we move this stack just below it. position--; 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 Math.min(position, candidatePosition); } while (position > 0) { final ActivityStack targetStack = mStacks.get(position - 1); 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; } position--; } return Math.min(position, candidatePosition); } Loading
services/core/java/com/android/server/wm/ConfigurationContainer.java +13 −1 Original line number Diff line number Diff line Loading @@ -302,6 +302,18 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { onOverrideConfigurationChanged(mTmpConfig); } /** Sets the always on top flag for this configuration container. * When you call this function, make sure that the following functions are called as well to * keep proper z-order. * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)}; * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)}; * */ public void setAlwaysOnTop(boolean alwaysOnTop) { mTmpConfig.setTo(getOverrideConfiguration()); mTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop); onOverrideConfigurationChanged(mTmpConfig); } /** * Returns true if this container is currently in multi-window mode. I.e. sharing the screen * with another activity. Loading Loading @@ -513,7 +525,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return toString(); } boolean isAlwaysOnTop() { public boolean isAlwaysOnTop() { return mFullConfiguration.windowConfiguration.isAlwaysOnTop(); } Loading
services/core/java/com/android/server/wm/DisplayContent.java +41 −13 Original line number Diff line number Diff line Loading @@ -1565,6 +1565,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mTaskStackContainers.getStack(windowingMode, activityType); } @VisibleForTesting WindowList<TaskStack> getStacks() { return mTaskStackContainers.mChildren; } @VisibleForTesting TaskStack getTopStack() { return mTaskStackContainers.getTopStack(); Loading Loading @@ -3426,21 +3431,44 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo boolean toTop = requestedPosition == POSITION_TOP; toTop |= adding ? requestedPosition >= topChildPosition + 1 : requestedPosition >= topChildPosition; int targetPosition = requestedPosition; if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED && hasPinnedStack()) { // The pinned stack is always the top most stack (always-on-top) when it is present. TaskStack topStack = mChildren.get(topChildPosition); if (topStack.getWindowingMode() != WINDOWING_MODE_PINNED) { throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); 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; } // 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 // 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. targetPosition = adding ? topChildPosition : topChildPosition - 1; if (toTop && adding) { 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; Loading
services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +24 −9 Original line number Diff line number Diff line Loading @@ -380,21 +380,36 @@ public class DisplayContentTests extends WindowTestsBase { } /** * This test enforces that the pinned stack is always kept as the top stack. * This test enforces that alwaysOnTop stack is placed at proper position. */ @Test public void testPinnedStackLocation() { public void testAlwaysOnTopStackLocation() { final TaskStack alwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); alwaysOnTopStack.setAlwaysOnTop(true); mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack); assertTrue(alwaysOnTopStack.isAlwaysOnTop()); assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack()); final TaskStack pinnedStack = createStackControllerOnStackOnDisplay( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; // Ensure that the pinned stack is the top stack assertEquals(pinnedStack, mDisplayContent.getPinnedStack()); assertEquals(pinnedStack, mDisplayContent.getTopStack()); // By default, this should try to create a new stack on top final TaskStack otherStack = createTaskStackOnDisplay(mDisplayContent); // Ensure that the other stack is on the display. assertEquals(mDisplayContent, otherStack.getDisplayContent()); // Ensure that the pinned stack is still on top assertEquals(pinnedStack, mDisplayContent.getTopStack()); final TaskStack anotherAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); anotherAlwaysOnTopStack.setAlwaysOnTop(true); mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack); assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); int topPosition = mDisplayContent.getStacks().size() - 1; // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the // existing alwaysOnTop stack. assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1)); final TaskStack nonAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent); assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent()); topPosition = mDisplayContent.getStacks().size() - 1; // 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)); } /** Loading