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

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

Schedule top-resumed-activity-gain after previous one paused

When the top-resumed-activity-gain event is scheduled immediately
after the previous top-resumed activity reports back (potentially
even before the previous activity has paused), it may lead to
unnecessary and rapid top-resumed activity switches, particularly
when having multiple resumed activities in a root task.

Consider the following scenario where Activity#C is the top-resumed
activity:

   Root-Task
      - Task#1
         - Activity#C (resumed)
         - Activity#A (stopped)
      - Task#2
         - Activity#B (resumed)

In this case, Activity#A is intended to resume once Activity#C
finishes. However, the top-resumed activity sequence would be
C -> B -> A.

To address this, this ensures that the top-resumed-activity-gain
event will now wait until the previous top-resumed activity has
paused and has scheduled the next activity to resume.

Bug: 417956804
Test: wm presubmit
Test: ActivityLifecycleTopResumedStateTests
Flag: com.android.window.flags.fix_rapid_top_resumed_switch
Change-Id: Ia849f816567e14a707793fd36eede0955c813394
parent b6a56c4f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -77,9 +77,9 @@ public class ActivityClient {
     * Reports after {@link Activity#onTopResumedActivityChanged(boolean)} is called for losing the
     * top most position.
     */
    public void activityTopResumedStateLost() {
    public void activityTopResumedStateLost(IBinder token) {
        try {
            getActivityClientController().activityTopResumedStateLost();
            getActivityClientController().activityTopResumedStateLost(token);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
+1 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ interface IActivityClientController {
     * This call is not one-way because {@link #activityPaused()) is not one-way, or
     * the top-resumed-lost could be reported after activity paused.
     */
    void activityTopResumedStateLost();
    void activityTopResumedStateLost(in IBinder token);
    /**
     * Notifies that the activity has completed paused. This call is not one-way because it can make
     * consecutive launch in the same process more coherent. About the order of binder call, it
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem {
        // 2. Activity wasn't RESUMED yet, which means that it didn't receive the top state yet.
        // 3. Activity is PAUSED or in other lifecycle state after PAUSED. In this case top resumed
        // state loss was already called right before pausing.
        ActivityClient.getInstance().activityTopResumedStateLost();
        ActivityClient.getInstance().activityTopResumedStateLost(getActivityToken());
    }

    // Parcelable implementation
+10 −0
Original line number Diff line number Diff line
@@ -196,3 +196,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    namespace: "windowing_sdk"
    name: "fix_rapid_top_resumed_switch"
    description: "Prevent top-resumed-activity rapidly switched in multi-window mode."
    bug: "417956804"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+10 −2
Original line number Diff line number Diff line
@@ -220,10 +220,18 @@ class ActivityClientController extends IActivityClientController.Stub {
    }

    @Override
    public void activityTopResumedStateLost() {
    public void activityTopResumedStateLost(IBinder token) {
        final long origId = Binder.clearCallingIdentity();
        synchronized (mGlobalLock) {
            mTaskSupervisor.handleTopResumedStateReleased(false /* timeout */);
            if (com.android.window.flags.Flags.fixRapidTopResumedSwitch()) {
                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                if (r != null) {
                    mTaskSupervisor.handleTopResumedStateReleasedIfNeeded(r, false /* timeout */);
                }
            } else {
                mTaskSupervisor.handleTopResumedStateReleasedIfNeeded(null, false /* timeout */);
            }

        }
        Binder.restoreCallingIdentity(origId);
    }
Loading