Lock : fix race condition on setup pin

This commit is contained in:
ganfra 2023-11-07 21:06:26 +01:00
parent 41517614c8
commit 8b4d3a4bc8
4 changed files with 15 additions and 10 deletions

View file

@ -17,6 +17,6 @@
package io.element.android.features.lockscreen.impl.setup.pin package io.element.android.features.lockscreen.impl.setup.pin
sealed interface SetupPinEvents { sealed interface SetupPinEvents {
data class OnPinEntryChanged(val entryAsText: String) : SetupPinEvents data class OnPinEntryChanged(val entryAsText: String, val fromConfirmationStep: Boolean) : SetupPinEvents
data object ClearFailure : SetupPinEvents data object ClearFailure : SetupPinEvents
} }

View file

@ -85,7 +85,8 @@ class SetupPinPresenter @Inject constructor(
fun handleEvents(event: SetupPinEvents) { fun handleEvents(event: SetupPinEvents) {
when (event) { when (event) {
is SetupPinEvents.OnPinEntryChanged -> { is SetupPinEvents.OnPinEntryChanged -> {
if (isConfirmationStep) { // Use the fromConfirmationStep flag from ui to avoid race condition.
if (event.fromConfirmationStep) {
confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText) confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText)
} else { } else {
choosePinEntry = choosePinEntry.fillWith(event.entryAsText) choosePinEntry = choosePinEntry.fillWith(event.entryAsText)

View file

@ -116,8 +116,8 @@ private fun SetupPinContent(
PinEntryTextField( PinEntryTextField(
pinEntry = state.activePinEntry, pinEntry = state.activePinEntry,
isSecured = true, isSecured = true,
onValueChange = { onValueChange = { entry ->
state.eventSink(SetupPinEvents.OnPinEntryChanged(it)) state.eventSink(SetupPinEvents.OnPinEntryChanged(entry, state.isConfirmationStep))
}, },
modifier = modifier modifier = modifier
.focusRequester(focusRequester) .focusRequester(focusRequester)

View file

@ -60,14 +60,14 @@ class SetupPinPresenterTest {
state.confirmPinEntry.assertEmpty() state.confirmPinEntry.assertEmpty()
assertThat(state.setupPinFailure).isNull() assertThat(state.setupPinFailure).isNull()
assertThat(state.isConfirmationStep).isFalse() assertThat(state.isConfirmationStep).isFalse()
state.eventSink(SetupPinEvents.OnPinEntryChanged(halfCompletePin)) state.onPinEntryChanged(halfCompletePin)
} }
awaitItem().also { state -> awaitItem().also { state ->
state.choosePinEntry.assertText(halfCompletePin) state.choosePinEntry.assertText(halfCompletePin)
state.confirmPinEntry.assertEmpty() state.confirmPinEntry.assertEmpty()
assertThat(state.setupPinFailure).isNull() assertThat(state.setupPinFailure).isNull()
assertThat(state.isConfirmationStep).isFalse() assertThat(state.isConfirmationStep).isFalse()
state.eventSink(SetupPinEvents.OnPinEntryChanged(blacklistedPin)) state.onPinEntryChanged(blacklistedPin)
} }
awaitLastSequentialItem().also { state -> awaitLastSequentialItem().also { state ->
state.choosePinEntry.assertText(blacklistedPin) state.choosePinEntry.assertText(blacklistedPin)
@ -77,7 +77,7 @@ class SetupPinPresenterTest {
awaitLastSequentialItem().also { state -> awaitLastSequentialItem().also { state ->
state.choosePinEntry.assertEmpty() state.choosePinEntry.assertEmpty()
assertThat(state.setupPinFailure).isNull() assertThat(state.setupPinFailure).isNull()
state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) state.onPinEntryChanged(completePin)
} }
consumeItemsUntilPredicate { consumeItemsUntilPredicate {
it.isConfirmationStep it.isConfirmationStep
@ -85,7 +85,7 @@ class SetupPinPresenterTest {
state.choosePinEntry.assertText(completePin) state.choosePinEntry.assertText(completePin)
state.confirmPinEntry.assertEmpty() state.confirmPinEntry.assertEmpty()
assertThat(state.isConfirmationStep).isTrue() assertThat(state.isConfirmationStep).isTrue()
state.eventSink(SetupPinEvents.OnPinEntryChanged(mismatchedPin)) state.onPinEntryChanged(mismatchedPin)
} }
awaitLastSequentialItem().also { state -> awaitLastSequentialItem().also { state ->
state.choosePinEntry.assertText(completePin) state.choosePinEntry.assertText(completePin)
@ -98,7 +98,7 @@ class SetupPinPresenterTest {
state.confirmPinEntry.assertEmpty() state.confirmPinEntry.assertEmpty()
assertThat(state.isConfirmationStep).isFalse() assertThat(state.isConfirmationStep).isFalse()
assertThat(state.setupPinFailure).isNull() assertThat(state.setupPinFailure).isNull()
state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) state.onPinEntryChanged(completePin)
} }
consumeItemsUntilPredicate { consumeItemsUntilPredicate {
it.isConfirmationStep it.isConfirmationStep
@ -106,7 +106,7 @@ class SetupPinPresenterTest {
state.choosePinEntry.assertText(completePin) state.choosePinEntry.assertText(completePin)
state.confirmPinEntry.assertEmpty() state.confirmPinEntry.assertEmpty()
assertThat(state.isConfirmationStep).isTrue() assertThat(state.isConfirmationStep).isTrue()
state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) state.onPinEntryChanged(completePin)
} }
awaitItem().also { state -> awaitItem().also { state ->
state.choosePinEntry.assertText(completePin) state.choosePinEntry.assertText(completePin)
@ -116,6 +116,10 @@ class SetupPinPresenterTest {
} }
} }
private fun SetupPinState.onPinEntryChanged(pinEntry: String){
eventSink(SetupPinEvents.OnPinEntryChanged(pinEntry, isConfirmationStep))
}
private fun createSetupPinPresenter( private fun createSetupPinPresenter(
callback: PinCodeManager.Callback, callback: PinCodeManager.Callback,
lockScreenConfig: LockScreenConfig = aLockScreenConfig( lockScreenConfig: LockScreenConfig = aLockScreenConfig(