Added the options to change the Security Lock option between PIN and None, and force the UI to show the correct one when it is changed.

This commit is contained in:
Severiano Jaramillo 2019-02-14 15:17:29 -06:00
parent b4965d8a01
commit e8e1259314
6 changed files with 150 additions and 26 deletions

View file

@ -18,8 +18,9 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
/** Used to denote that the user is in the step of creating the preferred security lock option */
const val STEP_SECURITY_LOCK_CREATE = 1
/** Used to denote that the user is in the step of confirming the newly created security lock option */
private const val STEP_SECURITY_LOCK_CONFIRM = 2
/** Used to denote that the user is in the step of confirming the newly created security lock option,
* this option should only be used internally */
const val STEP_SECURITY_LOCK_CONFIRM = 2
/** Used to denote that the user is in the step of verifying the current security lock option, to give
* permission to do a security constrained action like sending a transaction or trying to change the
@ -45,10 +46,10 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
protected var mCallback: OnPINPatternEnteredListener? = null
/** Keeps track of the current step, can be create, confirm of verify */
protected var currentStep: Int = 1
protected var currentStep: Int = -1
/** Used so the calling object knows what was the intention to ask for the Security Lock */
protected var actionIdentifier: Int = 0
protected var actionIdentifier: Int = -1
/** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */
protected var mDisposables = CompositeDisposable()
@ -64,9 +65,9 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
currentEncryptedPINPattern = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_ENCRYPTED_PIN, "")?.trim()
currentStep = arguments?.getInt(KEY_STEP_SECURITY_LOCK) ?: 0
currentStep = arguments?.getInt(KEY_STEP_SECURITY_LOCK) ?: -1
actionIdentifier = arguments?.getInt(KEY_ACTION_IDENTIFIER) ?: 0
actionIdentifier = arguments?.getInt(KEY_ACTION_IDENTIFIER) ?: -1
}
/**

View file

@ -1,12 +1,14 @@
package cy.agorise.bitsybitshareswallet.fragments
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.jakewharton.rxbinding3.widget.textChanges
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.utils.CryptoUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.dialog_pin_security_lock.*
@ -25,23 +27,50 @@ class PINSecurityLockDialog : BaseSecurityLockDialog() {
return inflater.inflate(R.layout.dialog_pin_security_lock, container, false)
}
private var newPIN = ""
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupScreen()
// Listens to the event when the user clicks the 'Enter' button in the keyboard and acts accordingly
tietPIN.setOnEditorActionListener { v, actionId, _ ->
var handled = false
if (actionId == EditorInfo.IME_ACTION_GO) {
val encryptedPIN = CryptoUtils.encrypt(v.context, v.text.toString()).trim()
if (currentStep == STEP_SECURITY_LOCK_VERIFY) {
// The user just wants to verify the current encrypted PIN/Pattern
val encryptedPIN = CryptoUtils.encrypt(v.context, v.text.toString()).trim()
if (encryptedPIN == currentEncryptedPINPattern) {
// PIN is correct, proceed
dismiss()
mCallback?.onPINPatternEntered(actionIdentifier)
} else {
tilPIN.error = "Wrong PIN"
tilPIN.error = getString(R.string.error__wrong_pin)
}
} else if (currentStep == STEP_SECURITY_LOCK_CREATE) {
// The user is trying to create a new PIN
if (v.text.toString().trim().length >= Constants.MIN_PIN_LENGTH) {
// Proceed to the next step only if the PIN has the min length
newPIN = v.text.toString().trim()
currentStep = STEP_SECURITY_LOCK_CONFIRM
setupScreen()
}
} else if (currentStep == STEP_SECURITY_LOCK_CONFIRM) {
val pinConfirm = v.text.toString().trim()
if (pinConfirm != newPIN) {
tvTitle.text = getString(R.string.title__pins_dont_match)
} else {
val encryptedPIN = CryptoUtils.encrypt(v.context, v.text.toString()).trim()
// Stores the newly selected PIN, encrypted
PreferenceManager.getDefaultSharedPreferences(v.context).edit()
.putString(Constants.KEY_ENCRYPTED_PIN, encryptedPIN)
.putInt(Constants.KEY_SECURITY_LOCK_SELECTED, 0).apply() // 0 -> PIN
dismiss()
mCallback?.onPINPatternChanged()
}
}
@ -50,11 +79,47 @@ class PINSecurityLockDialog : BaseSecurityLockDialog() {
handled
}
// Use RxBindings to clear the error when the user edits the PIN
mDisposables.add(
tietPIN.textChanges()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { tilPIN.isErrorEnabled = false }
.subscribe {
if (currentStep == STEP_SECURITY_LOCK_VERIFY) {
// Make sure the error is removed when the user types again
tilPIN.isErrorEnabled = false
} else if (currentStep == STEP_SECURITY_LOCK_CREATE) {
// Show the min length requirement for the PIN only when it has not been fulfilled
if (it.trim().length >= Constants.MIN_PIN_LENGTH) {
tilPIN.helperText = ""
} else {
tilPIN.helperText = getString(R.string.msg__min_pin_length)
}
}
}
)
}
private fun setupScreen() {
when (currentStep) {
STEP_SECURITY_LOCK_VERIFY -> {
tvTitle.text = getString(R.string.title__re_enter_your_pin)
tvSubTitle.text = getString(R.string.msg__enter_your_pin)
tilPIN.helperText = ""
tilPIN.isErrorEnabled = false
}
STEP_SECURITY_LOCK_CREATE -> {
tvTitle.text = getString(R.string.title__set_bitsy_screen_lock)
tvSubTitle.text = getString(R.string.msg__set_bitsy_pin)
tilPIN.helperText = getString(R.string.msg__min_pin_length)
tilPIN.isErrorEnabled = false
}
STEP_SECURITY_LOCK_CONFIRM -> {
tvTitle.text = getString(R.string.title__re_enter_your_pin)
tvSubTitle.text = ""
tvSubTitle.visibility = View.GONE
tietPIN.setText("")
tilPIN.helperText = ""
tilPIN.isErrorEnabled = false
}
}
}
}

View file

@ -21,7 +21,6 @@ import cy.agorise.bitsybitshareswallet.adapters.FullNodesAdapter
import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository
import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.utils.CryptoUtils
import cy.agorise.bitsybitshareswallet.utils.toast
import cy.agorise.graphenej.BrainKey
import cy.agorise.graphenej.api.android.NetworkService
import cy.agorise.graphenej.api.android.RxBus
@ -108,15 +107,12 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
// 1 -> Pattern
// 2 -> None
btnViewBrainKey.setOnClickListener {
if (!verifySecurityLock(securityLockSelected, ACTION_SHOW_BRAINKEY))
getBrainkey()
}
tvSecurityLockSelected.text = resources.getStringArray(R.array.security_lock_options)[securityLockSelected]
tvSecurityLock.setOnClickListener { onSecurityLockTextSelected(securityLockSelected) }
tvSecurityLockSelected.setOnClickListener { onSecurityLockTextSelected(securityLockSelected) }
tvSecurityLock.setOnClickListener { onSecurityLockTextSelected() }
tvSecurityLockSelected.setOnClickListener { onSecurityLockTextSelected() }
btnViewBrainKey.setOnClickListener { onShowBrainKeyButtonSelected() }
// Connect to the RxBus, which receives events from the NetworkService
mDisposables.add(
@ -216,7 +212,14 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
}
}
private fun onSecurityLockTextSelected(securityLockSelected: Int) {
private fun onSecurityLockTextSelected() {
val securityLockSelected = PreferenceManager.getDefaultSharedPreferences(context)
.getInt(Constants.KEY_SECURITY_LOCK_SELECTED, 0)
// Security Lock Options
// 0 -> PIN
// 1 -> Pattern
// 2 -> None
if (!verifySecurityLock(securityLockSelected, ACTION_CHANGE_SECURITY_LOCK))
showChooseSecurityLockDialog()
}
@ -231,7 +234,7 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
*/
private fun verifySecurityLock(securityLockSelected: Int, actionIdentifier: Int): Boolean {
return when (securityLockSelected) {
0 /* PIN */ -> {
0 -> { /* PIN */
val pinFrag = PINSecurityLockDialog()
val args = Bundle()
args.putInt(BaseSecurityLockDialog.KEY_STEP_SECURITY_LOCK,
@ -241,7 +244,7 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
pinFrag.show(childFragmentManager, "pin_security_lock_tag")
true
}
1 /* Pattern */ -> {
1 -> { /* Pattern */
true
}
@ -260,7 +263,15 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
}
override fun onPINPatternChanged() {
// Obtain the new Security Lock Option selected and display it in the screen
val securityLockSelected = PreferenceManager.getDefaultSharedPreferences(context)
.getInt(Constants.KEY_SECURITY_LOCK_SELECTED, 0)
// Security Lock Options
// 0 -> PIN
// 1 -> Pattern
// 2 -> None
tvSecurityLockSelected.text = resources.getStringArray(R.array.security_lock_options)[securityLockSelected]
}
/**
@ -271,12 +282,44 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
MaterialDialog(it).show {
title(R.string.title__security_dialog)
listItems(R.array.security_lock_options) {dialog, index, text ->
dialog.context.toast("$text selected!")
when (index) {
0 -> { /* PIN */
val pinFrag = PINSecurityLockDialog()
val args = Bundle()
args.putInt(BaseSecurityLockDialog.KEY_STEP_SECURITY_LOCK,
BaseSecurityLockDialog.STEP_SECURITY_LOCK_CREATE)
args.putInt(BaseSecurityLockDialog.KEY_ACTION_IDENTIFIER, -1)
pinFrag.arguments = args
pinFrag.show(childFragmentManager, "pin_security_lock_tag")
}
1 -> { /* Pattern */
}
else -> { /* None */
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putInt(Constants.KEY_SECURITY_LOCK_SELECTED, 2).apply() // 2 -> None
// Call this function to update the UI
onPINPatternChanged()
}
}
}
}
}
}
private fun onShowBrainKeyButtonSelected() {
val securityLockSelected = PreferenceManager.getDefaultSharedPreferences(context)
.getInt(Constants.KEY_SECURITY_LOCK_SELECTED, 0)
// Security Lock Options
// 0 -> PIN
// 1 -> Pattern
// 2 -> None
if (!verifySecurityLock(securityLockSelected, ACTION_SHOW_BRAINKEY))
getBrainkey()
}
/**
* Obtains the brainKey from the authorities db table for the current user account and if it is not null it passes
* the brainKey to a method to show it in a nice MaterialDialog

View file

@ -19,14 +19,15 @@
android:layout_marginTop="@dimen/spacing_same_topic"
android:src="@drawable/ic_lock"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
app:layout_constraintStart_toStartOf="parent"
android:contentDescription="@string/title__re_enter_your_pin" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_same_topic"
android:text="Enter your PIN"
tools:text="Enter your PIN"
android:textAppearance="@style/TextAppearance.Bitsy.Headline5"
app:layout_constraintTop_toBottomOf="@id/ivLock" />
@ -35,7 +36,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Enter your BiTSy PIN to continue"
tools:text="Enter your BiTSy PIN to continue"
android:textAppearance="@style/TextAppearance.Bitsy.Body1"
app:layout_constraintTop_toBottomOf="@id/tvTitle"/>

View file

@ -144,5 +144,12 @@
<string name="text__pin">PIN</string>
<string name="text__pattern">Patrón</string>
<string name="text__none">Ninguno</string>
<string name="title__re_enter_your_pin">Reingresa tu PIN</string>
<string name="msg__enter_your_pin">Digita tu PIN de BiTSy para continuar</string>
<string name="error__wrong_pin">PIN incorrecto</string>
<string name="title__set_bitsy_screen_lock">Crea un bloqueo de seguridad para BiTSy</string>
<string name="msg__set_bitsy_pin">Por seguridad, crea un PIN para BiTSy</string>
<string name="msg__min_pin_length">El PIN debe tener al menos 6 dígitos</string>
<string name="title__pins_dont_match">El PIN no concuerda</string>
</resources>

View file

@ -145,5 +145,12 @@
<string name="text__pin">PIN</string>
<string name="text__pattern">Pattern</string>
<string name="text__none">None</string>
<string name="title__re_enter_your_pin">Re-enter your PIN</string>
<string name="msg__enter_your_pin">Enter your BiTSy PIN to continue</string>
<string name="error__wrong_pin">Wrong PIN</string>
<string name="title__set_bitsy_screen_lock">Set BiTSy screen lock</string>
<string name="msg__set_bitsy_pin">For security, set BiTSy PIN</string>
<string name="msg__min_pin_length">PIN must be at least 6 digits</string>
<string name="title__pins_dont_match">PINs don\'t match</string>
</resources>