Fix race when rotating the display during an entry into PIP

Rotating the display while the PIP task had just appeared caused
a race between the alpha entry animation starting and the rotation
controller handling that changes the PIP bounds, resulting in
a bounds mismatch between the surface that was animated and the
PipBoundsState.mBounds

This CL tracks whether we're still waiting for the alpha entry
animation to start when a rotation callback comes in, and
restarts the fade in after adjusting to the rotation.

Bug: 184664409
Test: In gesure nav, open YT go to fullscreen landscape mode and
launch another an activity from a notification - verify PIP fades
in and its bounds match the ones in PipBoundsState

Change-Id: I339d5088fb5f23f08fe8d548b9d02a34c16779d6
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index a52db24..b396ce5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -37,6 +37,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Controller class of PiP animations (both from and to PiP mode).
@@ -112,6 +113,7 @@
                     PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart,
                             alphaEnd));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
+                && Objects.equals(destinationBounds, mCurrentAnimator.getDestinationBounds())
                 && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.updateEndValue(alphaEnd);
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index ffa821d..447e4f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -98,9 +98,10 @@
     private enum State {
         UNDEFINED(0),
         TASK_APPEARED(1),
-        ENTERING_PIP(2),
-        ENTERED_PIP(3),
-        EXITING_PIP(4);
+        ENTRY_SCHEDULED(2),
+        ENTERING_PIP(3),
+        ENTERED_PIP(4),
+        EXITING_PIP(5);
 
         private final int mStateValue;
 
@@ -264,6 +265,13 @@
     }
 
     /**
+     * Returns whether the entry animation is waiting to be started.
+     */
+    public boolean isEntryScheduled() {
+        return mState == State.ENTRY_SCHEDULED;
+    }
+
+    /**
      * Registers a callback when a display change has been detected when we enter PiP.
      */
     public void registerOnDisplayIdChangeCallback(IntConsumer onDisplayIdChangeCallback) {
@@ -481,6 +489,19 @@
         }
     }
 
+    /**
+     * Called when the display rotation handling is skipped (e.g. when rotation happens while in
+     * the middle of an entry transition).
+     */
+    public void onDisplayRotationSkipped() {
+        if (isEntryScheduled()) {
+            // The PIP animation is scheduled to start with the previous orientation's bounds,
+            // re-calculate the entry bounds and restart the alpha animation.
+            final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+            enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration);
+        }
+    }
+
     @VisibleForTesting
     void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
         // If we are fading the PIP in, then we should move the pip to the final location as
@@ -490,6 +511,7 @@
                 mSurfaceControlTransactionFactory.getTransaction();
         tx.setAlpha(mLeash, 0f);
         tx.apply();
+        mState = State.ENTRY_SCHEDULED;
         applyEnterPipSyncTransaction(destinationBounds, () -> {
             mPipAnimationController
                     .getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index d75c1d6..4b62b5f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -115,7 +115,8 @@
             int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
         if (!mPipTaskOrganizer.isInPip()
                 || mPipBoundsState.getDisplayLayout().rotation() == toRotation
-                || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
+                || mPipTaskOrganizer.isDeferringEnterPipAnimation()
+                || mPipTaskOrganizer.isEntryScheduled()) {
             // Skip if the same rotation has been set or we aren't in PIP or haven't actually
             // entered PIP yet. We still need to update the display layout in the bounds handler
             // in this case.
@@ -123,6 +124,7 @@
             // do not forget to update the movement bounds as well.
             updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
                     false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+            mPipTaskOrganizer.onDisplayRotationSkipped();
             return;
         }
         // If there is an animation running (ie. from a shelf offset), then ensure that we calculate