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

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

Set activity state to STARTED when making visible from STOPPED

An invisible activity state was set to PAUSED from STOPPING or STOPPED
when making it visible. Since the client’s lifecycle was transit to
onStart, the client-server state were inconsistent.

Adding a new STARTED state in order to have consistency with client state.

Bug: 135495279
Test: ActivityRecordTests
Test: ActivityVisibilityTests
Test: ActivityLifecycleTests

Change-Id: I887740312de8f8580c58cde36e0f5137365b607c
parent 9fd72003
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESTARTING_PROCESS;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStack.LAUNCH_TICK;
@@ -1924,6 +1925,15 @@ final class ActivityRecord extends ConfigurationContainer {
        return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
    }

    /**
     * Returns {@code true} if the Activity is in one of the specified states.
     */
    boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
            ActivityState state4, ActivityState state5) {
        return state1 == mState || state2 == mState || state3 == mState || state4 == mState
                || state5 == mState;
    }

    void notifyAppResumed(boolean wasStopped) {
        if (mAppWindowToken == null) {
            Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: "
@@ -2039,12 +2049,10 @@ final class ActivityRecord extends ConfigurationContainer {
            mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                    WindowVisibilityItem.obtain(true /* showWindow */));
            makeActiveIfNeeded(null /* activeActivity*/);
            if (isState(STOPPING, STOPPED) && isFocusable()) {
                // #shouldMakeActive() only evaluates the topmost activities in task, so
                // activities that are not the topmost in task are not being resumed or paused.
                // For activities that are still in STOPPING or STOPPED state, updates the state
                // to PAUSE at least when making it visible.
                setState(PAUSED, "makeClientVisible");
            if (isState(STOPPING, STOPPED)) {
                // Set state to STARTED in order to have consistent state with client while
                // making an non-active activity visible from stopped.
                setState(STARTED, "makeClientVisible");
            }
        } catch (Exception e) {
            Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
@@ -2120,7 +2128,7 @@ final class ActivityRecord extends ConfigurationContainer {
        // calls will lead to noticeable jank. A later call to
        // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper
        // active state.
        if (!isState(RESUMED, PAUSED, STOPPED, STOPPING)
        if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING)
                || getActivityStack().mTranslucentActivityWaiting != null) {
            return false;
        }
@@ -2648,7 +2656,7 @@ final class ActivityRecord extends ConfigurationContainer {
                compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
                allowTaskSnapshot(),
                mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
                mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
                fromRecents);
        if (shown) {
            mStartingWindowState = STARTING_WINDOW_SHOWN;
+6 −2
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
@@ -292,6 +293,7 @@ class ActivityStack extends ConfigurationContainer {

    enum ActivityState {
        INITIALIZING,
        STARTED,
        RESUMED,
        PAUSING,
        PAUSED,
@@ -1609,7 +1611,7 @@ class ActivityStack extends ConfigurationContainer {
            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                final ActivityRecord r = activities.get(activityNdx);
                if (r.isState(STOPPING, STOPPED, PAUSED, PAUSING)) {
                if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
                    r.setSleeping(true);
                }
            }
@@ -2437,6 +2439,7 @@ class ActivityStack extends ConfigurationContainer {
                case RESUMED:
                case PAUSING:
                case PAUSED:
                case STARTED:
                    addToStopping(r, true /* scheduleIdle */,
                            canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
                    break;
@@ -3873,7 +3876,7 @@ class ActivityStack extends ConfigurationContainer {
        }
        if (activityNdx >= 0) {
            r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
            if (r.isState(RESUMED, PAUSING, PAUSED)) {
            if (r.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
                if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
                    Slog.w(TAG, "  Force finishing activity "
                            + r.intent.getComponent().flattenToShortString());
@@ -4137,6 +4140,7 @@ class ActivityStack extends ConfigurationContainer {
                || (prevState == PAUSED
                    && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
                || finishingInNonFocusedStackOrNoRunning
                || prevState == STARTED
                || prevState == STOPPING
                || prevState == STOPPED
                || prevState == ActivityState.INITIALIZING) {
+3 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
@@ -731,10 +732,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
                return null;
            }
            // Don't consider any activies that are currently not in a state where they
            // Don't consider any activities that are currently not in a state where they
            // can be destroyed.
            if (r.visible || !r.stopped || !r.haveState
                    || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
                    || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
                continue;
            }
+9 −3
Original line number Diff line number Diff line
@@ -31,9 +31,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
@@ -166,7 +166,13 @@ public class ActivityRecordTests extends ActivityTestsBase {
        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
        mStack.mTranslucentActivityWaiting = topActivity;
        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
        assertTrue(mActivity.isState(PAUSED));
        assertTrue(mActivity.isState(STARTED));

        mStack.mTranslucentActivityWaiting = null;
        topActivity.changeWindowTranslucency(false);
        mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
        assertTrue(mActivity.isState(STARTED));
    }

    private void ensureActivityConfiguration() {
@@ -442,7 +448,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
        topActivity.changeWindowTranslucency(false);
        mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
        mActivity.makeClientVisible();
        assertEquals(PAUSED, mActivity.getState());
        assertEquals(STARTED, mActivity.getState());
    }

    @Test