Fix UDFPS icon of Biometric Prompt has no response after rotation

If configurationChanged occurs when playing BP showing animation,
onDialogAnimatedIn() might not be executed. It causes that
BiometricService doesn't get the notify from SysUI. To avoid this
problem, check the status of BP, if BP is still playing intro animation,
cancel the animation & force executed onDialogAnimatedIn() before
closing old BP.

Bug: b/249698846
Test: 1. Enroll fingerprints & enable auto rotate
      2. Play Store logged in user account
      3. Open "Play Store" and tap "Add another account"
      4. Rotate the DUT from portrait to landscape before the end of BP
	 showing animation
Change-Id: Id8d7601cc98d0071d53b36e93962bb800c9bf3bd
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index e74d810..029cde9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -127,7 +127,7 @@
     private final ScrollView mBiometricScrollView;
     private final View mPanelView;
     private final float mTranslationY;
-    @ContainerState private int mContainerState = STATE_UNKNOWN;
+    @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
     private final Set<Integer> mFailedModalities = new HashSet<Integer>();
     private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
 
@@ -657,11 +657,25 @@
         wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
     }
 
+    private void forceExecuteAnimatedIn() {
+        if (mContainerState == STATE_ANIMATING_IN) {
+            //clear all animators
+            if (mCredentialView != null && mCredentialView.isAttachedToWindow()) {
+                mCredentialView.animate().cancel();
+            }
+            mPanelView.animate().cancel();
+            mBiometricView.animate().cancel();
+            animate().cancel();
+            onDialogAnimatedIn();
+        }
+    }
+
     @Override
     public void dismissWithoutCallback(boolean animate) {
         if (animate) {
             animateAway(false /* sendReason */, 0 /* reason */);
         } else {
+            forceExecuteAnimatedIn();
             removeWindowIfAttached();
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index d52612b..e8c760c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -52,6 +52,7 @@
 import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
@@ -123,6 +124,21 @@
     }
 
     @Test
+    fun testDismissBeforeIntroEnd() {
+        val container = initializeFingerprintContainer()
+        waitForIdleSync()
+
+        // STATE_ANIMATING_IN = 1
+        container?.mContainerState = 1
+
+        container.dismissWithoutCallback(false)
+
+        // the first time is triggered by initializeFingerprintContainer()
+        // the second time was triggered by dismissWithoutCallback()
+        verify(callback, times(2)).onDialogAnimatedIn(authContainer?.requestId ?: 0L)
+    }
+
+    @Test
     fun testDismissesOnFocusLoss() {
         val container = initializeFingerprintContainer()
         waitForIdleSync()