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

Commit 26058dc2 authored by Andrii Kulian's avatar Andrii Kulian Committed by Android (Google) Code Review
Browse files

Merge "Multiple resumed activities"

parents 4073dc0b 5bca8b8c
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -558,22 +558,26 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
    }

    /**
     * Pause all activities in either all of the stacks or just the back stacks.
     * Pause all activities in either all of the stacks or just the back stacks. This is done before
     * resuming a new activity and to make sure that previously active activities are
     * paused in stacks that are no longer visible or in pinned windowing mode. This does not
     * pause activities in visible stacks, so if an activity is launched within the same stack/task,
     * then we should explicitly pause that stack's top activity.
     * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
     * @param resuming The resuming activity.
     * @param dontWait The resuming activity isn't going to wait for all activities to be paused
     *                 before resuming.
     * @return true if any activity was paused as a result of this call.
     * @return {@code true} if any activity was paused as a result of this call.
     */
    boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
        boolean someActivityPaused = false;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            // TODO(b/111541062): Check if resumed activity on this display instead
            if (!mRootActivityContainer.isTopDisplayFocusedStack(stack)
                    && stack.getResumedActivity() != null) {
            final ActivityRecord resumedActivity = stack.getResumedActivity();
            if (resumedActivity != null
                    && (!stack.shouldBeVisible(resuming) || !stack.isFocusable())) {
                if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                        " mResumedActivity=" + stack.getResumedActivity());
                        " mResumedActivity=" + resumedActivity);
                someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                        dontWait);
            }
+72 −18
Original line number Diff line number Diff line
@@ -1946,30 +1946,84 @@ final class ActivityRecord extends ConfigurationContainer {
        try {
            mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                    WindowVisibilityItem.obtain(true /* showWindow */));
            if (shouldPauseWhenBecomingVisible()) {
            makeActiveIfNeeded(null /* activeActivity*/);
        } catch (Exception e) {
            Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
        }
    }

    /**
     * Make activity resumed or paused if needed.
     * @param activeActivity an activity that is resumed or just completed pause action.
     *                       We won't change the state of this activity.
     */
    boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
        if (shouldResumeActivity(activeActivity)) {
            if (DEBUG_VISIBILITY) {
                Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this);
            }
            return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
                    null /* options */);
        } else if (shouldPauseActivity(activeActivity)) {
            if (DEBUG_VISIBILITY) {
                Slog.v("TAG_VISIBILITY", "Pause visible activity, " + this);
            }
            // An activity must be in the {@link PAUSING} state for the system to validate
            // the move to {@link PAUSED}.
            setState(PAUSING, "makeVisibleIfNeeded");
            try {
                mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                        PauseActivityItem.obtain(finishing, false /* userLeaving */,
                                configChangeFlags, false /* dontReport */));
            }
            } catch (Exception e) {
            Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
                Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
            }
        }
        return false;
    }

    /** Check if activity should be moved to PAUSED state when it becomes visible. */
    private boolean shouldPauseWhenBecomingVisible() {
        // If the activity is stopped or stopping, cycle to the paused state. We avoid doing
    /**
     * Check if activity should be moved to PAUSED state. The activity:
     * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
     * - should be non-focusable
     * - should not be currently pausing or paused
     * @param activeActivity the activity that is active or just completed pause action. We won't
     *                       resume if this activity is active.
     */
    private boolean shouldPauseActivity(ActivityRecord activeActivity) {
        return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED);
    }

    /**
     * Check if activity should be moved to RESUMED state. The activity:
     * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
     * - should be focusable
     * @param activeActivity the activity that is active or just completed pause action. We won't
     *                       resume if this activity is active.
     */
    private boolean shouldResumeActivity(ActivityRecord activeActivity) {
        return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED);
    }

    /**
     * Check if activity is eligible to be made active (resumed of paused). The activity:
     * - should be paused, stopped or stopping
     * - should not be the currently active one
     * - should be either the topmost in task, or right below the top activity that is finishing
     * If all of these conditions are not met at the same time, the activity cannot be made active.
     */
    private boolean shouldMakeActive(ActivityRecord activeActivity) {
        // If the activity is stopped, stopping, cycle to an active state. We avoid doing
        // this when there is an activity waiting to become translucent as the extra binder
        // calls will lead to noticeable jank. A later call to
        // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper
        // paused state. We also avoid doing this for the activity the stack supervisor
        // considers the resumed activity, as normal means will bring the activity from STOPPED
        // to RESUMED. Adding PAUSING in this scenario will lead to double lifecycles.
        if (!isState(STOPPED, STOPPING) || getActivityStack().mTranslucentActivityWaiting != null
                || isResumedActivityOnDisplay()) {
        // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper
        // active state.
        if (!isState(RESUMED, PAUSED, STOPPED, STOPPING)
                || getActivityStack().mTranslucentActivityWaiting != null) {
            return false;
        }

        if (this == activeActivity) {
            return false;
        }

@@ -1979,14 +2033,14 @@ final class ActivityRecord extends ConfigurationContainer {
            throw new IllegalStateException("Activity not found in its task");
        }
        if (positionInTask == task.mActivities.size() - 1) {
            // It's the topmost activity in the task - should become paused now
            // It's the topmost activity in the task - should become resumed now
            return true;
        }
        // Check if activity above is finishing now and this one becomes the topmost in task.
        final ActivityRecord activityAbove = task.mActivities.get(positionInTask + 1);
        if (activityAbove.finishing && results == null) {
            // We will only allow pausing if activity above wasn't launched for result. Otherwise it
            // will cause this activity to resume before getting result.
            // We will only allow making active if activity above wasn't launched for result.
            // Otherwise it will cause this activity to resume before getting result.
            return true;
        }
        return false;
+31 −8
Original line number Diff line number Diff line
@@ -357,6 +357,11 @@ class ActivityStack extends ConfigurationContainer {
     */
    boolean mForceHidden = false;

    /**
     * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively
     */
    boolean mInResumeTopActivity = false;

    private boolean mUpdateBoundsDeferred;
    private boolean mUpdateBoundsDeferredCalled;
    private boolean mUpdateDisplayedBoundsDeferredCalled;
@@ -1732,6 +1737,7 @@ class ActivityStack extends ConfigurationContainer {
            "Activity paused: token=" + token + ", timeout=" + timeout);

        final ActivityRecord r = isInStackLocked(token);

        if (r != null) {
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
@@ -2088,8 +2094,7 @@ class ActivityStack extends ConfigurationContainer {
            boolean aboveTop = top != null;
            final boolean stackShouldBeVisible = shouldBeVisible(starting);
            boolean behindFullscreenActivity = !stackShouldBeVisible;
            boolean resumeNextActivity = mRootActivityContainer.isTopDisplayFocusedStack(this)
                    && (isInStackLocked(starting) == null);
            boolean resumeNextActivity = isFocusable() && isInStackLocked(starting) == null;
            final boolean isTopNotPinnedStack =
                    isAttached() && getDisplay().isTopNotPinnedStack(this);
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -2150,6 +2155,10 @@ class ActivityStack extends ConfigurationContainer {
                            if (r.handleAlreadyVisible()) {
                                resumeNextActivity = false;
                            }

                            if (notifyClients) {
                                r.makeActiveIfNeeded(starting);
                            }
                        } else {
                            r.makeVisibleIfNeeded(starting, notifyClients);
                        }
@@ -2327,7 +2336,7 @@ class ActivityStack extends ConfigurationContainer {
                r.setVisible(true);
            }
            if (r != starting) {
                mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
                mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
                return true;
            }
        }
@@ -2505,7 +2514,7 @@ class ActivityStack extends ConfigurationContainer {
     */
    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }
@@ -2513,7 +2522,7 @@ class ActivityStack extends ConfigurationContainer {
        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            mInResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);

            // When resuming the top activity, it may be necessary to pause the top activity (for
@@ -2528,7 +2537,7 @@ class ActivityStack extends ConfigurationContainer {
                checkReadyForSleep();
            }
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
            mInResumeTopActivity = false;
        }

        return result;
@@ -2561,7 +2570,7 @@ class ActivityStack extends ConfigurationContainer {
        // Find the next top-most activity to resume in this stack that is not finishing and is
        // focusable. If it is not focusable, we will fall into the case below to resume the
        // top activity in the next focusable task.
        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);

        final boolean hasRunningActivity = next != null;

@@ -2649,6 +2658,12 @@ class ActivityStack extends ConfigurationContainer {
        if (!mRootActivityContainer.allPausedActivitiesComplete()) {
            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                    "resumeTopActivityLocked: Skip resume: some activity pausing.");

            // Adding previous activity to the waiting visible list, or it would be stopped
            // before top activity being visible.
            if (prev != null && !next.nowVisible) {
                mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
            }
            return false;
        }

@@ -2858,7 +2873,9 @@ class ActivityStack extends ConfigurationContainer {
            // the screen based on the new activity order.
            boolean notUpdated = true;

            if (isFocusedStackOnDisplay()) {
            // Activity should also be visible if set mLaunchTaskBehind to true (see
            // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
            if (shouldBeVisible(next)) {
                // We have special rotation behavior when here is some active activity that
                // requests specific orientation or Keyguard is locked. Make sure all activity
                // visibilities are set correctly as well as the transition is updated if needed
@@ -4087,6 +4104,12 @@ class ActivityStack extends ConfigurationContainer {
        mStackSupervisor.mFinishingActivities.add(r);
        r.resumeKeyDispatchingLocked();
        mRootActivityContainer.resumeFocusedStacksTopActivities();
        // If activity was not paused at this point - explicitly pause it to start finishing
        // process. Finishing will be completed once it reports pause back.
        if (r.isState(RESUMED) && mPausingActivity != null) {
            startPausingLocked(false /* userLeaving */, false /* uiSleeping */, next /* resuming */,
                    false /* dontWait */);
        }
        return r;
    }

+0 −3
Original line number Diff line number Diff line
@@ -327,9 +327,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
     */
    PowerManager.WakeLock mGoingToSleep;

    /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
    boolean inResumeTopActivity;

    /**
     * Temporary rect used during docked stack resize calculation so we don't need to create a new
     * object each time.
+4 −1
Original line number Diff line number Diff line
@@ -179,7 +179,10 @@ public class ActivityStartController {
                .setActivityOptions(options.toBundle())
                .execute();
        mLastHomeActivityStartRecord = tmpOutRecord[0];
        if (mSupervisor.inResumeTopActivity) {
        final ActivityDisplay display =
                mService.mRootActivityContainer.getActivityDisplay(displayId);
        final ActivityStack homeStack = display != null ? display.getHomeStack() : null;
        if (homeStack != null && homeStack.mInResumeTopActivity) {
            // If we are in resume section already, home activity will be initialized, but not
            // resumed (to avoid recursive resume) and will stay that way until something pokes it
            // again. We need to schedule another resume.
Loading