Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7073aa9d authored by Chris Li's avatar Chris Li
Browse files

Allow multiple adjacent TFs (3/n)

Migrate Task#getAdjacentTask

Bug: 373709676
Test: refactor, pass existing test
Flag: com.android.window.flags.allow_multiple_adjacent_task_fragments
Change-Id: I59f588891d5ba3055388589cbb2660bb22fe1247
parent f4840a01
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -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);
+1 −2
Original line number Diff line number Diff line
@@ -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;
                }

+1 −1
Original line number Diff line number Diff line
@@ -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);
+19 −6
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.utils.Slogf;
import com.android.server.wm.utils.RegionUtils;
import com.android.window.flags.Flags;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1794,12 +1795,24 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                    activityAssistInfos.clear();
                    activityAssistInfos.add(new ActivityAssistInfo(top));
                    // Check if the activity on the split screen.
                    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));
                                activityAssistInfos.add(
                                        new ActivityAssistInfo(adjacentActivityRecord));
                            }
                        }
                    }
                    if (rootTask == topFocusedRootTask) {
+65 −6
Original line number Diff line number Diff line
@@ -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;
        }
Loading