Add always on top feature support
Add basic functionalities for always on top feature.
- Add a new flag to WindowConfiguration to represent a task wanting to
be on top.
- Update the logic on changing the z-order of windows to make sure
always on top windows are placed above other windows.
Bug: 69370884
Test: go/wm-smoke
Test: atest DisplayContentTests
Test: Used ArcCompanionLibDemo app to verify that when always-on-top is
set, the app is above the other Android apps and Chrome windows.
Change-Id: Ie8edeb8ceeed0b9ec154b6031ed6cbe7ecc65b12
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b0e6208..578a1489 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1569,6 +1569,11 @@
}
@VisibleForTesting
+ WindowList<TaskStack> getStacks() {
+ return mTaskStackContainers.mChildren;
+ }
+
+ @VisibleForTesting
TaskStack getTopStack() {
return mTaskStackContainers.getTopStack();
}
@@ -3429,21 +3434,44 @@
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;
+ }
+
+ // 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) {
+ 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;
}
-
- // 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;
+ 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;