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

Commit 1e7ba58e authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Fix focused stack adjustment when finishing top activity

Since commit f2835df0, a stack won't be visible if it doesn't
contain running activity. So when checking if the stack order
needs to be adjusted after the top activity is set as finishing,
the adjustment will be skipped by invisible stack. It is resolved
by checking before the activity becomes finishing.

Also remove the activity focus adjustment in stopActivityLocked
because the original condition should be never satisfied: only
adjust for resumed activity in top focused stack. That doesn't
seem to be the condition for an activity that can be stopped.
So the adjustment logic becomes simpler to be inlined.

Bug: 138519583
Test: atest ActivityRecordTests#testFinishActivityIfPossible_adjustStackOrder

Change-Id: I0a0edc3f28acc4eb435dbbf2c71ab6119b155c39
parent 95f50d6e
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -1699,6 +1699,12 @@ final class ActivityRecord extends ConfigurationContainer {
            return FINISH_RESULT_CANCELLED;
        }

        final ActivityStack stack = getActivityStack();
        final boolean mayAdjustFocus = (isState(RESUMED) || stack.mResumedActivity == null)
                // It must be checked before {@link #makeFinishingLocked} is called, because a stack
                // is not visible if it only contains finishing activities.
                && mRootActivityContainer.isTopDisplayFocusedStack(stack);

        mAtmService.mWindowManager.deferSurfaceLayout();
        try {
            makeFinishingLocked();
@@ -1720,8 +1726,12 @@ final class ActivityRecord extends ConfigurationContainer {

            pauseKeyDispatchingLocked();

            final ActivityStack stack = getActivityStack();
            stack.adjustFocusedActivityStack(this, "finishIfPossible");
            // We are finishing the top focused activity and its stack has nothing to be focused so
            // the next focusable stack should be focused.
            if (mayAdjustFocus
                    && (stack.topRunningActivityLocked() == null || !stack.isFocusable())) {
                stack.adjustFocusToNextFocusableStack("finish-top");
            }

            finishActivityResults(resultCode, resultData);

@@ -3012,7 +3022,6 @@ final class ActivityRecord extends ConfigurationContainer {
                    if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + this);
                    if (finishIfPossible("stop-no-history", false /* oomAdj */)
                            != FINISH_RESULT_CANCELLED) {
                        // {@link adjustFocusedActivityStack} must have been already called.
                        resumeKeyDispatchingLocked();
                        return;
                    }
@@ -3028,7 +3037,6 @@ final class ActivityRecord extends ConfigurationContainer {
        if (!attachedToProcess()) {
            return;
        }
        stack.adjustFocusedActivityStack(this, "stopActivity");
        resumeKeyDispatchingLocked();
        try {
            stopped = false;
+4 −44
Original line number Diff line number Diff line
@@ -3542,50 +3542,6 @@ class ActivityStack extends ConfigurationContainer {
        return taskTop;
    }

    void adjustFocusedActivityStack(ActivityRecord r, String reason) {
        if (!mRootActivityContainer.isTopDisplayFocusedStack(this) ||
                ((mResumedActivity != r) && (mResumedActivity != null))) {
            return;
        }

        final ActivityRecord next = topRunningActivityLocked();
        final String myReason = reason + " adjustFocus";

        if (next == r) {
            final ActivityRecord top = mRootActivityContainer.topRunningActivity();
            if (top != null) {
                top.moveFocusableActivityToTop(myReason);
            }
            return;
        }

        if (next != null && isFocusable()) {
            // Keep focus in stack if we have a top running activity and are focusable.
            return;
        }

        // Task is not guaranteed to be non-null. For example, destroying the
        // {@link ActivityRecord} will disassociate the task from the activity.
        final TaskRecord task = r.getTaskRecord();

        if (task == null) {
            throw new IllegalStateException("activity no longer associated with task:" + r);
        }

        // Move focus to next focusable stack if possible.
        final ActivityStack nextFocusableStack = adjustFocusToNextFocusableStack(myReason);
        if (nextFocusableStack != null) {
            final ActivityRecord top = nextFocusableStack.topRunningActivityLocked();
            if (top != null && top == mRootActivityContainer.getTopResumedActivity()) {
                mService.setResumedActivityUncheckLocked(top, reason);
            }
            return;
        }

        // Whatever...go home.
        getDisplay().moveHomeActivityToTop(myReason);
    }

    /**
     * Find next proper focusable stack and make it focused.
     * @return The stack that now got the focus, {@code null} if none found.
@@ -3620,6 +3576,10 @@ class ActivityStack extends ConfigurationContainer {
        // Top display focused stack is changed, update top resumed activity if needed.
        if (stack.mResumedActivity != null) {
            mStackSupervisor.updateTopResumedActivityIfNeeded();
            // Set focused app directly because if the next focused activity is already resumed
            // (e.g. the next top activity is on a different display), there won't have activity
            // state change to update it.
            mService.setResumedActivityUncheckLocked(stack.mResumedActivity, reason);
        }
        return stack;
    }
+26 −0
Original line number Diff line number Diff line
@@ -797,6 +797,32 @@ public class ActivityRecordTests extends ActivityTestsBase {
        assertFalse(mActivity.isInStackLocked());
    }

    /**
     * Verify that when finishing the top focused activity on top display, the stack order will be
     * changed by adjusting focus.
     */
    @Test
    public void testFinishActivityIfPossible_adjustStackOrder() {
        // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
        final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
        mStack.moveToFront("test");
        // The stack2 is needed here for moving back to simulate the
        // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
        // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
        // stacks. Then when mActivity is finishing, its stack will be invisible (no running
        // activities in the stack) that is the key condition to verify.
        final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
        stack2.moveToBack("test", stack2.getChildAt(0));

        assertTrue(mStack.isTopStackOnDisplay());

        mActivity.setState(RESUMED, "test");
        mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
                false /* oomAdj */, false /* pauseImmediately */);

        assertTrue(stack1.isTopStackOnDisplay());
    }

    /**
     * Verify that resumed activity is paused due to finish request.
     */