Merge "Fix auto-pip visibility issues." into oc-dev
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 17459ea..cde3ec5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7803,7 +7803,7 @@
                 // Activity supports picture-in-picture, now check that we can enter PiP at this
                 // point, if it is
                 if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
-                        false /* noThrow */)) {
+                        false /* noThrow */, false /* beforeStopping */)) {
                     return false;
                 }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cfbd2b5..274dac6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1163,10 +1163,13 @@
     }
 
     /**
+     * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
+     *         the activity has requested to enter PiP when it would otherwise be stopped.
+     *
      * @return whether this activity is currently allowed to enter PIP, throwing an exception if
      *         the activity is not currently visible and {@param noThrow} is not set.
      */
-    boolean checkEnterPictureInPictureState(String caller, boolean noThrow) {
+    boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) {
         // Check app-ops and see if PiP is supported for this package
         if (!checkEnterPictureInPictureAppOpsState()) {
             return false;
@@ -1177,17 +1180,24 @@
             return false;
         }
 
-        boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
         boolean isKeyguardLocked = service.isKeyguardLocked();
+        boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
         boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
         // Don't return early if !isNotLocked, since we want to throw an exception if the activity
         // is in an incorrect state
         boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked;
+
+        // We don't allow auto-PiP when something else is already pipped.
+        if (beforeStopping && hasPinnedStack) {
+            return false;
+        }
+
         switch (state) {
             case RESUMED:
                 // When visible, allow entering PiP if the app is not locked.  If it is over the
                 // keyguard, then we will prompt to unlock in the caller before entering PiP.
-                return !isCurrentAppLocked;
+                return !isCurrentAppLocked &&
+                        (supportsPictureInPictureWhilePausing || !beforeStopping);
             case PAUSING:
             case PAUSED:
                 // When pausing, then only allow enter PiP as in the resume state, and in addition,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0e033d2..bb71499 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2001,10 +2001,10 @@
         // keeping the screen frozen.
         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
         try {
-            r.setVisible(false);
             switch (r.state) {
                 case STOPPING:
                 case STOPPED:
+                    r.setVisible(false);
                     if (r.app != null && r.app.thread != null) {
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                 "Scheduling invisibility: " + r);
@@ -2023,6 +2023,7 @@
                     // This case created for transitioning activities from
                     // translucent to opaque {@link Activity#convertToOpaque}.
                     if (visibleBehind == r) {
+                        r.setVisible(false);
                         releaseBackgroundResources(r);
                     } else {
                         // If this activity is in a state where it can currently enter
@@ -2030,7 +2031,18 @@
                         // the activity tries to enterPictureInPictureMode() later. Otherwise,
                         // we will try and stop the activity next time idle is processed.
                         final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
-                                "makeInvisible", true /* noThrow */);
+                                "makeInvisible", true /* noThrow */, true /* beforeStopping */);
+
+                        if (canEnterPictureInPicture) {
+                            // We set r.visible=false so that Stop will later
+                            // call setVisible for us. In this case
+                            // we don't want to call setVisible(false) to avoid
+                            // notifying the client of this intermittent invisible
+                            // state.
+                            r.visible = false;
+                        } else {
+                            r.setVisible(false);
+                        }
                         addToStopping(r, true /* scheduleIdle */,
                                 canEnterPictureInPicture /* idleDelayed */);
                     }