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

Commit b9faa03b authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Use START/STOP messages to update visibility

Activity visibility messages simply move the activity to STOPPED or
STARTED state. We can use the lifecycle messages to do the same and
simplify the logic/remove duplicated code.

This CL also removes the option to send STOP message without making
the client invisible and actually calling onStop(). This option
caused a mismatch of the state between server (STOPPED) and client
(PAUSED). Also, in cases when the device was going to sleep, STOP
message was always followed by SLEEP message, which called onStop()
anyway.

Bug: 137329632
Bug: 129750406
Test: AM/WM CTS and unit tests
Change-Id: I487575520ce301bb2f65519f0c0a30b6b9edac0c
parent 9e87abdc
Loading
Loading
Loading
Loading
+17 −49
Original line number Diff line number Diff line
@@ -3349,8 +3349,8 @@ public final class ActivityThread extends ClientTransactionHandler {
    }

    @Override
    public void handleStartActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions) {
    public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) {
        final ActivityClientRecord r = mActivities.get(token);
        final Activity activity = r.activity;
        if (r.activity == null) {
            // TODO(lifecycler): What do we do in this case?
@@ -3364,6 +3364,8 @@ public final class ActivityThread extends ClientTransactionHandler {
            return;
        }

        unscheduleGcIdler();

        // Start
        activity.performStart("handleStartActivity");
        r.setState(ON_START);
@@ -3400,6 +3402,9 @@ public final class ActivityThread extends ClientTransactionHandler {
                                + " did not call through to super.onPostCreate()");
            }
        }

        updateVisibility(r, true /* show */);
        mSomeActivitiesChanged = true;
    }

    /**
@@ -4660,8 +4665,8 @@ public final class ActivityThread extends ClientTransactionHandler {
    @UnsupportedAppUsage
    final void performStopActivity(IBinder token, boolean saveState, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        performStopActivityInner(r, null /* stopInfo */, false /* keepShown */, saveState,
                false /* finalStateRequest */, reason);
        performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */,
                reason);
    }

    private static final class ProviderRefCount {
@@ -4687,25 +4692,19 @@ public final class ActivityThread extends ClientTransactionHandler {
    }

    /**
     * Core implementation of stopping an activity.  Note this is a little
     * tricky because the server's meaning of stop is slightly different
     * than our client -- for the server, stop means to save state and give
     * it the result when it is done, but the window may still be visible.
     * For the client, we want to call onStop()/onStart() to indicate when
     * the activity's UI visibility changes.
     * Core implementation of stopping an activity.
     * @param r Target activity client record.
     * @param info Action that will report activity stop to server.
     * @param keepShown Flag indicating whether the activity is still shown.
     * @param saveState Flag indicating whether the activity state should be saved.
     * @param finalStateRequest Flag indicating if this call is handling final lifecycle state
     *                          request for a transaction.
     * @param reason Reason for performing this operation.
     */
    private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
    private void performStopActivityInner(ActivityClientRecord r, StopInfo info,
            boolean saveState, boolean finalStateRequest, String reason) {
        if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
        if (r != null) {
            if (!keepShown && r.stopped) {
            if (r.stopped) {
                if (r.activity.mFinished) {
                    // If we are finishing, we won't call onResume() in certain
                    // cases.  So here we likewise don't want to call onStop()
@@ -4740,11 +4739,9 @@ public final class ActivityThread extends ClientTransactionHandler {
                }
            }

            if (!keepShown) {
            callActivityOnStop(r, saveState, reason);
        }
    }
    }

    /**
     * Calls {@link Activity#onStop()} and {@link Activity#onSaveInstanceState(Bundle)}, and updates
@@ -4810,20 +4807,19 @@ public final class ActivityThread extends ClientTransactionHandler {
    }

    @Override
    public void handleStopActivity(IBinder token, boolean show, int configChanges,
    public void handleStopActivity(IBinder token, int configChanges,
            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
        final ActivityClientRecord r = mActivities.get(token);
        r.activity.mConfigChangeFlags |= configChanges;

        final StopInfo stopInfo = new StopInfo();
        performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
        performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest,
                reason);

        if (localLOGV) Slog.v(
            TAG, "Finishing stop of " + r + ": show=" + show
            + " win=" + r.window);
            TAG, "Finishing stop of " + r + ": win=" + r.window);

        updateVisibility(r, show);
        updateVisibility(r, false);

        // Make sure any pending writes are now committed.
        if (!r.isPreHoneycomb()) {
@@ -4859,34 +4855,6 @@ public final class ActivityThread extends ClientTransactionHandler {
        }
    }

    @Override
    public void handleWindowVisibility(IBinder token, boolean show) {
        ActivityClientRecord r = mActivities.get(token);

        if (r == null) {
            Log.w(TAG, "handleWindowVisibility: no activity for token " + token);
            return;
        }

        if (!show && !r.stopped) {
            performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */,
                    false /* finalStateRequest */, "handleWindowVisibility");
        } else if (show && r.getLifecycleState() == ON_STOP) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();

            r.activity.performRestart(true /* start */, "handleWindowVisibility");
            r.setState(ON_START);
        }
        if (r.activity.mDecor != null) {
            if (false) Slog.v(
                TAG, "Handle window " + r + " visibility: " + show);
            updateVisibility(r, show);
        }
        mSomeActivitiesChanged = true;
    }

    // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to
    // stop operation on the activity to reduce code duplication and the chance of fixing a bug in
    // one place and missing the other.
+2 −6
Original line number Diff line number Diff line
@@ -119,7 +119,6 @@ public abstract class ClientTransactionHandler {
    /**
     * Stop the activity.
     * @param token Target activity token.
     * @param show Flag indicating whether activity is still shown.
     * @param configChanges Activity configuration changes.
     * @param pendingActions Pending actions to be used on this or later stages of activity
     *                       transaction.
@@ -127,7 +126,7 @@ public abstract class ClientTransactionHandler {
     *                          request for a transaction.
     * @param reason Reason for performing this operation.
     */
    public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
    public abstract void handleStopActivity(IBinder token, int configChanges,
            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);

    /** Report that activity was stopped to server. */
@@ -161,15 +160,12 @@ public abstract class ClientTransactionHandler {
    /** Request that an activity enter picture-in-picture. */
    public abstract void handlePictureInPictureRequested(IBinder token);

    /** Update window visibility. */
    public abstract void handleWindowVisibility(IBinder token, boolean show);

    /** Perform activity launch. */
    public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent);

    /** Perform activity start. */
    public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r,
    public abstract void handleStartActivity(IBinder token,
            PendingTransactionActions pendingActions);

    /** Get package info. */
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ public class LocalActivityManager {
                pendingActions = null;
            }

            mActivityThread.handleStartActivity(clientRecord, pendingActions);
            mActivityThread.handleStartActivity(r, pendingActions);
            r.curState = STARTED;
            
            if (desiredState == RESUMED) {
+32 −29
Original line number Diff line number Diff line
/*
 * Copyright 2017 The Android Open Source Project
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -24,41 +24,44 @@ import android.os.Parcel;
import android.os.Trace;

/**
 * Window visibility change message.
 * Request to move an activity to started and visible state.
 * @hide
 */
public class WindowVisibilityItem extends ClientTransactionItem {
public class StartActivityItem extends ActivityLifecycleItem {

    private boolean mShowWindow;
    private static final String TAG = "StartActivityItem";

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
                mShowWindow ? "activityShowWindow" : "activityHideWindow");
        client.handleWindowVisibility(token, mShowWindow);
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem");
        client.handleStartActivity(token, pendingActions);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

    @Override
    public int getTargetState() {
        return ON_START;
    }


    // ObjectPoolItem implementation

    private WindowVisibilityItem() {}
    private StartActivityItem() {}

    /** Obtain an instance initialized with provided params. */
    public static WindowVisibilityItem obtain(boolean showWindow) {
        WindowVisibilityItem instance = ObjectPool.obtain(WindowVisibilityItem.class);
    public static StartActivityItem obtain() {
        StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class);
        if (instance == null) {
            instance = new WindowVisibilityItem();
            instance = new StartActivityItem();
        }
        instance.mShowWindow = showWindow;

        return instance;
    }

    @Override
    public void recycle() {
        mShowWindow = false;
        super.recycle();
        ObjectPool.recycle(this);
    }

@@ -68,22 +71,22 @@ public class WindowVisibilityItem extends ClientTransactionItem {
    /** Write to Parcel. */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBoolean(mShowWindow);
        // Empty
    }

    /** Read from Parcel. */
    private WindowVisibilityItem(Parcel in) {
        mShowWindow = in.readBoolean();
    private StartActivityItem(Parcel in) {
        // Empty
    }

    public static final @android.annotation.NonNull Creator<WindowVisibilityItem> CREATOR =
            new Creator<WindowVisibilityItem>() {
        public WindowVisibilityItem createFromParcel(Parcel in) {
            return new WindowVisibilityItem(in);
    public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR =
            new Creator<StartActivityItem>() {
                public StartActivityItem createFromParcel(Parcel in) {
                    return new StartActivityItem(in);
                }

        public WindowVisibilityItem[] newArray(int size) {
            return new WindowVisibilityItem[size];
                public StartActivityItem[] newArray(int size) {
                    return new StartActivityItem[size];
                }
            };

@@ -95,17 +98,17 @@ public class WindowVisibilityItem extends ClientTransactionItem {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final WindowVisibilityItem other = (WindowVisibilityItem) o;
        return mShowWindow == other.mShowWindow;
        return true;
    }

    @Override
    public int hashCode() {
        return 17 + 31 * (mShowWindow ? 1 : 0);
        return 17;
    }

    @Override
    public String toString() {
        return "WindowVisibilityItem{showWindow=" + mShowWindow + "}";
        return "StartActivityItem{}";
    }
}
+8 −12
Original line number Diff line number Diff line
@@ -31,14 +31,13 @@ public class StopActivityItem extends ActivityLifecycleItem {

    private static final String TAG = "StopActivityItem";

    private boolean mShowWindow;
    private int mConfigChanges;

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
        client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
        client.handleStopActivity(token, mConfigChanges, pendingActions,
                true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
@@ -59,13 +58,15 @@ public class StopActivityItem extends ActivityLifecycleItem {

    private StopActivityItem() {}

    /** Obtain an instance initialized with provided params. */
    public static StopActivityItem obtain(boolean showWindow, int configChanges) {
    /**
     * Obtain an instance initialized with provided params.
     * @param configChanges Configuration pieces that changed.
     */
    public static StopActivityItem obtain(int configChanges) {
        StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class);
        if (instance == null) {
            instance = new StopActivityItem();
        }
        instance.mShowWindow = showWindow;
        instance.mConfigChanges = configChanges;

        return instance;
@@ -74,7 +75,6 @@ public class StopActivityItem extends ActivityLifecycleItem {
    @Override
    public void recycle() {
        super.recycle();
        mShowWindow = false;
        mConfigChanges = 0;
        ObjectPool.recycle(this);
    }
@@ -85,13 +85,11 @@ public class StopActivityItem extends ActivityLifecycleItem {
    /** Write to Parcel. */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBoolean(mShowWindow);
        dest.writeInt(mConfigChanges);
    }

    /** Read from Parcel. */
    private StopActivityItem(Parcel in) {
        mShowWindow = in.readBoolean();
        mConfigChanges = in.readInt();
    }

@@ -115,20 +113,18 @@ public class StopActivityItem extends ActivityLifecycleItem {
            return false;
        }
        final StopActivityItem other = (StopActivityItem) o;
        return mShowWindow == other.mShowWindow && mConfigChanges == other.mConfigChanges;
        return mConfigChanges == other.mConfigChanges;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + (mShowWindow ? 1 : 0);
        result = 31 * result + mConfigChanges;
        return result;
    }

    @Override
    public String toString() {
        return "StopActivityItem{showWindow=" + mShowWindow + ",configChanges=" + mConfigChanges
                + "}";
        return "StopActivityItem{configChanges=" + mConfigChanges + "}";
    }
}
Loading