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

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

Merge "Report top resumed activity state change"

parents f8728771 d70cdb93
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3802,6 +3802,7 @@ package android.app {
    method @Deprecated public void onStateNotSaved();
    method @CallSuper protected void onStop();
    method protected void onTitleChanged(CharSequence, int);
    method public void onTopResumedActivityChanged(boolean);
    method public boolean onTouchEvent(android.view.MotionEvent);
    method public boolean onTrackballEvent(android.view.MotionEvent);
    method public void onTrimMemory(int);
+23 −0
Original line number Diff line number Diff line
@@ -1808,6 +1808,29 @@ public class Activity extends ContextThemeWrapper
        mCalled = true;
    }

    /**
     * Called when activity gets or looses the top resumed position in the system.
     *
     * <p>Starting with {@link android.os.Build.VERSION_CODES#Q} multiple activities can be resumed
     * at the same time in multi-window and multi-display modes. This callback should be used
     * instead of {@link #onResume()} as an indication that the activity can try to open
     * exclusive-access devices like camera.</p>
     *
     * <p>It will always be delivered after the activity was resumed and before it is paused. In
     * some cases it might be skipped and activity can go straight from {@link #onResume()} to
     * {@link #onPause()} without receiving the top resumed state.</p>
     *
     * @param isTopResumedActivity {@code true} if it's the topmost resumed activity in the system,
     *                             {@code false} otherwise. A call with this as {@code true} will
     *                             always be followed by another one with {@code false}.
     *
     * @see #onResume()
     * @see #onPause()
     * @see #onWindowFocusChanged(boolean)
     */
    public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
    }

    void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
        if (mVoiceInteractor != null) {
            for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
+56 −5
Original line number Diff line number Diff line
@@ -449,6 +449,14 @@ public final class ActivityThread extends ClientTransactionHandler {
        ViewRootImpl.ActivityConfigCallback configCallback;
        ActivityClientRecord nextIdle;

        // Indicates whether this activity is currently the topmost resumed one in the system.
        // This holds the last reported value from server.
        boolean isTopResumedActivity;
        // This holds the value last sent to the activity. This is needed, because an update from
        // server may come at random time, but we always need to report changes between ON_RESUME
        // and ON_PAUSE to the app.
        boolean lastReportedTopResumedState;

        ProfilerInfo profilerInfo;

        @UnsupportedAppUsage
@@ -3295,16 +3303,14 @@ public final class ActivityThread extends ClientTransactionHandler {
        final boolean resumed = !r.paused;
        if (resumed) {
            r.activity.mTemporaryPause = true;
            mInstrumentation.callActivityOnPause(r.activity);
            performPauseActivityIfNeeded(r, "performNewIntents");
        }
        checkAndBlockForNetworkAccess();
        deliverNewIntents(r, intents);
        if (resumed) {
            r.activity.performResume(false, "performNewIntents");
            performResumeActivity(token, false, "performNewIntents");
            r.activity.mTemporaryPause = false;
        }

        if (r.paused && andPause) {
        } else if (andPause) {
            // In this case the activity was in the paused state when we delivered the intent,
            // to guarantee onResume gets called after onNewIntent we temporarily resume the
            // activity and pause again as the caller wanted.
@@ -3957,6 +3963,8 @@ public final class ActivityThread extends ClientTransactionHandler {
            r.state = null;
            r.persistentState = null;
            r.setState(ON_RESUME);

            reportTopResumedActivityChanged(r, r.isTopResumedActivity);
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException("Unable to resume activity "
@@ -4111,6 +4119,45 @@ public final class ActivityThread extends ClientTransactionHandler {
        Looper.myQueue().addIdleHandler(new Idler());
    }


    @Override
    public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        if (r == null || r.activity == null) {
            Slog.w(TAG, "Not found target activity to report position change for token: " + token);
            return;
        }

        if (DEBUG_ORDER) {
            Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r);
        }

        if (r.isTopResumedActivity == onTop) {
            throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
        }

        r.isTopResumedActivity = onTop;

        if (r.getLifecycleState() == ON_RESUME) {
            reportTopResumedActivityChanged(r, onTop);
        } else {
            if (DEBUG_ORDER) {
                Slog.d(TAG, "Won't deliver top position change in state=" + r.getLifecycleState());
            }
        }
    }

    /**
     * Call {@link Activity#onTopResumedActivityChanged(boolean)} if its top resumed state changed
     * since the last report.
     */
    private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop) {
        if (r.lastReportedTopResumedState != onTop) {
            r.lastReportedTopResumedState = onTop;
            r.activity.onTopResumedActivityChanged(onTop);
        }
    }

    @Override
    public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
            int configChanges, PendingTransactionActions pendingActions, String reason) {
@@ -4202,6 +4249,10 @@ public final class ActivityThread extends ClientTransactionHandler {
            return;
        }

        // Always reporting top resumed position loss when pausing an activity. If necessary, it
        // will be restored in performResumeActivity().
        reportTopResumedActivityChanged(r, false /* onTop */);

        try {
            r.activity.mCalled = false;
            mInstrumentation.callActivityOnPause(r.activity);
+10 −0
Original line number Diff line number Diff line
@@ -104,6 +104,16 @@ public abstract class ClientTransactionHandler {
    public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
            boolean isForward, String reason);

    /**
     * Notify the activity about top resumed state change.
     * @param token Target activity token.
     * @param isTopResumedActivity Current state of the activity, {@code true} if it's the
     *                             topmost resumed activity in the system, {@code false} otherwise.
     * @param reason Reason for performing this operation.
     */
    public abstract void handleTopResumedActivityChanged(IBinder token,
            boolean isTopResumedActivity, String reason);

    /**
     * Stop the activity.
     * @param token Target activity token.
+112 −0
Original line number Diff line number Diff line
/*
 * 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.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.app.servertransaction;

import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;

import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Trace;

/**
 * Top resumed activity changed callback.
 * @hide
 */
public class TopResumedActivityChangeItem extends ClientTransactionItem {

    private boolean mOnTop;

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem");
        client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }


    // ObjectPoolItem implementation

    private TopResumedActivityChangeItem() {}

    /** Obtain an instance initialized with provided params. */
    public static TopResumedActivityChangeItem obtain(boolean onTop) {
        TopResumedActivityChangeItem instance =
                ObjectPool.obtain(TopResumedActivityChangeItem.class);
        if (instance == null) {
            instance = new TopResumedActivityChangeItem();
        }
        instance.mOnTop = onTop;

        return instance;
    }

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


    // Parcelable implementation

    /** Write to Parcel. */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBoolean(mOnTop);
    }

    /** Read from Parcel. */
    private TopResumedActivityChangeItem(Parcel in) {
        mOnTop = in.readBoolean();
    }

    public static final Creator<TopResumedActivityChangeItem> CREATOR =
            new Creator<TopResumedActivityChangeItem>() {
                public TopResumedActivityChangeItem createFromParcel(Parcel in) {
                    return new TopResumedActivityChangeItem(in);
                }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final TopResumedActivityChangeItem other = (TopResumedActivityChangeItem) o;
        return mOnTop == other.mOnTop;
    }

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

    @Override
    public String toString() {
        return "TopResumedActivityChangeItem{onTop=" + mOnTop + "}";
    }
}
Loading