Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/4967
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Bugfix: Hide keyboard and clear error when brute-force countdown ends

The number keyboard has been hidden during the brute-force protection countdown so users cannot interact with it. The wrong-passcode error message has been cleared once the countdown ends, leaving a clean screen for the next attempt.

https://github.com/owncloud/android/issues/4874
https://github.com/owncloud/android/pull/4967
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class PassCodeActivityTest {

private lateinit var timeToUnlockLiveData: MutableLiveData<Event<String>>
private lateinit var finishTimeToUnlockLiveData: MutableLiveData<Event<Boolean>>
private lateinit var statusLiveData: MutableLiveData<Status>
private lateinit var statusLiveData: MutableLiveData<Event<Status>>
private lateinit var passcodeLiveData: MutableLiveData<String>

private lateinit var passCodeViewModel: PassCodeViewModel
Expand Down Expand Up @@ -206,7 +206,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM)))

with(R.id.header) {
isDisplayed(true)
Expand All @@ -224,7 +224,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM)))

// Click dialog's enable option
onView(withText(R.string.common_yes)).perform(click())
Expand All @@ -238,7 +238,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.ERROR))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.ERROR)))

with(R.id.header) {
isDisplayed(true)
Expand Down Expand Up @@ -278,7 +278,7 @@ class PassCodeActivityTest {
// Open Activity in passcode deletion mode
openPasscodeActivity(PassCodeActivity.ACTION_REMOVE)

statusLiveData.postValue(Status(PasscodeAction.REMOVE, PasscodeType.OK))
statusLiveData.postValue(Event(Status(PasscodeAction.REMOVE, PasscodeType.OK)))

assertEquals(activityScenario.result.resultCode, Activity.RESULT_OK)
}
Expand All @@ -288,7 +288,7 @@ class PassCodeActivityTest {
// Open Activity in passcode deletion mode
openPasscodeActivity(PassCodeActivity.ACTION_REMOVE)

statusLiveData.postValue(Status(PasscodeAction.REMOVE, PasscodeType.ERROR))
statusLiveData.postValue(Event(Status(PasscodeAction.REMOVE, PasscodeType.ERROR)))

with(R.id.header) {
isDisplayed(true)
Expand All @@ -311,7 +311,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM)))

onView(withText(R.string.biometric_dialog_title)).check(matches(isDisplayed()))
onView(withText(R.string.common_yes)).check(matches(isDisplayed()))
Expand All @@ -325,7 +325,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM)))

onView(withText(R.string.common_yes)).perform(click())

Expand All @@ -340,7 +340,7 @@ class PassCodeActivityTest {
// Open Activity in passcode creation mode
openPasscodeActivity(PassCodeActivity.ACTION_CREATE)

statusLiveData.postValue(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM))
statusLiveData.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM)))

onView(withText(R.string.common_no)).perform(click())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,15 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet
})
passCodeViewModel.getFinishedTimeToUnlockLiveData.observe(this, Event.EventObserver {
binding.lockTime.visibility = View.INVISIBLE
binding.numberKeyboard.visibility = View.VISIBLE
binding.passcodeError.visibility = View.INVISIBLE
for (editText: EditText? in passCodeEditTexts) {
editText?.isEnabled = true
}
passCodeEditTexts.first()?.requestFocus()
})

passCodeViewModel.status.observe(this) { status ->
passCodeViewModel.status.observe(this, Event.EventObserver { status ->
when (status.action) {
PasscodeAction.CHECK -> {
when (status.type) {
Expand All @@ -260,7 +262,7 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet
}
}
}
}
})

passCodeViewModel.passcode.observe(this) { passcode ->
passCodeEditTexts.forEachIndexed { index, editText ->
Expand Down Expand Up @@ -346,7 +348,10 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet
private fun lockScreen() {
val timeToUnlock = passCodeViewModel.getTimeToUnlockLeft()
if (timeToUnlock > 0) {
binding.passcodeError.setText(R.string.pass_code_wrong)
binding.passcodeError.visibility = View.VISIBLE
binding.lockTime.visibility = View.VISIBLE
binding.numberKeyboard.visibility = View.INVISIBLE
for (editText: EditText? in passCodeEditTexts) {
editText?.isEnabled = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class PassCodeViewModel(
val passcode: LiveData<String>
get() = _passcode

private var _status = MutableLiveData<Status>()
val status: LiveData<Status>
private var _status = MutableLiveData<Event<Status>>()
val status: LiveData<Event<Status>>
get() = _status

private var numberOfPasscodeDigits: Int
Expand Down Expand Up @@ -116,24 +116,24 @@ class PassCodeViewModel(
if (passCode != null && passCode.length < getNumberOfPassCodeDigits()) {
setMigrationRequired(true)
removePassCode()
_status.postValue(Status(PasscodeAction.CHECK, PasscodeType.MIGRATION))
_status.postValue(Event(Status(PasscodeAction.CHECK, PasscodeType.MIGRATION)))
}
_status.postValue(Status(PasscodeAction.CHECK, PasscodeType.OK))
_status.postValue(Event(Status(PasscodeAction.CHECK, PasscodeType.OK)))
resetNumberOfAttempts()
} else {
increaseNumberOfAttempts()
clearPassCode()
_status.postValue(Status(PasscodeAction.CHECK, PasscodeType.ERROR))
_status.postValue(Event(Status(PasscodeAction.CHECK, PasscodeType.ERROR)))
}
}

private fun actionRemovePasscode() {
if (checkPassCodeIsValid(passcodeString.toString())) {
removePassCode()
_status.postValue(Status(PasscodeAction.REMOVE, PasscodeType.OK))
_status.postValue(Event(Status(PasscodeAction.REMOVE, PasscodeType.OK)))
} else {
clearPassCode()
_status.postValue(Status(PasscodeAction.REMOVE, PasscodeType.ERROR))
_status.postValue(Event(Status(PasscodeAction.REMOVE, PasscodeType.ERROR)))
}
}

Expand All @@ -142,13 +142,13 @@ class PassCodeViewModel(
if (!confirmingPassCode) {
requestPassCodeConfirmation()
clearPassCode()
_status.postValue(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM))
_status.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM)))
} else if (confirmPassCode()) {
setPassCode()
_status.postValue(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM))
_status.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM)))
} else {
clearPassCode()
_status.postValue(Status(PasscodeAction.CREATE, PasscodeType.ERROR))
_status.postValue(Event(Status(PasscodeAction.CREATE, PasscodeType.ERROR)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.CHECK, PasscodeType.OK), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.CHECK, PasscodeType.OK), passCodeViewModel.status.value?.peekContent())

verify(exactly = 1) {
preferencesProvider.putInt(PREFERENCE_LOCK_ATTEMPTS, 0)
Expand All @@ -161,7 +161,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.CHECK, PasscodeType.ERROR), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.CHECK, PasscodeType.ERROR), passCodeViewModel.status.value?.peekContent())

verify(exactly = 1) {
preferencesProvider.putInt(PREFERENCE_LOCK_ATTEMPTS, any())
Expand All @@ -180,7 +180,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.REMOVE, PasscodeType.OK), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.REMOVE, PasscodeType.OK), passCodeViewModel.status.value?.peekContent())

verify(exactly = 1) {
preferencesProvider.removePreference(PREFERENCE_PASSCODE)
Expand All @@ -199,7 +199,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.REMOVE, PasscodeType.ERROR), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.REMOVE, PasscodeType.ERROR), passCodeViewModel.status.value?.peekContent())
}

@Test
Expand All @@ -212,7 +212,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.CREATE, PasscodeType.NO_CONFIRM), passCodeViewModel.status.value?.peekContent())
}

@Test
Expand All @@ -231,7 +231,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.CREATE, PasscodeType.CONFIRM), passCodeViewModel.status.value?.peekContent())

verify(exactly = 1) {
preferencesProvider.putString(PREFERENCE_PASSCODE, any())
Expand All @@ -255,7 +255,7 @@ class PassCodeViewModelTest : ViewModelTest() {
passCodeViewModel.onNumberClicked(1)
passCodeViewModel.onNumberClicked(1)

assertEquals(Status(PasscodeAction.CREATE, PasscodeType.ERROR), passCodeViewModel.status.value)
assertEquals(Status(PasscodeAction.CREATE, PasscodeType.ERROR), passCodeViewModel.status.value?.peekContent())
}

@Test
Expand Down