Merge "Defer pausing apps when bringing up recents" into sc-dev
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 80f1e6e..306b54d 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -327,6 +327,9 @@
     private static final String KEY_LAUNCHED_FROM_BUBBLE =
             "android.activity.launchTypeBubble";
 
+    /** See {@link #setTransientLaunch()}. */
+    private static final String KEY_TRANSIENT_LAUNCH = "android.activity.transientLaunch";
+
     /**
      * @see #setLaunchCookie
      * @hide
@@ -414,6 +417,7 @@
     private int mSplashScreenThemeResId;
     private boolean mRemoveWithTaskOrganizer;
     private boolean mLaunchedFromBubble;
+    private boolean mTransientLaunch;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1166,6 +1170,7 @@
         mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
         mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
         mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE);
+        mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH);
     }
 
     /**
@@ -1663,6 +1668,28 @@
     }
 
     /**
+     * Sets whether the activity launch is part of a transient operation. If it is, it will not
+     * cause lifecycle changes in existing activities even if it were to occlude them (ie. other
+     * activities occluded by this one will not be paused or stopped until the launch is committed).
+     * As a consequence, it will start immediately since it doesn't need to wait for other
+     * lifecycles to evolve. Current user is recents.
+     * @hide
+     */
+    public ActivityOptions setTransientLaunch() {
+        mTransientLaunch = true;
+        return this;
+    }
+
+    /**
+     * @see #setTransientLaunch()
+     * @return whether the activity launch is part of a transient operation.
+     * @hide
+     */
+    public boolean getTransientLaunch() {
+        return mTransientLaunch;
+    }
+
+    /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
      * defined in <var>otherOptions</var> replace those in the base options.
@@ -1902,6 +1929,9 @@
         if (mLaunchedFromBubble) {
             b.putBoolean(KEY_LAUNCHED_FROM_BUBBLE, mLaunchedFromBubble);
         }
+        if (mTransientLaunch) {
+            b.putBoolean(KEY_TRANSIENT_LAUNCH, mTransientLaunch);
+        }
         return b;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0d3c74e..7bc29f2 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -192,6 +192,7 @@
     private boolean mKeepCurTransition;
     private boolean mAvoidMoveToFront;
     private boolean mFrozeTaskList;
+    private boolean mTransientLaunch;
 
     // We must track when we deliver the new intent since multiple code paths invoke
     // {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -1792,7 +1793,7 @@
                     mTargetRootTask.moveToFront("startActivityInner");
                 }
                 mRootWindowContainer.resumeFocusedTasksTopActivities(
-                        mTargetRootTask, mStartActivity, mOptions);
+                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
             }
         }
         mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
@@ -2209,6 +2210,7 @@
         mKeepCurTransition = false;
         mAvoidMoveToFront = false;
         mFrozeTaskList = false;
+        mTransientLaunch = false;
 
         mVoiceSession = null;
         mVoiceInteractor = null;
@@ -2311,6 +2313,7 @@
                 mDoResume = false;
                 mAvoidMoveToFront = true;
             }
+            mTransientLaunch = mOptions.getTransientLaunch();
             mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
         }
 
@@ -2642,7 +2645,7 @@
             }
             if (mTargetRootTask.isFocusable()) {
                 mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, null,
-                        mOptions);
+                        mOptions, mTransientLaunch);
             } else {
                 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
             }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 26dcf00..ea80b8b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2293,7 +2293,13 @@
 
     boolean resumeFocusedTasksTopActivities(
             Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) {
+        return resumeFocusedTasksTopActivities(targetRootTask, target, targetOptions,
+                false /* deferPause */);
+    }
 
+    boolean resumeFocusedTasksTopActivities(
+            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
+            boolean deferPause) {
         if (!mTaskSupervisor.readyToResume()) {
             return false;
         }
@@ -2301,7 +2307,8 @@
         boolean result = false;
         if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                 || getTopDisplayFocusedRootTask() == targetRootTask)) {
-            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions);
+            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
+                    deferPause);
         }
 
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e120754..1eb4122 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6066,6 +6066,7 @@
      * @param prev The previously resumed activity, for when in the process
      * of pausing; can be null to call from elsewhere.
      * @param options Activity options.
+     * @param deferPause When {@code true}, this will not pause back tasks.
      *
      * @return Returns true if something is being resumed, or false if
      * nothing happened.
@@ -6076,7 +6077,8 @@
      *       right activity for the current system state.
      */
     @GuardedBy("mService")
-    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
+    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
+            boolean deferPause) {
         if (mInResumeTopActivity) {
             // Don't even start recursing.
             return false;
@@ -6089,7 +6091,7 @@
 
             if (isLeafTask()) {
                 if (isFocusableAndVisible()) {
-                    someActivityResumed = resumeTopActivityInnerLocked(prev, options);
+                    someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
                 }
             } else {
                 int idx = mChildren.size() - 1;
@@ -6102,7 +6104,8 @@
                         break;
                     }
 
-                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options);
+                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
+                            deferPause);
                     // Doing so in order to prevent IndexOOB since hierarchy might changes while
                     // resuming activities, for example dismissing split-screen while starting
                     // non-resizeable activity.
@@ -6130,8 +6133,15 @@
         return someActivityResumed;
     }
 
+    /** @see #resumeTopActivityUncheckedLocked(ActivityRecord, ActivityOptions, boolean) */
     @GuardedBy("mService")
-    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
+    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
+        return resumeTopActivityUncheckedLocked(prev, options, false /* skipPause */);
+    }
+
+    @GuardedBy("mService")
+    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
+            boolean deferPause) {
         if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
             // Not ready yet!
             return false;
@@ -6227,7 +6237,7 @@
             lastResumed = lastFocusedRootTask.getResumedActivity();
         }
 
-        boolean pausing = taskDisplayArea.pauseBackTasks(next);
+        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
         if (mResumedActivity != null) {
             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
             pausing |= startPausingLocked(false /* uiSleeping */, next,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 7614579..9267285 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -560,7 +560,7 @@
 
         // Verify the target task should resume its activity.
         verify(rootTask, times(1)).resumeTopActivityUncheckedLocked(
-                eq(activity), eq(null /* targetOptions */));
+                eq(activity), eq(null /* targetOptions */), eq(false));
     }
 
     /**