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

Commit a4e102ee authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Work on issue #17357238: Recents is often slow if not used in a while

Add a new activity attribute, resumeWhilePausing, that allows an
activity specifying it to immediately start running without waiting
for the previous activity to pause.  The recents activity is updated
to use this.

The implementation of this is ultimately fairly simple -- if we are
in the path of resuming such an activity, and find that we first need
to pause the existing activity, then within the activity manager we
do the regular pause flow but act like it has immediately finished
pausing right then so that we can immediately go on to the resume.
To make this clean, we tell the activity when asking it to pause that
it should not come back and tell us it is done, because we aren't in
any way waiting for it.

One potentially important change I needed to make here is the pause
callback no longer provides the saved persistent state, because we
now can't count on that callback happening.  I don't think there was
really any utility in this anyway -- all modern apps will have their
save state flow happen as part of stopping, not pausing, so we'll
only capture that saved state when the stop is reported back anyway.
And since we do send the saved state back when stopping, it would
always blow away whatever we had gotten at the pause.

Finally, update the documentation for AppTask.startActivity(), and
fix the implementation handling that to be cleaner -- we need to
deal with inTask first before getting in to "oh noes add NEW_TASK
if this isn't coming from a calling activity" flow.

Change-Id: Ia1da0fac90d7bdbaafdda2e34850d795ce17a39f
parent b75dd5ce
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1062,6 +1062,7 @@ package android {
    field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
    field public static final int restrictedAccountType = 16843733; // 0x10103d5
    field public static final int restrictionType = 16843923; // 0x1010493
    field public static final int resumeWhilePausing = 16843955; // 0x10104b3
    field public static final int reversible = 16843851; // 0x101044b
    field public static final int right = 16843183; // 0x10101af
    field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
@@ -8411,6 +8412,7 @@ package android.content.pm {
    field public static final int FLAG_MULTIPROCESS = 1; // 0x1
    field public static final int FLAG_NO_HISTORY = 128; // 0x80
    field public static final int FLAG_RELINQUISH_TASK_IDENTITY = 4096; // 0x1000
    field public static final int FLAG_RESUME_WHILE_PAUSING = 16384; // 0x4000
    field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
    field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
    field public static final int LAUNCH_MULTIPLE = 0; // 0x0
+0 −16
Original line number Diff line number Diff line
package android {

  public static final class R.attr {
    field public static final int __removed1 = 16843955; // 0x10104b3
  }

}

package android.media {

  public class AudioFormat {
@@ -78,11 +70,3 @@ package android.view.inputmethod {

}
package com.android.internal {

  public static final class R.attr {
    field public static final int __removed1 = 16843955; // 0x10104b3
  }

}
+14 −7
Original line number Diff line number Diff line
@@ -2656,17 +2656,24 @@ public class ActivityManager {

        /**
         * Start an activity in this task.  Brings the task to the foreground.  If this task
         * is not currently active (that is, its id < 0), then the activity being started
         * needs to be started as a new task and the Intent's ComponentName must match the
         * base ComponenentName of the recent task entry.  Otherwise, the activity being
         * started must <b>not</b> be launched as a new task -- not through explicit intent
         * flags nor implicitly as the singleTask or singleInstance launch modes.
         * is not currently active (that is, its id < 0), then a new activity for the given
         * Intent will be launched as the root of the task and the task brought to the
         * foreground.  Otherwise, if this task is currently active and the Intent does not specify
         * an activity to launch in a new task, then a new activity for the given Intent will
         * be launched on top of the task and the task brought to the foreground.  If this
         * task is currently active and the Intent specifies {@link Intent#FLAG_ACTIVITY_NEW_TASK}
         * or would otherwise be launched in to a new task, then the activity not launched but
         * this task be brought to the foreground and a new intent delivered to the top
         * activity if appropriate.
         *
         * <p>See {@link Activity#startActivity(android.content.Intent, android.os.Bundle)
         * Activity.startActivity} for more information.</p>
         * <p>In other words, you generally want to use an Intent here that does not specify
         * {@link Intent#FLAG_ACTIVITY_NEW_TASK} or {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT},
         * and let the system do the right thing.</p>
         *
         * @param intent The Intent describing the new activity to be launched on the task.
         * @param options Optional launch options.
         *
         * @see Activity#startActivity(android.content.Intent, android.os.Bundle)
         */
        public void startActivity(Context context, Intent intent, Bundle options) {
            ActivityThread thread = ActivityThread.currentActivityThread();
+2 −4
Original line number Diff line number Diff line
@@ -509,8 +509,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
        case ACTIVITY_PAUSED_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder token = data.readStrongBinder();
            PersistableBundle persistentState = data.readPersistableBundle();
            activityPaused(token, persistentState);
            activityPaused(token);
            reply.writeNoException();
            return true;
        }
@@ -2829,13 +2828,12 @@ class ActivityManagerProxy implements IActivityManager
        data.recycle();
        reply.recycle();
    }
    public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
    public void activityPaused(IBinder token) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        data.writePersistableBundle(persistentState);
        mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
+12 −8
Original line number Diff line number Diff line
@@ -563,11 +563,11 @@ public final class ActivityThread {
        }

        public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges) {
                boolean userLeaving, int configChanges, boolean dontReport) {
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0),
                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
                    configChanges);
        }

@@ -1283,13 +1283,15 @@ public final class ActivityThread {
                } break;
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
                    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
                            (msg.arg1&2) != 0);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
                    handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,
                            (msg.arg1&1) != 0);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_ACTIVITY_SHOW:
@@ -3142,7 +3144,7 @@ public final class ActivityThread {
    }

    private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges) {
            boolean userLeaving, int configChanges, boolean dontReport) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
@@ -3159,10 +3161,12 @@ public final class ActivityThread {
            }

            // Tell the activity manager we have paused.
            if (!dontReport) {
                try {
                ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                }
            }
            mSomeActivitiesChanged = true;
        }
    }
Loading