[flexiglass] Add a "canSwipeToDismissState" state.
This tracks whether it's currently possible to swipe up to dismiss the lockscreen without requiring authentication. Bonus: Fixes a bug in the `isUnlocked` state definition. Fix: 294982161 Fix: 294984006 Test: new unit tests added, and existing ones modified. Change-Id: I1fa9d4ca97da737a1bcf386bd27ec3340aed1871
This commit is contained in:
@@ -27,6 +27,8 @@ import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
||||
import com.android.systemui.scene.domain.interactor.SceneInteractor
|
||||
import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.user.data.repository.UserRepository
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import javax.inject.Inject
|
||||
@@ -42,6 +44,7 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -57,6 +60,7 @@ constructor(
|
||||
@Background private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val userRepository: UserRepository,
|
||||
private val keyguardRepository: KeyguardRepository,
|
||||
sceneInteractor: SceneInteractor,
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
/**
|
||||
@@ -93,7 +97,7 @@ constructor(
|
||||
repository.isUnlocked,
|
||||
authenticationMethod,
|
||||
) { isUnlocked, authenticationMethod ->
|
||||
authenticationMethod is DomainLayerAuthenticationMethodModel.None || isUnlocked
|
||||
!authenticationMethod.isSecure || isUnlocked
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
@@ -101,6 +105,44 @@ constructor(
|
||||
initialValue = true,
|
||||
)
|
||||
|
||||
/**
|
||||
* Whether the lockscreen has been dismissed (by any method). This can be false even when the
|
||||
* device is unlocked, e.g. when swipe to unlock is enabled.
|
||||
*
|
||||
* Note:
|
||||
* - `false` doesn't mean the lockscreen is visible (it may be occluded or covered by other UI).
|
||||
* - `true` doesn't mean the lockscreen is invisible (since this state changes before the
|
||||
* transition occurs).
|
||||
*/
|
||||
private val isLockscreenDismissed =
|
||||
sceneInteractor.desiredScene
|
||||
.map { it.key }
|
||||
.filter { currentScene ->
|
||||
currentScene == SceneKey.Gone || currentScene == SceneKey.Lockscreen
|
||||
}
|
||||
.map { it == SceneKey.Gone }
|
||||
.distinctUntilChanged()
|
||||
|
||||
/**
|
||||
* Whether it's currently possible to swipe up to dismiss the lockscreen without requiring
|
||||
* authentication. This returns false whenever the lockscreen has been dismissed.
|
||||
*
|
||||
* Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other
|
||||
* UI.
|
||||
*/
|
||||
val canSwipeToDismiss =
|
||||
combine(authenticationMethod, isLockscreenDismissed) {
|
||||
authenticationMethod,
|
||||
isLockscreenDismissed ->
|
||||
authenticationMethod is DomainLayerAuthenticationMethodModel.Swipe &&
|
||||
!isLockscreenDismissed
|
||||
}
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
/** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
|
||||
val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
|
||||
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
|
||||
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
@@ -27,7 +26,6 @@ import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.scene.shared.model.SceneKey
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -53,14 +51,15 @@ constructor(
|
||||
)
|
||||
|
||||
/** The key of the scene we should switch to when swiping up. */
|
||||
val upDestinationSceneKey: Flow<SceneKey> =
|
||||
authenticationInteractor.authenticationMethod.map { authenticationMethod ->
|
||||
if (authenticationMethod is AuthenticationMethodModel.Swipe) {
|
||||
SceneKey.Gone
|
||||
} else {
|
||||
SceneKey.Bouncer
|
||||
}
|
||||
}
|
||||
val upDestinationSceneKey =
|
||||
authenticationInteractor.canSwipeToDismiss
|
||||
.map { canSwipeToDismiss -> upDestinationSceneKey(canSwipeToDismiss) }
|
||||
.stateIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue =
|
||||
upDestinationSceneKey(authenticationInteractor.canSwipeToDismiss.value),
|
||||
)
|
||||
|
||||
/** Notifies that the lock button on the lock screen was clicked. */
|
||||
fun onLockButtonClicked() {
|
||||
@@ -73,30 +72,24 @@ constructor(
|
||||
}
|
||||
|
||||
private fun upDestinationSceneKey(
|
||||
isSwipeToUnlockEnabled: Boolean,
|
||||
canSwipeToDismiss: Boolean,
|
||||
): SceneKey {
|
||||
return if (isSwipeToUnlockEnabled) SceneKey.Gone else SceneKey.Bouncer
|
||||
return if (canSwipeToDismiss) SceneKey.Gone else SceneKey.Bouncer
|
||||
}
|
||||
|
||||
private fun lockIcon(
|
||||
isUnlocked: Boolean,
|
||||
): Icon {
|
||||
return Icon.Resource(
|
||||
res =
|
||||
if (isUnlocked) {
|
||||
R.drawable.ic_device_lock_off
|
||||
} else {
|
||||
R.drawable.ic_device_lock_on
|
||||
},
|
||||
contentDescription =
|
||||
ContentDescription.Resource(
|
||||
res =
|
||||
if (isUnlocked) {
|
||||
R.string.accessibility_unlock_button
|
||||
} else {
|
||||
R.string.accessibility_lock_icon
|
||||
}
|
||||
)
|
||||
)
|
||||
return if (isUnlocked) {
|
||||
Icon.Resource(
|
||||
R.drawable.ic_device_lock_off,
|
||||
ContentDescription.Resource(R.string.accessibility_unlock_button)
|
||||
)
|
||||
} else {
|
||||
Icon.Resource(
|
||||
R.drawable.ic_device_lock_on,
|
||||
ContentDescription.Resource(R.string.accessibility_lock_icon)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.android.systemui.authentication.shared.model.AuthenticationPatternCoo
|
||||
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.scene.SceneTestUtils
|
||||
import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -46,9 +48,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
private val utils = SceneTestUtils(this)
|
||||
private val testScope = utils.testScope
|
||||
private val repository: AuthenticationRepository = utils.authenticationRepository()
|
||||
private val sceneInteractor = utils.sceneInteractor()
|
||||
private val underTest =
|
||||
utils.authenticationInteractor(
|
||||
repository = repository,
|
||||
sceneInteractor = sceneInteractor,
|
||||
)
|
||||
|
||||
@Test
|
||||
@@ -75,10 +79,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
val authMethod by collectLastValue(underTest.authenticationMethod)
|
||||
runCurrent()
|
||||
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.setLockscreenEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(true)
|
||||
}
|
||||
|
||||
assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.Swipe)
|
||||
assertThat(underTest.getAuthenticationMethod())
|
||||
@@ -91,10 +95,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
val authMethod by collectLastValue(underTest.authenticationMethod)
|
||||
runCurrent()
|
||||
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.setLockscreenEnabled(false)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(false)
|
||||
}
|
||||
|
||||
assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.None)
|
||||
assertThat(underTest.getAuthenticationMethod())
|
||||
@@ -104,51 +108,87 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.setLockscreenEnabled(false)
|
||||
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
// Toggle isUnlocked, twice.
|
||||
//
|
||||
// This is done because the underTest.isUnlocked flow doesn't receive values from
|
||||
// just changing the state above; the actual isUnlocked state needs to change to
|
||||
// cause the logic under test to "pick up" the current state again.
|
||||
//
|
||||
// It is done twice to make sure that we don't actually change the isUnlocked
|
||||
// state from what it originally was.
|
||||
utils.authenticationRepository.setUnlocked(
|
||||
!utils.authenticationRepository.isUnlocked.value
|
||||
)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setUnlocked(
|
||||
!utils.authenticationRepository.isUnlocked.value
|
||||
)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(false)
|
||||
// Toggle isUnlocked, twice.
|
||||
//
|
||||
// This is done because the underTest.isUnlocked flow doesn't receive values from
|
||||
// just changing the state above; the actual isUnlocked state needs to change to
|
||||
// cause the logic under test to "pick up" the current state again.
|
||||
//
|
||||
// It is done twice to make sure that we don't actually change the isUnlocked state
|
||||
// from what it originally was.
|
||||
setUnlocked(!utils.authenticationRepository.isUnlocked.value)
|
||||
runCurrent()
|
||||
setUnlocked(!utils.authenticationRepository.isUnlocked.value)
|
||||
runCurrent()
|
||||
}
|
||||
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isFalse() =
|
||||
fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isTrue() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.setLockscreenEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(true)
|
||||
}
|
||||
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canSwipeToDismiss_onLockscreenWithSwipe_isTrue() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(true)
|
||||
}
|
||||
switchToScene(SceneKey.Lockscreen)
|
||||
|
||||
val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
|
||||
assertThat(canSwipeToDismiss).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canSwipeToDismiss_onLockscreenWithPin_isFalse() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setLockscreenEnabled(true)
|
||||
}
|
||||
switchToScene(SceneKey.Lockscreen)
|
||||
|
||||
val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
|
||||
assertThat(canSwipeToDismiss).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canSwipeToDismiss_afterLockscreenDismissedInSwipeMode_isFalse() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
setLockscreenEnabled(true)
|
||||
}
|
||||
switchToScene(SceneKey.Lockscreen)
|
||||
switchToScene(SceneKey.Gone)
|
||||
|
||||
val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
|
||||
assertThat(canSwipeToDismiss).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isAuthenticationRequired_lockedAndSecured_true() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Password
|
||||
)
|
||||
utils.authenticationRepository.apply {
|
||||
setUnlocked(false)
|
||||
runCurrent()
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Password)
|
||||
}
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isTrue()
|
||||
}
|
||||
@@ -156,11 +196,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_lockedAndNotSecured_false() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.apply {
|
||||
setUnlocked(false)
|
||||
runCurrent()
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
}
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -168,11 +208,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_unlockedAndSecured_false() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Password
|
||||
)
|
||||
utils.authenticationRepository.apply {
|
||||
setUnlocked(true)
|
||||
runCurrent()
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Password)
|
||||
}
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -180,11 +220,11 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun isAuthenticationRequired_unlockedAndNotSecured_false() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
runCurrent()
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.None
|
||||
)
|
||||
utils.authenticationRepository.apply {
|
||||
setUnlocked(true)
|
||||
runCurrent()
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
|
||||
}
|
||||
|
||||
assertThat(underTest.isAuthenticationRequired()).isFalse()
|
||||
}
|
||||
@@ -221,11 +261,12 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun authenticate_withCorrectMaxLengthPin_returnsTrue() =
|
||||
testScope.runTest {
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
val pin = List(16) { 9 }
|
||||
utils.authenticationRepository.overrideCredential(pin)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
overrideCredential(pin)
|
||||
}
|
||||
|
||||
assertThat(underTest.authenticate(pin)).isTrue()
|
||||
}
|
||||
|
||||
@@ -308,10 +349,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
|
||||
testScope.runTest {
|
||||
val isThrottled by collectLastValue(underTest.isThrottled)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply {
|
||||
@@ -328,10 +369,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 },
|
||||
@@ -346,10 +387,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
FakeAuthenticationRepository.DEFAULT_PIN + listOf(7),
|
||||
@@ -364,10 +405,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
FakeAuthenticationRepository.DEFAULT_PIN,
|
||||
@@ -382,10 +423,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
|
||||
testScope.runTest {
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(false)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(false)
|
||||
}
|
||||
assertThat(
|
||||
underTest.authenticate(
|
||||
FakeAuthenticationRepository.DEFAULT_PIN,
|
||||
@@ -505,10 +546,10 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withoutAutoConfirm_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(false)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(false)
|
||||
}
|
||||
|
||||
assertThat(hintedPinLength).isNull()
|
||||
}
|
||||
@@ -517,15 +558,15 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinTooShort_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.overrideCredential(
|
||||
buildList {
|
||||
repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
|
||||
}
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
overrideCredential(
|
||||
buildList {
|
||||
repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
|
||||
}
|
||||
)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
|
||||
assertThat(hintedPinLength).isNull()
|
||||
}
|
||||
@@ -534,13 +575,15 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinAtRightLength_isSameLength() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.overrideCredential(
|
||||
buildList { repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) } }
|
||||
)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
setAutoConfirmEnabled(true)
|
||||
overrideCredential(
|
||||
buildList {
|
||||
repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
assertThat(hintedPinLength).isEqualTo(utils.authenticationRepository.hintedPinLength)
|
||||
}
|
||||
@@ -549,16 +592,20 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
fun hintedPinLength_withAutoConfirmPinTooLong_isNull() =
|
||||
testScope.runTest {
|
||||
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
|
||||
utils.authenticationRepository.setAuthenticationMethod(
|
||||
DataLayerAuthenticationMethodModel.Pin
|
||||
)
|
||||
utils.authenticationRepository.overrideCredential(
|
||||
buildList {
|
||||
repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
|
||||
}
|
||||
)
|
||||
utils.authenticationRepository.setAutoConfirmEnabled(true)
|
||||
utils.authenticationRepository.apply {
|
||||
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
|
||||
overrideCredential(
|
||||
buildList {
|
||||
repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
|
||||
}
|
||||
)
|
||||
setAutoConfirmEnabled(true)
|
||||
}
|
||||
|
||||
assertThat(hintedPinLength).isNull()
|
||||
}
|
||||
|
||||
private fun switchToScene(sceneKey: SceneKey) {
|
||||
sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,22 +84,24 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun upTransitionSceneKey_swipeToUnlockEnabled_gone() =
|
||||
fun upTransitionSceneKey_canSwipeToUnlock_gone() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
|
||||
utils.authenticationRepository.setLockscreenEnabled(true)
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
utils.authenticationRepository.setUnlocked(true)
|
||||
sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun upTransitionSceneKey_swipeToUnlockNotEnabled_bouncer() =
|
||||
fun upTransitionSceneKey_cannotSwipeToUnlock_bouncer() =
|
||||
testScope.runTest {
|
||||
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
|
||||
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
|
||||
utils.authenticationRepository.setUnlocked(false)
|
||||
sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
|
||||
|
||||
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ class SceneTestUtils(
|
||||
|
||||
fun authenticationInteractor(
|
||||
repository: AuthenticationRepository,
|
||||
sceneInteractor: SceneInteractor = sceneInteractor(),
|
||||
): AuthenticationInteractor {
|
||||
return AuthenticationInteractor(
|
||||
applicationScope = applicationScope(),
|
||||
@@ -141,6 +142,7 @@ class SceneTestUtils(
|
||||
backgroundDispatcher = testDispatcher,
|
||||
userRepository = userRepository,
|
||||
keyguardRepository = keyguardRepository,
|
||||
sceneInteractor = sceneInteractor,
|
||||
clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user