Merge "[flexiglass] Hooks up real app state and logic in keyguard (1)" into udc-qpr-dev

This commit is contained in:
TreeHugger Robot
2023-06-26 14:13:07 +00:00
committed by Android (Google) Code Review
22 changed files with 521 additions and 414 deletions

View File

@@ -16,8 +16,11 @@
package com.android.systemui.authentication package com.android.systemui.authentication
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryModule import com.android.systemui.authentication.data.repository.AuthenticationRepositoryModule
import dagger.Module import dagger.Module
import dagger.Provides
import java.util.function.Function
@Module( @Module(
includes = includes =
@@ -25,4 +28,12 @@ import dagger.Module
AuthenticationRepositoryModule::class, AuthenticationRepositoryModule::class,
], ],
) )
object AuthenticationModule object AuthenticationModule {
@Provides
fun getSecurityMode(
model: KeyguardSecurityModel,
): Function<Int, KeyguardSecurityModel.SecurityMode> {
return Function { userId -> model.getSecurityMode(userId) }
}
}

View File

@@ -16,13 +16,20 @@
package com.android.systemui.authentication.data.repository 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.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.user.data.repository.UserRepository
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
import java.util.function.Function
import javax.inject.Inject
/** Defines interface for classes that can access authentication-related application state. */ /** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository { interface AuthenticationRepository {
@@ -37,12 +44,6 @@ interface AuthenticationRepository {
*/ */
val isUnlocked: StateFlow<Boolean> val isUnlocked: StateFlow<Boolean>
/**
* The currently-configured authentication method. This determines how the authentication
* challenge is completed in order to unlock an otherwise locked device.
*/
val authenticationMethod: StateFlow<AuthenticationMethodModel>
/** /**
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
* dismisses once the authentication challenge is completed. For example, completing a biometric * dismisses once the authentication challenge is completed. For example, completing a biometric
@@ -57,12 +58,15 @@ interface AuthenticationRepository {
*/ */
val failedAuthenticationAttempts: StateFlow<Int> val failedAuthenticationAttempts: StateFlow<Int>
/**
* Returns the currently-configured authentication method. This determines how the
* authentication challenge is completed in order to unlock an otherwise locked device.
*/
suspend fun getAuthenticationMethod(): AuthenticationMethodModel
/** See [isUnlocked]. */ /** See [isUnlocked]. */
fun setUnlocked(isUnlocked: Boolean) fun setUnlocked(isUnlocked: Boolean)
/** See [authenticationMethod]. */
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel)
/** See [isBypassEnabled]. */ /** See [isBypassEnabled]. */
fun setBypassEnabled(isBypassEnabled: Boolean) fun setBypassEnabled(isBypassEnabled: Boolean)
@@ -70,19 +74,18 @@ interface AuthenticationRepository {
fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
} }
class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationRepository { class AuthenticationRepositoryImpl
// TODO(b/280883900): get data from real data sources in SysUI. @Inject
constructor(
private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val userRepository: UserRepository,
private val lockPatternUtils: LockPatternUtils,
) : AuthenticationRepository {
private val _isUnlocked = MutableStateFlow(false) private val _isUnlocked = MutableStateFlow(false)
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow() override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
private val _authenticationMethod =
MutableStateFlow<AuthenticationMethodModel>(
AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
)
override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
_authenticationMethod.asStateFlow()
private val _isBypassEnabled = MutableStateFlow(false) private val _isBypassEnabled = MutableStateFlow(false)
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow() override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
@@ -90,6 +93,41 @@ class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationReposit
override val failedAuthenticationAttempts: StateFlow<Int> = override val failedAuthenticationAttempts: StateFlow<Int> =
_failedAuthenticationAttempts.asStateFlow() _failedAuthenticationAttempts.asStateFlow()
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
val selectedUserId = userRepository.getSelectedUserInfo().id
when (getSecurityMode.apply(selectedUserId)) {
KeyguardSecurityModel.SecurityMode.PIN,
KeyguardSecurityModel.SecurityMode.SimPin ->
AuthenticationMethodModel.Pin(
code = listOf(1, 2, 3, 4), // TODO(b/280883900): remove this
autoConfirm = lockPatternUtils.isAutoPinConfirmEnabled(selectedUserId),
)
KeyguardSecurityModel.SecurityMode.Password,
KeyguardSecurityModel.SecurityMode.SimPuk ->
AuthenticationMethodModel.Password(
password = "password", // TODO(b/280883900): remove this
)
KeyguardSecurityModel.SecurityMode.Pattern ->
AuthenticationMethodModel.Pattern(
coordinates =
listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
), // TODO(b/280883900): remove this
)
KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
null -> error("Invalid security is null!")
}
}
}
override fun setUnlocked(isUnlocked: Boolean) { override fun setUnlocked(isUnlocked: Boolean) {
_isUnlocked.value = isUnlocked _isUnlocked.value = isUnlocked
} }
@@ -98,10 +136,6 @@ class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationReposit
_isBypassEnabled.value = isBypassEnabled _isBypassEnabled.value = isBypassEnabled
} }
override fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
_authenticationMethod.value = authenticationMethod
}
override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) { override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
_failedAuthenticationAttempts.value = failedAuthenticationAttempts _failedAuthenticationAttempts.value = failedAuthenticationAttempts
} }

View File

@@ -25,9 +25,8 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Hosts application business logic related to authentication. */ /** Hosts application business logic related to authentication. */
@SysUISingleton @SysUISingleton
@@ -37,12 +36,6 @@ constructor(
@Application applicationScope: CoroutineScope, @Application applicationScope: CoroutineScope,
private val repository: AuthenticationRepository, private val repository: AuthenticationRepository,
) { ) {
/**
* The currently-configured authentication method. This determines how the authentication
* challenge is completed in order to unlock an otherwise locked device.
*/
val authenticationMethod: StateFlow<AuthenticationMethodModel> = repository.authenticationMethod
/** /**
* Whether the device is unlocked. * Whether the device is unlocked.
* *
@@ -52,20 +45,18 @@ constructor(
* Note that this state has no real bearing on whether the lock screen is showing or dismissed. * Note that this state has no real bearing on whether the lock screen is showing or dismissed.
*/ */
val isUnlocked: StateFlow<Boolean> = val isUnlocked: StateFlow<Boolean> =
combine(authenticationMethod, repository.isUnlocked) { authMethod, isUnlocked -> repository.isUnlocked
isUnlockedWithAuthMethod( .map { isUnlocked ->
isUnlocked = isUnlocked, if (getAuthenticationMethod() is AuthenticationMethodModel.None) {
authMethod = authMethod, true
) } else {
isUnlocked
}
} }
.stateIn( .stateIn(
scope = applicationScope, scope = applicationScope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = initialValue = true,
isUnlockedWithAuthMethod(
isUnlocked = repository.isUnlocked.value,
authMethod = repository.authenticationMethod.value,
)
) )
/** /**
@@ -82,25 +73,20 @@ constructor(
*/ */
val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts
init { /**
// UNLOCKS WHEN AUTH METHOD REMOVED. * Returns the currently-configured authentication method. This determines how the
// * authentication challenge is completed in order to unlock an otherwise locked device.
// Unlocks the device if the auth method becomes None. */
applicationScope.launch { suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
repository.authenticationMethod.collect { return repository.getAuthenticationMethod()
if (it is AuthenticationMethodModel.None) {
unlockDevice()
}
}
}
} }
/** /**
* Returns `true` if the device currently requires authentication before content can be viewed; * Returns `true` if the device currently requires authentication before content can be viewed;
* `false` if content can be displayed without unlocking first. * `false` if content can be displayed without unlocking first.
*/ */
fun isAuthenticationRequired(): Boolean { suspend fun isAuthenticationRequired(): Boolean {
return !isUnlocked.value && authenticationMethod.value.isSecure return !isUnlocked.value && getAuthenticationMethod().isSecure
} }
/** /**
@@ -133,8 +119,8 @@ constructor(
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed. * authentication failed, `null` if the check was not performed.
*/ */
fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? { suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
val authMethod = this.authenticationMethod.value val authMethod = getAuthenticationMethod()
if (tryAutoConfirm) { if (tryAutoConfirm) {
if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) { if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
// Do not attempt to authenticate unless the PIN lock is set to auto-confirm. // Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
@@ -176,28 +162,12 @@ constructor(
repository.setUnlocked(true) repository.setUnlocked(true)
} }
/** See [authenticationMethod]. */
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
repository.setAuthenticationMethod(authenticationMethod)
}
/** See [isBypassEnabled]. */ /** See [isBypassEnabled]. */
fun toggleBypassEnabled() { fun toggleBypassEnabled() {
repository.setBypassEnabled(!repository.isBypassEnabled.value) repository.setBypassEnabled(!repository.isBypassEnabled.value)
} }
companion object { companion object {
private fun isUnlockedWithAuthMethod(
isUnlocked: Boolean,
authMethod: AuthenticationMethodModel,
): Boolean {
return if (authMethod is AuthenticationMethodModel.None) {
true
} else {
isUnlocked
}
}
/** /**
* Returns a PIN code from the given list. It's assumed the given list elements are all * Returns a PIN code from the given list. It's assumed the given list elements are all
* [Int] in the range [0-9]. * [Int] in the range [0-9].

View File

@@ -68,43 +68,39 @@ constructor(
) )
) )
/**
* The currently-configured authentication method. This determines how the authentication
* challenge is completed in order to unlock an otherwise locked device.
*/
val authenticationMethod: StateFlow<AuthenticationMethodModel> =
authenticationInteractor.authenticationMethod
/** The current authentication throttling state. If `null`, there's no throttling. */ /** The current authentication throttling state. If `null`, there's no throttling. */
val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
init { init {
applicationScope.launch { applicationScope.launch {
combine( sceneInteractor.currentScene(containerName).collect { currentScene ->
sceneInteractor.currentScene(containerName), if (currentScene.key == SceneKey.Bouncer) {
authenticationInteractor.authenticationMethod, when (getAuthenticationMethod()) {
::Pair, is AuthenticationMethodModel.None ->
) sceneInteractor.setCurrentScene(
.collect { (currentScene, authMethod) -> containerName,
if (currentScene.key == SceneKey.Bouncer) { SceneModel(SceneKey.Gone),
when (authMethod) { )
is AuthenticationMethodModel.None -> is AuthenticationMethodModel.Swipe ->
sceneInteractor.setCurrentScene( sceneInteractor.setCurrentScene(
containerName, containerName,
SceneModel(SceneKey.Gone), SceneModel(SceneKey.Lockscreen),
) )
is AuthenticationMethodModel.Swipe -> else -> Unit
sceneInteractor.setCurrentScene(
containerName,
SceneModel(SceneKey.Lockscreen),
)
else -> Unit
}
} }
} }
}
} }
} }
/**
* Returns the currently-configured authentication method. This determines how the
* authentication challenge is completed in order to unlock an otherwise locked device.
*/
suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return authenticationInteractor.getAuthenticationMethod()
}
/** /**
* Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown. * Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
* *
@@ -115,18 +111,20 @@ constructor(
containerName: String, containerName: String,
message: String? = null, message: String? = null,
) { ) {
if (authenticationInteractor.isAuthenticationRequired()) { applicationScope.launch {
repository.setMessage(message ?: promptMessage(authenticationMethod.value)) if (authenticationInteractor.isAuthenticationRequired()) {
sceneInteractor.setCurrentScene( repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
containerName = containerName, sceneInteractor.setCurrentScene(
scene = SceneModel(SceneKey.Bouncer), containerName = containerName,
) scene = SceneModel(SceneKey.Bouncer),
} else { )
authenticationInteractor.unlockDevice() } else {
sceneInteractor.setCurrentScene( authenticationInteractor.unlockDevice()
containerName = containerName, sceneInteractor.setCurrentScene(
scene = SceneModel(SceneKey.Gone), containerName = containerName,
) scene = SceneModel(SceneKey.Gone),
)
}
} }
} }
@@ -135,7 +133,7 @@ constructor(
* method. * method.
*/ */
fun resetMessage() { fun resetMessage() {
repository.setMessage(promptMessage(authenticationMethod.value)) applicationScope.launch { repository.setMessage(promptMessage(getAuthenticationMethod())) }
} }
/** Removes the user-facing message. */ /** Removes the user-facing message. */
@@ -160,7 +158,7 @@ constructor(
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed. * authentication failed, `null` if the check was not performed.
*/ */
fun authenticate( suspend fun authenticate(
input: List<Any>, input: List<Any>,
tryAutoConfirm: Boolean = false, tryAutoConfirm: Boolean = false,
): Boolean? { ): Boolean? {
@@ -198,7 +196,7 @@ constructor(
repository.setThrottling(null) repository.setThrottling(null)
clearMessage() clearMessage()
} }
else -> repository.setMessage(errorMessage(authenticationMethod.value)) else -> repository.setMessage(errorMessage(getAuthenticationMethod()))
} }
return isAuthenticated return isAuthenticated

View File

@@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -66,6 +67,7 @@ constructor(
private val password: PasswordBouncerViewModel by lazy { private val password: PasswordBouncerViewModel by lazy {
PasswordBouncerViewModel( PasswordBouncerViewModel(
applicationScope = applicationScope,
interactor = interactor, interactor = interactor,
isInputEnabled = isInputEnabled, isInputEnabled = isInputEnabled,
) )
@@ -81,14 +83,25 @@ constructor(
} }
/** View-model for the current UI, based on the current authentication method. */ /** View-model for the current UI, based on the current authentication method. */
val authMethod: StateFlow<AuthMethodBouncerViewModel?> = val authMethod: StateFlow<AuthMethodBouncerViewModel?>
interactor.authenticationMethod get() =
.map { authMethod -> toViewModel(authMethod) } flow {
.stateIn( emit(null)
scope = applicationScope, emit(interactor.getAuthenticationMethod())
started = SharingStarted.WhileSubscribed(), }
initialValue = toViewModel(interactor.authenticationMethod.value), .map { authMethod ->
) when (authMethod) {
is AuthenticationMethodModel.Pin -> pin
is AuthenticationMethodModel.Password -> password
is AuthenticationMethodModel.Pattern -> pattern
else -> null
}
}
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = null,
)
/** The user-facing message to show in the bouncer. */ /** The user-facing message to show in the bouncer. */
val message: StateFlow<MessageViewModel> = val message: StateFlow<MessageViewModel> =
@@ -125,7 +138,7 @@ constructor(
interactor.throttling interactor.throttling
.map { model -> .map { model ->
model?.let { model?.let {
when (interactor.authenticationMethod.value) { when (interactor.getAuthenticationMethod()) {
is AuthenticationMethodModel.Pin -> is AuthenticationMethodModel.Pin ->
R.string.kg_too_many_failed_pin_attempts_dialog_message R.string.kg_too_many_failed_pin_attempts_dialog_message
is AuthenticationMethodModel.Password -> is AuthenticationMethodModel.Password ->
@@ -161,17 +174,6 @@ constructor(
_throttlingDialogMessage.value = null _throttlingDialogMessage.value = null
} }
private fun toViewModel(
authMethod: AuthenticationMethodModel,
): AuthMethodBouncerViewModel? {
return when (authMethod) {
is AuthenticationMethodModel.Pin -> pin
is AuthenticationMethodModel.Password -> password
is AuthenticationMethodModel.Pattern -> pattern
else -> null
}
}
private fun toMessageViewModel( private fun toMessageViewModel(
message: String?, message: String?,
throttling: AuthenticationThrottledModel?, throttling: AuthenticationThrottledModel?,

View File

@@ -17,12 +17,15 @@
package com.android.systemui.bouncer.ui.viewmodel package com.android.systemui.bouncer.ui.viewmodel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the password bouncer UI. */ /** Holds UI state and handles user input for the password bouncer UI. */
class PasswordBouncerViewModel( class PasswordBouncerViewModel(
private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor, private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>, isInputEnabled: StateFlow<Boolean>,
) : ) :
@@ -50,10 +53,13 @@ class PasswordBouncerViewModel(
/** Notifies that the user has pressed the key for attempting to authenticate the password. */ /** Notifies that the user has pressed the key for attempting to authenticate the password. */
fun onAuthenticateKeyPressed() { fun onAuthenticateKeyPressed() {
if (interactor.authenticate(password.value.toCharArray().toList()) != true) { val password = _password.value.toCharArray().toList()
showFailureAnimation()
}
_password.value = "" _password.value = ""
applicationScope.launch {
if (interactor.authenticate(password) != true) {
showFailureAnimation()
}
}
} }
} }

View File

@@ -29,13 +29,15 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the pattern bouncer UI. */ /** Holds UI state and handles user input for the pattern bouncer UI. */
class PatternBouncerViewModel( class PatternBouncerViewModel(
private val applicationContext: Context, private val applicationContext: Context,
applicationScope: CoroutineScope, private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor, private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>, isInputEnabled: StateFlow<Boolean>,
) : ) :
@@ -69,12 +71,17 @@ class PatternBouncerViewModel(
/** Whether the pattern itself should be rendered visibly. */ /** Whether the pattern itself should be rendered visibly. */
val isPatternVisible: StateFlow<Boolean> = val isPatternVisible: StateFlow<Boolean> =
interactor.authenticationMethod flow {
.map { authMethod -> isPatternVisible(authMethod) } emit(null)
emit(interactor.getAuthenticationMethod())
}
.map { authMethod ->
(authMethod as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
}
.stateIn( .stateIn(
scope = applicationScope, scope = applicationScope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = isPatternVisible(interactor.authenticationMethod.value), initialValue = false,
) )
/** Notifies that the UI has been shown to the user. */ /** Notifies that the UI has been shown to the user. */
@@ -154,17 +161,15 @@ class PatternBouncerViewModel(
/** Notifies that the user has ended the drag gesture across the dot grid. */ /** Notifies that the user has ended the drag gesture across the dot grid. */
fun onDragEnd() { fun onDragEnd() {
val pattern = _selectedDots.value.map { it.toCoordinate() } val pattern = _selectedDots.value.map { it.toCoordinate() }
if (interactor.authenticate(pattern) != true) {
showFailureAnimation()
}
_dots.value = defaultDots() _dots.value = defaultDots()
_currentDot.value = null _currentDot.value = null
_selectedDots.value = linkedSetOf() _selectedDots.value = linkedSetOf()
}
private fun isPatternVisible(authMethodModel: AuthenticationMethodModel): Boolean { applicationScope.launch {
return (authMethodModel as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false if (interactor.authenticate(pattern) != true) {
showFailureAnimation()
}
}
} }
private fun defaultDots(): List<PatternDotViewModel> { private fun defaultDots(): List<PatternDotViewModel> {

View File

@@ -22,13 +22,14 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */ /** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel( class PinBouncerViewModel(
applicationScope: CoroutineScope, private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor, private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>, isInputEnabled: StateFlow<Boolean>,
) : ) :
@@ -39,40 +40,48 @@ class PinBouncerViewModel(
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList()) private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
/** The length of the hinted PIN, or null if pin length hint should not be shown. */ /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
val hintedPinLength: StateFlow<Int?> = val hintedPinLength: StateFlow<Int?> =
interactor.authenticationMethod flow {
.map { authMethod -> computeHintedPinLength(authMethod) } emit(null)
.stateIn( emit(interactor.getAuthenticationMethod())
scope = applicationScope, }
started = SharingStarted.Eagerly, .map { authMethod ->
initialValue = computeHintedPinLength(interactor.authenticationMethod.value), // Hinting is enabled for 6-digit codes only
) autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
/** Appearance of the backspace button. */
val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
combine(interactor.authenticationMethod, mutablePinEntries) { authMethod, enteredPin ->
computeBackspaceButtonAppearance(authMethod, enteredPin)
} }
.stateIn( .stateIn(
scope = applicationScope, scope = applicationScope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = initialValue = null,
computeBackspaceButtonAppearance( )
interactor.authenticationMethod.value,
mutablePinEntries.value /** Appearance of the backspace button. */
), val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
mutablePinEntries
.map { mutablePinEntries ->
computeBackspaceButtonAppearance(
interactor.getAuthenticationMethod(),
mutablePinEntries
)
}
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = ActionButtonAppearance.Hidden,
) )
/** Appearance of the confirm button. */ /** Appearance of the confirm button. */
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> = val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
interactor.authenticationMethod flow {
emit(null)
emit(interactor.getAuthenticationMethod())
}
.map { authMethod -> computeConfirmButtonAppearance(authMethod) } .map { authMethod -> computeConfirmButtonAppearance(authMethod) }
.stateIn( .stateIn(
scope = applicationScope, scope = applicationScope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = initialValue = ActionButtonAppearance.Hidden,
computeConfirmButtonAppearance(interactor.authenticationMethod.value),
) )
/** Notifies that the UI has been shown to the user. */ /** Notifies that the UI has been shown to the user. */
@@ -111,30 +120,28 @@ class PinBouncerViewModel(
private fun tryAuthenticate(useAutoConfirm: Boolean) { private fun tryAuthenticate(useAutoConfirm: Boolean) {
val pinCode = mutablePinEntries.value.map { it.input } val pinCode = mutablePinEntries.value.map { it.input }
val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return
if (!isSuccess) { applicationScope.launch {
showFailureAnimation() val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return@launch
if (!isSuccess) {
showFailureAnimation()
}
mutablePinEntries.value = emptyList()
} }
mutablePinEntries.value = emptyList()
} }
private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel): Boolean { private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel?): Boolean {
return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true
} }
private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel): Int? { private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel?): Int? {
if (!isAutoConfirmEnabled(authMethodModel)) return null if (!isAutoConfirmEnabled(authMethodModel)) return null
return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size
} }
private fun computeHintedPinLength(authMethodModel: AuthenticationMethodModel): Int? {
// Hinting is enabled for 6-digit codes only
return autoConfirmPinLength(authMethodModel).takeIf { it == HINTING_PASSCODE_LENGTH }
}
private fun computeBackspaceButtonAppearance( private fun computeBackspaceButtonAppearance(
authMethodModel: AuthenticationMethodModel, authMethodModel: AuthenticationMethodModel,
enteredPin: List<EnteredKey> enteredPin: List<EnteredKey>
@@ -149,7 +156,7 @@ class PinBouncerViewModel(
} }
} }
private fun computeConfirmButtonAppearance( private fun computeConfirmButtonAppearance(
authMethodModel: AuthenticationMethodModel authMethodModel: AuthenticationMethodModel?
): ActionButtonAppearance { ): ActionButtonAppearance {
return if (isAutoConfirmEnabled(authMethodModel)) { return if (isAutoConfirmEnabled(authMethodModel)) {
ActionButtonAppearance.Hidden ActionButtonAppearance.Hidden

View File

@@ -61,23 +61,16 @@ constructor(
/** Whether it's currently possible to swipe up to dismiss the lockscreen. */ /** Whether it's currently possible to swipe up to dismiss the lockscreen. */
val isSwipeToDismissEnabled: StateFlow<Boolean> = val isSwipeToDismissEnabled: StateFlow<Boolean> =
combine( authenticationInteractor.isUnlocked
authenticationInteractor.isUnlocked, .map { isUnlocked ->
authenticationInteractor.authenticationMethod, !isUnlocked &&
) { isUnlocked, authMethod -> authenticationInteractor.getAuthenticationMethod() is
isSwipeToUnlockEnabled( AuthenticationMethodModel.Swipe
isUnlocked = isUnlocked,
authMethod = authMethod,
)
} }
.stateIn( .stateIn(
scope = applicationScope, scope = applicationScope,
started = SharingStarted.WhileSubscribed(), started = SharingStarted.WhileSubscribed(),
initialValue = initialValue = false,
isSwipeToUnlockEnabled(
isUnlocked = authenticationInteractor.isUnlocked.value,
authMethod = authenticationInteractor.authenticationMethod.value,
),
) )
init { init {
@@ -124,44 +117,17 @@ constructor(
// If switched from the lockscreen to the gone scene and the auth method was a swipe, // If switched from the lockscreen to the gone scene and the auth method was a swipe,
// unlocks the device. // unlocks the device.
applicationScope.launch { applicationScope.launch {
combine( sceneInteractor.currentScene(containerName).pairwise().collect {
authenticationInteractor.authenticationMethod, (previousScene, currentScene) ->
sceneInteractor.currentScene(containerName).pairwise(), if (
::Pair, authenticationInteractor.getAuthenticationMethod() is
) AuthenticationMethodModel.Swipe &&
.collect { (authMethod, scenes) -> previousScene.key == SceneKey.Lockscreen &&
val (previousScene, currentScene) = scenes currentScene.key == SceneKey.Gone
if ( ) {
authMethod is AuthenticationMethodModel.Swipe && authenticationInteractor.unlockDevice()
previousScene.key == SceneKey.Lockscreen &&
currentScene.key == SceneKey.Gone
) {
authenticationInteractor.unlockDevice()
}
}
}
// DISMISS Lockscreen IF AUTH METHOD IS REMOVED.
//
// If the auth method becomes None while on the lockscreen scene, dismisses the lock
// screen.
applicationScope.launch {
combine(
authenticationInteractor.authenticationMethod,
sceneInteractor.currentScene(containerName),
::Pair,
)
.collect { (authMethod, scene) ->
if (
scene.key == SceneKey.Lockscreen &&
authMethod == AuthenticationMethodModel.None
) {
sceneInteractor.setCurrentScene(
containerName = containerName,
scene = SceneModel(SceneKey.Gone),
)
}
} }
}
} }
} }
@@ -170,13 +136,6 @@ constructor(
bouncerInteractor.showOrUnlockDevice(containerName = containerName) bouncerInteractor.showOrUnlockDevice(containerName = containerName)
} }
private fun isSwipeToUnlockEnabled(
isUnlocked: Boolean,
authMethod: AuthenticationMethodModel,
): Boolean {
return !isUnlocked && authMethod is AuthenticationMethodModel.Swipe
}
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create( fun create(

View File

@@ -25,7 +25,6 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -37,8 +36,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class AuthenticationInteractorTest : SysuiTestCase() { class AuthenticationInteractorTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val repository: AuthenticationRepository = utils.authenticationRepository() private val repository: AuthenticationRepository = utils.authenticationRepository()
private val underTest = private val underTest =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -46,23 +45,23 @@ class AuthenticationInteractorTest : SysuiTestCase() {
) )
@Test @Test
fun authMethod() = fun getAuthenticationMethod() =
testScope.runTest { testScope.runTest {
val authMethod by collectLastValue(underTest.authenticationMethod) assertThat(underTest.getAuthenticationMethod())
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234)) .isEqualTo(AuthenticationMethodModel.Pin(1234))
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password")) AuthenticationMethodModel.Password("password")
)
assertThat(underTest.getAuthenticationMethod())
.isEqualTo(AuthenticationMethodModel.Password("password"))
} }
@Test @Test
fun isUnlocked_whenAuthMethodIsNone_isTrue() = fun isUnlocked_whenAuthMethodIsNone_isTrue() =
testScope.runTest { testScope.runTest {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
assertThat(isUnlocked).isFalse()
underTest.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(isUnlocked).isTrue() assertThat(isUnlocked).isTrue()
} }
@@ -108,7 +107,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
underTest.lockDevice() underTest.lockDevice()
runCurrent() runCurrent()
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
assertThat(underTest.isAuthenticationRequired()).isTrue() assertThat(underTest.isAuthenticationRequired()).isTrue()
} }
@@ -118,7 +119,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
underTest.lockDevice() underTest.lockDevice()
runCurrent() runCurrent()
underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse() assertThat(underTest.isAuthenticationRequired()).isFalse()
} }
@@ -128,7 +129,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
underTest.unlockDevice() underTest.unlockDevice()
runCurrent() runCurrent()
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
assertThat(underTest.isAuthenticationRequired()).isFalse() assertThat(underTest.isAuthenticationRequired()).isFalse()
} }
@@ -138,7 +141,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
underTest.unlockDevice() underTest.unlockDevice()
runCurrent() runCurrent()
underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse() assertThat(underTest.isAuthenticationRequired()).isFalse()
} }
@@ -148,7 +151,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue() assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
@@ -161,7 +166,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse() assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
@@ -174,7 +181,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf())).isFalse() assertThat(underTest.authenticate(listOf())).isFalse()
@@ -187,7 +196,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(9999999999999999)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(List(16) { 9 })).isTrue() assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
@@ -206,7 +217,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(99999999999999999)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(List(17) { 9 })).isFalse() assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
@@ -219,7 +232,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("password".toList())).isTrue() assertThat(underTest.authenticate("password".toList())).isTrue()
@@ -232,7 +247,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("alohomora".toList())).isFalse() assertThat(underTest.authenticate("alohomora".toList())).isFalse()
@@ -245,7 +262,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern( AuthenticationMethodModel.Pattern(
listOf( listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate( AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -293,7 +310,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern( AuthenticationMethodModel.Pattern(
listOf( listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate( AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -341,7 +358,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -356,7 +373,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -371,7 +388,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -386,7 +403,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -402,7 +419,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -417,7 +434,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false) AuthenticationMethodModel.Pin(1234, autoConfirm = false)
) )
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -432,22 +449,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked) val isUnlocked by collectLastValue(underTest.isUnlocked)
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull() assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0) assertThat(failedAttemptCount).isEqualTo(0)
} }
@Test
fun unlocksDevice_whenAuthMethodBecomesNone() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
assertThat(isUnlocked).isFalse()
repository.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(isUnlocked).isTrue()
}
} }

View File

@@ -26,7 +26,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@@ -40,8 +39,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class BouncerInteractorTest : SysuiTestCase() { class BouncerInteractorTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
repository = utils.authenticationRepository(), repository = utils.authenticationRepository(),
@@ -69,7 +68,9 @@ class BouncerInteractorTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
underTest.showOrUnlockDevice("container1") underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -100,7 +101,7 @@ class BouncerInteractorTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -130,7 +131,7 @@ class BouncerInteractorTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false) AuthenticationMethodModel.Pin(1234, autoConfirm = false)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -154,7 +155,7 @@ class BouncerInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -186,7 +187,7 @@ class BouncerInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(emptyList()) AuthenticationMethodModel.Pattern(emptyList())
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -222,7 +223,9 @@ class BouncerInteractorTest : SysuiTestCase() {
fun showOrUnlockDevice_notLocked_switchesToGoneScene() = fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
runCurrent() runCurrent()
@@ -235,7 +238,7 @@ class BouncerInteractorTest : SysuiTestCase() {
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() = fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
underTest.showOrUnlockDevice("container1") underTest.showOrUnlockDevice("container1")
@@ -248,7 +251,7 @@ class BouncerInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -266,7 +269,9 @@ class BouncerInteractorTest : SysuiTestCase() {
val throttling by collectLastValue(underTest.throttling) val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(throttling).isNull() assertThat(throttling).isNull()
assertThat(message).isEqualTo("") assertThat(message).isEqualTo("")
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()

View File

@@ -24,7 +24,6 @@ import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -35,8 +34,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class AuthMethodBouncerViewModelTest : SysuiTestCase() { class AuthMethodBouncerViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
utils.authenticationRepository(), utils.authenticationRepository(),
@@ -55,7 +54,9 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {
@Test @Test
fun animateFailure() = fun animateFailure() =
testScope.runTest { testScope.runTest {
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
val animateFailure by collectLastValue(underTest.animateFailure) val animateFailure by collectLastValue(underTest.animateFailure)
assertThat(animateFailure).isFalse() assertThat(animateFailure).isFalse()

View File

@@ -26,7 +26,6 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -38,8 +37,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class BouncerViewModelTest : SysuiTestCase() { class BouncerViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
repository = utils.authenticationRepository(), repository = utils.authenticationRepository(),
@@ -54,11 +53,11 @@ class BouncerViewModelTest : SysuiTestCase() {
@Test @Test
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() = fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
testScope.runTest { testScope.runTest {
val authMethodViewModel: AuthMethodBouncerViewModel? by
collectLastValue(underTest.authMethod)
authMethodsToTest().forEach { authMethod -> authMethodsToTest().forEach { authMethod ->
authenticationInteractor.setAuthenticationMethod(authMethod) utils.authenticationRepository.setAuthenticationMethod(authMethod)
val authMethodViewModel: AuthMethodBouncerViewModel? by
collectLastValue(underTest.authMethod)
if (authMethod.isSecure) { if (authMethod.isSecure) {
assertThat(authMethodViewModel).isNotNull() assertThat(authMethodViewModel).isNotNull()
} else { } else {
@@ -75,13 +74,13 @@ class BouncerViewModelTest : SysuiTestCase() {
collectLastValue(underTest.authMethod) collectLastValue(underTest.authMethod)
// First pass, populate our "seen" map: // First pass, populate our "seen" map:
authMethodsToTest().forEach { authMethod -> authMethodsToTest().forEach { authMethod ->
authenticationInteractor.setAuthenticationMethod(authMethod) utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { seen[authMethod] = it } authMethodViewModel?.let { seen[authMethod] = it }
} }
// Second pass, assert same instances are reused: // Second pass, assert same instances are reused:
authMethodsToTest().forEach { authMethod -> authMethodsToTest().forEach { authMethod ->
authenticationInteractor.setAuthenticationMethod(authMethod) utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) } authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) }
} }
} }
@@ -97,7 +96,9 @@ class BouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val message by collectLastValue(underTest.message) val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling) val throttling by collectLastValue(bouncerInteractor.throttling)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(message?.isUpdateAnimated).isTrue() assertThat(message?.isUpdateAnimated).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) { repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -120,7 +121,9 @@ class BouncerViewModelTest : SysuiTestCase() {
} }
) )
val throttling by collectLastValue(bouncerInteractor.throttling) val throttling by collectLastValue(bouncerInteractor.throttling)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(isInputEnabled).isTrue() assertThat(isInputEnabled).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) { repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -137,7 +140,9 @@ class BouncerViewModelTest : SysuiTestCase() {
fun throttlingDialogMessage() = fun throttlingDialogMessage() =
testScope.runTest { testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage) val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
repeat(BouncerInteractor.THROTTLE_EVERY) { repeat(BouncerInteractor.THROTTLE_EVERY) {
// Wrong PIN. // Wrong PIN.

View File

@@ -28,7 +28,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -40,8 +40,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class PasswordBouncerViewModelTest : SysuiTestCase() { class PasswordBouncerViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
repository = utils.authenticationRepository(), repository = utils.authenticationRepository(),
@@ -58,6 +58,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
) )
private val underTest = private val underTest =
PasswordBouncerViewModel( PasswordBouncerViewModel(
applicationScope = testScope.backgroundScope,
interactor = bouncerInteractor, interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(), isInputEnabled = MutableStateFlow(true).asStateFlow(),
) )
@@ -75,7 +76,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password) val password by collectLastValue(underTest.password)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -98,7 +99,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password) val password by collectLastValue(underTest.password)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -106,6 +107,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown() underTest.onShown()
runCurrent()
underTest.onPasswordInputChanged("password") underTest.onPasswordInputChanged("password")
@@ -120,7 +122,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -143,7 +145,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password) val password by collectLastValue(underTest.password)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -168,7 +170,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password) val password by collectLastValue(underTest.password)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()

View File

@@ -29,7 +29,7 @@ import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -41,8 +41,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class PatternBouncerViewModelTest : SysuiTestCase() { class PatternBouncerViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
repository = utils.authenticationRepository(), repository = utils.authenticationRepository(),
@@ -79,7 +79,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots) val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot) val currentDot by collectLastValue(underTest.currentDot)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN) AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -104,7 +104,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots) val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot) val currentDot by collectLastValue(underTest.currentDot)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN) AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -112,6 +112,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown() underTest.onShown()
runCurrent()
underTest.onDragStart() underTest.onDragStart()
@@ -129,7 +130,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val selectedDots by collectLastValue(underTest.selectedDots) val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot) val currentDot by collectLastValue(underTest.currentDot)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN) AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -180,7 +181,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots) val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot) val currentDot by collectLastValue(underTest.currentDot)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN) AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -215,7 +216,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots) val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot) val currentDot by collectLastValue(underTest.currentDot)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN) AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()

View File

@@ -29,7 +29,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -41,8 +41,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class PinBouncerViewModelTest : SysuiTestCase() { class PinBouncerViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor() private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -85,7 +85,6 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -106,12 +105,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown() underTest.onShown()
runCurrent()
underTest.onPinButtonClicked(1) underTest.onPinButtonClicked(1)
@@ -129,12 +131,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown() underTest.onShown()
runCurrent()
underTest.onPinButtonClicked(1) underTest.onPinButtonClicked(1)
assertThat(entries).hasSize(1) assertThat(entries).hasSize(1)
@@ -153,7 +158,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -180,12 +187,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown() underTest.onShown()
runCurrent()
underTest.onPinButtonClicked(1) underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2) underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3) underTest.onPinButtonClicked(3)
@@ -204,7 +214,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -228,7 +240,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -255,7 +269,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -290,7 +306,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -314,7 +330,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message) val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries) val entries by collectLastValue(underTest.pinEntries)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -338,7 +354,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance) val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false) AuthenticationMethodModel.Pin(1234, autoConfirm = false)
) )
@@ -349,7 +365,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() = fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
testScope.runTest { testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance) val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
@@ -360,7 +376,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() = fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
testScope.runTest { testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance) val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
@@ -374,7 +390,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance) val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false) AuthenticationMethodModel.Pin(1234, autoConfirm = false)
) )
@@ -385,7 +401,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun confirmButtonAppearance_withAutoConfirm_isHidden() = fun confirmButtonAppearance_withAutoConfirm_isHidden() =
testScope.runTest { testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance) val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true) AuthenticationMethodModel.Pin(1234, autoConfirm = true)
) )
@@ -396,7 +412,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun hintedPinLength_withoutAutoConfirm_isNull() = fun hintedPinLength_withoutAutoConfirm_isNull() =
testScope.runTest { testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength) val hintedPinLength by collectLastValue(underTest.hintedPinLength)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false) AuthenticationMethodModel.Pin(1234, autoConfirm = false)
) )
@@ -407,7 +423,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() = fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
testScope.runTest { testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength) val hintedPinLength by collectLastValue(underTest.hintedPinLength)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(12345, autoConfirm = true) AuthenticationMethodModel.Pin(12345, autoConfirm = true)
) )
@@ -418,7 +434,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() = fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
testScope.runTest { testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength) val hintedPinLength by collectLastValue(underTest.hintedPinLength)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(123456, autoConfirm = true) AuthenticationMethodModel.Pin(123456, autoConfirm = true)
) )
@@ -429,7 +445,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() = fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
testScope.runTest { testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength) val hintedPinLength by collectLastValue(underTest.hintedPinLength)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234567, autoConfirm = true) AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
) )

View File

@@ -26,7 +26,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -38,8 +37,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class LockscreenSceneInteractorTest : SysuiTestCase() { class LockscreenSceneInteractorTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor() private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -74,7 +73,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled) val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isTrue() assertThat(isSwipeToDismissEnabled).isTrue()
} }
@@ -85,7 +84,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled) val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isFalse() assertThat(isSwipeToDismissEnabled).isFalse()
} }
@@ -95,7 +94,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen() underTest.dismissLockscreen()
@@ -108,7 +109,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen() underTest.dismissLockscreen()
@@ -121,7 +124,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen() underTest.dismissLockscreen()
@@ -182,7 +185,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
@@ -195,7 +198,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest { testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
@@ -210,7 +215,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
runCurrent() runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade))
runCurrent() runCurrent()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent() runCurrent()
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
@@ -219,30 +224,17 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
assertThat(isUnlocked).isFalse() assertThat(isUnlocked).isFalse()
} }
@Test
fun authMethodChangedToNone_onLockScreenScene_dismissesLockScreen() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test @Test
fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() = fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent() runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings)) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings))
runCurrent() runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
} }

View File

@@ -29,7 +29,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -41,8 +40,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class LockscreenSceneViewModelTest : SysuiTestCase() { class LockscreenSceneViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor() private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -73,7 +72,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun lockButtonIcon_whenLocked() = fun lockButtonIcon_whenLocked() =
testScope.runTest { testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon) val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
@@ -86,7 +85,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun lockButtonIcon_whenUnlocked() = fun lockButtonIcon_whenUnlocked() =
testScope.runTest { testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon) val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
authenticationInteractor.setAuthenticationMethod( utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password") AuthenticationMethodModel.Password("password")
) )
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
@@ -99,7 +98,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() = fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() =
testScope.runTest { testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone) assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -109,7 +108,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() = fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
testScope.runTest { testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer) assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
@@ -119,7 +120,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() = fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
runCurrent() runCurrent()
@@ -132,7 +135,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceUnlocked_switchesToGone() = fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
runCurrent() runCurrent()
@@ -145,7 +150,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
runCurrent() runCurrent()
@@ -158,7 +165,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
fun onLockButtonClicked_deviceUnlocked_switchesToGone() = fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
runCurrent() runCurrent()

View File

@@ -27,7 +27,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -39,8 +38,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class QuickSettingsSceneViewModelTest : SysuiTestCase() { class QuickSettingsSceneViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor() private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -70,7 +69,9 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceUnlocked_switchesToGone() = fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
runCurrent() runCurrent()
@@ -83,7 +84,9 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
runCurrent() runCurrent()

View File

@@ -27,7 +27,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -39,8 +38,8 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class ShadeSceneViewModelTest : SysuiTestCase() { class ShadeSceneViewModelTest : SysuiTestCase() {
private val testScope = TestScope() private val utils = SceneTestUtils(this)
private val utils = SceneTestUtils(this, testScope) private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor() private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor = private val authenticationInteractor =
utils.authenticationInteractor( utils.authenticationInteractor(
@@ -71,7 +70,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun upTransitionSceneKey_deviceLocked_lockScreen() = fun upTransitionSceneKey_deviceLocked_lockScreen() =
testScope.runTest { testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen) assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
@@ -81,7 +82,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun upTransitionSceneKey_deviceUnlocked_gone() = fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest { testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone) assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -91,7 +94,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceUnlocked_switchesToGone() = fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.unlockDevice() authenticationInteractor.unlockDevice()
runCurrent() runCurrent()
@@ -104,7 +109,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest { testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234)
)
authenticationInteractor.lockDevice() authenticationInteractor.lockDevice()
runCurrent() runCurrent()

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.authentication.data.repository
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
class FakeAuthenticationRepository(
private val delegate: AuthenticationRepository,
private val onSecurityModeChanged: (SecurityMode) -> Unit,
) : AuthenticationRepository by delegate {
private var authenticationMethod: AuthenticationMethodModel = DEFAULT_AUTHENTICATION_METHOD
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return authenticationMethod
}
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
this.authenticationMethod = authenticationMethod
onSecurityModeChanged(authenticationMethod.toSecurityMode())
}
companion object {
val DEFAULT_AUTHENTICATION_METHOD =
AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
return when (this) {
is AuthenticationMethodModel.Pin -> SecurityMode.PIN
is AuthenticationMethodModel.Password -> SecurityMode.Password
is AuthenticationMethodModel.Pattern -> SecurityMode.Pattern
is AuthenticationMethodModel.Swipe,
is AuthenticationMethodModel.None -> SecurityMode.None
}
}
}
}

View File

@@ -16,9 +16,12 @@
package com.android.systemui.scene package com.android.systemui.scene
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository.Companion.toSecurityMode
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.data.repository.BouncerRepository import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
@@ -28,8 +31,12 @@ import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
/** /**
@@ -39,9 +46,23 @@ import kotlinx.coroutines.test.TestScope
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
class SceneTestUtils( class SceneTestUtils(
test: SysuiTestCase, test: SysuiTestCase,
private val testScope: TestScope? = null,
) { ) {
val testDispatcher: TestDispatcher by lazy { StandardTestDispatcher() }
val testScope: TestScope by lazy { TestScope(testDispatcher) }
private var securityMode: SecurityMode =
FakeAuthenticationRepository.DEFAULT_AUTHENTICATION_METHOD.toSecurityMode()
val authenticationRepository: FakeAuthenticationRepository by lazy {
FakeAuthenticationRepository(
delegate =
AuthenticationRepositoryImpl(
getSecurityMode = { securityMode },
backgroundDispatcher = testDispatcher,
userRepository = FakeUserRepository(),
lockPatternUtils = mock(),
),
onSecurityModeChanged = { securityMode = it },
)
}
private val context = test.context private val context = test.context
fun fakeSceneContainerRepository( fun fakeSceneContainerRepository(
@@ -82,7 +103,7 @@ class SceneTestUtils(
} }
fun authenticationRepository(): AuthenticationRepository { fun authenticationRepository(): AuthenticationRepository {
return AuthenticationRepositoryImpl() return authenticationRepository
} }
fun authenticationInteractor( fun authenticationInteractor(
@@ -94,17 +115,6 @@ class SceneTestUtils(
) )
} }
private fun applicationScope(): CoroutineScope {
return checkNotNull(testScope) {
"""
TestScope not initialized, please create a TestScope and inject it into
SceneTestUtils.
"""
.trimIndent()
}
.backgroundScope
}
fun bouncerInteractor( fun bouncerInteractor(
authenticationInteractor: AuthenticationInteractor, authenticationInteractor: AuthenticationInteractor,
sceneInteractor: SceneInteractor, sceneInteractor: SceneInteractor,
@@ -154,6 +164,10 @@ class SceneTestUtils(
) )
} }
private fun applicationScope(): CoroutineScope {
return testScope.backgroundScope
}
companion object { companion object {
const val CONTAINER_1 = "container1" const val CONTAINER_1 = "container1"
const val CONTAINER_2 = "container2" const val CONTAINER_2 = "container2"