5/n Add support for multiple task display areas
Replaces the references to DisplayContent#mTaskContainers field with
iteration over all child task containers where necessary.
This does not change the behavior for the regular non-foldable
devices, since they would normally have only one task display area,
so iterating throught the list is logically equivalent to referencing
it directly.
Bug: 152116619
Test: WM CTS and unit tests
Change-Id: Ibc1b18ad4c06236e944abd49089672105506ec2c
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 13e4d8b..8e45dc3 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -63,6 +63,7 @@
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -134,6 +135,12 @@
*/
private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
+ /**
+ * The task display area is removed from the system and we are just waiting for all activities
+ * on it to be finished before removing this object.
+ */
+ private boolean mRemoved;
+
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
mDisplayContent = displayContent;
@@ -986,7 +993,7 @@
return candidate;
}
- ActivityRecord getResumedActivity() {
+ ActivityRecord getFocusedActivity() {
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack == null) {
return null;
@@ -1572,7 +1579,7 @@
}
boolean isRemoved() {
- return mDisplayContent.isRemoved();
+ return mRemoved;
}
/**
@@ -1609,4 +1616,82 @@
interface OnStackOrderChangedListener {
void onStackOrderChanged(ActivityStack stack);
}
+
+ void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+ boolean preserveWindows, boolean notifyClients) {
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+ notifyClients);
+ }
+ }
+
+ void prepareFreezingTaskBounds() {
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
+ stack.prepareFreezingTaskBounds();
+ }
+ }
+
+ /**
+ * Removes the stacks in the node applying the content removal node from the display.
+ * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
+ */
+ ActivityStack remove() {
+ mPreferredTopFocusableStack = null;
+ // TODO(b/153090332): Allow setting content removal mode per task display area
+ final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
+ final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack lastReparentedStack = null;
+
+ // Stacks could be reparented from the removed display area to other display area. After
+ // reparenting the last stack of the removed display area, the display area becomes ready to
+ // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
+ // related WindowContainer will also be removed. So, we set display area as removed after
+ // reparenting stack finished.
+ // Keep the order from bottom to top.
+ int numStacks = getStackCount();
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ // Always finish non-standard type stacks.
+ if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ stack.finishAllActivitiesImmediately();
+ } else {
+ // If default display is in split-window mode, set windowing mode of the
+ // stack to split-screen secondary. Otherwise, set the windowing mode to
+ // undefined by default to let stack inherited the windowing mode from the
+ // new display.
+ final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_UNDEFINED;
+ stack.reparent(toDisplayArea, true /* onTop */);
+ stack.setWindowingMode(windowingMode);
+ lastReparentedStack = stack;
+ }
+ // Stacks may be removed from this display. Ensure each stack will be processed
+ // and the loop will end.
+ stackNdx -= numStacks - getStackCount();
+ numStacks = getStackCount();
+ }
+ mRemoved = true;
+
+ return lastReparentedStack;
+ }
+
+
+ @Override
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ pw.println(prefix + "TaskDisplayArea " + getName());
+ if (mPreferredTopFocusableStack != null) {
+ pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+ }
+ if (mLastFocusedStack != null) {
+ pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack);
+ }
+ pw.println(prefix + " Application tokens in top down Z order:");
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
+ stack.dump(pw, prefix + " ", dumpAll);
+ }
+ }
}