diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt
index 6099f3c..a911d75 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt
@@ -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
}
/**
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt
index df9e30a..8d7603b 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt
@@ -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
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt
index f6b13d4..c8354bf 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt
@@ -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
diff --git a/app/src/main/res/layout/dialog_pin_security_lock.xml b/app/src/main/res/layout/dialog_pin_security_lock.xml
index c7f96a3..5d75a31 100644
--- a/app/src/main/res/layout/dialog_pin_security_lock.xml
+++ b/app/src/main/res/layout/dialog_pin_security_lock.xml
@@ -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" />
@@ -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"/>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 117e636..6c2bea3 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -144,5 +144,12 @@
PIN
Patrón
Ninguno
+ Reingresa tu PIN
+ Digita tu PIN de BiTSy para continuar
+ PIN incorrecto
+ Crea un bloqueo de seguridad para BiTSy
+ Por seguridad, crea un PIN para BiTSy
+ El PIN debe tener al menos 6 dígitos
+ El PIN no concuerda
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 35f6e73..67f7e56 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -145,5 +145,12 @@
PIN
Pattern
None
+ Re-enter your PIN
+ Enter your BiTSy PIN to continue
+ Wrong PIN
+ Set BiTSy screen lock
+ For security, set BiTSy PIN
+ PIN must be at least 6 digits
+ PINs don\'t match