Merge "Revert "Use biometricUnlockController state change to show the unlock ripple."" into tm-qpr-dev am: 8606354ee9 am: 2848d01356

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22212379

Change-Id: Ib3298d705ee869d7af492de41bbf0c8cb5681e47
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2023-03-23 17:47:27 +00:00
committed by Automerger Merge Worker
2 changed files with 139 additions and 102 deletions

View File

@@ -42,8 +42,8 @@ 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.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -61,9 +61,7 @@ import javax.inject.Provider
* The ripple uses the accent color of the current theme.
*/
@CentralSurfacesScope
class AuthRippleController
@Inject
constructor(
class AuthRippleController @Inject constructor(
private val centralSurfaces: CentralSurfaces,
private val sysuiContext: Context,
private val authController: AuthController,
@@ -73,18 +71,18 @@ constructor(
private val wakefulnessLifecycle: WakefulnessLifecycle,
private val commandRegistry: CommandRegistry,
private val notificationShadeWindowController: NotificationShadeWindowController,
private val bypassController: KeyguardBypassController,
private val biometricUnlockController: BiometricUnlockController,
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
private val featureFlags: FeatureFlags,
private val logger: KeyguardLogger,
rippleView: AuthRippleView?
) :
ViewController<AuthRippleView>(rippleView),
KeyguardStateController.Callback,
rippleView: AuthRippleView?
) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
WakefulnessLifecycle.Observer {
@VisibleForTesting internal var startLightRevealScrimOnKeyguardFadingAway = false
@VisibleForTesting
internal var startLightRevealScrimOnKeyguardFadingAway = false
var lightRevealScrimAnimator: ValueAnimator? = null
var fingerprintSensorLocation: Point? = null
private var faceSensorLocation: Point? = null
@@ -93,16 +91,6 @@ constructor(
private var udfpsController: UdfpsController? = null
private var udfpsRadius: Float = -1f
private val biometricModeListener = object : BiometricUnlockController.BiometricModeListener {
override fun onModeChanged(mode: Int) {
// isBiometricUnlock does not cover the scenario when biometrics unlocks
// the device while the bouncer is showing.
if (biometricUnlockController.isBiometricUnlock || mode == MODE_DISMISS_BOUNCER) {
showUnlockRipple(biometricUnlockController.biometricType)
}
}
}
@VisibleForTesting
public override fun onViewAttached() {
authController.addCallback(authControllerCallback)
@@ -114,7 +102,6 @@ constructor(
keyguardStateController.addCallback(this)
wakefulnessLifecycle.addObserver(this)
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
biometricUnlockController.addBiometricModeListener(biometricModeListener)
}
@VisibleForTesting
@@ -126,7 +113,6 @@ constructor(
keyguardStateController.removeCallback(this)
wakefulnessLifecycle.removeObserver(this)
commandRegistry.unregisterCommand("auth-ripple")
biometricUnlockController.removeBiometricModeListener(biometricModeListener)
notificationShadeWindowController.setForcePluginOpen(false, this)
}
@@ -157,7 +143,10 @@ constructor(
showUnlockedRipple()
}
} else if (biometricSourceType == BiometricSourceType.FACE) {
faceSensorLocation?.let {
if (!bypassController.canBypass() && !authController.isUdfpsFingerDown) {
return
}
faceSensorLocation?.let {
mView.setSensorLocation(it)
circleReveal = CircleReveal(
it.x,
@@ -278,6 +267,7 @@ constructor(
if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
mView.fadeDwellRipple()
}
showUnlockRipple(biometricSourceType)
}
override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType) {

View File

@@ -17,14 +17,14 @@
package com.android.systemui.biometrics
import android.graphics.Point
import android.hardware.biometrics.BiometricSourceType.FACE
import android.hardware.biometrics.BiometricSourceType.FINGERPRINT
import android.hardware.biometrics.BiometricSourceType
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
@@ -36,11 +36,11 @@ import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.mockito.any
import javax.inject.Provider
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -50,15 +50,15 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
import javax.inject.Provider
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -75,6 +75,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock private lateinit var bypassController: KeyguardBypassController
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
@Mock private lateinit var udfpsController: UdfpsController
@@ -83,15 +84,10 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var lightRevealScrim: LightRevealScrim
@Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
@Captor
private lateinit var biometricModeListener:
ArgumentCaptor<BiometricUnlockController.BiometricModeListener>
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
staticMockSession =
mockitoSession()
staticMockSession = mockitoSession()
.mockStatic(RotationUtils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
@@ -100,24 +96,24 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(authController.udfpsProps).thenReturn(listOf(fpSensorProp))
`when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
controller =
AuthRippleController(
mCentralSurfaces,
context,
authController,
configurationController,
keyguardUpdateMonitor,
keyguardStateController,
wakefulnessLifecycle,
commandRegistry,
notificationShadeWindowController,
biometricUnlockController,
udfpsControllerProvider,
statusBarStateController,
featureFlags,
KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
rippleView
)
controller = AuthRippleController(
mCentralSurfaces,
context,
authController,
configurationController,
keyguardUpdateMonitor,
keyguardStateController,
wakefulnessLifecycle,
commandRegistry,
notificationShadeWindowController,
bypassController,
biometricUnlockController,
udfpsControllerProvider,
statusBarStateController,
featureFlags,
KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
rippleView
)
controller.init()
`when`(mCentralSurfaces.lightRevealScrim).thenReturn(lightRevealScrim)
}
@@ -134,14 +130,16 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT)))
.thenReturn(true)
`when`(biometricUnlockController.isBiometricUnlock).thenReturn(true)
`when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
// WHEN unlocked with fingerprint
verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture())
biometricModeListener.value.onModeChanged(/* mode= */ 0)
// 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).setFingerprintSensorLocation(fpsLocation, 0f)
@@ -154,15 +152,17 @@ class AuthRippleControllerTest : SysuiTestCase() {
val fpsLocation = Point(5, 5)
`when`(authController.udfpsLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT)))
.thenReturn(true)
`when`(biometricUnlockController.isBiometricUnlock).thenReturn(true)
`when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
// WHEN keyguard is NOT showing & fingerprint authenticated
`when`(keyguardStateController.isShowing).thenReturn(false)
verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture())
biometricModeListener.value.onModeChanged(/* mode= */ 0)
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()).startUnlockedRipple(any())
@@ -175,14 +175,61 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(authController.udfpsLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(biometricUnlockController.isBiometricUnlock).thenReturn(true)
`when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT)
// WHEN unlocking with fingerprint is NOT allowed & fingerprint authenticated
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT)))
.thenReturn(false)
verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture())
biometricModeListener.value.onModeChanged(/* mode= */ 0)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
eq(BiometricSourceType.FINGERPRINT))).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()).startUnlockedRipple(any())
}
@Test
fun testFaceTriggerBypassEnabled_Ripple() {
// GIVEN face auth sensor exists, keyguard is showing & unlocking with face is allowed
val faceLocation = Point(5, 5)
`when`(authController.faceSensorLocation).thenReturn(faceLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
BiometricSourceType.FACE)).thenReturn(true)
// 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).startUnlockedRipple(any())
}
@Test
fun testFaceTriggerNonBypass_NoRipple() {
// GIVEN face auth sensor exists
val faceLocation = Point(5, 5)
`when`(authController.faceSensorLocation).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()).startUnlockedRipple(any())
@@ -192,12 +239,14 @@ class AuthRippleControllerTest : SysuiTestCase() {
fun testNullFaceSensorLocationDoesNothing() {
`when`(authController.faceSensorLocation).thenReturn(null)
controller.onViewAttached()
`when`(biometricUnlockController.biometricType).thenReturn(FACE)
`when`(biometricUnlockController.isBiometricUnlock).thenReturn(true)
verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture())
biometricModeListener.value.onModeChanged(/* mode= */ 0)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FACE /* type */,
false /* isStrongBiometric */)
verify(rippleView, never()).startUnlockedRipple(any())
}
@@ -205,21 +254,25 @@ class AuthRippleControllerTest : SysuiTestCase() {
fun testNullFingerprintSensorLocationDoesNothing() {
`when`(authController.fingerprintSensorLocation).thenReturn(null)
controller.onViewAttached()
`when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT)
`when`(biometricUnlockController.isBiometricUnlock).thenReturn(true)
verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture())
biometricModeListener.value.onModeChanged(/* mode= */ 0)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
false /* isStrongBiometric */)
verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
fun registersAndDeregisters() {
controller.onViewAttached()
val captor = ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java)
val captor = ArgumentCaptor
.forClass(KeyguardStateController.Callback::class.java)
verify(keyguardStateController).addCallback(captor.capture())
val captor2 = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
val captor2 = ArgumentCaptor
.forClass(WakefulnessLifecycle.Observer::class.java)
verify(wakefulnessLifecycle).addObserver(captor2.capture())
controller.onViewDetached()
verify(keyguardStateController).removeCallback(any())
@@ -233,20 +286,17 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(FINGERPRINT)).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
BiometricSourceType.FINGERPRINT)).thenReturn(true)
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
controller.showUnlockRipple(FINGERPRINT)
assertTrue(
"reveal didn't start on keyguardFadingAway",
controller.startLightRevealScrimOnKeyguardFadingAway
)
controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
assertTrue("reveal didn't start on keyguardFadingAway",
controller.startLightRevealScrimOnKeyguardFadingAway)
`when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
controller.onKeyguardFadingAwayChanged()
assertFalse(
"reveal triggers multiple times",
controller.startLightRevealScrimOnKeyguardFadingAway
)
assertFalse("reveal triggers multiple times",
controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test
@@ -258,26 +308,23 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
`when`(authController.isUdfpsFingerDown).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FACE))).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
eq(BiometricSourceType.FACE))).thenReturn(true)
controller.showUnlockRipple(FACE)
assertTrue(
"reveal didn't start on keyguardFadingAway",
controller.startLightRevealScrimOnKeyguardFadingAway
)
controller.showUnlockRipple(BiometricSourceType.FACE)
assertTrue("reveal didn't start on keyguardFadingAway",
controller.startLightRevealScrimOnKeyguardFadingAway)
`when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
controller.onKeyguardFadingAwayChanged()
assertFalse(
"reveal triggers multiple times",
controller.startLightRevealScrimOnKeyguardFadingAway
)
assertFalse("reveal triggers multiple times",
controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test
fun testUpdateRippleColor() {
controller.onViewAttached()
val captor =
ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
val captor = ArgumentCaptor
.forClass(ConfigurationController.ConfigurationListener::class.java)
verify(configurationController).addCallback(captor.capture())
reset(rippleView)