diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt index 5d09de167dc56..4fe9f89830f64 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt @@ -59,5 +59,20 @@ object Easings { /** The linear interpolator. */ val Linear = fromInterpolator(InterpolatorsAndroidX.LINEAR) + /** The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN. */ + val Legacy = fromInterpolator(InterpolatorsAndroidX.LEGACY) + + /** + * The default legacy accelerating interpolator as defined in Material 1. Also known as + * FAST_OUT_LINEAR_IN. + */ + val LegacyAccelerate = fromInterpolator(InterpolatorsAndroidX.LEGACY_ACCELERATE) + + /** + * T The default legacy decelerating interpolator as defined in Material 1. Also known as + * LINEAR_OUT_SLOW_IN. + */ + val LegacyDecelerate = fromInterpolator(InterpolatorsAndroidX.LEGACY_DECELERATE) + private fun fromInterpolator(source: Interpolator) = Easing { x -> source.getInterpolation(x) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt index 20b859a6a242f..f801434999287 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt @@ -19,23 +19,19 @@ package com.android.systemui.bouncer.ui.composable import android.view.HapticFeedbackConstants -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.AnimationSpec -import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.MutableTransitionState +import androidx.compose.animation.core.Transition +import androidx.compose.animation.core.animateDp import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.keyframes +import androidx.compose.animation.core.snap import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleIn -import androidx.compose.animation.scaleOut -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.foundation.background +import androidx.compose.animation.core.updateTransition +import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -43,35 +39,40 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.Layout import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.compose.animation.Easings import com.android.compose.grid.VerticalGrid import com.android.systemui.R +import com.android.systemui.bouncer.ui.viewmodel.EnteredKey import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.compose.modifiers.thenIf -import kotlin.math.max import kotlin.time.Duration.Companion.milliseconds import kotlin.time.DurationUnit import kotlinx.coroutines.async @@ -86,8 +87,6 @@ internal fun PinBouncer( // Report that the UI is shown to let the view-model run some logic. LaunchedEffect(Unit) { viewModel.onShown() } - // The length of the PIN input received so far, so we know how many dots to render. - val pinLength: Pair by viewModel.pinLengths.collectAsState() val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() @@ -103,30 +102,7 @@ internal fun PinBouncer( horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier, ) { - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - modifier = Modifier.heightIn(min = 16.dp).animateContentSize(), - ) { - // TODO(b/281871687): add support for dot shapes. - val (previousPinLength, currentPinLength) = pinLength - val dotCount = max(previousPinLength, currentPinLength) + 1 - repeat(dotCount) { index -> - AnimatedVisibility( - visible = index < currentPinLength, - enter = fadeIn() + scaleIn() + slideInHorizontally(), - exit = fadeOut() + scaleOut() + slideOutHorizontally(), - ) { - Box( - modifier = - Modifier.size(16.dp) - .background( - MaterialTheme.colorScheme.onSurfaceVariant, - CircleShape, - ) - ) - } - } - } + PinInputDisplay(viewModel) Spacer(Modifier.height(100.dp)) @@ -186,6 +162,148 @@ internal fun PinBouncer( } } +@Composable +private fun PinInputDisplay(viewModel: PinBouncerViewModel) { + val currentPinEntries: List by viewModel.pinEntries.collectAsState() + + // visiblePinEntries keeps pins removed from currentPinEntries in the composition until their + // disappear-animation completed. The list is sorted by the natural ordering of EnteredKey, + // which is guaranteed to produce the original edit order, since the model only modifies entries + // at the end. + val visiblePinEntries = remember { SnapshotStateList() } + currentPinEntries.forEach { + val index = visiblePinEntries.binarySearch(it) + if (index < 0) { + val insertionPoint = -(index + 1) + visiblePinEntries.add(insertionPoint, it) + } + } + + Row( + modifier = + Modifier.heightIn(min = entryShapeSize) + // Pins overflowing horizontally should still be shown as scrolling. + .wrapContentSize(unbounded = true), + ) { + visiblePinEntries.forEachIndexed { index, entry -> + key(entry) { + val visibility = remember { + MutableTransitionState(EntryVisibility.Hidden) + } + visibility.targetState = + when { + currentPinEntries.isEmpty() && visiblePinEntries.size > 1 -> + EntryVisibility.BulkHidden(index, visiblePinEntries.size) + currentPinEntries.contains(entry) -> EntryVisibility.Shown + else -> EntryVisibility.Hidden + } + + ObscuredInputEntry(updateTransition(visibility, label = "Pin Entry $entry")) + + LaunchedEffect(entry) { + // Remove entry from visiblePinEntries once the hide transition completed. + snapshotFlow { + visibility.currentState == visibility.targetState && + visibility.targetState != EntryVisibility.Shown + } + .collect { isRemoved -> + if (isRemoved) { + visiblePinEntries.remove(entry) + } + } + } + } + } + } +} + +private sealed class EntryVisibility { + object Shown : EntryVisibility() + + object Hidden : EntryVisibility() + + /** + * Same as [Hidden], but applies when multiple entries are hidden simultaneously, without + * collapsing during the hide. + */ + data class BulkHidden(val staggerIndex: Int, val totalEntryCount: Int) : EntryVisibility() +} + +@Composable +private fun ObscuredInputEntry(transition: Transition) { + // spec: http://shortn/_DEhE3Xl2bi + val shapePadding = 6.dp + val shapeOvershootSize = 22.dp + val dismissStaggerDelayMs = 33 + val dismissDurationMs = 450 + val expansionDurationMs = 250 + val shapeExpandDurationMs = 83 + val shapeRetractDurationMs = 167 + val shapeCollapseDurationMs = 200 + + val animatedEntryWidth by + transition.animateDp( + transitionSpec = { + when (val target = targetState) { + is EntryVisibility.BulkHidden -> + // only collapse horizontal space once all entries are removed + snap(dismissDurationMs + dismissStaggerDelayMs * target.totalEntryCount) + else -> tween(expansionDurationMs, easing = Easings.Standard) + } + }, + label = "entry space" + ) { state -> + if (state == EntryVisibility.Shown) entryShapeSize + (shapePadding * 2) else 0.dp + } + + val animatedShapeSize by + transition.animateDp( + transitionSpec = { + when { + EntryVisibility.Hidden isTransitioningTo EntryVisibility.Shown -> + keyframes { + durationMillis = shapeExpandDurationMs + shapeRetractDurationMs + 0.dp at 0 with Easings.Linear + shapeOvershootSize at shapeExpandDurationMs with Easings.Legacy + } + targetState is EntryVisibility.BulkHidden -> { + val target = targetState as EntryVisibility.BulkHidden + tween( + dismissDurationMs, + delayMillis = target.staggerIndex * dismissStaggerDelayMs, + easing = Easings.Legacy, + ) + } + else -> tween(shapeCollapseDurationMs, easing = Easings.StandardDecelerate) + } + }, + label = "shape size" + ) { state -> + when (state) { + EntryVisibility.Shown -> entryShapeSize + else -> 0.dp + } + } + + val dotColor = MaterialTheme.colorScheme.onSurfaceVariant + Layout( + content = { + // TODO(b/282730134): add support for dot shapes. + Canvas(Modifier) { drawCircle(dotColor) } + } + ) { measurables, _ -> + val shapeSizePx = animatedShapeSize.roundToPx() + val placeable = measurables.single().measure(Constraints.fixed(shapeSizePx, shapeSizePx)) + + layout(animatedEntryWidth.roundToPx(), entryShapeSize.roundToPx()) { + placeable.place( + ((animatedEntryWidth - animatedShapeSize) / 2f).roundToPx(), + ((entryShapeSize - animatedShapeSize) / 2f).roundToPx() + ) + } + } +} + @Composable private fun PinDigit( digit: Int, @@ -310,11 +428,13 @@ private fun showFailureAnimation() { // TODO(b/282730134): implement. } +private val entryShapeSize = 16.dp + private val pinButtonSize = 84.dp // Pin button motion spec: http://shortn/_9TTIG6SoEa private val pinButtonPressedDuration = 100.milliseconds -private val pinButtonPressedEasing = LinearEasing +private val pinButtonPressedEasing = Easings.Linear private val pinButtonHoldTime = 33.milliseconds private val pinButtonReleasedDuration = 420.milliseconds private val pinButtonReleasedEasing = Easings.Standard diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt index c684dc54c6fdd..c4ebee2a9197e 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt @@ -77,7 +77,7 @@ class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationReposit override val isUnlocked: StateFlow = _isUnlocked.asStateFlow() private val _authenticationMethod = - MutableStateFlow(AuthenticationMethodModel.PIN(1234)) + MutableStateFlow(AuthenticationMethodModel.Pin(1234)) override val authenticationMethod: StateFlow = _authenticationMethod.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt index 3984627a181dc..dd9dcbedd6fc8 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.authentication.domain.interactor +import android.app.admin.DevicePolicyManager import com.android.systemui.authentication.data.repository.AuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.dagger.SysUISingleton @@ -129,7 +130,7 @@ constructor( fun authenticate(input: List): Boolean { val isSuccessful = when (val authMethod = this.authenticationMethod.value) { - is AuthenticationMethodModel.PIN -> input.asCode() == authMethod.code + is AuthenticationMethodModel.Pin -> input.asCode() == authMethod.code is AuthenticationMethodModel.Password -> input.asPassword() == authMethod.password is AuthenticationMethodModel.Pattern -> input.asPattern() == authMethod.coordinates else -> true @@ -177,15 +178,21 @@ constructor( /** * Returns a PIN code from the given list. It's assumed the given list elements are all - * [Int]. + * [Int] in the range [0-9]. */ - private fun List.asCode(): Int? { - if (isEmpty()) { + private fun List.asCode(): Long? { + if (isEmpty() || size > DevicePolicyManager.MAX_PASSWORD_LENGTH) { return null } - var code = 0 - map { it as Int }.forEach { integer -> code = code * 10 + integer } + var code = 0L + map { + require(it is Int && it in 0..9) { + "Pin is required to be Int in range [0..9], but got $it" + } + it + } + .forEach { integer -> code = code * 10 + integer } return code } diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt index 6f008c3017b91..e4fbf9af35eaf 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt @@ -32,7 +32,13 @@ sealed class AuthenticationMethodModel( /** The most basic authentication method. The lock screen can be swiped away when displayed. */ object Swipe : AuthenticationMethodModel(isSecure = false) - data class PIN(val code: Int) : AuthenticationMethodModel(isSecure = true) + /** + * Authentication method using a PIN. + * + * In practice, a pin is restricted to 16 decimal digits , see + * [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH] + */ + data class Pin(val code: Long) : AuthenticationMethodModel(isSecure = true) data class Password(val password: String) : AuthenticationMethodModel(isSecure = true) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt index 1d2fce7d8b05f..a24a421ff2e17 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt @@ -197,7 +197,7 @@ constructor( private fun promptMessage(authMethod: AuthenticationMethodModel): String { return when (authMethod) { - is AuthenticationMethodModel.PIN -> + is AuthenticationMethodModel.Pin -> applicationContext.getString(R.string.keyguard_enter_your_pin) is AuthenticationMethodModel.Password -> applicationContext.getString(R.string.keyguard_enter_your_password) @@ -209,7 +209,7 @@ constructor( private fun errorMessage(authMethod: AuthenticationMethodModel): String { return when (authMethod) { - is AuthenticationMethodModel.PIN -> applicationContext.getString(R.string.kg_wrong_pin) + is AuthenticationMethodModel.Pin -> applicationContext.getString(R.string.kg_wrong_pin) is AuthenticationMethodModel.Password -> applicationContext.getString(R.string.kg_wrong_password) is AuthenticationMethodModel.Pattern -> diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt index 984d9ab1c1be2..527fe6ec847d0 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt @@ -126,7 +126,7 @@ constructor( .map { model -> model?.let { when (interactor.authenticationMethod.value) { - is AuthenticationMethodModel.PIN -> + is AuthenticationMethodModel.Pin -> R.string.kg_too_many_failed_pin_attempts_dialog_message is AuthenticationMethodModel.Password -> R.string.kg_too_many_failed_password_attempts_dialog_message @@ -165,7 +165,7 @@ constructor( authMethod: AuthenticationMethodModel, ): AuthMethodBouncerViewModel? { return when (authMethod) { - is AuthenticationMethodModel.PIN -> pin + is AuthenticationMethodModel.Pin -> pin is AuthenticationMethodModel.Password -> password is AuthenticationMethodModel.Pattern -> pattern else -> null diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt index 5c0fd92e72997..94d3d193e9cc2 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt @@ -16,18 +16,10 @@ package com.android.systemui.bouncer.ui.viewmodel -import androidx.annotation.VisibleForTesting import com.android.systemui.bouncer.domain.interactor.BouncerInteractor -import com.android.systemui.util.kotlin.pairwise import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -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( @@ -39,21 +31,8 @@ class PinBouncerViewModel( isInputEnabled = isInputEnabled, ) { - private val entered = MutableStateFlow>(emptyList()) - /** - * The length of the PIN digits that were input so far, two values are supplied the previous and - * the current. - */ - val pinLengths: StateFlow> = - entered - .pairwise() - .map { it.previousValue.size to it.newValue.size } - .stateIn( - scope = applicationScope, - started = SharingStarted.WhileSubscribed(), - initialValue = 0 to 0, - ) - private var resetPinJob: Job? = null + private val mutablePinEntries = MutableStateFlow>(emptyList()) + val pinEntries: StateFlow> = mutablePinEntries /** Notifies that the UI has been shown to the user. */ fun onShown() { @@ -62,47 +41,48 @@ class PinBouncerViewModel( /** Notifies that the user clicked on a PIN button with the given digit value. */ fun onPinButtonClicked(input: Int) { - resetPinJob?.cancel() - resetPinJob = null - - if (entered.value.isEmpty()) { + if (mutablePinEntries.value.isEmpty()) { interactor.clearMessage() } - entered.value += input + mutablePinEntries.value += EnteredKey(input) } /** Notifies that the user clicked the backspace button. */ fun onBackspaceButtonClicked() { - if (entered.value.isEmpty()) { + if (mutablePinEntries.value.isEmpty()) { return } - - entered.value = entered.value.toMutableList().apply { removeLast() } + mutablePinEntries.value = mutablePinEntries.value.toMutableList().apply { removeLast() } } /** Notifies that the user long-pressed the backspace button. */ fun onBackspaceButtonLongPressed() { - resetPinJob?.cancel() - resetPinJob = - applicationScope.launch { - while (entered.value.isNotEmpty()) { - onBackspaceButtonClicked() - delay(BACKSPACE_LONG_PRESS_DELAY_MS) - } - } + mutablePinEntries.value = emptyList() } /** Notifies that the user clicked the "enter" button. */ fun onAuthenticateButtonClicked() { - if (!interactor.authenticate(entered.value)) { + if (!interactor.authenticate(mutablePinEntries.value.map { it.input })) { showFailureAnimation() } - entered.value = emptyList() - } - - companion object { - @VisibleForTesting const val BACKSPACE_LONG_PRESS_DELAY_MS = 80L + mutablePinEntries.value = emptyList() } } + +private var nextSequenceNumber = 1 + +/** + * The pin bouncer [input] as digits 0-9, together with a [sequenceNumber] to indicate the ordering. + * + * Since the model only allows appending/removing [EnteredKey]s from the end, the [sequenceNumber] + * is strictly increasing in input order of the pin, but not guaranteed to be monotonic or start at + * a specific number. + */ +data class EnteredKey +internal constructor(val input: Int, val sequenceNumber: Int = nextSequenceNumber++) : + Comparable { + override fun compareTo(other: EnteredKey): Int = + compareValuesBy(this, other, EnteredKey::sequenceNumber) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt index 1990c8f644b41..3a93e7744d00a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.authentication.domain.interactor +import android.app.admin.DevicePolicyManager import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.AuthenticationRepository @@ -48,7 +49,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { fun authMethod() = testScope.runTest { val authMethod by collectLastValue(underTest.authenticationMethod) - assertThat(authMethod).isEqualTo(AuthenticationMethodModel.PIN(1234)) + assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234)) underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password")) assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password")) @@ -147,7 +148,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { testScope.runTest { val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val isUnlocked by collectLastValue(underTest.isUnlocked) - underTest.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(isUnlocked).isFalse() assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue() @@ -160,7 +161,7 @@ class AuthenticationInteractorTest : SysuiTestCase() { testScope.runTest { val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) val isUnlocked by collectLastValue(underTest.isUnlocked) - underTest.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(isUnlocked).isFalse() assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse() @@ -168,6 +169,51 @@ class AuthenticationInteractorTest : SysuiTestCase() { assertThat(failedAttemptCount).isEqualTo(1) } + @Test + fun authenticate_withEmptyPin_returnsFalseAndDoesNotUnlockDevice() = + testScope.runTest { + val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) + val isUnlocked by collectLastValue(underTest.isUnlocked) + underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) + assertThat(isUnlocked).isFalse() + + assertThat(underTest.authenticate(listOf())).isFalse() + assertThat(isUnlocked).isFalse() + assertThat(failedAttemptCount).isEqualTo(1) + } + + @Test + fun authenticate_withCorrectMaxLengthPin_returnsTrueAndUnlocksDevice() = + testScope.runTest { + val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) + val isUnlocked by collectLastValue(underTest.isUnlocked) + underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999)) + assertThat(isUnlocked).isFalse() + + assertThat(underTest.authenticate(List(16) { 9 })).isTrue() + assertThat(isUnlocked).isTrue() + assertThat(failedAttemptCount).isEqualTo(0) + } + + @Test + fun authenticate_withCorrectTooLongPin_returnsFalseAndDoesNotUnlockDevice() = + testScope.runTest { + // Max pin length is 16 digits. To avoid issues with overflows, this test ensures + // that all pins > 16 decimal digits are rejected. + + // If the policy changes, there is work to do in SysUI. + assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17) + + val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts) + val isUnlocked by collectLastValue(underTest.isUnlocked) + underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999)) + assertThat(isUnlocked).isFalse() + + assertThat(underTest.authenticate(List(17) { 9 })).isFalse() + assertThat(isUnlocked).isFalse() + assertThat(failedAttemptCount).isEqualTo(1) + } + @Test fun authenticate_withCorrectPassword_returnsTrueAndUnlocksDevice() = testScope.runTest { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt index 374c28d6dce88..6a63c32f2c404 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt @@ -69,7 +69,7 @@ class BouncerInteractorTest : SysuiTestCase() { val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) val message by collectLastValue(underTest.message) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() underTest.showOrUnlockDevice("container1") assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) @@ -167,7 +167,7 @@ class BouncerInteractorTest : SysuiTestCase() { fun showOrUnlockDevice_notLocked_switchesToGoneScene() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene("container1")) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() runCurrent() @@ -211,7 +211,7 @@ 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)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(throttling).isNull() assertThat(message).isEqualTo("") assertThat(isUnlocked).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt index 1642410e5a3fb..b53e03419df3b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt @@ -55,7 +55,7 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() { @Test fun animateFailure() = testScope.runTest { - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) val animateFailure by collectLastValue(underTest.animateFailure) assertThat(animateFailure).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt index e8c946cdd59d1..c6074962ee8e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt @@ -97,7 +97,7 @@ class BouncerViewModelTest : SysuiTestCase() { testScope.runTest { val message by collectLastValue(underTest.message) val throttling by collectLastValue(bouncerInteractor.throttling) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(message?.isUpdateAnimated).isTrue() repeat(BouncerInteractor.THROTTLE_EVERY) { @@ -120,7 +120,7 @@ class BouncerViewModelTest : SysuiTestCase() { } ) val throttling by collectLastValue(bouncerInteractor.throttling) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(isInputEnabled).isTrue() repeat(BouncerInteractor.THROTTLE_EVERY) { @@ -137,7 +137,7 @@ class BouncerViewModelTest : SysuiTestCase() { fun throttlingDialogMessage() = testScope.runTest { val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) repeat(BouncerInteractor.THROTTLE_EVERY) { // Wrong PIN. @@ -154,7 +154,7 @@ class BouncerViewModelTest : SysuiTestCase() { return listOf( AuthenticationMethodModel.None, AuthenticationMethodModel.Swipe, - AuthenticationMethodModel.PIN(1234), + AuthenticationMethodModel.Pin(1234), AuthenticationMethodModel.Password("password"), AuthenticationMethodModel.Pattern( listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 3bdaf05908888..7b6bb37459a78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -25,12 +25,12 @@ 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.Correspondence 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.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -85,8 +85,8 @@ class PinBouncerViewModelTest : SysuiTestCase() { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -95,7 +95,7 @@ class PinBouncerViewModelTest : SysuiTestCase() { underTest.onShown() assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN) - assertThat(pinLengths).isEqualTo(0 to 0) + assertThat(entries).hasSize(0) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) } @@ -106,8 +106,8 @@ class PinBouncerViewModelTest : SysuiTestCase() { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -117,7 +117,8 @@ class PinBouncerViewModelTest : SysuiTestCase() { underTest.onPinButtonClicked(1) assertThat(message?.text).isEmpty() - assertThat(pinLengths).isEqualTo(0 to 1) + assertThat(entries).hasSize(1) + assertThat(entries?.map { it.input }).containsExactly(1) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) } @@ -128,32 +129,59 @@ class PinBouncerViewModelTest : SysuiTestCase() { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPinButtonClicked(1) - assertThat(pinLengths).isEqualTo(0 to 1) + assertThat(entries).hasSize(1) underTest.onBackspaceButtonClicked() assertThat(message?.text).isEmpty() - assertThat(pinLengths).isEqualTo(1 to 0) + assertThat(entries).hasSize(0) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) } + @Test + fun onPinEdit() = + testScope.runTest { + val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) + val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) + val message by collectLastValue(bouncerViewModel.message) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) + authenticationInteractor.lockDevice() + sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) + assertThat(isUnlocked).isFalse() + assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) + underTest.onShown() + + underTest.onPinButtonClicked(1) + underTest.onPinButtonClicked(2) + underTest.onPinButtonClicked(3) + underTest.onBackspaceButtonClicked() + underTest.onBackspaceButtonClicked() + underTest.onPinButtonClicked(4) + underTest.onPinButtonClicked(5) + + assertThat(entries).hasSize(3) + assertThat(entries?.map { it.input }).containsExactly(1, 4, 5).inOrder() + assertThat(entries?.map { it.sequenceNumber }).isInStrictOrder() + } + @Test fun onBackspaceButtonLongPressed() = testScope.runTest { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -165,13 +193,9 @@ class PinBouncerViewModelTest : SysuiTestCase() { underTest.onPinButtonClicked(4) underTest.onBackspaceButtonLongPressed() - repeat(4) { index -> - assertThat(pinLengths).isEqualTo(4 - index to 3 - index) - advanceTimeBy(PinBouncerViewModel.BACKSPACE_LONG_PRESS_DELAY_MS) - } assertThat(message?.text).isEmpty() - assertThat(pinLengths).isEqualTo(1 to 0) + assertThat(entries).hasSize(0) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) } @@ -181,7 +205,7 @@ class PinBouncerViewModelTest : SysuiTestCase() { testScope.runTest { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -204,8 +228,8 @@ class PinBouncerViewModelTest : SysuiTestCase() { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -219,7 +243,7 @@ class PinBouncerViewModelTest : SysuiTestCase() { underTest.onAuthenticateButtonClicked() - assertThat(pinLengths).isEqualTo(0 to 0) + assertThat(entries).hasSize(0) assertThat(message?.text).isEqualTo(WRONG_PIN) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) @@ -231,8 +255,8 @@ class PinBouncerViewModelTest : SysuiTestCase() { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME)) val message by collectLastValue(bouncerViewModel.message) - val pinLengths by collectLastValue(underTest.pinLengths) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + val entries by collectLastValue(underTest.pinEntries) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer)) assertThat(isUnlocked).isFalse() @@ -245,7 +269,7 @@ class PinBouncerViewModelTest : SysuiTestCase() { underTest.onPinButtonClicked(5) // PIN is now wrong! underTest.onAuthenticateButtonClicked() assertThat(message?.text).isEqualTo(WRONG_PIN) - assertThat(pinLengths).isEqualTo(0 to 0) + assertThat(entries).hasSize(0) assertThat(isUnlocked).isFalse() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) @@ -266,5 +290,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { private const val CONTAINER_NAME = "container1" private const val ENTER_YOUR_PIN = "Enter your pin" private const val WRONG_PIN = "Wrong pin" + + val KEY_CODE = + Correspondence.transforming( + { it?.input }, + "has a eventId of", + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt index d622f1c30816b..65781c4979441 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt @@ -95,7 +95,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) authenticationInteractor.lockDevice() - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) underTest.dismissLockscreen() @@ -108,7 +108,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) authenticationInteractor.unlockDevice() - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) underTest.dismissLockscreen() @@ -195,7 +195,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { testScope.runTest { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) assertThat(isUnlocked).isFalse() sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index 8ba3f0f57eed6..f0ea0077596ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -109,7 +109,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() = testScope.runTest { val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer) @@ -119,7 +119,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() runCurrent() @@ -132,7 +132,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() runCurrent() @@ -145,7 +145,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() runCurrent() @@ -158,7 +158,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { fun onLockButtonClicked_deviceUnlocked_switchesToGone() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index 105387d49bd49..05a16994e021c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -70,7 +70,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() runCurrent() @@ -83,7 +83,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt index 69d03d9b0e4cc..f8e1a9d12657e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt @@ -71,7 +71,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { fun upTransitionSceneKey_deviceLocked_lockScreen() = testScope.runTest { val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen) @@ -81,7 +81,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { fun upTransitionSceneKey_deviceUnlocked_gone() = testScope.runTest { val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone) @@ -91,7 +91,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.unlockDevice() runCurrent() @@ -104,7 +104,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) - authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234)) + authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234)) authenticationInteractor.lockDevice() runCurrent()