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

Commit c49b7a9c authored by Evan Rosky's avatar Evan Rosky
Browse files

Defer pausing apps when bringing up recents

This adds an ActivityOption call "transient launch" which can be
used to tell WM that this particular launch is likely temporary
and may not be committed. This is for recents where it exists
for the duration of the transition, but then disappears once the
user's intention is resolved.

The effect of this is that it won't pause the running app while
in recents -- instead deferring pause until the transition finishes
and the final visibility states are committed.

Bug: 183993884
Test: enable shell transitions, open app, swipe to overview and
      check dumpsys to see that the app is still RESUMED
Change-Id: Iba6b8faf4e42c645bfd0305b93b7e0b542fd2c96
parent 673a8c59
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -327,6 +327,9 @@ public class ActivityOptions {
    private static final String KEY_LAUNCHED_FROM_BUBBLE =
            "android.activity.launchTypeBubble";

    /** See {@link #setTransientLaunch()}. */
    private static final String KEY_TRANSIENT_LAUNCH = "android.activity.transientLaunch";

    /**
     * @see #setLaunchCookie
     * @hide
@@ -414,6 +417,7 @@ public class ActivityOptions {
    private int mSplashScreenThemeResId;
    private boolean mRemoveWithTaskOrganizer;
    private boolean mLaunchedFromBubble;
    private boolean mTransientLaunch;

    /**
     * Create an ActivityOptions specifying a custom animation to run when
@@ -1166,6 +1170,7 @@ public class ActivityOptions {
        mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
        mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
        mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE);
        mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH);
    }

    /**
@@ -1662,6 +1667,28 @@ public class ActivityOptions {
        return mLaunchedFromBubble;
    }

    /**
     * Sets whether the activity launch is part of a transient operation. If it is, it will not
     * cause lifecycle changes in existing activities even if it were to occlude them (ie. other
     * activities occluded by this one will not be paused or stopped until the launch is committed).
     * As a consequence, it will start immediately since it doesn't need to wait for other
     * lifecycles to evolve. Current user is recents.
     * @hide
     */
    public ActivityOptions setTransientLaunch() {
        mTransientLaunch = true;
        return this;
    }

    /**
     * @see #setTransientLaunch()
     * @return whether the activity launch is part of a transient operation.
     * @hide
     */
    public boolean getTransientLaunch() {
        return mTransientLaunch;
    }

    /**
     * Update the current values in this ActivityOptions from those supplied
     * in <var>otherOptions</var>.  Any values
@@ -1902,6 +1929,9 @@ public class ActivityOptions {
        if (mLaunchedFromBubble) {
            b.putBoolean(KEY_LAUNCHED_FROM_BUBBLE, mLaunchedFromBubble);
        }
        if (mTransientLaunch) {
            b.putBoolean(KEY_TRANSIENT_LAUNCH, mTransientLaunch);
        }
        return b;
    }

+5 −2
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ class ActivityStarter {
    private boolean mKeepCurTransition;
    private boolean mAvoidMoveToFront;
    private boolean mFrozeTaskList;
    private boolean mTransientLaunch;

    // We must track when we deliver the new intent since multiple code paths invoke
    // {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -1792,7 +1793,7 @@ class ActivityStarter {
                    mTargetRootTask.moveToFront("startActivityInner");
                }
                mRootWindowContainer.resumeFocusedTasksTopActivities(
                        mTargetRootTask, mStartActivity, mOptions);
                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
            }
        }
        mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
@@ -2209,6 +2210,7 @@ class ActivityStarter {
        mKeepCurTransition = false;
        mAvoidMoveToFront = false;
        mFrozeTaskList = false;
        mTransientLaunch = false;

        mVoiceSession = null;
        mVoiceInteractor = null;
@@ -2311,6 +2313,7 @@ class ActivityStarter {
                mDoResume = false;
                mAvoidMoveToFront = true;
            }
            mTransientLaunch = mOptions.getTransientLaunch();
            mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
        }

@@ -2642,7 +2645,7 @@ class ActivityStarter {
            }
            if (mTargetRootTask.isFocusable()) {
                mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, null,
                        mOptions);
                        mOptions, mTransientLaunch);
            } else {
                mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
            }
+8 −1
Original line number Diff line number Diff line
@@ -2292,7 +2292,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>

    boolean resumeFocusedTasksTopActivities(
            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) {
        return resumeFocusedTasksTopActivities(targetRootTask, target, targetOptions,
                false /* deferPause */);
    }

    boolean resumeFocusedTasksTopActivities(
            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
            boolean deferPause) {
        if (!mTaskSupervisor.readyToResume()) {
            return false;
        }
@@ -2300,7 +2306,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        boolean result = false;
        if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                || getTopDisplayFocusedRootTask() == targetRootTask)) {
            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions);
            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
                    deferPause);
        }

        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
+15 −5
Original line number Diff line number Diff line
@@ -6059,6 +6059,7 @@ class Task extends WindowContainer<WindowContainer> {
     * @param prev The previously resumed activity, for when in the process
     * of pausing; can be null to call from elsewhere.
     * @param options Activity options.
     * @param deferPause When {@code true}, this will not pause back tasks.
     *
     * @return Returns true if something is being resumed, or false if
     * nothing happened.
@@ -6069,7 +6070,8 @@ class Task extends WindowContainer<WindowContainer> {
     *       right activity for the current system state.
     */
    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
@@ -6082,7 +6084,7 @@ class Task extends WindowContainer<WindowContainer> {

            if (isLeafTask()) {
                if (isFocusableAndVisible()) {
                    someActivityResumed = resumeTopActivityInnerLocked(prev, options);
                    someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
                }
            } else {
                int idx = mChildren.size() - 1;
@@ -6095,7 +6097,8 @@ class Task extends WindowContainer<WindowContainer> {
                        break;
                    }

                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options);
                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
                            deferPause);
                    // Doing so in order to prevent IndexOOB since hierarchy might changes while
                    // resuming activities, for example dismissing split-screen while starting
                    // non-resizeable activity.
@@ -6123,8 +6126,15 @@ class Task extends WindowContainer<WindowContainer> {
        return someActivityResumed;
    }

    /** @see #resumeTopActivityUncheckedLocked(ActivityRecord, ActivityOptions, boolean) */
    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        return resumeTopActivityUncheckedLocked(prev, options, false /* skipPause */);
    }

    @GuardedBy("mService")
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
        if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
            // Not ready yet!
            return false;
@@ -6220,7 +6230,7 @@ class Task extends WindowContainer<WindowContainer> {
            lastResumed = lastFocusedRootTask.getResumedActivity();
        }

        boolean pausing = taskDisplayArea.pauseBackTasks(next);
        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
        if (mResumedActivity != null) {
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
            pausing |= startPausingLocked(false /* uiSleeping */, next,
+1 −1
Original line number Diff line number Diff line
@@ -560,7 +560,7 @@ public class RootWindowContainerTests extends WindowTestsBase {

        // Verify the target task should resume its activity.
        verify(rootTask, times(1)).resumeTopActivityUncheckedLocked(
                eq(activity), eq(null /* targetOptions */));
                eq(activity), eq(null /* targetOptions */), eq(false));
    }

    /**