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

Commit c48a7ca8 authored by Louis Chang's avatar Louis Chang
Browse files

Ensure next invisible activity can be resumed while finishing top

The top activity was added to finishing list and set the next top
activity to resume while the top activity finished itself during
screen off. However, the next top activity was not resumed since it
was on another task and it was the last paused activity of the task.

Clear the last paused activity while focused task changed during
sleeping.

Also fixes RWC#resumeFocusedStacksTopActivities() not returning true
while activities resumed.

Bug: 172189606
Test: atest ActivityRecordTests
Test: finish top activity while screen off
Change-Id: I14b6e48f6f1d8c30716f9838c8a19a11815f8975
parent 571c3ba5
Loading
Loading
Loading
Loading
+26 −12
Original line number Diff line number Diff line
@@ -2761,19 +2761,33 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // than destroy immediately.
        final boolean isNextNotYetVisible = next != null
                && (!next.nowVisible || !next.mVisibleRequested);
        if (isCurrentVisible && isNextNotYetVisible) {

        // Clear last paused activity to ensure top activity can be resumed during sleeping.
        if (isNextNotYetVisible && mDisplayContent.isSleeping()
                && next == next.getRootTask().mLastPausedActivity) {
            next.getRootTask().mLastPausedActivity = null;
        }

        if (isCurrentVisible) {
            if (isNextNotYetVisible) {
                // Add this activity to the list of stopping activities. It will be processed and
                // destroyed when the next activity reports idle.
                addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
                        "completeFinishing");
                setState(STOPPING, "completeFinishing");
            } else if (addToFinishingAndWaitForIdle()) {
            // We added this activity to the finishing list and something else is becoming resumed.
            // The activity will complete finishing when the next activity reports idle. No need to
            // do anything else here.
                // We added this activity to the finishing list and something else is becoming
                // resumed. The activity will complete finishing when the next activity reports
                // idle. No need to do anything else here.
            } else {
            // Not waiting for the next one to become visible, and nothing else will be resumed in
            // place of this activity - requesting destruction right away.
                // Not waiting for the next one to become visible, and nothing else will be
                // resumed in place of this activity - requesting destruction right away.
                activityRemoved = destroyIfPossible(reason);
            }
        } else {
            // Just need to make sure the next activities can be resumed (if needed) and is free
            // to destroy this activity since it is currently not visible.
            addToFinishingAndWaitForIdle();
            activityRemoved = destroyIfPossible(reason);
        }

+1 −0
Original line number Diff line number Diff line
@@ -2377,6 +2377,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                        }
                        return resumed;
                    }, false /* initValue */);
            result |= resumedOnDisplay;
            if (!resumedOnDisplay) {
                // In cases when there are no valid activities (e.g. device just booted or launcher
                // crashed) it's possible that nothing was resumed on a display. Requesting resume
+6 −0
Original line number Diff line number Diff line
@@ -1189,6 +1189,12 @@ final class TaskDisplayArea extends DisplayArea<Task> {
            return;
        }

        // Clear last paused activity if focused root task changed while sleeping, so that the
        // top activity of current focused task can be resumed.
        if (mDisplayContent.isSleeping()) {
            currentFocusedTask.mLastPausedActivity = null;
        }

        mLastFocusedStack = prevFocusedTask;
        EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
                mDisplayContent.mDisplayId,
+31 −4
Original line number Diff line number Diff line
@@ -1019,6 +1019,32 @@ public class ActivityRecordTests extends WindowTestsBase {
        verify(topActivity, never()).destroyIfPossible(anyString());
    }

    /**
     * Verify that complete finish request for top invisible activity must not be delayed while
     * sleeping, but next invisible activity must be resumed (and paused/stopped)
     */
    @Test
    public void testCompleteFinishing_noWaitForNextVisible_sleeping() {
        // Create a top activity on a new task
        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
        mDisplayContent.setIsSleeping(true);
        doReturn(true).when(mActivity).shouldBeVisible();
        topActivity.mVisibleRequested = false;
        topActivity.nowVisible = false;
        topActivity.finishing = true;
        topActivity.setState(STOPPED, "true");

        // Mark the activity behind (on a separate task) as not visible
        mActivity.mVisibleRequested = false;
        mActivity.nowVisible = false;
        mActivity.setState(STOPPED, "test");

        clearInvocations(mActivity);
        topActivity.completeFinishing("test");
        verify(mActivity).setState(eq(RESUMED), any());
        verify(topActivity).destroyIfPossible(anyString());
    }

    /**
     * Verify that complete finish request for invisible activity must not be delayed.
     */
@@ -1231,12 +1257,13 @@ public class ActivityRecordTests extends WindowTestsBase {
     */
    @Test
    public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
        // Empty the home stack.
        final Task homeStack = mActivity.getDisplayArea().getRootHomeTask();
        homeStack.forAllLeafTasks((t) -> {
            homeStack.removeChild(t, "test");
        // Empty the home root task.
        final Task homeRootTask = mActivity.getDisplayArea().getRootHomeTask();
        homeRootTask.forAllLeafTasks((t) -> {
            homeRootTask.removeChild(t, "test");
        }, true /* traverseTopToBottom */);
        mActivity.finishing = true;
        mActivity.mVisibleRequested = true;
        spyOn(mStack);

        // Try to finish the last activity above the home stack.