PIP: Fix potential stuck state

Fixes an issue where the leave-PIP-animation could be erroneously
canceled and replaced with one that does not leave PIP. This happens
for example when launching a notification that restarts the PIP task
and maximizes it, if that notification is launched from the lockscreen
with a password set.

The task is animating out of PIP, but concurrently, a move animation
is scheduled because the IME that was up for the password is being
dismissed. If the order is such that the leave-PIP-animation is scheduled
first, the task will never be reparented out of PIP.

To fix that, we maintain the to/fromFullscreen flags when recreating the
animation.

Change-Id: I79d6d1907fcb25561d87b746cfb054f230d9d7b9
Fixes: 77334925
Test: Set lockscreen password (not PIN/Pattern). Open PIP app that has a notification from which it can be relaunched. Enter PIP. Lock screen. Relaunch PIP app from lockscreen notification. Verify things look appropriate after unlocking.
Test: atest BoundsAnimationControllerTests
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 112d93c..b2a12be 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -401,12 +401,13 @@
                 + " replacing=" + replacing);
 
         if (replacing) {
-            if (existing.isAnimatingTo(to)) {
+            if (existing.isAnimatingTo(to) && (!moveToFullscreen || existing.mMoveToFullscreen)
+                    && (!moveFromFullscreen || existing.mMoveFromFullscreen)) {
                 // Just let the current animation complete if it has the same destination as the
-                // one we are trying to start.
-                if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing
-                        + " ignoring...");
-
+                // one we are trying to start, and, if moveTo/FromFullscreen was requested, already
+                // has that flag set.
+                if (DEBUG) Slog.d(TAG, "animateBounds: same destination and moveTo/From flags as "
+                        + "existing=" + existing + ", ignoring...");
                 return existing;
             }
 
@@ -434,6 +435,13 @@
                 }
             }
 
+            // We need to keep the previous moveTo/FromFullscreen flag, unless the new animation
+            // specifies a direction.
+            if (!moveFromFullscreen && !moveToFullscreen) {
+                moveToFullscreen = existing.mMoveToFullscreen;
+                moveFromFullscreen = existing.mMoveFromFullscreen;
+            }
+
             // Since we are replacing, we skip both animation start and end callbacks
             existing.cancel();
         }