summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-12-11 03:33:26 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-12-11 03:33:26 +0000
commit3ffdc22a059a7e0520f11c4036c1c98e6fa1a36c (patch)
tree1358c31ed1f4f0ef14d0557010f862d1c1e49f63
parent6591b9a7220603271694719f176327622754945b (diff)
parent7073aa9d179def871222c52d0e36dabc1fbda762 (diff)
Merge "Allow multiple adjacent TFs (3/n)" into main
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java16
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java24
-rw-r--r--services/core/java/com/android/server/wm/Task.java71
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java72
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java94
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java2
8 files changed, 241 insertions, 43 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 3f814f9db1c8..417d6a5d12ee 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -110,6 +110,7 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.apphibernation.AppHibernationService;
+import com.android.window.flags.Flags;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
@@ -778,11 +779,12 @@ class ActivityMetricsLogger {
*/
private void updateSplitPairLaunches(@NonNull TransitionInfo info) {
final Task launchedActivityTask = info.mLastLaunchedActivity.getTask();
- final Task adjacentToLaunchedTask = launchedActivityTask.getAdjacentTask();
- if (adjacentToLaunchedTask == null) {
+ final Task launchedSplitRootTask = launchedActivityTask.getTaskWithAdjacent();
+ if (launchedSplitRootTask == null) {
// Not a part of a split pair
return;
}
+
for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
final TransitionInfo otherInfo = mTransitionInfoList.get(i);
if (otherInfo == info) {
@@ -790,7 +792,15 @@ class ActivityMetricsLogger {
}
final Task otherTask = otherInfo.mLastLaunchedActivity.getTask();
// The adjacent task is the split root in which activities are started
- if (otherTask.isDescendantOf(adjacentToLaunchedTask)) {
+ final boolean isDescendantOfAdjacent;
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ isDescendantOfAdjacent = launchedSplitRootTask.forOtherAdjacentTasks(
+ otherTask::isDescendantOf);
+ } else {
+ isDescendantOfAdjacent = otherTask.isDescendantOf(
+ launchedSplitRootTask.getAdjacentTask());
+ }
+ if (isDescendantOfAdjacent) {
if (DEBUG_METRICS) {
Slog.i(TAG, "Found adjacent tasks t1=" + launchedActivityTask.mTaskId
+ " t2=" + otherTask.mTaskId);
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 741eefae4462..492d84f4a12f 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -996,8 +996,7 @@ public class AppTransitionController {
// If the current window container is a task with adjacent task set, the both
// adjacent tasks will be opened or closed together. To get their opening or
// closing animation target independently, skip promoting their animation targets.
- if (current.asTask() != null
- && current.asTask().getAdjacentTask() != null) {
+ if (current.asTask() != null && current.asTask().hasAdjacentTask()) {
canPromote = false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 659bb6784c89..01e00e9d67f7 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2485,7 +2485,7 @@ public class DisplayPolicy {
final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final boolean adjacentTasksVisible =
defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
- && task.getTopLeafTask().getAdjacentTask() != null)
+ && task.getTopLeafTask().hasAdjacentTask())
!= null;
final Task topFreeformTask = defaultTaskDisplayArea
.getTopRootTaskInWindowingMode(WINDOWING_MODE_FREEFORM);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b3b8c6eab25e..3d2868540334 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1796,12 +1796,24 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
activityAssistInfos.clear();
activityAssistInfos.add(new ActivityAssistInfo(top));
// Check if the activity on the split screen.
- final Task adjacentTask = top.getTask().getAdjacentTask();
- if (adjacentTask != null) {
- final ActivityRecord adjacentActivityRecord =
- adjacentTask.getTopNonFinishingActivity();
- if (adjacentActivityRecord != null) {
- activityAssistInfos.add(new ActivityAssistInfo(adjacentActivityRecord));
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ top.getTask().forOtherAdjacentTasks(task -> {
+ final ActivityRecord adjacentActivityRecord =
+ task.getTopNonFinishingActivity();
+ if (adjacentActivityRecord != null) {
+ activityAssistInfos.add(
+ new ActivityAssistInfo(adjacentActivityRecord));
+ }
+ });
+ } else {
+ final Task adjacentTask = top.getTask().getAdjacentTask();
+ if (adjacentTask != null) {
+ final ActivityRecord adjacentActivityRecord =
+ adjacentTask.getTopNonFinishingActivity();
+ if (adjacentActivityRecord != null) {
+ activityAssistInfos.add(
+ new ActivityAssistInfo(adjacentActivityRecord));
+ }
}
}
if (rootTask == topFocusedRootTask) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c8befb21fe13..76d8861022bb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2500,20 +2500,79 @@ class Task extends TaskFragment {
return parentTask == null ? null : parentTask.getCreatedByOrganizerTask();
}
- /** @return the first adjacent task of this task or its parent. */
+ /** @deprecated b/373709676 replace with {@link #forOtherAdjacentTasks(Consumer)} ()}. */
+ @Deprecated
@Nullable
Task getAdjacentTask() {
- final TaskFragment adjacentTaskFragment = getAdjacentTaskFragment();
- if (adjacentTaskFragment != null && adjacentTaskFragment.asTask() != null) {
- return adjacentTaskFragment.asTask();
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ throw new IllegalStateException("allowMultipleAdjacentTaskFragments is enabled. "
+ + "Use #forOtherAdjacentTasks instead");
+ }
+ final Task taskWithAdjacent = getTaskWithAdjacent();
+ if (taskWithAdjacent == null) {
+ return null;
}
+ return taskWithAdjacent.getAdjacentTaskFragment().asTask();
+ }
+ /** Finds the first Task parent (or itself) that has adjacent. */
+ @Nullable
+ Task getTaskWithAdjacent() {
+ if (hasAdjacentTaskFragment()) {
+ return this;
+ }
final WindowContainer parent = getParent();
if (parent == null || parent.asTask() == null) {
return null;
}
+ return parent.asTask().getTaskWithAdjacent();
+ }
+
+ /** Returns true if this or its parent has adjacent Task. */
+ boolean hasAdjacentTask() {
+ return getTaskWithAdjacent() != null;
+ }
- return parent.asTask().getAdjacentTask();
+ /**
+ * Finds the first Task parent (or itself) that has adjacent. Runs callback on all the adjacent
+ * Tasks. The invoke order is not guaranteed.
+ */
+ void forOtherAdjacentTasks(@NonNull Consumer<Task> callback) {
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ throw new IllegalStateException("allowMultipleAdjacentTaskFragments is not enabled. "
+ + "Use #getAdjacentTask instead");
+ }
+
+ final Task taskWithAdjacent = getTaskWithAdjacent();
+ if (taskWithAdjacent == null) {
+ return;
+ }
+ final AdjacentSet adjacentTasks = taskWithAdjacent.getAdjacentTaskFragments();
+ adjacentTasks.forAllTaskFragments(tf -> {
+ // We don't support Task adjacent to non-Task TaskFragment.
+ callback.accept(tf.asTask());
+ }, taskWithAdjacent /* exclude */);
+ }
+
+ /**
+ * Finds the first Task parent (or itself) that has adjacent. Runs callback on all the adjacent
+ * Tasks. Returns early if callback returns true on any of them. The invoke order is not
+ * guaranteed.
+ */
+ boolean forOtherAdjacentTasks(@NonNull Predicate<Task> callback) {
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ throw new IllegalStateException("allowMultipleAdjacentTaskFragments is not enabled. "
+ + "Use getAdjacentTask instead");
+ }
+ final Task taskWithAdjacent = getTaskWithAdjacent();
+ if (taskWithAdjacent == null) {
+ return false;
+ }
+ final AdjacentSet adjacentTasks = taskWithAdjacent.getAdjacentTaskFragments();
+ return adjacentTasks.forAllTaskFragments(tf -> {
+ // We don't support Task adjacent to non-Task TaskFragment.
+ return callback.test(tf.asTask());
+ }, taskWithAdjacent /* exclude */);
}
// TODO(task-merge): Figure out what's the right thing to do for places that used it.
@@ -2907,7 +2966,7 @@ class Task extends TaskFragment {
Rect outSurfaceInsets) {
// If this task has its adjacent task, it means they should animate together. Use display
// bounds for them could move same as full screen task.
- if (getAdjacentTask() != null) {
+ if (hasAdjacentTask()) {
super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
return;
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index c1a33c468cee..9564c5959d98 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -61,6 +61,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.LaunchParamsController.LaunchParams;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1088,8 +1089,19 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// Use launch-adjacent-flag-root if launching with launch-adjacent flag.
if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
&& mLaunchAdjacentFlagRootTask != null) {
- final Task launchAdjacentRootAdjacentTask =
- mLaunchAdjacentFlagRootTask.getAdjacentTask();
+ final Task launchAdjacentRootAdjacentTask;
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ final Task[] tmpTask = new Task[1];
+ mLaunchAdjacentFlagRootTask.forOtherAdjacentTasks(task -> {
+ // TODO(b/382208145): enable FLAG_ACTIVITY_LAUNCH_ADJACENT for 3+.
+ // Find the first adjacent for now.
+ tmpTask[0] = task;
+ return true;
+ });
+ launchAdjacentRootAdjacentTask = tmpTask[0];
+ } else {
+ launchAdjacentRootAdjacentTask = mLaunchAdjacentFlagRootTask.getAdjacentTask();
+ }
if (sourceTask != null && (sourceTask == candidateTask
|| sourceTask.topRunningActivity() == null)) {
// Do nothing when task that is getting opened is same as the source or when
@@ -1114,15 +1126,26 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
final Task launchRootTask = mLaunchRootTasks.get(i).task;
- final Task adjacentRootTask = launchRootTask != null
- ? launchRootTask.getAdjacentTask() : null;
- if (sourceTask != null && adjacentRootTask != null
- && (sourceTask == adjacentRootTask
- || sourceTask.isDescendantOf(adjacentRootTask))) {
- return adjacentRootTask;
- } else {
+ if (launchRootTask == null || sourceTask == null) {
+ return launchRootTask;
+ }
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ final Task adjacentRootTask = launchRootTask.getAdjacentTask();
+ if (adjacentRootTask != null && (sourceTask == adjacentRootTask
+ || sourceTask.isDescendantOf(adjacentRootTask))) {
+ return adjacentRootTask;
+ }
return launchRootTask;
}
+ final Task[] adjacentRootTask = new Task[1];
+ launchRootTask.forOtherAdjacentTasks(task -> {
+ if (sourceTask == task || sourceTask.isDescendantOf(task)) {
+ adjacentRootTask[0] = task;
+ return true;
+ }
+ return false;
+ });
+ return adjacentRootTask[0] != null ? adjacentRootTask[0] : launchRootTask;
}
}
@@ -1133,12 +1156,31 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// A pinned task relaunching should be handled by its task organizer. Skip fallback
// launch target of a pinned task from source task.
|| candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) {
- final Task adjacentTarget = sourceTask.getAdjacentTask();
- if (adjacentTarget != null) {
- if (candidateTask != null
- && (candidateTask == adjacentTarget
- || candidateTask.isDescendantOf(adjacentTarget))) {
- return adjacentTarget;
+ final Task taskWithAdjacent = sourceTask.getTaskWithAdjacent();
+ if (taskWithAdjacent != null) {
+ // Has adjacent.
+ if (candidateTask == null) {
+ return sourceTask.getCreatedByOrganizerTask();
+ }
+ // Check if the candidate is already positioned in the adjacent Task.
+ if (Flags.allowMultipleAdjacentTaskFragments()) {
+ final Task[] adjacentRootTask = new Task[1];
+ sourceTask.forOtherAdjacentTasks(task -> {
+ if (candidateTask == task || candidateTask.isDescendantOf(task)) {
+ adjacentRootTask[0] = task;
+ return true;
+ }
+ return false;
+ });
+ if (adjacentRootTask[0] != null) {
+ return adjacentRootTask[0];
+ }
+ } else {
+ final Task adjacentTarget = taskWithAdjacent.getAdjacentTask();
+ if (candidateTask == adjacentTarget
+ || candidateTask.isDescendantOf(adjacentTarget)) {
+ return adjacentTarget;
+ }
}
return sourceTask.getCreatedByOrganizerTask();
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 9fb5bea132ef..cb6b69072e14 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -531,6 +531,28 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return mAdjacentTaskFragments;
}
+ /**
+ * Runs callback on all TaskFragments that are adjacent to this. The invoke order is not
+ * guaranteed.
+ */
+ void forOtherAdjacentTaskFragments(@NonNull Consumer<TaskFragment> callback) {
+ if (mAdjacentTaskFragments == null) {
+ return;
+ }
+ mAdjacentTaskFragments.forAllTaskFragments(callback, this /* exclude */);
+ }
+
+ /**
+ * Runs callback on all TaskFragments that are adjacent to this. Returns early if callback
+ * returns true on any of them. The invoke order is not guaranteed.
+ */
+ boolean forOtherAdjacentTaskFragments(@NonNull Predicate<TaskFragment> callback) {
+ if (mAdjacentTaskFragments == null) {
+ return false;
+ }
+ return mAdjacentTaskFragments.forAllTaskFragments(callback, this /* exclude */);
+ }
+
boolean hasAdjacentTaskFragment() {
if (!Flags.allowMultipleAdjacentTaskFragments()) {
return mAdjacentTaskFragment != null;
@@ -3198,24 +3220,47 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
- final TaskFragment adjacentTf = getAdjacentTaskFragment();
- if (adjacentTf == null) {
+ if (!hasAdjacentTaskFragment()) {
// early return if no adjacent TF.
return false;
}
- if (getParent().mChildren.indexOf(adjacentTf) < getParent().mChildren.indexOf(this)) {
- // early return if this TF already has higher z-ordering.
- return false;
+ final ArrayList<WindowContainer> siblings = getParent().mChildren;
+ final int zOrder = siblings.indexOf(this);
+
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ if (siblings.indexOf(getAdjacentTaskFragment()) < zOrder) {
+ // early return if this TF already has higher z-ordering.
+ return false;
+ }
+ } else {
+ final boolean hasAdjacentOnTop = forOtherAdjacentTaskFragments(
+ tf -> siblings.indexOf(tf) > zOrder);
+ if (!hasAdjacentOnTop) {
+ // early return if this TF already has higher z-ordering.
+ return false;
+ }
}
- ToBooleanFunction<WindowState> getDimBehindWindow =
+ final ToBooleanFunction<WindowState> getDimBehindWindow =
(w) -> (w.mAttrs.flags & FLAG_DIM_BEHIND) != 0 && w.mActivityRecord != null
&& w.mActivityRecord.isEmbedded() && (w.mActivityRecord.isVisibleRequested()
|| w.mActivityRecord.isVisible());
- if (adjacentTf.forAllWindows(getDimBehindWindow, true)) {
- // early return if the adjacent Tf has a dimming window.
- return false;
+
+ if (!Flags.allowMultipleAdjacentTaskFragments()) {
+ final TaskFragment adjacentTf = getAdjacentTaskFragment();
+ if (adjacentTf.forAllWindows(getDimBehindWindow, true)) {
+ // early return if the adjacent Tf has a dimming window.
+ return false;
+ }
+ } else {
+ final boolean adjacentHasDimmingWindow = forOtherAdjacentTaskFragments(tf -> {
+ return tf.forAllWindows(getDimBehindWindow, true);
+ });
+ if (adjacentHasDimmingWindow) {
+ // early return if the adjacent Tf has a dimming window.
+ return false;
+ }
}
// boost if there's an Activity window that has FLAG_DIM_BEHIND flag.
@@ -3528,6 +3573,37 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return mAdjacentSet.contains(taskFragment);
}
+ /**
+ * Runs the callback on all adjacent TaskFragments. Skips the exclude one if not null.
+ */
+ void forAllTaskFragments(@NonNull Consumer<TaskFragment> callback,
+ @Nullable TaskFragment exclude) {
+ for (int i = mAdjacentSet.size() - 1; i >= 0; i--) {
+ final TaskFragment taskFragment = mAdjacentSet.valueAt(i);
+ if (taskFragment != exclude) {
+ callback.accept(taskFragment);
+ }
+ }
+ }
+
+ /**
+ * Runs the callback on all adjacent TaskFragments until one returns {@code true}. Skips the
+ * exclude one if not null.
+ */
+ boolean forAllTaskFragments(@NonNull Predicate<TaskFragment> callback,
+ @Nullable TaskFragment exclude) {
+ for (int i = mAdjacentSet.size() - 1; i >= 0; i--) {
+ final TaskFragment taskFragment = mAdjacentSet.valueAt(i);
+ if (taskFragment == exclude) {
+ continue;
+ }
+ if (callback.test(taskFragment)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 7f0c33657144..80e4c30b73f8 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1263,7 +1263,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (windowingMode == WINDOWING_MODE_MULTI_WINDOW
&& com.android.window.flags.Flags
.processPriorityPolicyForMultiWindowMode()
- && task.getAdjacentTask() != null) {
+ && task.hasAdjacentTask()) {
stateFlags |= ACTIVITY_STATE_FLAG_RESUMED_SPLIT_SCREEN;
} else if (windowingMode == WINDOWING_MODE_FREEFORM) {
hasResumedFreeform = true;