Add FP running state and FP sensor type information to DeviceEntryFPAuthRepository
Bug: 262838215 Test: atest DeviceEntryFingerprintAuthRepositoryTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:86b1c272439ff87eb409d9dce1799a1d2ac6aba1) Merged-In: I0e7196db2eda7a42885658dee22a7ae585b20af2 Change-Id: I0e7196db2eda7a42885658dee22a7ae585b20af2
This commit is contained in:
committed by
Cherrypicker Worker
parent
5308553f06
commit
e6462e402f
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user