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/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 698b6f7..e65ae5c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -173,12 +173,22 @@
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);
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 7df057c..f2ce63c 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -302,6 +302,18 @@
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.
@@ -513,7 +525,7 @@
return toString();
}
- boolean isAlwaysOnTop() {
+ public boolean isAlwaysOnTop() {
return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
}
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;