Loading packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +3 −3 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ interface AuthenticationRepository { * Note that the length of the PIN is also important to take into consideration, please see * [hintedPinLength]. */ val isAutoConfirmEnabled: StateFlow<Boolean> val isAutoConfirmFeatureEnabled: StateFlow<Boolean> /** * The exact length a PIN should be for us to enable PIN length hinting. Loading Loading @@ -152,14 +152,14 @@ class AuthenticationRepositoryImpl @Inject constructor( @Application private val applicationScope: CoroutineScope, private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>, @Background private val backgroundDispatcher: CoroutineDispatcher, private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>, private val userRepository: UserRepository, private val lockPatternUtils: LockPatternUtils, broadcastDispatcher: BroadcastDispatcher, ) : AuthenticationRepository { override val isAutoConfirmEnabled: StateFlow<Boolean> = override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> = refreshingFlow( initialValue = false, getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled, Loading packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +22 −4 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading Loading @@ -103,9 +104,29 @@ constructor( initialValue = throttling.value.remainingMs > 0, ) /** * Whether the auto confirm feature is enabled for the currently-selected user. * * Note that the length of the PIN is also important to take into consideration, please see * [hintedPinLength]. * * During throttling, this is always disabled (`false`). */ val isAutoConfirmEnabled: StateFlow<Boolean> = combine(repository.isAutoConfirmFeatureEnabled, isThrottled) { featureEnabled, isThrottled -> // Disable auto-confirm during throttling. featureEnabled && !isThrottled } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = false, ) /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */ val hintedPinLength: StateFlow<Int?> = repository.isAutoConfirmEnabled isAutoConfirmEnabled .map { isAutoConfirmEnabled -> repository.getPinLength().takeIf { isAutoConfirmEnabled && it == repository.hintedPinLength Loading @@ -119,9 +140,6 @@ constructor( initialValue = null, ) /** Whether the auto confirm feature is enabled for the currently-selected user. */ val isAutoConfirmEnabled: StateFlow<Boolean> = repository.isAutoConfirmEnabled /** Whether the pattern should be visible for the currently-selected user. */ val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible Loading packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -100,12 +100,12 @@ class AuthenticationRepositoryTest : SysuiTestCase() { } @Test fun isAutoConfirmEnabled() = fun isAutoConfirmFeatureEnabled() = testScope.runTest { whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true) whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[1].id)).thenReturn(false) val values by collectValues(underTest.isAutoConfirmEnabled) val values by collectValues(underTest.isAutoConfirmFeatureEnabled) assertThat(values.first()).isFalse() assertThat(values.last()).isTrue() Loading packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +45 −9 Original line number Diff line number Diff line Loading @@ -213,11 +213,14 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) val isThrottled by collectLastValue(underTest.isThrottled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply { Loading @@ -233,10 +236,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 }, Loading @@ -251,10 +257,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN + listOf(7), Loading @@ -269,10 +278,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN, Loading @@ -284,12 +296,36 @@ class AuthenticationInteractorTest : SysuiTestCase() { assertThat(isUnlocked).isTrue() } @Test fun tryAutoConfirm_withAutoConfirmCorrectPinButDuringThrottling_returnsNullAndHasNoEffects() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked) val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmFeatureEnabled(true) setThrottleDuration(42) } val authResult = underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN, tryAutoConfirm = true ) assertThat(authResult).isEqualTo(AuthenticationResult.SKIPPED) assertThat(isAutoConfirmEnabled).isFalse() assertThat(isUnlocked).isFalse() assertThat(hintedPinLength).isNull() } @Test fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() = testScope.runTest { utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(false) setAutoConfirmFeatureEnabled(false) } assertThat( underTest.authenticate( Loading Loading @@ -416,7 +452,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(false) setAutoConfirmFeatureEnabled(false) } assertThat(hintedPinLength).isNull() Loading @@ -433,7 +469,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) } } ) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(hintedPinLength).isNull() Loading @@ -445,7 +481,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) overrideCredential( buildList { repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) } Loading @@ -467,7 +503,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) } } ) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(hintedPinLength).isNull() Loading packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +3 −1 Original line number Diff line number Diff line Loading @@ -110,12 +110,14 @@ class BouncerInteractorTest : SysuiTestCase() { testScope.runTest { val currentScene by collectLastValue(sceneInteractor.desiredScene) val message by collectLastValue(underTest.message) val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) runCurrent() utils.authenticationRepository.setAutoConfirmEnabled(true) utils.authenticationRepository.setAutoConfirmFeatureEnabled(true) utils.deviceEntryRepository.setUnlocked(false) underTest.showOrUnlockDevice() assertThat(isAutoConfirmEnabled).isTrue() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN) underTest.clearMessage() Loading Loading
packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +3 −3 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ interface AuthenticationRepository { * Note that the length of the PIN is also important to take into consideration, please see * [hintedPinLength]. */ val isAutoConfirmEnabled: StateFlow<Boolean> val isAutoConfirmFeatureEnabled: StateFlow<Boolean> /** * The exact length a PIN should be for us to enable PIN length hinting. Loading Loading @@ -152,14 +152,14 @@ class AuthenticationRepositoryImpl @Inject constructor( @Application private val applicationScope: CoroutineScope, private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>, @Background private val backgroundDispatcher: CoroutineDispatcher, private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>, private val userRepository: UserRepository, private val lockPatternUtils: LockPatternUtils, broadcastDispatcher: BroadcastDispatcher, ) : AuthenticationRepository { override val isAutoConfirmEnabled: StateFlow<Boolean> = override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> = refreshingFlow( initialValue = false, getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled, Loading
packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +22 −4 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading Loading @@ -103,9 +104,29 @@ constructor( initialValue = throttling.value.remainingMs > 0, ) /** * Whether the auto confirm feature is enabled for the currently-selected user. * * Note that the length of the PIN is also important to take into consideration, please see * [hintedPinLength]. * * During throttling, this is always disabled (`false`). */ val isAutoConfirmEnabled: StateFlow<Boolean> = combine(repository.isAutoConfirmFeatureEnabled, isThrottled) { featureEnabled, isThrottled -> // Disable auto-confirm during throttling. featureEnabled && !isThrottled } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = false, ) /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */ val hintedPinLength: StateFlow<Int?> = repository.isAutoConfirmEnabled isAutoConfirmEnabled .map { isAutoConfirmEnabled -> repository.getPinLength().takeIf { isAutoConfirmEnabled && it == repository.hintedPinLength Loading @@ -119,9 +140,6 @@ constructor( initialValue = null, ) /** Whether the auto confirm feature is enabled for the currently-selected user. */ val isAutoConfirmEnabled: StateFlow<Boolean> = repository.isAutoConfirmEnabled /** Whether the pattern should be visible for the currently-selected user. */ val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible Loading
packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -100,12 +100,12 @@ class AuthenticationRepositoryTest : SysuiTestCase() { } @Test fun isAutoConfirmEnabled() = fun isAutoConfirmFeatureEnabled() = testScope.runTest { whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true) whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[1].id)).thenReturn(false) val values by collectValues(underTest.isAutoConfirmEnabled) val values by collectValues(underTest.isAutoConfirmFeatureEnabled) assertThat(values.first()).isFalse() assertThat(values.last()).isTrue() Loading
packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +45 −9 Original line number Diff line number Diff line Loading @@ -213,11 +213,14 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) val isThrottled by collectLastValue(underTest.isThrottled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply { Loading @@ -233,10 +236,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 }, Loading @@ -251,10 +257,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN + listOf(7), Loading @@ -269,10 +278,13 @@ class AuthenticationInteractorTest : SysuiTestCase() { @Test fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(isAutoConfirmEnabled).isTrue() assertThat( underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN, Loading @@ -284,12 +296,36 @@ class AuthenticationInteractorTest : SysuiTestCase() { assertThat(isUnlocked).isTrue() } @Test fun tryAutoConfirm_withAutoConfirmCorrectPinButDuringThrottling_returnsNullAndHasNoEffects() = testScope.runTest { val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked) val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmFeatureEnabled(true) setThrottleDuration(42) } val authResult = underTest.authenticate( FakeAuthenticationRepository.DEFAULT_PIN, tryAutoConfirm = true ) assertThat(authResult).isEqualTo(AuthenticationResult.SKIPPED) assertThat(isAutoConfirmEnabled).isFalse() assertThat(isUnlocked).isFalse() assertThat(hintedPinLength).isNull() } @Test fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() = testScope.runTest { utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(false) setAutoConfirmFeatureEnabled(false) } assertThat( underTest.authenticate( Loading Loading @@ -416,7 +452,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(false) setAutoConfirmFeatureEnabled(false) } assertThat(hintedPinLength).isNull() Loading @@ -433,7 +469,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) } } ) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(hintedPinLength).isNull() Loading @@ -445,7 +481,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { val hintedPinLength by collectLastValue(underTest.hintedPinLength) utils.authenticationRepository.apply { setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) overrideCredential( buildList { repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) } Loading @@ -467,7 +503,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) } } ) setAutoConfirmEnabled(true) setAutoConfirmFeatureEnabled(true) } assertThat(hintedPinLength).isNull() Loading
packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +3 −1 Original line number Diff line number Diff line Loading @@ -110,12 +110,14 @@ class BouncerInteractorTest : SysuiTestCase() { testScope.runTest { val currentScene by collectLastValue(sceneInteractor.desiredScene) val message by collectLastValue(underTest.message) val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) runCurrent() utils.authenticationRepository.setAutoConfirmEnabled(true) utils.authenticationRepository.setAutoConfirmFeatureEnabled(true) utils.deviceEntryRepository.setUnlocked(false) underTest.showOrUnlockDevice() assertThat(isAutoConfirmEnabled).isTrue() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN) underTest.clearMessage() Loading