Fix udfps flicker on camera launch + exit

Test: atest UdfpsKeyguardViewControllerTest
Test: manually trigger double-tap power button for camera
and then dismiss the camera
Bug: 197160246

Merged-In: Id3aa20662df8cdd6676141f5f70e5eae0cec6215
Change-Id: Id3aa20662df8cdd6676141f5f70e5eae0cec6215
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e612fb4..2de489d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -781,6 +781,7 @@
                         mKeyguardViewMediator,
                         mLockscreenShadeTransitionController,
                         mConfigurationController,
+                        mKeyguardStateController,
                         this
                 );
             case IUdfpsOverlayController.REASON_AUTH_BP:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 4896305..3ca7a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.io.FileDescriptor;
@@ -50,6 +51,7 @@
     @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
     @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
     @NonNull private final ConfigurationController mConfigurationController;
+    @NonNull private final KeyguardStateController mKeyguardStateController;
     @NonNull private final UdfpsController mUdfpsController;
 
     private boolean mShowingUdfpsBouncer;
@@ -60,6 +62,9 @@
     private float mTransitionToFullShadeProgress;
     private float mLastDozeAmount;
 
+    private float mStatusBarExpansion;
+    private boolean mLaunchTransitionFadingAway;
+
     /**
      * hidden amount of pin/pattern/password bouncer
      * {@link KeyguardBouncer#EXPANSION_VISIBLE} (0f) to
@@ -79,6 +84,7 @@
             @NonNull KeyguardViewMediator keyguardViewMediator,
             @NonNull LockscreenShadeTransitionController transitionController,
             @NonNull ConfigurationController configurationController,
+            @NonNull KeyguardStateController keyguardStateController,
             @NonNull UdfpsController udfpsController) {
         super(view, statusBarStateController, statusBar, dumpManager);
         mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -87,6 +93,7 @@
         mKeyguardViewMediator = keyguardViewMediator;
         mLockScreenShadeTransitionController = transitionController;
         mConfigurationController = configurationController;
+        mKeyguardStateController = keyguardStateController;
         mUdfpsController = udfpsController;
     }
 
@@ -105,11 +112,14 @@
 
         mUdfpsRequested = false;
 
+        mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
+        mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
         mStatusBarState = mStatusBarStateController.getState();
         mQsExpanded = mKeyguardViewManager.isQsExpanded();
         mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
         mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
         mConfigurationController.addCallback(mConfigurationListener);
+        mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
         updateAlpha();
         updatePauseAuth();
 
@@ -122,10 +132,12 @@
         super.onViewDetached();
         mFaceDetectRunning = false;
 
+        mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
         mStatusBarStateController.removeCallback(mStateListener);
         mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
         mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
         mConfigurationController.removeCallback(mConfigurationListener);
+        mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
         if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
             mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
         }
@@ -140,9 +152,11 @@
         pw.println("mQsExpanded=" + mQsExpanded);
         pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
         pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
+        pw.println("mStatusBarExpansion=" + mStatusBarExpansion);
         pw.println("mAlpha=" + mView.getAlpha());
         pw.println("mUdfpsRequested=" + mUdfpsRequested);
         pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
+        pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
     }
 
     /**
@@ -189,6 +203,10 @@
             return false;
         }
 
+        if (mLaunchTransitionFadingAway) {
+            return true;
+        }
+
         if (mStatusBarState != KEYGUARD) {
             return true;
         }
@@ -237,10 +255,13 @@
     }
 
     private void updateAlpha() {
-        // fade icon on transition to showing bouncer
+        // fade icon on transitions to showing the status bar, but if mUdfpsRequested, then
+        // the keyguard is occluded by some application - so instead use the input bouncer
+        // hidden amount to determine the fade
+        float expansion = mUdfpsRequested ? mInputBouncerHiddenAmount : mStatusBarExpansion;
         int alpha = mShowingUdfpsBouncer ? 255
                 : (int) MathUtils.constrain(
-                    MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount),
+                    MathUtils.map(.5f, .9f, 0f, 255f, expansion),
                     0f, 255f);
         alpha *= (1.0f - mTransitionToFullShadeProgress);
         mView.setUnpausedAlpha(alpha);
@@ -356,4 +377,23 @@
                     mView.updateColor();
                 }
             };
+
+    private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+            new StatusBar.ExpansionChangedListener() {
+                @Override
+                public void onExpansionChanged(float expansion, boolean expanded) {
+                    mStatusBarExpansion = expansion;
+                    updateAlpha();
+                }
+            };
+
+    private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
+            new KeyguardStateController.Callback() {
+                @Override
+                public void onLaunchTransitionFadingAwayChanged() {
+                    mLaunchTransitionFadingAway =
+                            mKeyguardStateController.isLaunchTransitionFadingAway();
+                    updatePauseAuth();
+                }
+            };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index dfbea37..4705a36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1148,6 +1148,9 @@
                     mStatusBarView.setPanel(mNotificationPanelViewController);
                     mStatusBarView.setScrimController(mScrimController);
                     mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+                    for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+                        sendInitialExpansionAmount(listener);
+                    }
 
                     // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
                     // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
@@ -4932,6 +4935,14 @@
 
     public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
         mExpansionChangedListeners.add(listener);
+        sendInitialExpansionAmount(listener);
+    }
+
+    private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
+        if (mStatusBarView != null) {
+            expansionChangedListener.onExpansionChanged(mStatusBarView.getExpansionFraction(),
+                    mStatusBarView.isExpanded());
+        }
     }
 
     public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index fcfc967..7057618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -245,5 +245,11 @@
          * animation.
          */
         default void onKeyguardDismissAmountChanged() {}
+
+        /**
+         * Triggered when the notification panel is starting or has finished
+         * fading away on transition to an app.
+         */
+        default void onLaunchTransitionFadingAwayChanged() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 64750bd..f787ecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -343,6 +343,7 @@
     @Override
     public void setLaunchTransitionFadingAway(boolean fadingAway) {
         mLaunchTransitionFadingAway = fadingAway;
+        new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 0c03a51..47e060e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -20,6 +20,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeast;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -30,7 +35,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -40,6 +44,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import org.junit.Before;
@@ -50,6 +55,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -75,6 +82,8 @@
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
     private KeyguardViewMediator mKeyguardViewMediator;
     @Mock
     private ConfigurationController mConfigurationController;
@@ -88,14 +97,15 @@
     private StatusBarStateController.StateListener mStatusBarStateListener;
 
     @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
-    private StatusBar.ExpansionChangedListener mExpansionListener;
+    private List<StatusBar.ExpansionChangedListener> mExpansionListeners;
 
     @Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
             mAltAuthInterceptorCaptor;
     private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
 
-    @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateMonitorCallbackCaptor;
-    private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+    @Captor private ArgumentCaptor<KeyguardStateController.Callback>
+            mKeyguardStateControllerCallbackCaptor;
+    private KeyguardStateController.Callback mKeyguardStateControllerCallback;
 
     @Before
     public void setUp() {
@@ -114,13 +124,14 @@
                 mKeyguardViewMediator,
                 mLockscreenShadeTransitionController,
                 mConfigurationController,
+                mKeyguardStateController,
                 mUdfpsController);
     }
 
     @Test
     public void testRegistersExpansionChangedListenerOnAttached() {
         mController.onViewAttached();
-        captureExpansionListener();
+        captureExpansionListeners();
     }
 
     @Test
@@ -149,11 +160,15 @@
     public void testListenersUnregisteredOnDetached() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
+        captureExpansionListeners();
+        captureKeyguardStateControllerCallback();
         mController.onViewDetached();
 
         verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
-        verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+        for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+            verify(mStatusBar).removeExpansionChangedListener(listener);
+        }
+        verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
     }
 
     @Test
@@ -172,7 +187,6 @@
     public void testShouldPauseAuthBouncerShowing() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
 
@@ -183,7 +197,6 @@
     public void testShouldNotPauseAuthOnKeyguard() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
 
@@ -191,10 +204,25 @@
     }
 
     @Test
+    public void testShouldPauseAuthIsLaunchTransitionFadingAway() {
+        // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
+        mController.onViewAttached();
+        captureStatusBarStateListeners();
+        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
+
+        // WHEN isLaunchTransitionFadingAway=true
+        captureKeyguardStateControllerCallback();
+        when(mKeyguardStateController.isLaunchTransitionFadingAway()).thenReturn(true);
+        mKeyguardStateControllerCallback.onLaunchTransitionFadingAwayChanged();
+
+        // THEN pause auth
+        assertTrue(mController.shouldPauseAuth());
+    }
+
+    @Test
     public void testShouldPauseAuthOnShadeLocked() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
 
@@ -205,7 +233,6 @@
     public void testShouldPauseAuthOnShade() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN not on keyguard yet (shade = home)
         sendStatusBarStateChanged(StatusBarState.SHADE);
@@ -218,7 +245,6 @@
     public void testShouldPauseAuthAnimatingScreenOffFromShade() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN transitioning from home/shade => keyguard + animating screen off
         mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
@@ -232,7 +258,6 @@
     public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN animating screen off transition from LS => AOD
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -273,6 +298,21 @@
         verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAltAuthInterceptor);
     }
 
+    @Test
+    public void testFadeInWithStatusBarExpansion() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureExpansionListeners();
+        captureKeyguardStateControllerCallback();
+        reset(mView);
+
+        // WHEN status bar expansion is 0
+        updateStatusBarExpansion(0, true);
+
+        // THEN alpha is 0
+        verify(mView).setUnpausedAlpha(0);
+    }
+
     private void sendStatusBarStateChanged(int statusBarState) {
         mStatusBarStateListener.onStateChanged(statusBarState);
     }
@@ -282,9 +322,18 @@
         mStatusBarStateListener = mStateListenerCaptor.getValue();
     }
 
-    private void captureExpansionListener() {
-        verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
-        mExpansionListener = mExpansionListenerCaptor.getValue();
+    private void captureExpansionListeners() {
+        verify(mStatusBar, times(2))
+                .addExpansionChangedListener(mExpansionListenerCaptor.capture());
+        // first (index=0) is from super class, UdfpsAnimationViewController.
+        // second (index=1) is from UdfpsKeyguardViewController
+        mExpansionListeners = mExpansionListenerCaptor.getAllValues();
+    }
+
+    private void updateStatusBarExpansion(float expansion, boolean expanded) {
+        for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+            listener.onExpansionChanged(expansion, expanded);
+        }
     }
 
     private void captureAltAuthInterceptor() {
@@ -293,8 +342,9 @@
         mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
     }
 
-    private void captureKeyguardUpdateMonitorCallback() {
-        verify(mKeyguardUpdateMonitor).registerCallback(mUpdateMonitorCallbackCaptor.capture());
-        mKeyguardUpdateMonitorCallback = mUpdateMonitorCallbackCaptor.getValue();
+    private void captureKeyguardStateControllerCallback() {
+        verify(mKeyguardStateController).addCallback(
+                mKeyguardStateControllerCallbackCaptor.capture());
+        mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
     }
 }