Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/BiometricAuthIconViewModelTest.kt +121 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.platform.test.annotations.EnableFlags import android.security.Flags.FLAG_SECURE_LOCK_DEVICE import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -41,9 +43,11 @@ import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.biometrics.shared.model.toSensorType import com.android.systemui.biometrics.ui.viewmodel.BiometricAuthIconViewModel.BiometricAuthModalities import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel import com.android.systemui.securelockdevice.ui.viewmodel.secureLockDeviceBiometricAuthContentViewModel import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runCurrent Loading Loading @@ -77,6 +81,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } else if (sensorType == TYPE_REAR) { kosmos.fingerprintPropertyRepository.supportsRearFps(sensorStrength) } kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) } private fun enrollFace(isStrongBiometric: Boolean) { Loading @@ -86,6 +91,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { strength = if (isStrongBiometric) SensorStrength.STRONG else SensorStrength.WEAK, ) kosmos.facePropertyRepository.setSensorInfo(faceSensorInfo) kosmos.biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) } private fun startBiometricPrompt(hasFpAuth: Boolean, isImplicitFlow: Boolean = false) { Loading @@ -103,12 +109,22 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } private fun startSecureLockDevicePrompt() { secureLockDeviceViewModel!!.showAuthenticating() } private fun initPromptViewModel() { promptViewModel = kosmos.promptViewModel underTest = promptViewModel!!.iconViewModel.internal underTest.activateIn(testScope) } private fun initSecureLockDeviceViewModel() { secureLockDeviceViewModel = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest = secureLockDeviceViewModel!!.iconViewModel underTest.activateIn(testScope) } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_face() { testScope.runTest { Loading @@ -127,6 +143,21 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_face() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Face) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfps() { testScope.runTest { Loading @@ -147,6 +178,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_POWER_BUTTON, ) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Sfps) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_nonSfps() { testScope.runTest { Loading @@ -168,6 +217,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_nonSfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_UDFPS_OPTICAL, ) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfps) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfpsCoexImplicit() { testScope.runTest { Loading Loading @@ -212,6 +279,25 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfpsCoex() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_POWER_BUTTON, ) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.SfpsCoex) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_coexNonSfpsImplicit() { testScope.runTest { Loading Loading @@ -256,6 +342,41 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_coexNonSfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_UDFPS_OPTICAL, ) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfpsCoex) } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthNone_forNonStrongBiometrics_forSecureLockDevice() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint(sensorStrength = SensorStrength.WEAK, sensorType = TYPE_UDFPS_OPTICAL) enrollFace(isStrongBiometric = false) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.None) } } /** Initialize the prompt according to the test configuration. */ private fun PromptSelectorInteractor.initializePrompt( fingerprint: FingerprintSensorPropertiesInternal? = null, Loading packages/SystemUI/multivalentTests/src/com/android/systemui/securelockdevice/ui/viewmodel/SecureLockDeviceBiometricAuthContentViewModelTest.kt +78 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.systemui.securelockdevice.domain.interactor.secureLockDeviceI import com.android.systemui.testKosmos import com.google.android.msdl.data.model.MSDLToken import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Job import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before Loading @@ -50,21 +51,32 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private lateinit var secureLockDeviceInteractor: SecureLockDeviceInteractor private lateinit var underTest: SecureLockDeviceBiometricAuthContentViewModel @Before fun setUp() { kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled() kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth() secureLockDeviceInteractor = kosmos.secureLockDeviceInteractor } @Test fun onBiometricAuthRequested_showsAuthenticating_() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) secureLockDeviceInteractor.onBiometricAuthRequested() runCurrent() underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(testScope) assertThat(isAuthenticating).isTrue() } @Test fun updatesStateAndPlaysHaptics_onFaceFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectValues(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectValues(underTest.showingError) Loading @@ -90,6 +102,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateOnRetryAfterFaceFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -115,6 +129,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndSkipsHaptics_onFaceHelp() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -133,6 +149,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesState_onFaceSuccess_andPlaysHapticsOnConfirm() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading Loading @@ -161,6 +179,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndPlaysHaptics_onFingerprintFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectValues(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectValues(underTest.showingError) Loading @@ -186,6 +206,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndSkipsHaptics_onFingerprintHelp() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -204,6 +226,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndPlaysHaptics_onFingerprintSuccess() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -219,4 +243,54 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { assertThat(isAuthenticated?.isAuthenticatedAndConfirmed).isTrue() assertThat(kosmos.fakeMSDLPlayer.latestTokenPlayed).isEqualTo(MSDLToken.UNLOCK) } @Test fun onSuccessfulAuthentication_notifiesInteractorAndHides_uponAnimationFinished() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isReadyToDismiss by collectLastValue(secureLockDeviceInteractor.isFullyUnlockedAndReadyToDismiss) underTest.startAppearAnimation() runCurrent() assertThat(underTest.isVisible).isTrue() assertThat(isReadyToDismiss).isFalse() underTest.showAuthenticated(BiometricModality.Fingerprint) runCurrent() assertThat(underTest.isAuthenticationComplete).isTrue() assertThat(isReadyToDismiss).isFalse() underTest.onIconAnimationFinished() runCurrent() assertThat(isReadyToDismiss).isTrue() assertThat(underTest.isVisible).isFalse() } @Test fun onDeactivated_hidesComposable_notifiesInteractor() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel val job = Job() underTest.activateIn(this, job) runCurrent() secureLockDeviceInteractor.onBiometricAuthRequested() underTest.startAppearAnimation() runCurrent() assertThat(underTest.isVisible).isTrue() assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isTrue() job.cancel() runCurrent() // THEN the viewmodel is no longer visible and the interactor is notified assertThat(underTest.isVisible).isFalse() assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isFalse() } } packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/BiometricAuthIconViewModel.kt +1 −1 Original line number Diff line number Diff line Loading @@ -162,11 +162,11 @@ constructor( ?: secureLockDeviceViewModel?.isAuthenticated ?: emptyFlow() /** If the auth is pending confirmation. */ private val isPendingConfirmation: Flow<Boolean> = isAuthenticated.map { authState -> authState.isAuthenticated && authState.needsUserConfirmation } /** If the auth is pending confirmation. */ val isPendingConfirmationState: Boolean by isPendingConfirmation.hydratedStateOf( traceName = "isPendingConfirmation", Loading packages/SystemUI/src/com/android/systemui/securelockdevice/ui/composable/SecureLockDeviceBiometricAuthContent.kt +2 −2 Original line number Diff line number Diff line Loading @@ -72,7 +72,7 @@ import com.android.systemui.bouncer.shared.model.SecureLockDeviceBouncerActionBu import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel import com.android.systemui.lifecycle.rememberActivated import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.res.R import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel import com.android.systemui.util.ui.compose.LottieColorUtils Loading @@ -88,7 +88,7 @@ fun SecureLockDeviceContent( modifier: Modifier = Modifier, ) { val secureLockDeviceViewModel = rememberActivated(traceName = "SecureLockDeviceBiometricAuthContentViewModel") { rememberViewModel(traceName = "SecureLockDeviceBiometricAuthContentViewModel") { secureLockDeviceViewModelFactory.create() } Loading packages/SystemUI/src/com/android/systemui/securelockdevice/ui/viewmodel/SecureLockDeviceBiometricAuthContentViewModel.kt +50 −53 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/BiometricAuthIconViewModelTest.kt +121 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.platform.test.annotations.EnableFlags import android.security.Flags.FLAG_SECURE_LOCK_DEVICE import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -41,9 +43,11 @@ import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.biometrics.shared.model.toSensorType import com.android.systemui.biometrics.ui.viewmodel.BiometricAuthIconViewModel.BiometricAuthModalities import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel import com.android.systemui.securelockdevice.ui.viewmodel.secureLockDeviceBiometricAuthContentViewModel import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runCurrent Loading Loading @@ -77,6 +81,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } else if (sensorType == TYPE_REAR) { kosmos.fingerprintPropertyRepository.supportsRearFps(sensorStrength) } kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) } private fun enrollFace(isStrongBiometric: Boolean) { Loading @@ -86,6 +91,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { strength = if (isStrongBiometric) SensorStrength.STRONG else SensorStrength.WEAK, ) kosmos.facePropertyRepository.setSensorInfo(faceSensorInfo) kosmos.biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) } private fun startBiometricPrompt(hasFpAuth: Boolean, isImplicitFlow: Boolean = false) { Loading @@ -103,12 +109,22 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } private fun startSecureLockDevicePrompt() { secureLockDeviceViewModel!!.showAuthenticating() } private fun initPromptViewModel() { promptViewModel = kosmos.promptViewModel underTest = promptViewModel!!.iconViewModel.internal underTest.activateIn(testScope) } private fun initSecureLockDeviceViewModel() { secureLockDeviceViewModel = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest = secureLockDeviceViewModel!!.iconViewModel underTest.activateIn(testScope) } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_face() { testScope.runTest { Loading @@ -127,6 +143,21 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_face() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Face) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfps() { testScope.runTest { Loading @@ -147,6 +178,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_POWER_BUTTON, ) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Sfps) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_nonSfps() { testScope.runTest { Loading @@ -168,6 +217,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_nonSfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_UDFPS_OPTICAL, ) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfps) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfpsCoexImplicit() { testScope.runTest { Loading Loading @@ -212,6 +279,25 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfpsCoex() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_POWER_BUTTON, ) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.SfpsCoex) } } @Test fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_coexNonSfpsImplicit() { testScope.runTest { Loading Loading @@ -256,6 +342,41 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() { } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_coexNonSfps() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint( sensorStrength = SensorStrength.STRONG, sensorType = TYPE_UDFPS_OPTICAL, ) enrollFace(isStrongBiometric = true) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfpsCoex) } } @EnableFlags(FLAG_SECURE_LOCK_DEVICE) @Test fun activeBiometricAuthNone_forNonStrongBiometrics_forSecureLockDevice() { testScope.runTest { initSecureLockDeviceViewModel() val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType) enrollFingerprint(sensorStrength = SensorStrength.WEAK, sensorType = TYPE_UDFPS_OPTICAL) enrollFace(isStrongBiometric = false) runCurrent() startSecureLockDevicePrompt() assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.None) } } /** Initialize the prompt according to the test configuration. */ private fun PromptSelectorInteractor.initializePrompt( fingerprint: FingerprintSensorPropertiesInternal? = null, Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/securelockdevice/ui/viewmodel/SecureLockDeviceBiometricAuthContentViewModelTest.kt +78 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.systemui.securelockdevice.domain.interactor.secureLockDeviceI import com.android.systemui.testKosmos import com.google.android.msdl.data.model.MSDLToken import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Job import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before Loading @@ -50,21 +51,32 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private lateinit var secureLockDeviceInteractor: SecureLockDeviceInteractor private lateinit var underTest: SecureLockDeviceBiometricAuthContentViewModel @Before fun setUp() { kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled() kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth() secureLockDeviceInteractor = kosmos.secureLockDeviceInteractor } @Test fun onBiometricAuthRequested_showsAuthenticating_() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) secureLockDeviceInteractor.onBiometricAuthRequested() runCurrent() underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(testScope) assertThat(isAuthenticating).isTrue() } @Test fun updatesStateAndPlaysHaptics_onFaceFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectValues(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectValues(underTest.showingError) Loading @@ -90,6 +102,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateOnRetryAfterFaceFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -115,6 +129,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndSkipsHaptics_onFaceHelp() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -133,6 +149,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesState_onFaceSuccess_andPlaysHapticsOnConfirm() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading Loading @@ -161,6 +179,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndPlaysHaptics_onFingerprintFailureOrError() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectValues(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectValues(underTest.showingError) Loading @@ -186,6 +206,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndSkipsHaptics_onFingerprintHelp() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -204,6 +226,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { @Test fun updatesStateAndPlaysHaptics_onFingerprintSuccess() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isAuthenticating by collectLastValue(underTest.isAuthenticating) val isAuthenticated by collectLastValue(underTest.isAuthenticated) val showingError by collectLastValue(underTest.showingError) Loading @@ -219,4 +243,54 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() { assertThat(isAuthenticated?.isAuthenticatedAndConfirmed).isTrue() assertThat(kosmos.fakeMSDLPlayer.latestTokenPlayed).isEqualTo(MSDLToken.UNLOCK) } @Test fun onSuccessfulAuthentication_notifiesInteractorAndHides_uponAnimationFinished() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel underTest.activateIn(this) val isReadyToDismiss by collectLastValue(secureLockDeviceInteractor.isFullyUnlockedAndReadyToDismiss) underTest.startAppearAnimation() runCurrent() assertThat(underTest.isVisible).isTrue() assertThat(isReadyToDismiss).isFalse() underTest.showAuthenticated(BiometricModality.Fingerprint) runCurrent() assertThat(underTest.isAuthenticationComplete).isTrue() assertThat(isReadyToDismiss).isFalse() underTest.onIconAnimationFinished() runCurrent() assertThat(isReadyToDismiss).isTrue() assertThat(underTest.isVisible).isFalse() } @Test fun onDeactivated_hidesComposable_notifiesInteractor() = testScope.runTest { val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel val job = Job() underTest.activateIn(this, job) runCurrent() secureLockDeviceInteractor.onBiometricAuthRequested() underTest.startAppearAnimation() runCurrent() assertThat(underTest.isVisible).isTrue() assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isTrue() job.cancel() runCurrent() // THEN the viewmodel is no longer visible and the interactor is notified assertThat(underTest.isVisible).isFalse() assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isFalse() } }
packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/BiometricAuthIconViewModel.kt +1 −1 Original line number Diff line number Diff line Loading @@ -162,11 +162,11 @@ constructor( ?: secureLockDeviceViewModel?.isAuthenticated ?: emptyFlow() /** If the auth is pending confirmation. */ private val isPendingConfirmation: Flow<Boolean> = isAuthenticated.map { authState -> authState.isAuthenticated && authState.needsUserConfirmation } /** If the auth is pending confirmation. */ val isPendingConfirmationState: Boolean by isPendingConfirmation.hydratedStateOf( traceName = "isPendingConfirmation", Loading
packages/SystemUI/src/com/android/systemui/securelockdevice/ui/composable/SecureLockDeviceBiometricAuthContent.kt +2 −2 Original line number Diff line number Diff line Loading @@ -72,7 +72,7 @@ import com.android.systemui.bouncer.shared.model.SecureLockDeviceBouncerActionBu import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel import com.android.systemui.lifecycle.rememberActivated import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.res.R import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel import com.android.systemui.util.ui.compose.LottieColorUtils Loading @@ -88,7 +88,7 @@ fun SecureLockDeviceContent( modifier: Modifier = Modifier, ) { val secureLockDeviceViewModel = rememberActivated(traceName = "SecureLockDeviceBiometricAuthContentViewModel") { rememberViewModel(traceName = "SecureLockDeviceBiometricAuthContentViewModel") { secureLockDeviceViewModelFactory.create() } Loading
packages/SystemUI/src/com/android/systemui/securelockdevice/ui/viewmodel/SecureLockDeviceBiometricAuthContentViewModel.kt +50 −53 File changed.Preview size limit exceeded, changes collapsed. Show changes