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

Commit 7943b5c2 authored by Louis Chang's avatar Louis Chang
Browse files

Pause activity before resuming the next one

The occluded activity was still visible while starting an Activity
on a new TaskFragment on top because the occluded TaskFragment was
still adjacent to the pinned TaskFragment. The state was unset until
the TFOrganizer gets the #onTaskFragmentAppeared callback and perform
updates via WCT.

This CL makes sure the TaskFragments are updated along with the
activity launch. So, the activities on the occluded TaskFragments
should immediately become invisible.

And in the WM Core, similar to commit dce1d3ab, we should pause all
non-top child TFs in the Task if needed.

Bug: 300019674
Test: atest PinActivityStackTests
Change-Id: I7505ffe4b9d664fe8858b83c3744324401ed3db6
parent 8610fc92
Loading
Loading
Loading
Loading
+46 −6
Original line number Diff line number Diff line
@@ -879,14 +879,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen

        // Skip resolving if the activity is on a pinned TaskFragmentContainer.
        // TODO(b/243518738): skip resolving for overlay container.
        if (container != null) {
            final TaskContainer taskContainer = container.getTaskContainer();
            if (taskContainer.isTaskFragmentContainerPinned(container)) {
        final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null;
        if (container != null && taskContainer != null
                && taskContainer.isTaskFragmentContainerPinned(container)) {
            return true;
        }
        }

        final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null;
        if (!isOnReparent && taskContainer != null
                && taskContainer.getTopNonFinishingTaskFragmentContainer(false /* includePin */)
                        != container) {
@@ -895,6 +893,28 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return true;
        }

        // Ensure the top TaskFragments are updated to the right config if activity is resolved
        // to a new TaskFragment while pin TF exists.
        final boolean handled = resolveActivityToContainerByRule(wct, activity, container,
                isOnReparent);
        if (handled && taskContainer != null) {
            final SplitPinContainer splitPinContainer = taskContainer.getSplitPinContainer();
            if (splitPinContainer != null) {
                final TaskFragmentContainer resolvedContainer = getContainerWithActivity(activity);
                if (resolvedContainer != null && resolvedContainer.getRunningActivityCount() <= 1) {
                    updateContainer(wct, splitPinContainer.getSecondaryContainer());
                }
            }
        }
        return handled;
    }

    /**
     * Resolves the activity to a {@link TaskFragmentContainer} according to the Split-rules.
     */
    boolean resolveActivityToContainerByRule(@NonNull WindowContainerTransaction wct,
            @NonNull Activity activity, @Nullable TaskFragmentContainer container,
            boolean isOnReparent) {
        /*
         * We will check the following to see if there is any embedding rule matched:
         * 1. Whether the new launched activity should always expand.
@@ -1301,6 +1321,26 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            }
        }

        // Ensure the top TaskFragments are updated to the right config if the intent is resolved
        // to a new TaskFragment while pin TF exists.
        final TaskFragmentContainer launchingContainer = resolveStartActivityIntentByRule(wct,
                taskId, intent, launchingActivity);
        if (launchingContainer != null && launchingContainer.getRunningActivityCount() == 0) {
            final SplitPinContainer splitPinContainer =
                    launchingContainer.getTaskContainer().getSplitPinContainer();
            if (splitPinContainer != null) {
                updateContainer(wct, splitPinContainer.getSecondaryContainer());
            }
        }
        return launchingContainer;
    }

    /**
     * Resolves the intent to a {@link TaskFragmentContainer} according to the Split-rules.
     */
    @Nullable
    TaskFragmentContainer resolveStartActivityIntentByRule(@NonNull WindowContainerTransaction wct,
            int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
        /*
         * We will check the following to see if there is any embedding rule matched:
         * 1. Whether the new activity intent should always expand.
+4 −8
Original line number Diff line number Diff line
@@ -795,17 +795,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
            return false;
        }

        // Try pausing the existing resumed activity in the same TaskFragment if any.
        final TaskFragment taskFragment = r.getTaskFragment();
        if (taskFragment != null && taskFragment.getResumedActivity() != null) {
            if (taskFragment.startPausing(mUserLeaving, false /* uiSleeping */, r, "realStart")) {
        // Try pausing the existing resumed activity in the Task if any.
        final Task task = r.getTask();
        if (task.pauseActivityIfNeeded(r, "realStart")) {
            return false;
        }
        }

        final Task task = r.getTask();
        final Task rootTask = task.getRootTask();

        beginDeferResume();
        // The LaunchActivityItem also contains process configuration, so the configuration change
        // from WindowProcessController#setProcess can be deferred. The major reason is that if
+31 −0
Original line number Diff line number Diff line
@@ -1262,6 +1262,37 @@ class Task extends TaskFragment {
        return null;
    }

    boolean pauseActivityIfNeeded(@Nullable ActivityRecord resuming, @NonNull String reason) {
        if (!isLeafTask()) {
            return false;
        }

        final int[] someActivityPaused = {0};
        // Check if the direct child resumed activity in the leaf task needed to be paused if
        // the leaf task is not a leaf task fragment.
        if (!isLeafTaskFragment()) {
            final ActivityRecord top = topRunningActivity();
            final ActivityRecord resumedActivity = getResumedActivity();
            if (resumedActivity != null && top.getTaskFragment() != this) {
                // Pausing the resumed activity because it is occluded by other task fragment.
                if (startPausing(false /* uiSleeping*/, resuming, reason)) {
                    someActivityPaused[0]++;
                }
            }
        }

        forAllLeafTaskFragments((taskFrag) -> {
            final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
            if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                if (taskFrag.startPausing(false /* uiSleeping*/, resuming, reason)) {
                    someActivityPaused[0]++;
                }
            }
        }, true /* traverseTopToBottom */);

        return someActivityPaused[0] > 0;
    }

    void updateTaskMovement(boolean toTop, boolean toBottom, int position) {
        EventLogTags.writeWmTaskMoved(mTaskId, getRootTaskId(), getDisplayId(), toTop ? 1 : 0,
                position);
+2 −20
Original line number Diff line number Diff line
@@ -1271,27 +1271,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
    boolean pauseBackTasks(ActivityRecord resuming) {
        final int[] someActivityPaused = {0};
        forAllLeafTasks(leafTask -> {
            // Check if the direct child resumed activity in the leaf task needed to be paused if
            // the leaf task is not a leaf task fragment.
            if (!leafTask.isLeafTaskFragment()) {
                final ActivityRecord top = topRunningActivity();
                final ActivityRecord resumedActivity = leafTask.getResumedActivity();
                if (resumedActivity != null && top.getTaskFragment() != leafTask) {
                    // Pausing the resumed activity because it is occluded by other task fragment.
                    if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
            if (leafTask.pauseActivityIfNeeded(resuming, "pauseBackTasks")) {
                someActivityPaused[0]++;
            }
                }
            }

            leafTask.forAllLeafTaskFragments((taskFrag) -> {
                final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
                if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                    if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
                        someActivityPaused[0]++;
                    }
                }
            }, true /* traverseTopToBottom */);
        }, true /* traverseTopToBottom */);
        return someActivityPaused[0] > 0;
    }