Loading packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +55 −24 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.view.KeyEvent.KEYCODE_0 import android.view.KeyEvent.KEYCODE_4 import android.view.KeyEvent.KEYCODE_A import android.view.KeyEvent.KEYCODE_DEL import android.view.KeyEvent.KEYCODE_ENTER import android.view.KeyEvent.KEYCODE_NUMPAD_0 import androidx.compose.ui.input.key.KeyEventType import androidx.test.ext.junit.runners.AndroidJUnit4 Loading @@ -46,8 +47,6 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.testKosmos import com.google.android.msdl.data.model.MSDLToken import com.google.common.truth.Truth.assertThat import kotlin.random.Random import kotlin.random.nextInt import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map import org.junit.Before Loading Loading @@ -444,37 +443,64 @@ class PinBouncerViewModelTest : SysuiTestCase() { kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) lockDeviceAndOpenPinBouncer() val random = Random(System.currentTimeMillis()) // Generate a random 4 digit PIN val expectedPin = with(random) { arrayOf(nextInt(0..9), nextInt(0..9), nextInt(0..9), nextInt(0..9)) } val expectedPin = FakeAuthenticationRepository.WRONG_PIN.take(4).toTypedArray() // Enter the PIN using NUM pad and normal number keyboard events underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[0]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[0]) pressKey(KEYCODE_0 + expectedPin[0]) pressKey(KEYCODE_NUMPAD_0 + expectedPin[1]) pressKey(KEYCODE_0 + expectedPin[2]) underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[1]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[1]) // Enter an additional digit in between and delete it pressKey(KEYCODE_4) pressKey(KEYCODE_DEL) underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[2]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[2]) // Try entering a non digit character, this should be ignored. pressKey(KEYCODE_A) // Enter an additional digit in between and delete it underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_4) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_4) pressKey(KEYCODE_NUMPAD_0 + expectedPin[3]) // Delete that additional digit underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_DEL) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_DEL) assertThat(pin).containsExactly(*expectedPin).inOrder() } // Try entering a non digit character, this should be ignored. underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_A) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_A) @Test fun onKeyboardInput_submitOnEnter_wrongPin() = kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult) fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(false) lockDeviceAndOpenPinBouncer() val wrongPin = FakeAuthenticationRepository.WRONG_PIN.toTypedArray() wrongPin.forEach { pressKey(KEYCODE_0 + it) } assertThat(pin).containsExactly(*wrongPin).inOrder() assertThat(underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_ENTER)).isTrue() assertThat(underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_ENTER)).isTrue() assertThat(authResult).isFalse() assertThat(pin).isEmpty() } @Test fun onKeyboardInput_submitOnEnter_correctPin() = kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult) fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(false) lockDeviceAndOpenPinBouncer() val correctPin = FakeAuthenticationRepository.DEFAULT_PIN.toTypedArray() correctPin.forEach { pressKey(KEYCODE_0 + it) } underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[3]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[3]) assertThat(pin).containsExactly(*correctPin).inOrder() assertThat(pin).containsExactly(*expectedPin) assertThat(underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_ENTER)).isTrue() assertThat(underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_ENTER)).isTrue() assertThat(authResult).isTrue() } @Test Loading Loading @@ -527,6 +553,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { showBouncer() } private fun pressKey(keyCode: Int) { underTest.onKeyEvent(KeyEventType.KeyDown, keyCode) underTest.onKeyEvent(KeyEventType.KeyUp, keyCode) } companion object { private const val ENTER_YOUR_PIN = "Enter your pin" private const val WRONG_PIN = "Wrong pin" Loading packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +20 −26 Original line number Diff line number Diff line Loading @@ -248,17 +248,16 @@ constructor( * @return `true` when the [KeyEvent] was consumed as user input on bouncer; `false` otherwise. */ override fun onKeyEvent(type: KeyEventType, keyCode: Int): Boolean { return when (type) { KeyEventType.KeyUp -> { if (isConfirmKey(keyCode)) { if (type == KeyEventType.KeyUp) { onAuthenticateButtonClicked() true } else { false } return true } KeyEventType.KeyDown -> { when (keyCode) { if (type != KeyEventType.KeyDown) return false return when (keyCode) { KEYCODE_DEL -> { onBackspaceButtonClicked() true Loading @@ -271,11 +270,6 @@ constructor( onPinButtonClicked(keyCode - KEYCODE_NUMPAD_0) true } else -> { false } } } else -> false } } Loading packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +1 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,7 @@ class FakeAuthenticationRepository(private val currentTime: () -> Long) : Authen const val LOCKOUT_DURATION_MS = LOCKOUT_DURATION_SECONDS * 1000 const val HINTING_PIN_LENGTH = 6 val DEFAULT_PIN = buildList { repeat(HINTING_PIN_LENGTH) { add(it + 1) } } val WRONG_PIN = buildList { repeat(HINTING_PIN_LENGTH) { add(9 - it) } } private fun AuthenticationMethodModel.toSecurityMode(): SecurityMode { return when (this) { Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +55 −24 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.view.KeyEvent.KEYCODE_0 import android.view.KeyEvent.KEYCODE_4 import android.view.KeyEvent.KEYCODE_A import android.view.KeyEvent.KEYCODE_DEL import android.view.KeyEvent.KEYCODE_ENTER import android.view.KeyEvent.KEYCODE_NUMPAD_0 import androidx.compose.ui.input.key.KeyEventType import androidx.test.ext.junit.runners.AndroidJUnit4 Loading @@ -46,8 +47,6 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.testKosmos import com.google.android.msdl.data.model.MSDLToken import com.google.common.truth.Truth.assertThat import kotlin.random.Random import kotlin.random.nextInt import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map import org.junit.Before Loading Loading @@ -444,37 +443,64 @@ class PinBouncerViewModelTest : SysuiTestCase() { kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) lockDeviceAndOpenPinBouncer() val random = Random(System.currentTimeMillis()) // Generate a random 4 digit PIN val expectedPin = with(random) { arrayOf(nextInt(0..9), nextInt(0..9), nextInt(0..9), nextInt(0..9)) } val expectedPin = FakeAuthenticationRepository.WRONG_PIN.take(4).toTypedArray() // Enter the PIN using NUM pad and normal number keyboard events underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[0]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[0]) pressKey(KEYCODE_0 + expectedPin[0]) pressKey(KEYCODE_NUMPAD_0 + expectedPin[1]) pressKey(KEYCODE_0 + expectedPin[2]) underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[1]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[1]) // Enter an additional digit in between and delete it pressKey(KEYCODE_4) pressKey(KEYCODE_DEL) underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[2]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[2]) // Try entering a non digit character, this should be ignored. pressKey(KEYCODE_A) // Enter an additional digit in between and delete it underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_4) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_4) pressKey(KEYCODE_NUMPAD_0 + expectedPin[3]) // Delete that additional digit underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_DEL) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_DEL) assertThat(pin).containsExactly(*expectedPin).inOrder() } // Try entering a non digit character, this should be ignored. underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_A) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_A) @Test fun onKeyboardInput_submitOnEnter_wrongPin() = kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult) fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(false) lockDeviceAndOpenPinBouncer() val wrongPin = FakeAuthenticationRepository.WRONG_PIN.toTypedArray() wrongPin.forEach { pressKey(KEYCODE_0 + it) } assertThat(pin).containsExactly(*wrongPin).inOrder() assertThat(underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_ENTER)).isTrue() assertThat(underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_ENTER)).isTrue() assertThat(authResult).isFalse() assertThat(pin).isEmpty() } @Test fun onKeyboardInput_submitOnEnter_correctPin() = kosmos.runTest { val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult) fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(false) lockDeviceAndOpenPinBouncer() val correctPin = FakeAuthenticationRepository.DEFAULT_PIN.toTypedArray() correctPin.forEach { pressKey(KEYCODE_0 + it) } underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[3]) underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[3]) assertThat(pin).containsExactly(*correctPin).inOrder() assertThat(pin).containsExactly(*expectedPin) assertThat(underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_ENTER)).isTrue() assertThat(underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_ENTER)).isTrue() assertThat(authResult).isTrue() } @Test Loading Loading @@ -527,6 +553,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { showBouncer() } private fun pressKey(keyCode: Int) { underTest.onKeyEvent(KeyEventType.KeyDown, keyCode) underTest.onKeyEvent(KeyEventType.KeyUp, keyCode) } companion object { private const val ENTER_YOUR_PIN = "Enter your pin" private const val WRONG_PIN = "Wrong pin" Loading
packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +20 −26 Original line number Diff line number Diff line Loading @@ -248,17 +248,16 @@ constructor( * @return `true` when the [KeyEvent] was consumed as user input on bouncer; `false` otherwise. */ override fun onKeyEvent(type: KeyEventType, keyCode: Int): Boolean { return when (type) { KeyEventType.KeyUp -> { if (isConfirmKey(keyCode)) { if (type == KeyEventType.KeyUp) { onAuthenticateButtonClicked() true } else { false } return true } KeyEventType.KeyDown -> { when (keyCode) { if (type != KeyEventType.KeyDown) return false return when (keyCode) { KEYCODE_DEL -> { onBackspaceButtonClicked() true Loading @@ -271,11 +270,6 @@ constructor( onPinButtonClicked(keyCode - KEYCODE_NUMPAD_0) true } else -> { false } } } else -> false } } Loading
packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +1 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,7 @@ class FakeAuthenticationRepository(private val currentTime: () -> Long) : Authen const val LOCKOUT_DURATION_MS = LOCKOUT_DURATION_SECONDS * 1000 const val HINTING_PIN_LENGTH = 6 val DEFAULT_PIN = buildList { repeat(HINTING_PIN_LENGTH) { add(it + 1) } } val WRONG_PIN = buildList { repeat(HINTING_PIN_LENGTH) { add(9 - it) } } private fun AuthenticationMethodModel.toSecurityMode(): SecurityMode { return when (this) { Loading