Merge "[flexiglass] Hooks up real app state and logic in keyguard (1)" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
848b73fe14
@@ -16,8 +16,11 @@
|
||||
|
||||
package com.android.systemui.authentication
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryModule
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import java.util.function.Function
|
||||
|
||||
@Module(
|
||||
includes =
|
||||
@@ -25,4 +28,12 @@ import dagger.Module
|
||||
AuthenticationRepositoryModule::class,
|
||||
],
|
||||
)
|
||||
object AuthenticationModule
|
||||
object AuthenticationModule {
|
||||
|
||||
@Provides
|
||||
fun getSecurityMode(
|
||||
model: KeyguardSecurityModel,
|
||||
): Function<Int, KeyguardSecurityModel.SecurityMode> {
|
||||
return Function { userId -> model.getSecurityMode(userId) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,20 @@
|
||||
|
||||
package com.android.systemui.authentication.data.repository
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.user.data.repository.UserRepository
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.function.Function
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Defines interface for classes that can access authentication-related application state. */
|
||||
interface AuthenticationRepository {
|
||||
@@ -37,12 +44,6 @@ interface AuthenticationRepository {
|
||||
*/
|
||||
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
|
||||
* dismisses once the authentication challenge is completed. For example, completing a biometric
|
||||
@@ -57,12 +58,15 @@ interface AuthenticationRepository {
|
||||
*/
|
||||
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]. */
|
||||
fun setUnlocked(isUnlocked: Boolean)
|
||||
|
||||
/** See [authenticationMethod]. */
|
||||
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel)
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun setBypassEnabled(isBypassEnabled: Boolean)
|
||||
|
||||
@@ -70,19 +74,18 @@ interface AuthenticationRepository {
|
||||
fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
|
||||
}
|
||||
|
||||
class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationRepository {
|
||||
// TODO(b/280883900): get data from real data sources in SysUI.
|
||||
class AuthenticationRepositoryImpl
|
||||
@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)
|
||||
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)
|
||||
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
|
||||
|
||||
@@ -90,6 +93,41 @@ class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationReposit
|
||||
override val failedAuthenticationAttempts: StateFlow<Int> =
|
||||
_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) {
|
||||
_isUnlocked.value = isUnlocked
|
||||
}
|
||||
@@ -98,10 +136,6 @@ class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationReposit
|
||||
_isBypassEnabled.value = isBypassEnabled
|
||||
}
|
||||
|
||||
override fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
|
||||
_authenticationMethod.value = authenticationMethod
|
||||
}
|
||||
|
||||
override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
|
||||
_failedAuthenticationAttempts.value = failedAuthenticationAttempts
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Hosts application business logic related to authentication. */
|
||||
@SysUISingleton
|
||||
@@ -37,12 +36,6 @@ constructor(
|
||||
@Application applicationScope: CoroutineScope,
|
||||
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.
|
||||
*
|
||||
@@ -52,20 +45,18 @@ constructor(
|
||||
* Note that this state has no real bearing on whether the lock screen is showing or dismissed.
|
||||
*/
|
||||
val isUnlocked: StateFlow<Boolean> =
|
||||
combine(authenticationMethod, repository.isUnlocked) { authMethod, isUnlocked ->
|
||||
isUnlockedWithAuthMethod(
|
||||
isUnlocked = isUnlocked,
|
||||
authMethod = authMethod,
|
||||
)
|
||||
repository.isUnlocked
|
||||
.map { isUnlocked ->
|
||||
if (getAuthenticationMethod() is AuthenticationMethodModel.None) {
|
||||
true
|
||||
} else {
|
||||
isUnlocked
|
||||
}
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue =
|
||||
isUnlockedWithAuthMethod(
|
||||
isUnlocked = repository.isUnlocked.value,
|
||||
authMethod = repository.authenticationMethod.value,
|
||||
)
|
||||
initialValue = true,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -82,25 +73,20 @@ constructor(
|
||||
*/
|
||||
val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts
|
||||
|
||||
init {
|
||||
// UNLOCKS WHEN AUTH METHOD REMOVED.
|
||||
//
|
||||
// Unlocks the device if the auth method becomes None.
|
||||
applicationScope.launch {
|
||||
repository.authenticationMethod.collect {
|
||||
if (it is AuthenticationMethodModel.None) {
|
||||
unlockDevice()
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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 repository.getAuthenticationMethod()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the device currently requires authentication before content can be viewed;
|
||||
* `false` if content can be displayed without unlocking first.
|
||||
*/
|
||||
fun isAuthenticationRequired(): Boolean {
|
||||
return !isUnlocked.value && authenticationMethod.value.isSecure
|
||||
suspend fun isAuthenticationRequired(): Boolean {
|
||||
return !isUnlocked.value && getAuthenticationMethod().isSecure
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,8 +119,8 @@ constructor(
|
||||
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
|
||||
* authentication failed, `null` if the check was not performed.
|
||||
*/
|
||||
fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
|
||||
val authMethod = this.authenticationMethod.value
|
||||
suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
|
||||
val authMethod = getAuthenticationMethod()
|
||||
if (tryAutoConfirm) {
|
||||
if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
|
||||
// Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
|
||||
@@ -176,28 +162,12 @@ constructor(
|
||||
repository.setUnlocked(true)
|
||||
}
|
||||
|
||||
/** See [authenticationMethod]. */
|
||||
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
|
||||
repository.setAuthenticationMethod(authenticationMethod)
|
||||
}
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun toggleBypassEnabled() {
|
||||
repository.setBypassEnabled(!repository.isBypassEnabled.value)
|
||||
}
|
||||
|
||||
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
|
||||
* [Int] in the range [0-9].
|
||||
|
||||
@@ -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. */
|
||||
val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
|
||||
|
||||
init {
|
||||
applicationScope.launch {
|
||||
combine(
|
||||
sceneInteractor.currentScene(containerName),
|
||||
authenticationInteractor.authenticationMethod,
|
||||
::Pair,
|
||||
)
|
||||
.collect { (currentScene, authMethod) ->
|
||||
if (currentScene.key == SceneKey.Bouncer) {
|
||||
when (authMethod) {
|
||||
is AuthenticationMethodModel.None ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Gone),
|
||||
)
|
||||
is AuthenticationMethodModel.Swipe ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Lockscreen),
|
||||
)
|
||||
else -> Unit
|
||||
}
|
||||
sceneInteractor.currentScene(containerName).collect { currentScene ->
|
||||
if (currentScene.key == SceneKey.Bouncer) {
|
||||
when (getAuthenticationMethod()) {
|
||||
is AuthenticationMethodModel.None ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Gone),
|
||||
)
|
||||
is AuthenticationMethodModel.Swipe ->
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName,
|
||||
SceneModel(SceneKey.Lockscreen),
|
||||
)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -115,18 +111,20 @@ constructor(
|
||||
containerName: String,
|
||||
message: String? = null,
|
||||
) {
|
||||
if (authenticationInteractor.isAuthenticationRequired()) {
|
||||
repository.setMessage(message ?: promptMessage(authenticationMethod.value))
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Bouncer),
|
||||
)
|
||||
} else {
|
||||
authenticationInteractor.unlockDevice()
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Gone),
|
||||
)
|
||||
applicationScope.launch {
|
||||
if (authenticationInteractor.isAuthenticationRequired()) {
|
||||
repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Bouncer),
|
||||
)
|
||||
} else {
|
||||
authenticationInteractor.unlockDevice()
|
||||
sceneInteractor.setCurrentScene(
|
||||
containerName = containerName,
|
||||
scene = SceneModel(SceneKey.Gone),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +133,7 @@ constructor(
|
||||
* method.
|
||||
*/
|
||||
fun resetMessage() {
|
||||
repository.setMessage(promptMessage(authenticationMethod.value))
|
||||
applicationScope.launch { repository.setMessage(promptMessage(getAuthenticationMethod())) }
|
||||
}
|
||||
|
||||
/** Removes the user-facing message. */
|
||||
@@ -160,7 +158,7 @@ constructor(
|
||||
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
|
||||
* authentication failed, `null` if the check was not performed.
|
||||
*/
|
||||
fun authenticate(
|
||||
suspend fun authenticate(
|
||||
input: List<Any>,
|
||||
tryAutoConfirm: Boolean = false,
|
||||
): Boolean? {
|
||||
@@ -198,7 +196,7 @@ constructor(
|
||||
repository.setThrottling(null)
|
||||
clearMessage()
|
||||
}
|
||||
else -> repository.setMessage(errorMessage(authenticationMethod.value))
|
||||
else -> repository.setMessage(errorMessage(getAuthenticationMethod()))
|
||||
}
|
||||
|
||||
return isAuthenticated
|
||||
|
||||
@@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -66,6 +67,7 @@ constructor(
|
||||
|
||||
private val password: PasswordBouncerViewModel by lazy {
|
||||
PasswordBouncerViewModel(
|
||||
applicationScope = applicationScope,
|
||||
interactor = interactor,
|
||||
isInputEnabled = isInputEnabled,
|
||||
)
|
||||
@@ -81,14 +83,25 @@ constructor(
|
||||
}
|
||||
|
||||
/** View-model for the current UI, based on the current authentication method. */
|
||||
val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
|
||||
interactor.authenticationMethod
|
||||
.map { authMethod -> toViewModel(authMethod) }
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = toViewModel(interactor.authenticationMethod.value),
|
||||
)
|
||||
val authMethod: StateFlow<AuthMethodBouncerViewModel?>
|
||||
get() =
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
.map { authMethod ->
|
||||
when (authMethod) {
|
||||
is AuthenticationMethodModel.Pin -> pin
|
||||
is AuthenticationMethodModel.Password -> password
|
||||
is AuthenticationMethodModel.Pattern -> pattern
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
/** The user-facing message to show in the bouncer. */
|
||||
val message: StateFlow<MessageViewModel> =
|
||||
@@ -125,7 +138,7 @@ constructor(
|
||||
interactor.throttling
|
||||
.map { model ->
|
||||
model?.let {
|
||||
when (interactor.authenticationMethod.value) {
|
||||
when (interactor.getAuthenticationMethod()) {
|
||||
is AuthenticationMethodModel.Pin ->
|
||||
R.string.kg_too_many_failed_pin_attempts_dialog_message
|
||||
is AuthenticationMethodModel.Password ->
|
||||
@@ -161,17 +174,6 @@ constructor(
|
||||
_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(
|
||||
message: String?,
|
||||
throttling: AuthenticationThrottledModel?,
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
package com.android.systemui.bouncer.ui.viewmodel
|
||||
|
||||
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Holds UI state and handles user input for the password bouncer UI. */
|
||||
class PasswordBouncerViewModel(
|
||||
private val applicationScope: CoroutineScope,
|
||||
private val interactor: BouncerInteractor,
|
||||
isInputEnabled: StateFlow<Boolean>,
|
||||
) :
|
||||
@@ -50,10 +53,13 @@ class PasswordBouncerViewModel(
|
||||
|
||||
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
|
||||
fun onAuthenticateKeyPressed() {
|
||||
if (interactor.authenticate(password.value.toCharArray().toList()) != true) {
|
||||
showFailureAnimation()
|
||||
}
|
||||
|
||||
val password = _password.value.toCharArray().toList()
|
||||
_password.value = ""
|
||||
|
||||
applicationScope.launch {
|
||||
if (interactor.authenticate(password) != true) {
|
||||
showFailureAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +29,15 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Holds UI state and handles user input for the pattern bouncer UI. */
|
||||
class PatternBouncerViewModel(
|
||||
private val applicationContext: Context,
|
||||
applicationScope: CoroutineScope,
|
||||
private val applicationScope: CoroutineScope,
|
||||
private val interactor: BouncerInteractor,
|
||||
isInputEnabled: StateFlow<Boolean>,
|
||||
) :
|
||||
@@ -69,12 +71,17 @@ class PatternBouncerViewModel(
|
||||
|
||||
/** Whether the pattern itself should be rendered visibly. */
|
||||
val isPatternVisible: StateFlow<Boolean> =
|
||||
interactor.authenticationMethod
|
||||
.map { authMethod -> isPatternVisible(authMethod) }
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
.map { authMethod ->
|
||||
(authMethod as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = isPatternVisible(interactor.authenticationMethod.value),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
/** 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. */
|
||||
fun onDragEnd() {
|
||||
val pattern = _selectedDots.value.map { it.toCoordinate() }
|
||||
if (interactor.authenticate(pattern) != true) {
|
||||
showFailureAnimation()
|
||||
}
|
||||
|
||||
_dots.value = defaultDots()
|
||||
_currentDot.value = null
|
||||
_selectedDots.value = linkedSetOf()
|
||||
}
|
||||
|
||||
private fun isPatternVisible(authMethodModel: AuthenticationMethodModel): Boolean {
|
||||
return (authMethodModel as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
|
||||
applicationScope.launch {
|
||||
if (interactor.authenticate(pattern) != true) {
|
||||
showFailureAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun defaultDots(): List<PatternDotViewModel> {
|
||||
|
||||
@@ -22,13 +22,14 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Holds UI state and handles user input for the PIN code bouncer UI. */
|
||||
class PinBouncerViewModel(
|
||||
applicationScope: CoroutineScope,
|
||||
private val applicationScope: CoroutineScope,
|
||||
private val interactor: BouncerInteractor,
|
||||
isInputEnabled: StateFlow<Boolean>,
|
||||
) :
|
||||
@@ -39,40 +40,48 @@ class PinBouncerViewModel(
|
||||
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
|
||||
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?> =
|
||||
interactor.authenticationMethod
|
||||
.map { authMethod -> computeHintedPinLength(authMethod) }
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = computeHintedPinLength(interactor.authenticationMethod.value),
|
||||
)
|
||||
|
||||
/** Appearance of the backspace button. */
|
||||
val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
|
||||
combine(interactor.authenticationMethod, mutablePinEntries) { authMethod, enteredPin ->
|
||||
computeBackspaceButtonAppearance(authMethod, enteredPin)
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
.map { authMethod ->
|
||||
// Hinting is enabled for 6-digit codes only
|
||||
autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue =
|
||||
computeBackspaceButtonAppearance(
|
||||
interactor.authenticationMethod.value,
|
||||
mutablePinEntries.value
|
||||
),
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
/** 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. */
|
||||
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
|
||||
interactor.authenticationMethod
|
||||
flow {
|
||||
emit(null)
|
||||
emit(interactor.getAuthenticationMethod())
|
||||
}
|
||||
.map { authMethod -> computeConfirmButtonAppearance(authMethod) }
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue =
|
||||
computeConfirmButtonAppearance(interactor.authenticationMethod.value),
|
||||
initialValue = ActionButtonAppearance.Hidden,
|
||||
)
|
||||
|
||||
/** Notifies that the UI has been shown to the user. */
|
||||
@@ -111,30 +120,28 @@ class PinBouncerViewModel(
|
||||
|
||||
private fun tryAuthenticate(useAutoConfirm: Boolean) {
|
||||
val pinCode = mutablePinEntries.value.map { it.input }
|
||||
val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return
|
||||
|
||||
if (!isSuccess) {
|
||||
showFailureAnimation()
|
||||
applicationScope.launch {
|
||||
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
|
||||
}
|
||||
|
||||
private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel): Int? {
|
||||
private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel?): Int? {
|
||||
if (!isAutoConfirmEnabled(authMethodModel)) return null
|
||||
|
||||
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(
|
||||
authMethodModel: AuthenticationMethodModel,
|
||||
enteredPin: List<EnteredKey>
|
||||
@@ -149,7 +156,7 @@ class PinBouncerViewModel(
|
||||
}
|
||||
}
|
||||
private fun computeConfirmButtonAppearance(
|
||||
authMethodModel: AuthenticationMethodModel
|
||||
authMethodModel: AuthenticationMethodModel?
|
||||
): ActionButtonAppearance {
|
||||
return if (isAutoConfirmEnabled(authMethodModel)) {
|
||||
ActionButtonAppearance.Hidden
|
||||
|
||||
@@ -61,23 +61,16 @@ constructor(
|
||||
|
||||
/** Whether it's currently possible to swipe up to dismiss the lockscreen. */
|
||||
val isSwipeToDismissEnabled: StateFlow<Boolean> =
|
||||
combine(
|
||||
authenticationInteractor.isUnlocked,
|
||||
authenticationInteractor.authenticationMethod,
|
||||
) { isUnlocked, authMethod ->
|
||||
isSwipeToUnlockEnabled(
|
||||
isUnlocked = isUnlocked,
|
||||
authMethod = authMethod,
|
||||
)
|
||||
authenticationInteractor.isUnlocked
|
||||
.map { isUnlocked ->
|
||||
!isUnlocked &&
|
||||
authenticationInteractor.getAuthenticationMethod() is
|
||||
AuthenticationMethodModel.Swipe
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue =
|
||||
isSwipeToUnlockEnabled(
|
||||
isUnlocked = authenticationInteractor.isUnlocked.value,
|
||||
authMethod = authenticationInteractor.authenticationMethod.value,
|
||||
),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
init {
|
||||
@@ -124,44 +117,17 @@ constructor(
|
||||
// If switched from the lockscreen to the gone scene and the auth method was a swipe,
|
||||
// unlocks the device.
|
||||
applicationScope.launch {
|
||||
combine(
|
||||
authenticationInteractor.authenticationMethod,
|
||||
sceneInteractor.currentScene(containerName).pairwise(),
|
||||
::Pair,
|
||||
)
|
||||
.collect { (authMethod, scenes) ->
|
||||
val (previousScene, currentScene) = scenes
|
||||
if (
|
||||
authMethod is AuthenticationMethodModel.Swipe &&
|
||||
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),
|
||||
)
|
||||
}
|
||||
sceneInteractor.currentScene(containerName).pairwise().collect {
|
||||
(previousScene, currentScene) ->
|
||||
if (
|
||||
authenticationInteractor.getAuthenticationMethod() is
|
||||
AuthenticationMethodModel.Swipe &&
|
||||
previousScene.key == SceneKey.Lockscreen &&
|
||||
currentScene.key == SceneKey.Gone
|
||||
) {
|
||||
authenticationInteractor.unlockDevice()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,13 +136,6 @@ constructor(
|
||||
bouncerInteractor.showOrUnlockDevice(containerName = containerName)
|
||||
}
|
||||
|
||||
private fun isSwipeToUnlockEnabled(
|
||||
isUnlocked: Boolean,
|
||||
authMethod: AuthenticationMethodModel,
|
||||
): Boolean {
|
||||
return !isUnlocked && authMethod is AuthenticationMethodModel.Swipe
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.scene.SceneTestUtils
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -37,8 +36,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val repository: AuthenticationRepository = utils.authenticationRepository()
|
||||
private val underTest =
|
||||
utils.authenticationInteractor(
|
||||
@@ -46,23 +45,23 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
|
||||
@Test
|
||||
fun authMethod() =
|
||||
fun getAuthenticationMethod() =
|
||||
testScope.runTest {
|
||||
val authMethod by collectLastValue(underTest.authenticationMethod)
|
||||
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234))
|
||||
assertThat(underTest.getAuthenticationMethod())
|
||||
.isEqualTo(AuthenticationMethodModel.Pin(1234))
|
||||
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(underTest.getAuthenticationMethod())
|
||||
.isEqualTo(AuthenticationMethodModel.Password("password"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isUnlocked_whenAuthMethodIsNone_isTrue() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.None)
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@@ -108,7 +107,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
underTest.lockDevice()
|
||||
runCurrent()
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isTrue()
|
||||
}
|
||||
@@ -118,7 +119,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
underTest.lockDevice()
|
||||
runCurrent()
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -128,7 +129,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
underTest.unlockDevice()
|
||||
runCurrent()
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -138,7 +141,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
underTest.unlockDevice()
|
||||
runCurrent()
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -148,7 +151,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
|
||||
@@ -161,7 +166,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
|
||||
@@ -174,7 +181,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf())).isFalse()
|
||||
@@ -187,7 +196,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(9999999999999999)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
|
||||
@@ -206,7 +217,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(99999999999999999)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
|
||||
@@ -219,7 +232,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("password".toList())).isTrue()
|
||||
@@ -232,7 +247,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
|
||||
@@ -245,7 +262,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(
|
||||
listOf(
|
||||
AuthenticationMethodModel.Pattern.PatternCoordinate(
|
||||
@@ -293,7 +310,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(
|
||||
listOf(
|
||||
AuthenticationMethodModel.Pattern.PatternCoordinate(
|
||||
@@ -341,7 +358,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -356,7 +373,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -371,7 +388,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -386,7 +403,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -402,7 +419,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -417,7 +434,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -432,22 +449,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -40,8 +39,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class BouncerInteractorTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
repository = utils.authenticationRepository(),
|
||||
@@ -69,7 +68,9 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
@@ -100,7 +101,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -130,7 +131,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -154,7 +155,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -186,7 +187,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(emptyList())
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -222,7 +223,9 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -235,7 +238,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
underTest.showOrUnlockDevice("container1")
|
||||
@@ -248,7 +251,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
|
||||
val message by collectLastValue(underTest.message)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -266,7 +269,9 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
val throttling by collectLastValue(underTest.throttling)
|
||||
val message by collectLastValue(underTest.message)
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(throttling).isNull()
|
||||
assertThat(message).isEqualTo("")
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.android.systemui.scene.SceneTestUtils
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -35,8 +34,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class AuthMethodBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
utils.authenticationRepository(),
|
||||
@@ -55,7 +54,9 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun animateFailure() =
|
||||
testScope.runTest {
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
val animateFailure by collectLastValue(underTest.animateFailure)
|
||||
assertThat(animateFailure).isFalse()
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -38,8 +37,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class BouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
repository = utils.authenticationRepository(),
|
||||
@@ -54,11 +53,11 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
|
||||
testScope.runTest {
|
||||
val authMethodViewModel: AuthMethodBouncerViewModel? by
|
||||
collectLastValue(underTest.authMethod)
|
||||
authMethodsToTest().forEach { authMethod ->
|
||||
authenticationInteractor.setAuthenticationMethod(authMethod)
|
||||
utils.authenticationRepository.setAuthenticationMethod(authMethod)
|
||||
|
||||
val authMethodViewModel: AuthMethodBouncerViewModel? by
|
||||
collectLastValue(underTest.authMethod)
|
||||
if (authMethod.isSecure) {
|
||||
assertThat(authMethodViewModel).isNotNull()
|
||||
} else {
|
||||
@@ -75,13 +74,13 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
collectLastValue(underTest.authMethod)
|
||||
// First pass, populate our "seen" map:
|
||||
authMethodsToTest().forEach { authMethod ->
|
||||
authenticationInteractor.setAuthenticationMethod(authMethod)
|
||||
utils.authenticationRepository.setAuthenticationMethod(authMethod)
|
||||
authMethodViewModel?.let { seen[authMethod] = it }
|
||||
}
|
||||
|
||||
// Second pass, assert same instances are reused:
|
||||
authMethodsToTest().forEach { authMethod ->
|
||||
authenticationInteractor.setAuthenticationMethod(authMethod)
|
||||
utils.authenticationRepository.setAuthenticationMethod(authMethod)
|
||||
authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) }
|
||||
}
|
||||
}
|
||||
@@ -97,7 +96,9 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val message by collectLastValue(underTest.message)
|
||||
val throttling by collectLastValue(bouncerInteractor.throttling)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(message?.isUpdateAnimated).isTrue()
|
||||
|
||||
repeat(BouncerInteractor.THROTTLE_EVERY) {
|
||||
@@ -120,7 +121,9 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
)
|
||||
val throttling by collectLastValue(bouncerInteractor.throttling)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isInputEnabled).isTrue()
|
||||
|
||||
repeat(BouncerInteractor.THROTTLE_EVERY) {
|
||||
@@ -137,7 +140,9 @@ class BouncerViewModelTest : SysuiTestCase() {
|
||||
fun throttlingDialogMessage() =
|
||||
testScope.runTest {
|
||||
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
|
||||
repeat(BouncerInteractor.THROTTLE_EVERY) {
|
||||
// Wrong PIN.
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -40,8 +40,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
repository = utils.authenticationRepository(),
|
||||
@@ -58,6 +58,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
)
|
||||
private val underTest =
|
||||
PasswordBouncerViewModel(
|
||||
applicationScope = testScope.backgroundScope,
|
||||
interactor = bouncerInteractor,
|
||||
isInputEnabled = MutableStateFlow(true).asStateFlow(),
|
||||
)
|
||||
@@ -75,7 +76,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -98,7 +99,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -106,6 +107,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
|
||||
underTest.onPasswordInputChanged("password")
|
||||
|
||||
@@ -120,7 +122,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -143,7 +145,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -168,7 +170,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val password by collectLastValue(underTest.password)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.google.common.truth.Truth.assertWithMessage
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -41,8 +41,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
repository = utils.authenticationRepository(),
|
||||
@@ -79,7 +79,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -104,7 +104,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -112,6 +112,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
|
||||
underTest.onDragStart()
|
||||
|
||||
@@ -129,7 +130,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -180,7 +181,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -215,7 +216,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val selectedDots by collectLastValue(underTest.selectedDots)
|
||||
val currentDot by collectLastValue(underTest.currentDot)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -41,8 +41,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
@@ -85,7 +85,6 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -106,12 +105,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
|
||||
underTest.onPinButtonClicked(1)
|
||||
|
||||
@@ -129,12 +131,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
underTest.onPinButtonClicked(1)
|
||||
assertThat(entries).hasSize(1)
|
||||
|
||||
@@ -153,7 +158,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -180,12 +187,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
|
||||
underTest.onShown()
|
||||
runCurrent()
|
||||
underTest.onPinButtonClicked(1)
|
||||
underTest.onPinButtonClicked(2)
|
||||
underTest.onPinButtonClicked(3)
|
||||
@@ -204,7 +214,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -228,7 +240,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -255,7 +269,9 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
@@ -290,7 +306,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -314,7 +330,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
|
||||
val message by collectLastValue(bouncerViewModel.message)
|
||||
val entries by collectLastValue(underTest.pinEntries)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -338,7 +354,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
|
||||
@@ -349,7 +365,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
|
||||
testScope.runTest {
|
||||
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
|
||||
@@ -360,7 +376,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
|
||||
testScope.runTest {
|
||||
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
|
||||
@@ -374,7 +390,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
|
||||
@@ -385,7 +401,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun confirmButtonAppearance_withAutoConfirm_isHidden() =
|
||||
testScope.runTest {
|
||||
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
|
||||
)
|
||||
|
||||
@@ -396,7 +412,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withoutAutoConfirm_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
|
||||
)
|
||||
|
||||
@@ -407,7 +423,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(12345, autoConfirm = true)
|
||||
)
|
||||
|
||||
@@ -418,7 +434,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(123456, autoConfirm = true)
|
||||
)
|
||||
|
||||
@@ -429,7 +445,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
|
||||
)
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -38,8 +37,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
@@ -74,7 +73,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
|
||||
|
||||
authenticationInteractor.lockDevice()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(isSwipeToDismissEnabled).isTrue()
|
||||
}
|
||||
@@ -85,7 +84,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
|
||||
|
||||
authenticationInteractor.unlockDevice()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
|
||||
assertThat(isSwipeToDismissEnabled).isFalse()
|
||||
}
|
||||
@@ -95,7 +94,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
underTest.dismissLockscreen()
|
||||
@@ -108,7 +109,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.unlockDevice()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
underTest.dismissLockscreen()
|
||||
@@ -121,7 +124,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.lockDevice()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
|
||||
|
||||
underTest.dismissLockscreen()
|
||||
@@ -182,7 +185,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
|
||||
@@ -195,7 +198,9 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
|
||||
@@ -210,7 +215,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
runCurrent()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade))
|
||||
runCurrent()
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
runCurrent()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
@@ -219,30 +224,17 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
|
||||
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
|
||||
fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
runCurrent()
|
||||
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings))
|
||||
runCurrent()
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
|
||||
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
|
||||
|
||||
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -41,8 +40,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
@@ -73,7 +72,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun lockButtonIcon_whenLocked() =
|
||||
testScope.runTest {
|
||||
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
@@ -86,7 +85,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun lockButtonIcon_whenUnlocked() =
|
||||
testScope.runTest {
|
||||
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
|
||||
authenticationInteractor.setAuthenticationMethod(
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Password("password")
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
@@ -99,7 +98,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
|
||||
@@ -109,7 +108,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
|
||||
@@ -119,7 +120,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -132,7 +135,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceUnlocked_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -145,7 +150,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -158,7 +165,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -39,8 +38,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class QuickSettingsSceneViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
@@ -70,7 +69,9 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceUnlocked_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -83,7 +84,9 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
runCurrent()
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -39,8 +38,8 @@ import org.junit.runners.JUnit4
|
||||
@RunWith(JUnit4::class)
|
||||
class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val utils = SceneTestUtils(this, testScope)
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val authenticationInteractor =
|
||||
utils.authenticationInteractor(
|
||||
@@ -71,7 +70,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
fun upTransitionSceneKey_deviceLocked_lockScreen() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
|
||||
@@ -81,7 +82,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
fun upTransitionSceneKey_deviceUnlocked_gone() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
|
||||
@@ -91,7 +94,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceUnlocked_switchesToGone() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.unlockDevice()
|
||||
runCurrent()
|
||||
|
||||
@@ -104,7 +109,9 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
|
||||
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
|
||||
testScope.runTest {
|
||||
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
|
||||
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
AuthenticationMethodModel.Pin(1234)
|
||||
)
|
||||
authenticationInteractor.lockDevice()
|
||||
runCurrent()
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package com.android.systemui.scene
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.authentication.data.repository.AuthenticationRepository
|
||||
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.bouncer.data.repository.BouncerRepository
|
||||
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.shared.model.SceneContainerConfig
|
||||
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.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
||||
/**
|
||||
@@ -39,9 +46,23 @@ import kotlinx.coroutines.test.TestScope
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class SceneTestUtils(
|
||||
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
|
||||
|
||||
fun fakeSceneContainerRepository(
|
||||
@@ -82,7 +103,7 @@ class SceneTestUtils(
|
||||
}
|
||||
|
||||
fun authenticationRepository(): AuthenticationRepository {
|
||||
return AuthenticationRepositoryImpl()
|
||||
return authenticationRepository
|
||||
}
|
||||
|
||||
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(
|
||||
authenticationInteractor: AuthenticationInteractor,
|
||||
sceneInteractor: SceneInteractor,
|
||||
@@ -154,6 +164,10 @@ class SceneTestUtils(
|
||||
)
|
||||
}
|
||||
|
||||
private fun applicationScope(): CoroutineScope {
|
||||
return testScope.backgroundScope
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CONTAINER_1 = "container1"
|
||||
const val CONTAINER_2 = "container2"
|
||||
|
||||
Reference in New Issue
Block a user