Loading packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +1 −1 Original line number Diff line number Diff line Loading @@ -2143,7 +2143,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenUdfpsState = !isUdfps || (!getUserCanSkipBouncer(getCurrentUser()) && !isEncryptedOrLockdown(getCurrentUser()) && mStrongAuthTracker.hasUserAuthenticatedSinceBoot() && !userNeedsStrongAuth() && userDoesNotHaveTrust); return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +10 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.settingslib.Utils import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.ViewController Loading @@ -45,6 +46,7 @@ class AuthRippleController @Inject constructor( private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val commandRegistry: CommandRegistry, private val notificationShadeWindowController: NotificationShadeWindowController, private val bypassController: KeyguardBypassController, rippleView: AuthRippleView? ) : ViewController<AuthRippleView>(rippleView) { private var fingerprintSensorLocation: PointF? = null Loading @@ -69,12 +71,20 @@ class AuthRippleController @Inject constructor( } private fun showRipple(biometricSourceType: BiometricSourceType?) { if (!keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.userNeedsStrongAuth()) { return } if (biometricSourceType == BiometricSourceType.FINGERPRINT && fingerprintSensorLocation != null) { mView.setSensorLocation(fingerprintSensorLocation!!) showRipple() } else if (biometricSourceType == BiometricSourceType.FACE && faceSensorLocation != null) { if (!bypassController.canBypass()) { return } mView.setSensorLocation(faceSensorLocation!!) showRipple() } Loading packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +7 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.keyguard; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -477,7 +479,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testFingerprintDoesNotAuth_whenEncrypted() { testFingerprintWhenStrongAuth( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); } @Test Loading Loading @@ -576,7 +578,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void skipsAuthentication_whenEncryptedKeyguard() { when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); mKeyguardUpdateMonitor.dispatchStartedWakingUp(); Loading @@ -588,7 +590,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void requiresAuthentication_whenEncryptedKeyguard_andBypass() { testStrongAuthExceptOnBouncer( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); } @Test Loading Loading @@ -893,7 +895,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD); // WHEN user hasn't authenticated since last boot when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(false); when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT); // THEN we shouldn't listen for udfps assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false); Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +81 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import org.junit.Before import org.junit.Test Loading @@ -49,6 +50,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var authController: AuthController @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var bypassController: KeyguardBypassController @Before fun setUp() { Loading @@ -60,45 +62,120 @@ class AuthRippleControllerTest : SysuiTestCase() { keyguardUpdateMonitor, commandRegistry, notificationShadeWindowController, bypassController, rippleView ) controller.init() } @Test fun testFingerprintTriggerRipple() { fun testFingerprintTrigger_Ripple() { // GIVEN fp exists, keyguard is visible, user doesn't need strong auth val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN fingerprint authenticated val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN update sensor location and show ripple verify(rippleView).setSensorLocation(fpsLocation) verify(rippleView).startRipple(any()) } @Test fun testFaceTriggerRipple() { fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() { // GIVEN fp exists & user doesn't need strong auth val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN keyguard is NOT visible & fingerprint authenticated `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testFingerprintTrigger_StrongAuthRequired_NoRipple() { // GIVEN fp exists & keyguard is visible val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) // WHEN user needs strong auth & fingerprint authenticated `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(true) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testFaceTriggerBypassEnabled_Ripple() { // GIVEN face auth sensor exists, keyguard is visible & strong auth isn't required val faceLocation = PointF(5f, 5f) `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN bypass is enabled & face authenticated `when`(bypassController.canBypass()).thenReturn(true) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FACE /* type */, false /* isStrongBiometric */) // THEN show ripple verify(rippleView).setSensorLocation(faceLocation) verify(rippleView).startRipple(any()) } @Test fun testFaceTriggerNonBypass_NoRipple() { // GIVEN face auth sensor exists val faceLocation = PointF(5f, 5f) `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) controller.onViewAttached() // WHEN bypass isn't enabled & face authenticated `when`(bypassController.canBypass()).thenReturn(false) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FACE /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testNullFaceSensorLocationDoesNothing() { `when`(authController.faceAuthSensorLocation).thenReturn(null) Loading Loading
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +1 −1 Original line number Diff line number Diff line Loading @@ -2143,7 +2143,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenUdfpsState = !isUdfps || (!getUserCanSkipBouncer(getCurrentUser()) && !isEncryptedOrLockdown(getCurrentUser()) && mStrongAuthTracker.hasUserAuthenticatedSinceBoot() && !userNeedsStrongAuth() && userDoesNotHaveTrust); return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +10 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.settingslib.Utils import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.ViewController Loading @@ -45,6 +46,7 @@ class AuthRippleController @Inject constructor( private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val commandRegistry: CommandRegistry, private val notificationShadeWindowController: NotificationShadeWindowController, private val bypassController: KeyguardBypassController, rippleView: AuthRippleView? ) : ViewController<AuthRippleView>(rippleView) { private var fingerprintSensorLocation: PointF? = null Loading @@ -69,12 +71,20 @@ class AuthRippleController @Inject constructor( } private fun showRipple(biometricSourceType: BiometricSourceType?) { if (!keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.userNeedsStrongAuth()) { return } if (biometricSourceType == BiometricSourceType.FINGERPRINT && fingerprintSensorLocation != null) { mView.setSensorLocation(fingerprintSensorLocation!!) showRipple() } else if (biometricSourceType == BiometricSourceType.FACE && faceSensorLocation != null) { if (!bypassController.canBypass()) { return } mView.setSensorLocation(faceSensorLocation!!) showRipple() } Loading
packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +7 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.keyguard; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -477,7 +479,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testFingerprintDoesNotAuth_whenEncrypted() { testFingerprintWhenStrongAuth( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); } @Test Loading Loading @@ -576,7 +578,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void skipsAuthentication_whenEncryptedKeyguard() { when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); mKeyguardUpdateMonitor.dispatchStartedWakingUp(); Loading @@ -588,7 +590,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void requiresAuthentication_whenEncryptedKeyguard_andBypass() { testStrongAuthExceptOnBouncer( KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT); STRONG_AUTH_REQUIRED_AFTER_BOOT); } @Test Loading Loading @@ -893,7 +895,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD); // WHEN user hasn't authenticated since last boot when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(false); when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT); // THEN we shouldn't listen for udfps assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false); Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +81 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import org.junit.Before import org.junit.Test Loading @@ -49,6 +50,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var authController: AuthController @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var bypassController: KeyguardBypassController @Before fun setUp() { Loading @@ -60,45 +62,120 @@ class AuthRippleControllerTest : SysuiTestCase() { keyguardUpdateMonitor, commandRegistry, notificationShadeWindowController, bypassController, rippleView ) controller.init() } @Test fun testFingerprintTriggerRipple() { fun testFingerprintTrigger_Ripple() { // GIVEN fp exists, keyguard is visible, user doesn't need strong auth val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN fingerprint authenticated val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN update sensor location and show ripple verify(rippleView).setSensorLocation(fpsLocation) verify(rippleView).startRipple(any()) } @Test fun testFaceTriggerRipple() { fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() { // GIVEN fp exists & user doesn't need strong auth val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN keyguard is NOT visible & fingerprint authenticated `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testFingerprintTrigger_StrongAuthRequired_NoRipple() { // GIVEN fp exists & keyguard is visible val fpsLocation = PointF(5f, 5f) `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) // WHEN user needs strong auth & fingerprint authenticated `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(true) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testFaceTriggerBypassEnabled_Ripple() { // GIVEN face auth sensor exists, keyguard is visible & strong auth isn't required val faceLocation = PointF(5f, 5f) `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) // WHEN bypass is enabled & face authenticated `when`(bypassController.canBypass()).thenReturn(true) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FACE /* type */, false /* isStrongBiometric */) // THEN show ripple verify(rippleView).setSensorLocation(faceLocation) verify(rippleView).startRipple(any()) } @Test fun testFaceTriggerNonBypass_NoRipple() { // GIVEN face auth sensor exists val faceLocation = PointF(5f, 5f) `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) controller.onViewAttached() // WHEN bypass isn't enabled & face authenticated `when`(bypassController.canBypass()).thenReturn(false) val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) verify(keyguardUpdateMonitor).registerCallback(captor.capture()) captor.value.onBiometricAuthenticated( 0 /* userId */, BiometricSourceType.FACE /* type */, false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startRipple(any()) } @Test fun testNullFaceSensorLocationDoesNothing() { `when`(authController.faceAuthSensorLocation).thenReturn(null) Loading