Updating picture-in-picture API.

- Consolidating to enterPictureInPictureMode(), the new method will
  attempt to put the activity into picture-in-picture mode if the
  activity is visible or pausing in a state that would allow us to
  pip it.  Also consolidate the setting of the PiP aspect ratio and
  actions into setPictureInPictureArgs().
- Fixing issue with onPause not completing when moving the
  paused activity between stacks while dispatching onPause

Bug: 33692987
Test: android.server.cts.ActivityManagerPinnedStackTests

Change-Id: I3af2365f31a9b95de4a92eae46b77108947b2a49
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2a324eb..db7d505 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -151,7 +151,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManager.TaskThumbnailInfo;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ActivityManagerInternal.SleepToken;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -182,6 +181,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.PictureInPictureArgs;
 import android.app.ProfilerInfo;
 import android.app.RemoteAction;
 import android.app.WaitResult;
@@ -229,7 +229,6 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.location.LocationManager;
@@ -7556,45 +7555,31 @@
     }
 
     @Override
-    public void enterPictureInPictureMode(IBinder token) {
-        enterPictureInPictureMode(token, DEFAULT_DISPLAY, -1f /* aspectRatio */,
-                false /* checkAspectRatio */);
-    }
-
-    @Override
-    public void enterPictureInPictureModeWithAspectRatio(IBinder token, float aspectRatio) {
-        enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio, true /* checkAspectRatio */);
-    }
-
-    @Override
-    public void enterPictureInPictureModeOnMoveToBackground(IBinder token,
-            boolean enterPictureInPictureOnMoveToBg) {
+    public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureArgs args) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "enterPictureInPictureModeOnMoveToBackground", token, -1f /* aspectRatio */,
-                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+                final ActivityRecord r = ensureValidPictureInPictureActivityArgsLocked(
+                        "enterPictureInPictureMode", token, args);
 
-                r.supportsPipOnMoveToBackground = enterPictureInPictureOnMoveToBg;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
+                // Activity supports picture-in-picture, now check that we can enter PiP at this
+                // point, if it is
+                if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode")) {
+                    return false;
+                }
 
-    private void enterPictureInPictureMode(IBinder token, int displayId, float aspectRatio,
-            boolean checkAspectRatio) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "enterPictureInPictureMode", token, aspectRatio, checkAspectRatio,
-                        true /* checkActivityVisibility */);
                 final Runnable enterPipRunnable = () -> {
-                    r.pictureInPictureArgs.aspectRatio = aspectRatio;
-                    enterPictureInPictureModeLocked(r, displayId, r.pictureInPictureArgs,
-                            true /* moveHomeStackToFront */, "enterPictureInPictureMode");
+                    // Only update the saved args from the args that are set
+                    r.pictureInPictureArgs.copyOnlySet(args);
+                    final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
+                    final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
+                    final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
+                            ? mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
+                                    aspectRatio)
+                            : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY);
+                    mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
+                            bounds, true /* moveHomeStackToFront */);
+                    mWindowManager.setPictureInPictureActions(actions);
                 };
 
                 if (isKeyguardLocked()) {
@@ -7625,35 +7610,7 @@
                     // Enter picture in picture immediately otherwise
                     enterPipRunnable.run();
                 }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    void enterPictureInPictureModeLocked(ActivityRecord r, int displayId,
-            PictureInPictureArguments pipArgs, boolean moveHomeStackToFront, String reason) {
-        final Rect bounds = isValidPictureInPictureAspectRatio(pipArgs.aspectRatio)
-                ? mWindowManager.getPictureInPictureBounds(displayId, pipArgs.aspectRatio)
-                : mWindowManager.getPictureInPictureDefaultBounds(displayId);
-        mStackSupervisor.moveActivityToPinnedStackLocked(r, reason, bounds, moveHomeStackToFront);
-        mWindowManager.setPictureInPictureActions(pipArgs.userActions);
-    }
-
-    @Override
-    public void setPictureInPictureAspectRatio(IBinder token, float aspectRatio) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "setPictureInPictureAspectRatio", token, aspectRatio,
-                        true /* checkAspectRatio */, false /* checkActivityVisibility */);
-
-                r.pictureInPictureArgs.aspectRatio = aspectRatio;
-                if (r.getStack().getStackId() == PINNED_STACK_ID) {
-                    // If the activity is already in picture-in-picture, update the pinned stack now
-                    mWindowManager.setPictureInPictureAspectRatio(aspectRatio);
-                }
+                return true;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -7661,26 +7618,21 @@
     }
 
     @Override
-    public void setPictureInPictureActions(IBinder token, ParceledListSlice actionsList) {
+    public void setPictureInPictureArgs(IBinder token, final PictureInPictureArgs args) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "setPictureInPictureActions", token, -1 /* aspectRatio */,
-                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+                final ActivityRecord r = ensureValidPictureInPictureActivityArgsLocked(
+                        "setPictureInPictureArgs", token, args);
 
-                final List<RemoteAction> actions = actionsList.getList();
-                if (actions.size() > ActivityManager.getMaxNumPictureInPictureActions()) {
-                    throw new IllegalArgumentException("setPictureInPictureActions: Invalid number"
-                            + " of picture-in-picture actions.  Only a maximum of "
-                            + ActivityManager.getMaxNumPictureInPictureActions()
-                            + " actions allowed");
-                }
-
-                r.pictureInPictureArgs.userActions = actions;
+                // Only update the saved args from the args that are set
+                r.pictureInPictureArgs.copyOnlySet(args);
                 if (r.getStack().getStackId() == PINNED_STACK_ID) {
                     // If the activity is already in picture-in-picture, update the pinned stack now
-                    mWindowManager.setPictureInPictureActions(actions);
+                    mWindowManager.setPictureInPictureAspectRatio(
+                            r.pictureInPictureArgs.getAspectRatio());
+                    mWindowManager.setPictureInPictureActions(
+                            r.pictureInPictureArgs.getActions());
                 }
             }
         } finally {
@@ -7696,14 +7648,10 @@
      * Checks the state of the system and the activity associated with the given {@param token} to
      * verify that picture-in-picture is supported for that activity.
      *
-     * @param checkAspectRatio whether or not to check {@param aspectRatio} is within a valid range
-     * @param checkActivityVisibility whether or not to enforce that the activity is currently
-     *                                visible
-     *
      * @return the activity record for the given {@param token} if all the checks pass.
      */
-    private ActivityRecord ensureValidPictureInPictureActivityLocked(String caller, IBinder token,
-            float aspectRatio, boolean checkAspectRatio, boolean checkActivityVisibility) {
+    private ActivityRecord ensureValidPictureInPictureActivityArgsLocked(String caller,
+            IBinder token, PictureInPictureArgs args) {
         if (!mSupportsPictureInPicture) {
             throw new IllegalStateException(caller
                     + ": Device doesn't support picture-in-picture mode.");
@@ -7715,10 +7663,9 @@
                     + ": Can't find activity for token=" + token);
         }
 
-        if (!r.canEnterPictureInPicture(checkActivityVisibility)) {
-            throw new IllegalArgumentException(caller
-                    + ": Current activity does not support picture-in-picture or is not "
-                    + "visible r=" + r);
+        if (!r.supportsPictureInPicture()) {
+            throw new IllegalStateException(caller
+                    + ": Current activity does not support picture-in-picture.");
         }
 
         if (r.getStack().isHomeStack()) {
@@ -7726,12 +7673,20 @@
                     + ": Activities on the home stack not supported");
         }
 
-        if (checkAspectRatio && !isValidPictureInPictureAspectRatio(aspectRatio)) {
+        if (args.hasSetAspectRatio()
+                && !isValidPictureInPictureAspectRatio(args.getAspectRatio())) {
             throw new IllegalArgumentException(String.format(caller
                     + ": Aspect ratio is too extreme (must be between %f and %f).",
                             mMinPipAspectRatio, mMaxPipAspectRatio));
         }
 
+        if (args.hasSetActions()
+                && args.getActions().size() > ActivityManager.getMaxNumPictureInPictureActions()) {
+            throw new IllegalArgumentException(String.format(caller + ": Invalid number of"
+                    + "picture-in-picture actions.  Only a maximum of %d actions allowed",
+                            ActivityManager.getMaxNumPictureInPictureActions()));
+        }
+
         return r;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index a2fb9f9..6134d75 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -63,9 +63,9 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
+import android.app.PictureInPictureArgs;
 import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -229,13 +229,10 @@
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
-    boolean supportsPipOnMoveToBackground;   // Supports automatically entering picture-in-picture
-        // when this activity is hidden. This flag is requested by the activity.
-    private boolean enterPipOnMoveToBackground; // Flag to enter picture in picture when this
-        // activity is made invisible. This flag is set specifically when another task is being
-        // launched or moved to the front which may cause this activity to try and enter PiP
-        // when it is next made invisible.
-    PictureInPictureArguments pictureInPictureArgs = new PictureInPictureArguments();  // The PiP
+    boolean supportsPictureInPictureWhilePausing;  // This flag is set by the system to indicate
+        // that the activity can enter picture in picture while pausing (ie. only when another
+        // task is brought to front or started)
+    PictureInPictureArgs pictureInPictureArgs = new PictureInPictureArgs();  // The PiP
         // arguments used when deferring the entering of picture-in-picture.
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last launch of this activity
@@ -453,12 +450,8 @@
         if (info != null) {
             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
         }
-        if (supportsPipOnMoveToBackground) {
-            pw.println(prefix + "supportsPipOnMoveToBackground=1");
-            pw.println(prefix + "enterPipOnMoveToBackground=" +
-                    (enterPipOnMoveToBackground ? 1 : 0));
-            pictureInPictureArgs.dump(pw, prefix);
-        }
+        pw.println(prefix + "supportsPictureInPictureWhilePausing: "
+                + supportsPictureInPictureWhilePausing);
     }
 
     private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
@@ -819,23 +812,6 @@
     }
 
     /**
-     * If this activity has requested that it auto-enter picture-in-picture and we can actually do
-     * this, then mark it to enter picture in picture at that point.
-     */
-    void setEnterPipOnMoveToBackground(boolean enterPipOnInvisible) {
-        if (supportsPipOnMoveToBackground) {
-            enterPipOnMoveToBackground = enterPipOnInvisible;
-        }
-    }
-
-    /**
-     * @return whether to enter PiP when this activity is made invisible.
-     */
-    public boolean shouldEnterPictureInPictureOnInvisible() {
-        return enterPipOnMoveToBackground;
-    }
-
-    /**
      * @return Stack value from current task, null if there is no task.
      */
     ActivityStack getStack() {
@@ -918,24 +894,34 @@
     }
 
     /**
-     * @return whether this activity is currently allowed to enter PIP, if
-     * {@param checkActivityVisibility} is set, then the current activity visibility is taken into
-     * account.
+     * @return whether this activity is currently allowed to enter PIP, throwing an exception if
+     *         the activity is not currently visible.
      */
-    boolean canEnterPictureInPicture(boolean checkActivityVisibility) {
-        if (!checkActivityVisibility) {
-            return supportsPictureInPicture();
+    boolean checkEnterPictureInPictureState(String caller) {
+        boolean isKeyguardLocked = service.isKeyguardLocked();
+        boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
+        switch (state) {
+            case RESUMED:
+                // When visible, allow entering PiP if not on the lockscreen.  If there is another
+                // PiP activity, the logic to handle that comes later in enterPictureInPictureMode()
+                return !isKeyguardLocked;
+            case PAUSING:
+            case PAUSED:
+                // When pausing, only allow enter PiP if not on the lockscreen and there is not
+                // already an existing PiP activity
+                return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing;
+            case STOPPING:
+                // When stopping in a valid state, then only allow enter PiP as in the pause state.
+                // Otherwise, fall through to throw an exception if the caller is trying to enter
+                // PiP in an invalid stopping state.
+                if (supportsPictureInPictureWhilePausing) {
+                    return !isKeyguardLocked && !hasPinnedStack;
+                }
+            default:
+                throw new IllegalStateException(caller
+                        + ": Current activity is not visible (state=" + state.name() + ") "
+                        + "r=" + this);
         }
-
-        if (supportsPictureInPicture()) {
-            switch (state) {
-                case RESUMED:
-                case PAUSING:
-                case PAUSED:
-                    return true;
-            }
-        }
-        return false;
     }
 
     boolean canGoInDockedStack() {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4df0cb1..cd11d21 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1698,9 +1698,7 @@
                                 + stackInvisible + " behindFullscreenActivity="
                                 + behindFullscreenActivity + " mLaunchTaskBehind="
                                 + r.mLaunchTaskBehind);
-                        if (!enterPictureInPictureOnActivityInvisible(r)) {
-                            makeInvisible(r, visibleBehind);
-                        }
+                        makeInvisible(r, visibleBehind);
                     }
                 }
                 if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
@@ -1859,35 +1857,6 @@
         return false;
     }
 
-    /**
-     * Attempts to enter picture-in-picture if the activity that is being made invisible supports
-     * it.  If not, then
-     *
-     * @return whether or not picture-in-picture mode was entered.
-     */
-    private boolean enterPictureInPictureOnActivityInvisible(ActivityRecord r) {
-        final boolean hasPinnedStack =
-                mStackSupervisor.getStack(PINNED_STACK_ID) != null;
-        final boolean isKeyguardLocked = mService.isKeyguardLocked();
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, " enterPictureInPictureOnInvisible="
-                + r.shouldEnterPictureInPictureOnInvisible()
-                + " hasPinnedStack=" + hasPinnedStack
-                + " isKeyguardLocked=" + isKeyguardLocked);
-        if (!hasPinnedStack && !isKeyguardLocked && r.visible &&
-                r.shouldEnterPictureInPictureOnInvisible()) {
-            r.setEnterPipOnMoveToBackground(false);
-
-            // Enter picture in picture, but don't move the home stack to the front
-            // since it will affect the focused stack's visibility and occlude
-            // starting activities
-            mService.enterPictureInPictureModeLocked(r, r.getDisplayId(),
-                    r.pictureInPictureArgs, false /* moveHomeStackToFront */,
-                    "ensureActivitiesVisibleLocked");
-            return true;
-        }
-        return false;
-    }
-
     private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) {
         if (!r.visible) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
@@ -1906,6 +1875,10 @@
                                 "Scheduling invisibility: " + r);
                         r.app.thread.scheduleWindowVisibility(r.appToken, false);
                     }
+
+                    // Reset the flag indicating that an app can enter picture-in-picture once the
+                    // activity is hidden
+                    r.supportsPictureInPictureWhilePausing = false;
                     break;
 
                 case INITIALIZING:
@@ -2187,15 +2160,16 @@
 
         mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
 
-        // We need to start pausing the current activity so the top one can be resumed...
-        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
-        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
+        // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
+        // to be paused, while at the same time resuming the new resume activity
+        final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
+        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
         if (mResumedActivity != null) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Pausing " + mResumedActivity);
-            pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
+            pausing |= startPausingLocked(userLeaving, false, next, false);
         }
-        if (pausing) {
+        if (pausing && !resumeWhilePausing) {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
                     "resumeTopActivityLocked: Skip resume: need to start pausing");
             // At this point we want to put the upcoming activity's process
@@ -2696,10 +2670,10 @@
                     if (r.mLaunchTaskBehind) {
                         transit = TRANSIT_TASK_OPEN_BEHIND;
                     } else {
-                        // If a new task is being launched, then mark the existing top activity to
-                        // enter picture-in-picture if it supports auto-entering PiP
+                        // If a new task is being launched, then mark the existing top activity as
+                        // supporting picture-in-picture while pausing
                         if (focusedTopActivity != null) {
-                            focusedTopActivity.setEnterPipOnMoveToBackground(true);
+                            focusedTopActivity.supportsPictureInPictureWhilePausing = true;
                         }
                         transit = TRANSIT_TASK_OPEN;
                     }
@@ -4245,10 +4219,10 @@
         } else {
             updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
         }
-        // If a new task is moved to the front, then mark the existing top activity to enter
-        // picture-in-picture if it supports auto-entering PiP
+        // If a new task is moved to the front, then mark the existing top activity as supporting
+        // picture-in-picture while paused
         if (focusedTopActivity != null) {
-            focusedTopActivity.setEnterPipOnMoveToBackground(true);
+            focusedTopActivity.supportsPictureInPictureWhilePausing = true;
         }
 
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
@@ -4966,8 +4940,8 @@
         }
     }
 
-    void moveToFrontAndResumeStateIfNeeded(
-            ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+    void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
+            boolean setPause, String reason) {
         if (!moveToFront) {
             return;
         }
@@ -4978,6 +4952,10 @@
         if (setResume) {
             mResumedActivity = r;
         }
+        // If the activity was previously pausing, then ensure we transfer that as well
+        if (setPause) {
+            mPausingActivity = r;
+        }
         // Move the stack in which we are placing the activity to the front. The call will also
         // make sure the activity focus is set.
         moveToFront(reason);
@@ -4998,6 +4976,7 @@
         final boolean wasFocused = mStackSupervisor.isFocusedStack(prevStack)
                 && (mStackSupervisor.topRunningActivityLocked() == r);
         final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+        final boolean wasPaused = prevStack.mPausingActivity == r;
 
         final TaskRecord task = createTaskRecord(
                 mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
@@ -5005,10 +4984,14 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
-        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, wasPaused,
+                "moveActivityToStack");
         if (wasResumed) {
             prevStack.mResumedActivity = null;
         }
+        if (wasPaused) {
+            prevStack.mPausingActivity = null;
+        }
     }
 
     public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4fe8939..1224abd 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2617,6 +2617,7 @@
         final ActivityStack prevStack = task.getStack();
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = prevStack.mResumedActivity == r;
+        final boolean wasPaused = prevStack.mPausingActivity == r;
         // In some cases the focused stack isn't the front stack. E.g. pinned stack.
         // Whenever we are moving the top activity from the front stack we want to make sure to move
         // the stack to the front.
@@ -2641,10 +2642,19 @@
         task.mTemporarilyUnresizable = false;
         task.reparent(stack.mStackId, toTop ? MAX_VALUE : 0, reason);
 
+        // Reset the resumed activity on the previous stack
+        if (wasResumed) {
+            prevStack.mResumedActivity = null;
+        }
+        // Reset the paused activity on the previous stack
+        if (wasPaused) {
+            prevStack.mPausingActivity = null;
+        }
+
         // If the task had focus before (or we're requested to move focus),
         // move focus to the new stack by moving the stack to the front.
-        stack.moveToFrontAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
+        stack.moveToFrontAndResumeStateIfNeeded(r, forceFocus || wasFocused || wasFront, wasResumed,
+                wasPaused, reason);
 
         return stack;
     }
@@ -2795,8 +2805,12 @@
 
             if (task.mActivities.size() == 1) {
                 // There is only one activity in the task. So, we can just move the task over to
-                // the stack without re-parenting the activity in a different task.
-                if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+                // the stack without re-parenting the activity in a different task.  We don't
+                // move the home stack forward if we are currently entering picture-in-picture
+                // while pausing because that changes the focused stack and may prevent the new
+                // starting activity from resuming.
+                if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE
+                        && !r.supportsPictureInPictureWhilePausing) {
                     // Move the home stack forward if the task we just moved to the pinned stack
                     // was launched from home so home should be visible behind it.
                     moveHomeStackToFront(reason);
@@ -2808,6 +2822,10 @@
                 // reveal/leave the other activities in their original task
                 stack.moveActivityToStack(r);
             }
+
+            // Reset the state that indicates it can enter PiP while pausing after we've moved it
+            // to the pinned stack
+            r.supportsPictureInPictureWhilePausing = false;
         } finally {
             mWindowManager.continueSurfaceLayout();
         }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index bfb4269..08f9b45 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -333,7 +333,9 @@
      */
     void setActions(List<RemoteAction> actions) {
         mActions.clear();
-        mActions.addAll(actions);
+        if (actions != null) {
+            mActions.addAll(actions);
+        }
         notifyActionsChanged(mActions);
     }