Hide the alternate bouncer after dismiss actions have run
If we hide the alternate bouncer too early, then
sometimes the dismiss action intent will fail. This
CL moves the logic for hiding the alternate bouncer
after a successful biometric auth to when the keyguard
transition to gone is finished.
Flag: None
Flag: ACONFIG com.android.systemui.device_entry_udfps_refactor TEAMFOOD
Bug: 327570518
Test: test with and without udfps_refactor enabled
Test: atest StatusBarKeyguardViewManagerTest AlternateBouncerViewModelTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d553f16a292d4ba7f00ea245884291fc6265a852)
Merged-In: I24c98eeec6c76f777033be88ee2d0d54d31e71f4
Change-Id: I24c98eeec6c76f777033be88ee2d0d54d31e71f4
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 8c87b0c..893887f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -93,6 +93,8 @@
val keyguardAuthenticatedPrimaryAuth: Flow<Int> = repository.keyguardAuthenticatedPrimaryAuth
val keyguardAuthenticatedBiometrics: Flow<Boolean> =
repository.keyguardAuthenticatedBiometrics.filterNotNull()
+ val keyguardAuthenticatedBiometricsHandled: Flow<Unit> =
+ repository.keyguardAuthenticatedBiometrics.filter { it == null }.map {}
val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
repository.userRequestedBouncerWhenAlreadyAuthenticated.filterNotNull()
val isShowing: StateFlow<Boolean> = repository.primaryBouncerShow
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 1c9d1f0..e1fea5f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -23,12 +23,14 @@
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.BouncerViewDelegate
import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
/** Models UI state for the lock screen bouncer; handles user input. */
+@ExperimentalCoroutinesApi
class KeyguardBouncerViewModel
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index d400210..3a2781c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -102,9 +102,16 @@
launch {
viewModel.scrimAlpha.collect {
+ val wasVisible = alternateBouncerViewContainer.visibility == View.VISIBLE
alternateBouncerViewContainer.visibility =
if (it < .1f) View.INVISIBLE else View.VISIBLE
scrim.viewAlpha = it
+ if (
+ wasVisible && alternateBouncerViewContainer.visibility == View.INVISIBLE
+ ) {
+ // view is no longer visible
+ viewModel.hideAlternateBouncer()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
index 2526f0a..10a9e3b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
@@ -89,4 +89,8 @@
fun showPrimaryBouncer() {
statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
}
+
+ fun hideAlternateBouncer() {
+ statusBarKeyguardViewManager.hideAlternateBouncer(false)
+ }
}
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 d1055c7..9cfedaab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -76,6 +76,8 @@
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.keyguard.shared.model.DismissAction;
import com.android.systemui.keyguard.shared.model.KeyguardDone;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
@@ -101,6 +103,8 @@
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -112,6 +116,7 @@
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.ExperimentalCoroutinesApi;
+import kotlinx.coroutines.Job;
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -158,6 +163,9 @@
private final BouncerView mPrimaryBouncerView;
private final Lazy<ShadeController> mShadeController;
+ private Job mListenForAlternateBouncerTransitionSteps = null;
+ private Job mListenForKeyguardAuthenticatedBiometricsHandled = null;
+
// Local cache of expansion events, to avoid duplicates
private float mFraction = -1f;
private boolean mTracking = false;
@@ -482,6 +490,26 @@
mDockManager.addListener(mDockEventListener);
mIsDocked = mDockManager.isDocked();
}
+ if (mListenForAlternateBouncerTransitionSteps != null) {
+ mListenForAlternateBouncerTransitionSteps.cancel(null);
+ }
+ mListenForAlternateBouncerTransitionSteps = null;
+ if (mListenForKeyguardAuthenticatedBiometricsHandled != null) {
+ mListenForKeyguardAuthenticatedBiometricsHandled.cancel(null);
+ }
+ mListenForKeyguardAuthenticatedBiometricsHandled = null;
+ if (!DeviceEntryUdfpsRefactor.isEnabled()) {
+ mListenForAlternateBouncerTransitionSteps = mJavaAdapter.alwaysCollectFlow(
+ mKeyguardTransitionInteractor.transitionStepsFromState(
+ KeyguardState.ALTERNATE_BOUNCER),
+ this::consumeFromAlternateBouncerTransitionSteps
+ );
+
+ mListenForKeyguardAuthenticatedBiometricsHandled = mJavaAdapter.alwaysCollectFlow(
+ mPrimaryBouncerInteractor.getKeyguardAuthenticatedBiometricsHandled(),
+ this::consumeKeyguardAuthenticatedBiometricsHandled
+ );
+ }
if (KeyguardWmStateRefactor.isEnabled()) {
// Show the keyguard views whenever we've told WM that the lockscreen is visible.
@@ -500,6 +528,22 @@
}
}
+ @VisibleForTesting
+ void consumeFromAlternateBouncerTransitionSteps(TransitionStep step) {
+ hideAlternateBouncer(false);
+ }
+
+ /**
+ * Required without fix for b/328643370: missing AlternateBouncer (when occluded) => Gone
+ * transition.
+ */
+ @VisibleForTesting
+ void consumeKeyguardAuthenticatedBiometricsHandled(Unit handled) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
+ hideAlternateBouncer(false);
+ }
+ }
+
private void consumeShowStatusBarKeyguardView(boolean show) {
if (show != mLastShowing) {
if (show) {
@@ -1441,7 +1485,6 @@
mPrimaryBouncerInteractor.notifyKeyguardAuthenticatedBiometrics(strongAuth);
if (mAlternateBouncerInteractor.isVisibleState()) {
- hideAlternateBouncer(false);
executeAfterKeyguardGoneAction();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
index 87391cc..d410dac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -36,6 +37,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.Mockito.verify
@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
@@ -48,6 +50,20 @@
private val underTest = kosmos.alternateBouncerViewModel
@Test
+ fun showPrimaryBouncer() =
+ testScope.runTest {
+ underTest.showPrimaryBouncer()
+ verify(statusBarKeyguardViewManager).showPrimaryBouncer(any())
+ }
+
+ @Test
+ fun hideAlternateBouncer() =
+ testScope.runTest {
+ underTest.hideAlternateBouncer()
+ verify(statusBarKeyguardViewManager).hideAlternateBouncer(any())
+ }
+
+ @Test
fun transitionToAlternateBouncer_scrimAlphaUpdate() =
testScope.runTest {
val scrimAlphas by collectValues(underTest.scrimAlpha)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 3666248..a715556 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -82,6 +82,9 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
import com.android.systemui.plugins.ActivityStarter;
@@ -101,6 +104,8 @@
import com.google.common.truth.Truth;
+import kotlin.Unit;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -1039,4 +1044,35 @@
verify(mCentralSurfaces, never()).hideKeyguard();
verify(mPrimaryBouncerInteractor, never()).show(true);
}
+
+ @Test
+ public void altBouncerNotVisible_keyguardAuthenticatedBiometricsHandled() {
+ clearInvocations(mAlternateBouncerInteractor);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
+ mStatusBarKeyguardViewManager.consumeKeyguardAuthenticatedBiometricsHandled(Unit.INSTANCE);
+ verify(mAlternateBouncerInteractor, never()).hide();
+ }
+
+ @Test
+ public void altBouncerVisible_keyguardAuthenticatedBiometricsHandled() {
+ clearInvocations(mAlternateBouncerInteractor);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+ mStatusBarKeyguardViewManager.consumeKeyguardAuthenticatedBiometricsHandled(Unit.INSTANCE);
+ verify(mAlternateBouncerInteractor).hide();
+ }
+
+ @Test
+ public void fromAlternateBouncerTransitionStep() {
+ clearInvocations(mAlternateBouncerInteractor);
+ mStatusBarKeyguardViewManager.consumeFromAlternateBouncerTransitionSteps(
+ new TransitionStep(
+ /* from */ KeyguardState.ALTERNATE_BOUNCER,
+ /* to */ KeyguardState.GONE,
+ /* value */ 1f,
+ TransitionState.FINISHED,
+ "StatusBarKeyguardViewManagerTest"
+ )
+ );
+ verify(mAlternateBouncerInteractor).hide();
+ }
}