Fix persisting SFPS indicator issue.

KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never reset.

This is caused by usages of show()/forceShow() that only read (but not collect) the canShowAlternateBouncer flow to set the alternate bouncer visible state, if there is a race condition between when canShowAlternateBouncer flow changes to false and when the read happens, alternateBouncerVisible state will be set to an incorrect value and not reset on time.

Confirmed with additional logs that this is what is happening.

Flag: EXEMPT bugfix
Fixes: 360737693
Test: verified manually
 1. Enable screensaver while charging (on a large screen device with side fingerprint sensor)
 2. Go to screensaver
 3. Try authenticating with un-enrolled finger 5 times
 4. Bouncer should be shown
 5. SFPS indicator should not be visible on bouncer
 6. unlock the device with PIN/pattern/password
 7. SFPS indicator should not be visible after device is entered
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:070817baf2efe665c186e19775c9beda05199a72)
Merged-In: I3bad4783b4283820bcf6473fd87da8cc8173c07f
Change-Id: I3bad4783b4283820bcf6473fd87da8cc8173c07f
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 373671d0..0949ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
+import android.util.Log
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
@@ -46,6 +47,7 @@
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
@@ -137,6 +139,8 @@
                     flowOf(false)
                 }
             }
+            .distinctUntilChanged()
+            .onEach { Log.d(TAG, "canShowAlternateBouncer changed to $it") }
             .stateIn(
                 scope = scope,
                 started = WhileSubscribed(),
@@ -234,5 +238,7 @@
 
     companion object {
         private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
+
+        private const val TAG = "AlternateBouncerInteractor"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 1ea26e5..6fde603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -528,6 +528,7 @@
                     this::consumeKeyguardAuthenticatedBiometricsHandled
             );
         } else {
+            // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
             mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
                     mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
                     this::consumeCanShowAlternateBouncer
@@ -576,8 +577,17 @@
     }
 
     private void consumeCanShowAlternateBouncer(boolean canShow) {
-        // do nothing, we only are registering for the flow to ensure that there's at least
-        // one subscriber that will update AlternateBouncerInteractor.canShowAlternateBouncer.value
+        // Hack: this is required to fix issues where
+        // KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never
+        // reset. This is caused by usages of show()/forceShow() that only read this flow to set the
+        // alternate bouncer visible state, if there is a race condition between when that flow
+        // changes to false and when the read happens, the flow will be set to an incorrect value
+        // and not reset on time.
+        if (!canShow) {
+            Log.d(TAG, "canShowAlternateBouncer turned false, maybe try hiding the alternate "
+                    + "bouncer if it is already visible");
+            mAlternateBouncerInteractor.maybeHide();
+        }
     }
 
     /** Register a callback, to be invoked by the Predictive Back system. */