[flexiglass] Hooks up real app state and logic in keyguard (2)
- Connects the lock state (device locked or unlocked) to Flexiglass to let it show the lock screen when the device becomes locked or dismiss the lock screen when the device becomes unlocked. Bug: 280883900 Test: Unit tests still pass. Test: manually verified that unlocking the device through the real bouncer automatically shows the lock screen as unlocked (the lock icon becomes unlocked) and moves to the Gone scene Test: manually verified that locking the device by shutting off the screen via power button click (with "instantly lock device" setting both on and off) properly moves back to the Lockscreen scene that shows the lock icon as locked. Change-Id: I82a61ade9d064597466fdaee4c01fbcf18350fea
This commit is contained in:
@@ -19,17 +19,22 @@ package com.android.systemui.authentication.data.repository
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
||||
import com.android.systemui.user.data.repository.UserRepository
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.function.Function
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/** Defines interface for classes that can access authentication-related application state. */
|
||||
interface AuthenticationRepository {
|
||||
@@ -64,9 +69,6 @@ interface AuthenticationRepository {
|
||||
*/
|
||||
suspend fun getAuthenticationMethod(): AuthenticationMethodModel
|
||||
|
||||
/** See [isUnlocked]. */
|
||||
fun setUnlocked(isUnlocked: Boolean)
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun setBypassEnabled(isBypassEnabled: Boolean)
|
||||
|
||||
@@ -77,14 +79,20 @@ interface AuthenticationRepository {
|
||||
class AuthenticationRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Application private val applicationScope: CoroutineScope,
|
||||
private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
|
||||
@Background private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val userRepository: UserRepository,
|
||||
private val lockPatternUtils: LockPatternUtils,
|
||||
keyguardRepository: KeyguardRepository,
|
||||
) : AuthenticationRepository {
|
||||
|
||||
private val _isUnlocked = MutableStateFlow(false)
|
||||
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
|
||||
override val isUnlocked: StateFlow<Boolean> =
|
||||
keyguardRepository.isKeyguardUnlocked.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
private val _isBypassEnabled = MutableStateFlow(false)
|
||||
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
|
||||
@@ -128,10 +136,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUnlocked(isUnlocked: Boolean) {
|
||||
_isUnlocked.value = isUnlocked
|
||||
}
|
||||
|
||||
override fun setBypassEnabled(isBypassEnabled: Boolean) {
|
||||
_isBypassEnabled.value = isBypassEnabled
|
||||
}
|
||||
|
||||
@@ -89,22 +89,6 @@ constructor(
|
||||
return !isUnlocked.value && getAuthenticationMethod().isSecure
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the device, assuming that the authentication challenge has been completed
|
||||
* successfully.
|
||||
*/
|
||||
fun unlockDevice() {
|
||||
repository.setUnlocked(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the device. From now on, the device will remain locked until [authenticate] is called
|
||||
* with the correct input.
|
||||
*/
|
||||
fun lockDevice() {
|
||||
repository.setUnlocked(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the user and unlock the device.
|
||||
*
|
||||
@@ -146,7 +130,6 @@ constructor(
|
||||
|
||||
if (isSuccessful) {
|
||||
repository.setFailedAuthenticationAttempts(0)
|
||||
repository.setUnlocked(true)
|
||||
} else {
|
||||
repository.setFailedAuthenticationAttempts(
|
||||
repository.failedAuthenticationAttempts.value + 1
|
||||
@@ -156,12 +139,6 @@ constructor(
|
||||
return isSuccessful
|
||||
}
|
||||
|
||||
/** Triggers a biometric-powered unlock of the device. */
|
||||
fun biometricUnlock() {
|
||||
// TODO(b/280883900): only allow this if the biometric is enabled and there's a match.
|
||||
repository.setUnlocked(true)
|
||||
}
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun toggleBypassEnabled() {
|
||||
repository.setBypassEnabled(!repository.isBypassEnabled.value)
|
||||
|
||||
@@ -35,6 +35,9 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -72,24 +75,28 @@ constructor(
|
||||
val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
|
||||
|
||||
init {
|
||||
// UNLOCKING SHOWS Gone.
|
||||
//
|
||||
// Move to the gone scene if the device becomes unlocked while on the bouncer scene.
|
||||
applicationScope.launch {
|
||||
sceneInteractor.currentScene(containerName).collect { currentScene ->
|
||||
if (currentScene.key == SceneKey.Bouncer) {
|
||||
when (getAuthenticationMethod()) {
|
||||
is AuthenticationMethodModel.None ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Gone),
|
||||
)
|
||||
is AuthenticationMethodModel.Swipe ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Lockscreen),
|
||||
)
|
||||
else -> Unit
|
||||
sceneInteractor
|
||||
.currentScene(containerName)
|
||||
.flatMapLatest { currentScene ->
|
||||
if (currentScene.key == SceneKey.Bouncer) {
|
||||
authenticationInteractor.isUnlocked
|
||||
} else {
|
||||
flowOf(false)
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.collect { isUnlocked ->
|
||||
if (isUnlocked) {
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Gone),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +126,6 @@ constructor(
|
||||
scene = SceneModel(SceneKey.Bouncer),
|
||||
)
|
||||
} else {
|
||||
authenticationInteractor.unlockDevice()
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Gone),
|
||||
|
||||
@@ -22,17 +22,19 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode
|
||||
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.util.kotlin.pairwise
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -83,25 +85,30 @@ constructor(
|
||||
}
|
||||
|
||||
/** View-model for the current UI, based on the current authentication method. */
|
||||
val authMethod: StateFlow<AuthMethodBouncerViewModel?>
|
||||
get() =
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
.map { authMethod ->
|
||||
when (authMethod) {
|
||||
is AuthenticationMethodModel.Pin -> pin
|
||||
is AuthenticationMethodModel.Password -> password
|
||||
is AuthenticationMethodModel.Pattern -> pattern
|
||||
else -> null
|
||||
private val _authMethod =
|
||||
MutableSharedFlow<AuthMethodBouncerViewModel?>(
|
||||
replay = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
|
||||
_authMethod.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
init {
|
||||
applicationScope.launch {
|
||||
_authMethod.subscriptionCount
|
||||
.pairwise()
|
||||
.map { (previousCount, currentCount) -> currentCount > previousCount }
|
||||
.collect { subscriberAdded ->
|
||||
if (subscriberAdded) {
|
||||
reloadAuthMethod()
|
||||
}
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The user-facing message to show in the bouncer. */
|
||||
val message: StateFlow<MessageViewModel> =
|
||||
@@ -184,6 +191,17 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun reloadAuthMethod() {
|
||||
_authMethod.tryEmit(
|
||||
when (interactor.getAuthenticationMethod()) {
|
||||
is AuthenticationMethodModel.Pin -> pin
|
||||
is AuthenticationMethodModel.Password -> password
|
||||
is AuthenticationMethodModel.Pattern -> pattern
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
data class MessageViewModel(
|
||||
val text: String,
|
||||
|
||||
|
||||
@@ -42,10 +42,7 @@ class PinBouncerViewModel(
|
||||
|
||||
/** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
|
||||
val hintedPinLength: StateFlow<Int?> =
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
flow { emit(interactor.getAuthenticationMethod()) }
|
||||
.map { authMethod ->
|
||||
// Hinting is enabled for 6-digit codes only
|
||||
autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
|
||||
|
||||
@@ -302,7 +302,15 @@ constructor(
|
||||
trySendWithFailureLogging(
|
||||
keyguardStateController.isUnlocked,
|
||||
TAG,
|
||||
"updated isKeyguardUnlocked"
|
||||
"updated isKeyguardUnlocked due to onUnlockedChanged"
|
||||
)
|
||||
}
|
||||
|
||||
override fun onKeyguardShowingChanged() {
|
||||
trySendWithFailureLogging(
|
||||
keyguardStateController.isUnlocked,
|
||||
TAG,
|
||||
"updated isKeyguardUnlocked due to onKeyguardShowingChanged"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.scene.domain.interactor.SceneInteractor
|
||||
import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.android.systemui.util.kotlin.pairwise
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
@@ -111,24 +110,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SWIPE TO DISMISS Lockscreen.
|
||||
//
|
||||
// If switched from the lockscreen to the gone scene and the auth method was a swipe,
|
||||
// unlocks the device.
|
||||
applicationScope.launch {
|
||||
sceneInteractor.currentScene(containerName).pairwise().collect {
|
||||
(previousScene, currentScene) ->
|
||||
if (
|
||||
authenticationInteractor.getAuthenticationMethod() is
|
||||
AuthenticationMethodModel.Swipe &&
|
||||
previousScene.key == SceneKey.Lockscreen &&
|
||||
currentScene.key == SceneKey.Gone
|
||||
) {
|
||||
authenticationInteractor.unlockDevice()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
|
||||
|
||||
@@ -65,30 +65,6 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unlockDevice() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
underTest.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun biometricUnlock() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
underTest.biometricUnlock()
|
||||
runCurrent()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toggleBypassEnabled() =
|
||||
testScope.runTest {
|
||||
@@ -105,7 +81,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_lockedAndSecured_true() =
|
||||
testScope.runTest {
|
||||
underTest.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
@@ -117,7 +93,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_lockedAndNotSecured_false() =
|
||||
testScope.runTest {
|
||||
underTest.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
@@ -127,7 +103,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_unlockedAndSecured_false() =
|
||||
testScope.runTest {
|
||||
underTest.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
@@ -139,7 +115,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_unlockedAndNotSecured_false() =
|
||||
testScope.runTest {
|
||||
underTest.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
@@ -147,67 +123,55 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectPin_returnsTrueAndUnlocksDevice() =
|
||||
fun authenticate_withCorrectPin_returnsTrue() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withIncorrectPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
fun authenticate_withIncorrectPin_returnsFalse() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withEmptyPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
fun authenticate_withEmptyPin_returnsFalse() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf())).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectMaxLengthPin_returnsTrueAndUnlocksDevice() =
|
||||
fun authenticate_withCorrectMaxLengthPin_returnsTrue() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(9999999999999999)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectTooLongPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
fun authenticate_withCorrectTooLongPin_returnsFalse() =
|
||||
testScope.runTest {
|
||||
// Max pin length is 16 digits. To avoid issues with overflows, this test ensures
|
||||
// that all pins > 16 decimal digits are rejected.
|
||||
@@ -216,52 +180,42 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
|
||||
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(99999999999999999)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectPassword_returnsTrueAndUnlocksDevice() =
|
||||
fun authenticate_withCorrectPassword_returnsTrue() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("password".toList())).isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withIncorrectPassword_returnsFalseAndDoesNotUnlockDevice() =
|
||||
fun authenticate_withIncorrectPassword_returnsFalse() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectPattern_returnsTrueAndUnlocksDevice() =
|
||||
fun authenticate_withCorrectPattern_returnsTrue() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(
|
||||
listOf(
|
||||
@@ -280,7 +234,6 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
@@ -301,15 +254,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
.isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withIncorrectPattern_returnsFalseAndDoesNotUnlockDevice() =
|
||||
fun authenticate_withIncorrectPattern_returnsFalse() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(
|
||||
listOf(
|
||||
@@ -328,7 +279,6 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
@@ -349,22 +299,18 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
)
|
||||
.isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNullAndHasNoEffect() =
|
||||
fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNull() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(), tryAutoConfirm = true)).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@@ -372,14 +318,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3), tryAutoConfirm = true)).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@@ -387,14 +330,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@@ -402,15 +342,12 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4, 5), tryAutoConfirm = true))
|
||||
.isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@@ -418,14 +355,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@@ -433,14 +367,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@@ -448,14 +379,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withoutCorrectPassword_returnsNullAndHasNoEffects() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
|
||||
@@ -104,7 +104,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
|
||||
@@ -134,7 +134,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.clearMessage()
|
||||
@@ -158,7 +158,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
|
||||
@@ -190,7 +190,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(emptyList())
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
|
||||
@@ -226,7 +226,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
@@ -239,7 +239,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
|
||||
@@ -254,7 +254,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
val customMessage = "Hello there!"
|
||||
underTest.showOrUnlockDevice("container1", customMessage)
|
||||
@@ -268,13 +268,17 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val throttling by collectLastValue(underTest.throttling)
|
||||
val message by collectLastValue(underTest.message)
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by
|
||||
collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
runCurrent()
|
||||
underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
|
||||
runCurrent()
|
||||
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
|
||||
assertThat(throttling).isNull()
|
||||
assertThat(message).isEqualTo("")
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
|
||||
repeat(BouncerInteractor.THROTTLE_EVERY) { times ->
|
||||
// Wrong PIN.
|
||||
assertThat(underTest.authenticate(listOf(6, 7, 8, 9))).isFalse()
|
||||
@@ -285,9 +289,9 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
assertThat(throttling).isNotNull()
|
||||
assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
|
||||
|
||||
// Correct PIN, but throttled, so doesn't unlock:
|
||||
// Correct PIN, but throttled, so doesn't change away from the bouncer scene:
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
|
||||
assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
|
||||
|
||||
throttling?.totalDurationSec?.let { seconds ->
|
||||
@@ -301,11 +305,28 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
assertThat(message).isEqualTo("")
|
||||
assertThat(throttling).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
|
||||
|
||||
// Correct PIN and no longer throttled so unlocks:
|
||||
// Correct PIN and no longer throttled so changes to the Gone scene:
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene?.key).isEqualTo(SceneKey.Gone)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun switchesToGone_whenUnlocked() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(
|
||||
SceneTestUtils.CONTAINER_1,
|
||||
SceneModel(SceneKey.Bouncer)
|
||||
)
|
||||
val currentScene by
|
||||
collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
private fun assertTryAgainMessage(
|
||||
|
||||
@@ -23,10 +23,14 @@ import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.scene.SceneTestUtils
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -53,16 +57,26 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
|
||||
testScope.runTest {
|
||||
var authMethodViewModel: AuthMethodBouncerViewModel? = null
|
||||
|
||||
authMethodsToTest().forEach { authMethod ->
|
||||
utils.authenticationRepository.setAuthenticationMethod(authMethod)
|
||||
val job = underTest.authMethod.onEach { authMethodViewModel = it }.launchIn(this)
|
||||
runCurrent()
|
||||
|
||||
val authMethodViewModel: AuthMethodBouncerViewModel? by
|
||||
collectLastValue(underTest.authMethod)
|
||||
if (authMethod.isSecure) {
|
||||
assertThat(authMethodViewModel).isNotNull()
|
||||
assertWithMessage("View-model unexpectedly null for auth method $authMethod")
|
||||
.that(authMethodViewModel)
|
||||
.isNotNull()
|
||||
} else {
|
||||
assertThat(authMethodViewModel).isNull()
|
||||
assertWithMessage(
|
||||
"View-model unexpectedly non-null for auth method $authMethod"
|
||||
)
|
||||
.that(authMethodViewModel)
|
||||
.isNull()
|
||||
}
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,39 +72,34 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun onShown() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
underTest.onShown()
|
||||
|
||||
assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
|
||||
assertThat(password).isEqualTo("")
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPasswordInputChanged() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
@@ -113,44 +108,38 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(message?.text).isEmpty()
|
||||
assertThat(password).isEqualTo("password")
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateKeyPressed_whenCorrect() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPasswordInputChanged("password")
|
||||
|
||||
underTest.onAuthenticateKeyPressed()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateKeyPressed_whenWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPasswordInputChanged("wrong")
|
||||
@@ -159,30 +148,26 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(password).isEqualTo("")
|
||||
assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateKeyPressed_correctAfterWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPasswordInputChanged("wrong")
|
||||
underTest.onAuthenticateKeyPressed()
|
||||
assertThat(password).isEqualTo("")
|
||||
assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
// Enter the correct password:
|
||||
@@ -191,7 +176,6 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
underTest.onAuthenticateKeyPressed()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun onShown() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
@@ -82,9 +81,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
underTest.onShown()
|
||||
@@ -92,14 +90,12 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(message?.text).isEqualTo(ENTER_YOUR_PATTERN)
|
||||
assertThat(selectedDots).isEmpty()
|
||||
assertThat(currentDot).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDragStart() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
@@ -107,9 +103,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
@@ -119,23 +114,20 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(message?.text).isEmpty()
|
||||
assertThat(selectedDots).isEmpty()
|
||||
assertThat(currentDot).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDragEnd_whenCorrect() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onDragStart()
|
||||
@@ -169,14 +161,12 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
underTest.onDragEnd()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDragEnd_whenWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
@@ -184,9 +174,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onDragStart()
|
||||
@@ -204,14 +193,12 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(selectedDots).isEmpty()
|
||||
assertThat(currentDot).isNull()
|
||||
assertThat(message?.text).isEqualTo(WRONG_PATTERN)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDragEnd_correctAfterWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
@@ -219,9 +206,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onDragStart()
|
||||
@@ -237,7 +223,6 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(selectedDots).isEmpty()
|
||||
assertThat(currentDot).isNull()
|
||||
assertThat(message?.text).isEqualTo(WRONG_PATTERN)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
// Enter the correct pattern:
|
||||
@@ -252,7 +237,6 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
underTest.onDragEnd()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
|
||||
@@ -81,36 +81,31 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun onShown() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
underTest.onShown()
|
||||
|
||||
assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN)
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPinButtonClicked() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
@@ -120,23 +115,20 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(message?.text).isEmpty()
|
||||
assertThat(entries).hasSize(1)
|
||||
assertThat(entries?.map { it.input }).containsExactly(1)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onBackspaceButtonClicked() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
@@ -147,23 +139,19 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(message?.text).isEmpty()
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPinEdit() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
|
||||
@@ -183,16 +171,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun onBackspaceButtonLongPressed() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
@@ -205,21 +191,18 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(message?.text).isEmpty()
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateButtonClicked_whenCorrect() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPinButtonClicked(1)
|
||||
@@ -229,23 +212,20 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
underTest.onAuthenticateButtonClicked()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateButtonClicked_whenWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPinButtonClicked(1)
|
||||
@@ -258,23 +238,20 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(message?.text).isEqualTo(WRONG_PIN)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAuthenticateButtonClicked_correctAfterWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPinButtonClicked(1)
|
||||
@@ -285,7 +262,6 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
underTest.onAuthenticateButtonClicked()
|
||||
assertThat(message?.text).isEqualTo(WRONG_PIN)
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
|
||||
// Enter the correct PIN:
|
||||
@@ -297,21 +273,18 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
underTest.onAuthenticateButtonClicked()
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAutoConfirm_whenCorrect() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPinButtonClicked(1)
|
||||
@@ -319,23 +292,20 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
underTest.onPinButtonClicked(3)
|
||||
underTest.onPinButtonClicked(4)
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAutoConfirm_whenWrong() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
underTest.onPinButtonClicked(1)
|
||||
@@ -345,7 +315,6 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
assertThat(entries).hasSize(0)
|
||||
assertThat(message?.text).isEqualTo(WRONG_PIN)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
}
|
||||
|
||||
|
||||
@@ -235,11 +235,10 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
fun isKeyguardUnlocked() =
|
||||
testScope.runTest {
|
||||
whenever(keyguardStateController.isUnlocked).thenReturn(false)
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
|
||||
val isKeyguardUnlocked by collectLastValue(underTest.isKeyguardUnlocked)
|
||||
|
||||
runCurrent()
|
||||
assertThat(latest).isFalse()
|
||||
assertThat(isKeyguardUnlocked).isFalse()
|
||||
|
||||
val captor = argumentCaptor<KeyguardStateController.Callback>()
|
||||
verify(keyguardStateController).addCallback(captor.capture())
|
||||
@@ -247,14 +246,12 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
whenever(keyguardStateController.isUnlocked).thenReturn(true)
|
||||
captor.value.onUnlockedChanged()
|
||||
runCurrent()
|
||||
assertThat(latest).isTrue()
|
||||
assertThat(isKeyguardUnlocked).isTrue()
|
||||
|
||||
whenever(keyguardStateController.isUnlocked).thenReturn(false)
|
||||
captor.value.onUnlockedChanged()
|
||||
captor.value.onKeyguardShowingChanged()
|
||||
runCurrent()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
assertThat(isKeyguardUnlocked).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -60,10 +60,10 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isDeviceLocked by collectLastValue(underTest.isDeviceLocked)
|
||||
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
assertThat(isDeviceLocked).isTrue()
|
||||
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
assertThat(isDeviceLocked).isFalse()
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
|
||||
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(isSwipeToDismissEnabled).isTrue()
|
||||
@@ -83,7 +83,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
|
||||
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(isSwipeToDismissEnabled).isFalse()
|
||||
@@ -93,7 +93,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
fun dismissLockScreen_deviceLockedWithSecureAuthMethod_switchesToBouncer() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
@@ -108,7 +108,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
fun dismissLockScreen_deviceUnlocked_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
@@ -123,7 +123,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
fun dismissLockScreen_deviceLockedWithInsecureAuthMethod_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
@@ -139,60 +139,15 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
runCurrent()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
|
||||
runCurrent()
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceBiometricUnlockedInLockScreen_bypassEnabled_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
|
||||
if (!authenticationInteractor.isBypassEnabled.value) {
|
||||
authenticationInteractor.toggleBypassEnabled()
|
||||
}
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
authenticationInteractor.biometricUnlock()
|
||||
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceBiometricUnlockedInLockScreen_bypassNotEnabled_doesNotSwitch() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
|
||||
if (authenticationInteractor.isBypassEnabled.value) {
|
||||
authenticationInteractor.toggleBypassEnabled()
|
||||
}
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
authenticationInteractor.biometricUnlock()
|
||||
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun switchFromLockScreenToGone_authMethodSwipe_unlocksDevice() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
|
||||
@@ -75,7 +75,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
assertThat((lockButtonIcon as? Icon.Resource)?.res)
|
||||
.isEqualTo(R.drawable.ic_device_lock_on)
|
||||
@@ -88,7 +88,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
|
||||
assertThat((lockButtonIcon as? Icon.Resource)?.res)
|
||||
.isEqualTo(R.drawable.ic_device_lock_off)
|
||||
@@ -99,7 +99,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
|
||||
underTest.onLockButtonClicked()
|
||||
@@ -138,7 +138,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
@@ -153,7 +153,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
@@ -168,7 +168,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
|
||||
underTest.onLockButtonClicked()
|
||||
|
||||
@@ -72,7 +72,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
@@ -87,7 +87,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
|
||||
@@ -73,7 +73,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
|
||||
}
|
||||
@@ -97,7 +97,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
@@ -112,7 +112,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
|
||||
underTest.onContentClicked()
|
||||
|
||||
@@ -18,12 +18,18 @@ package com.android.systemui.authentication.data.repository
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
|
||||
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class FakeAuthenticationRepository(
|
||||
private val delegate: AuthenticationRepository,
|
||||
private val onSecurityModeChanged: (SecurityMode) -> Unit,
|
||||
) : AuthenticationRepository by delegate {
|
||||
|
||||
private val _isUnlocked = MutableStateFlow(false)
|
||||
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
|
||||
|
||||
private var authenticationMethod: AuthenticationMethodModel = DEFAULT_AUTHENTICATION_METHOD
|
||||
|
||||
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
|
||||
@@ -35,6 +41,10 @@ class FakeAuthenticationRepository(
|
||||
onSecurityModeChanged(authenticationMethod.toSecurityMode())
|
||||
}
|
||||
|
||||
fun setUnlocked(isUnlocked: Boolean) {
|
||||
_isUnlocked.value = isUnlocked
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT_AUTHENTICATION_METHOD =
|
||||
AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.systemui.authentication.domain.interactor.AuthenticationInter
|
||||
import com.android.systemui.bouncer.data.repository.BouncerRepository
|
||||
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
|
||||
import com.android.systemui.scene.data.repository.SceneContainerRepository
|
||||
import com.android.systemui.scene.domain.interactor.SceneInteractor
|
||||
@@ -55,10 +56,12 @@ class SceneTestUtils(
|
||||
FakeAuthenticationRepository(
|
||||
delegate =
|
||||
AuthenticationRepositoryImpl(
|
||||
applicationScope = applicationScope(),
|
||||
getSecurityMode = { securityMode },
|
||||
backgroundDispatcher = testDispatcher,
|
||||
userRepository = FakeUserRepository(),
|
||||
lockPatternUtils = mock(),
|
||||
keyguardRepository = FakeKeyguardRepository(),
|
||||
),
|
||||
onSecurityModeChanged = { securityMode = it },
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user