diff options
| author | 2023-03-28 15:51:44 +0000 | |
|---|---|---|
| committer | 2023-03-28 15:51:44 +0000 | |
| commit | 8b8848020de152d2a88298ff7b195e70fde8c6b3 (patch) | |
| tree | 1728a1c9705263d9a0549fceb1afbb095e607d7f | |
| parent | 2835276515a0b9cc53a6b0435d91f6fb35e4bed5 (diff) | |
| parent | e6462e402f5b9dead837304c34d8236ab3b6045e (diff) | |
Merge "Add FP running state and FP sensor type information to DeviceEntryFPAuthRepository" into udc-dev
6 files changed, 158 insertions, 17 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 1de3ddd7c1dd..30321f75dd73 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2476,8 +2476,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered. */ public boolean isUdfpsSupported() { - return mAuthController.getUdfpsProps() != null - && !mAuthController.getUdfpsProps().isEmpty(); + return mAuthController.isUdfpsSupported(); } /** @@ -2492,8 +2491,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. */ public boolean isSfpsSupported() { - return mAuthController.getSfpsProps() != null - && !mAuthController.getSfpsProps().isEmpty(); + return mAuthController.isSfpsSupported(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 705fc8c1a8fd..92344dbbfe15 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -984,6 +984,36 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, return mSidefpsProps; } + /** + * @return true if udfps HW is supported on this device. Can return true even if the user has + * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isUdfpsSupported() { + return getUdfpsProps() != null && !getUdfpsProps().isEmpty(); + } + + /** + * @return true if sfps HW is supported on this device. Can return true even if the user has + * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isSfpsSupported() { + return getSfpsProps() != null && !getSfpsProps().isEmpty(); + } + + /** + * @return true if rear fps HW is supported on this device. Can return true even if the user has + * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isRearFpsSupported() { + for (FingerprintSensorPropertiesInternal prop: mFpProps) { + if (prop.sensorType == TYPE_REAR) { + return true; + } + } + return false; + } + + private String getErrorString(@Modality int modality, int error, int vendorCode) { switch (modality) { case TYPE_FACE: diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt index 7c466845a923..4fa56ee8e4d2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt @@ -20,6 +20,7 @@ import android.hardware.biometrics.BiometricSourceType import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dumpable +import com.android.systemui.biometrics.AuthController import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton @@ -29,6 +30,7 @@ import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn @@ -37,6 +39,17 @@ import kotlinx.coroutines.flow.stateIn interface DeviceEntryFingerprintAuthRepository { /** Whether the device entry fingerprint auth is locked out. */ val isLockedOut: StateFlow<Boolean> + + /** + * Whether the fingerprint sensor is currently listening, this doesn't mean that the user is + * actively authenticating. + */ + val isRunning: Flow<Boolean> + + /** + * Fingerprint sensor type present on the device, null if fingerprint sensor is not available. + */ + val availableFpSensorType: BiometricType? } /** @@ -50,6 +63,7 @@ interface DeviceEntryFingerprintAuthRepository { class DeviceEntryFingerprintAuthRepositoryImpl @Inject constructor( + val authController: AuthController, val keyguardUpdateMonitor: KeyguardUpdateMonitor, @Application scope: CoroutineScope, dumpManager: DumpManager, @@ -63,6 +77,12 @@ constructor( pw.println("isLockedOut=${isLockedOut.value}") } + override val availableFpSensorType: BiometricType? + get() = + if (authController.isUdfpsSupported) BiometricType.UNDER_DISPLAY_FINGERPRINT + else if (authController.isSfpsSupported) BiometricType.SIDE_FINGERPRINT + else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null + override val isLockedOut: StateFlow<Boolean> = conflatedCallbackFlow { val sendLockoutUpdate = @@ -89,6 +109,32 @@ constructor( } .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false) + override val isRunning: Flow<Boolean> + get() = conflatedCallbackFlow { + val callback = + object : KeyguardUpdateMonitorCallback() { + override fun onBiometricRunningStateChanged( + running: Boolean, + biometricSourceType: BiometricSourceType? + ) { + if (biometricSourceType == BiometricSourceType.FINGERPRINT) { + trySendWithFailureLogging( + running, + TAG, + "Fingerprint running state changed" + ) + } + } + } + keyguardUpdateMonitor.registerCallback(callback) + trySendWithFailureLogging( + keyguardUpdateMonitor.isFingerprintDetectionRunning, + TAG, + "Initial fingerprint running state" + ) + awaitClose { keyguardUpdateMonitor.removeCallback(callback) } + } + companion object { const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl" } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index a8b42544fd87..4ed4e20e7e1a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -1360,9 +1360,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void startsListeningForSfps_whenKeyguardIsVisible_ifRequireInteractiveToAuthEnabled() throws RemoteException { // SFPS supported and enrolled - final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON)); - when(mAuthController.getSfpsProps()).thenReturn(props); + when(mAuthController.isSfpsSupported()).thenReturn(true); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); // WHEN require interactive to auth is disabled, and keyguard is not awake @@ -1401,9 +1399,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void notListeningForSfps_whenGoingToSleep_ifRequireInteractiveToAuthEnabled() throws RemoteException { // GIVEN SFPS supported and enrolled - final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON)); - when(mAuthController.getSfpsProps()).thenReturn(props); + when(mAuthController.isSfpsSupported()).thenReturn(true); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); // GIVEN Preconditions for sfps auth to run @@ -2843,8 +2839,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void givenUdfpsSupported() { - Assert.assertFalse(mFingerprintSensorProperties.isEmpty()); - when(mAuthController.getUdfpsProps()).thenReturn(mFingerprintSensorProperties); + when(mAuthController.isUdfpsSupported()).thenReturn(true); Assert.assertTrue(mKeyguardUpdateMonitor.isUdfpsSupported()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt index 0519a44d55ba..70f766f719e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt @@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.AuthController import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dump.DumpManager import com.android.systemui.util.mockito.whenever @@ -37,6 +38,7 @@ import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -46,7 +48,9 @@ import org.mockito.MockitoAnnotations class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var dumpManager: DumpManager - @Captor private lateinit var callbackCaptor: ArgumentCaptor<KeyguardUpdateMonitorCallback> + @Mock private lateinit var authController: AuthController + @Captor + private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> private lateinit var testScope: TestScope @@ -59,6 +63,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { underTest = DeviceEntryFingerprintAuthRepositoryImpl( + authController, keyguardUpdateMonitor, testScope.backgroundScope, dumpManager, @@ -67,7 +72,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { @After fun tearDown() { - verify(keyguardUpdateMonitor).removeCallback(callbackCaptor.value) + // verify(keyguardUpdateMonitor).removeCallback(updateMonitorCallback.value) } @Test @@ -76,8 +81,8 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { val isLockedOutValue = collectLastValue(underTest.isLockedOut) runCurrent() - verify(keyguardUpdateMonitor).registerCallback(callbackCaptor.capture()) - val callback = callbackCaptor.value + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + val callback = updateMonitorCallback.value whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true) callback.onLockedOutStateChanged(BiometricSourceType.FACE) @@ -90,4 +95,63 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { callback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT) assertThat(isLockedOutValue()).isFalse() } + + @Test + fun fpRunningStateIsPropagated() = + testScope.runTest { + val isRunning = collectLastValue(underTest.isRunning) + whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(true) + + // Initial value is available + assertThat(isRunning()).isTrue() + + verify(keyguardUpdateMonitor, atLeastOnce()) + .registerCallback(updateMonitorCallback.capture()) + invokeOnCallback { + it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT) + } + + assertThat(isRunning()).isFalse() + + invokeOnCallback { it.onBiometricRunningStateChanged(true, BiometricSourceType.FACE) } + + assertThat(isRunning()).isFalse() + + updateMonitorCallback.value.onBiometricRunningStateChanged( + true, + BiometricSourceType.FINGERPRINT + ) + assertThat(isRunning()).isTrue() + } + + private fun invokeOnCallback(action: (KeyguardUpdateMonitorCallback) -> Unit) { + updateMonitorCallback.allValues.forEach { action(it) } + } + + @Test + fun enabledFingerprintTypeProvidesTheCorrectOutput() = + testScope.runTest { + whenever(authController.isSfpsSupported).thenReturn(true) + whenever(authController.isUdfpsSupported).thenReturn(false) + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.SIDE_FINGERPRINT) + + whenever(authController.isSfpsSupported).thenReturn(false) + whenever(authController.isUdfpsSupported).thenReturn(true) + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType) + .isEqualTo(BiometricType.UNDER_DISPLAY_FINGERPRINT) + + whenever(authController.isSfpsSupported).thenReturn(false) + whenever(authController.isUdfpsSupported).thenReturn(false) + whenever(authController.isRearFpsSupported).thenReturn(true) + + assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.REAR_FINGERPRINT) + + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType).isNull() + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt index 5641832b6ae2..00b1a401ac79 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt @@ -17,14 +17,22 @@ package com.android.systemui.keyguard.data.repository +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository { - private val _isLockedOut = MutableStateFlow<Boolean>(false) + private val _isLockedOut = MutableStateFlow(false) override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow() + private val _isRunning = MutableStateFlow(false) + override val isRunning: Flow<Boolean> + get() = _isRunning + + override val availableFpSensorType: BiometricType? + get() = null + fun setLockedOut(lockedOut: Boolean) { _isLockedOut.value = lockedOut } |