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.

master
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>