Added the functionality to PINSecurityLockDialog to check if the entered PIN corresponds with the current PIN and if that is the case let the calling fragmet about it, so that the fragment can respond accordingly

This commit is contained in:
Severiano Jaramillo 2019-02-14 12:53:35 -06:00
parent 123482e996
commit f3c85e8875
6 changed files with 111 additions and 17 deletions

View file

@ -32,7 +32,7 @@ abstract class BaseAccountFragment : ConnectedFragment() {
* @param accountProperties Account properties object
*/
protected fun onAccountSelected(accountProperties: AccountProperties, pin: String) {
val encryptedPIN = CryptoUtils.encrypt(context!!, pin)
val encryptedPIN = CryptoUtils.encrypt(context!!, pin).trim()
// Stores the user selected PIN encrypted
PreferenceManager.getDefaultSharedPreferences(context!!)

View file

@ -1,8 +1,13 @@
package cy.agorise.bitsybitshareswallet.fragments
import android.app.Dialog
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import cy.agorise.bitsybitshareswallet.utils.Constants
import io.reactivex.disposables.CompositeDisposable
/**
* Encapsulates the shared logic required for the PIN and Pattern Security Lock Fragments.
@ -11,18 +16,72 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
companion object {
/** Used to denote that the user is in the step of creating the preferred security lock option */
const val SECURITY_LOG_STEP_CREATE = 0x01
const val SECURITY_LOG_STEP_CREATE = 1
/** Used to denote that the user is in the step of confirming the just created security lock option */
const val SECURITY_LOG_STEP_CONFIRM = 0x02
/** Used to denote that the user is in the step of confirming the newly created security lock option */
private const val SECURITY_LOG_STEP_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
* current security lock option */
const val SECURITY_LOG_STEP_VERIFY = 0x04
const val SECURITY_LOG_STEP_VERIFY = 3
/** The calling fragment can be calling this dialog to unlock many different things, this variable helps to
* keep track of what action the calling fragment wants to achieve */
const val KEY_ACTION_IDENTIFIER = "key_action_identifier"
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState)
// Container Fragment must implement this interface
interface OnPINPatternEnteredListener {
fun onPINPatternEntered(actionIdentifier: Int)
fun onPINPatternChanged()
}
/** Callback used to notify the parent that a PIN/Pattern has been entered successfully */
protected var mCallback: OnPINPatternEnteredListener? = null
protected var actionIdentifier: Int = 0
/** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */
protected var mDisposables = CompositeDisposable()
/** Current encrypted version of the PIN/Pattern */
protected var currentEncryptedPINPattern: String? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
onAttachToParentFragment(parentFragment)
currentEncryptedPINPattern = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_ENCRYPTED_PIN, "")?.trim()
actionIdentifier = arguments?.getInt(KEY_ACTION_IDENTIFIER) ?: 0
}
/**
* Attaches the current [DialogFragment] to its [Fragment] parent, to initialize the
* [OnPINPatternEnteredListener] interface
*/
private fun onAttachToParentFragment(fragment: Fragment?) {
try {
mCallback = fragment as OnPINPatternEnteredListener
} catch (e: ClassCastException) {
throw ClassCastException("$fragment must implement OnFilterOptionsSelectedListener")
}
}
override fun onResume() {
super.onResume()
// Force dialog fragment to use the full width of the screen
val dialogWindow = dialog.window
dialogWindow?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
}
override fun onDestroy() {
super.onDestroy()
if (!mDisposables.isDisposed) mDisposables.dispose()
}
}

View file

@ -149,7 +149,7 @@ class FilterOptionsDialog : DialogFragment() {
tvEndDate.text = dateFormat.format(date)
}
// Container Activity must implement this interface
// Container Fragment must implement this interface
interface OnFilterOptionsSelectedListener {
fun onFilterOptionsSelected(filterTransactionsDirection: Int,
filterDateRangeAll: Boolean,

View file

@ -4,7 +4,12 @@ import android.os.Bundle
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.CryptoUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.dialog_pin_security_lock.*
/**
* Contains all the specific logic to create and confirm a new PIN or verifying the validity of the current one.
@ -23,14 +28,29 @@ class PINSecurityLockDialog : BaseSecurityLockDialog() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 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 (encryptedPIN == currentEncryptedPINPattern) {
// PIN is correct, proceed
dismiss()
mCallback?.onPINPatternEntered(actionIdentifier)
} else {
tilPIN.error = "Wrong PIN"
}
}
handled = true
}
handled
}
override fun onResume() {
super.onResume()
// Force dialog fragment to use the full width of the screen
val dialogWindow = dialog.window
dialogWindow?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
// Use RxBindings to clear the error when the user edits the PIN
mDisposables.add(
tietPIN.textChanges()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { tilPIN.isErrorEnabled = false }
)
}
}

View file

@ -37,10 +37,12 @@ import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.fragment_settings.*
import java.text.NumberFormat
class SettingsFragment : Fragment(), ServiceConnection {
class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.OnPINPatternEnteredListener {
companion object {
private const val TAG = "SettingsFragment"
private const val ACTION_CHANGE_SECURITY_LOCK = 1
}
private var mDisposables = CompositeDisposable()
@ -214,6 +216,9 @@ class SettingsFragment : Fragment(), ServiceConnection {
when (securityLockSelected) {
0 /* PIN */ -> {
val pinFrag = PINSecurityLockDialog()
val args = Bundle()
args.putInt(BaseSecurityLockDialog.KEY_ACTION_IDENTIFIER, ACTION_CHANGE_SECURITY_LOCK)
pinFrag.arguments = args
pinFrag.show(childFragmentManager, "pin_security_lock_tag")
}
1 /* Pattern */ -> {
@ -225,6 +230,15 @@ class SettingsFragment : Fragment(), ServiceConnection {
}
}
override fun onPINPatternEntered(actionIdentifier: Int) {
if (actionIdentifier == ACTION_CHANGE_SECURITY_LOCK)
showChooseSecurityLockDialog()
}
override fun onPINPatternChanged() {
}
/**
* Shows a dialog so the user can select its desired Security Lock option.
*/

View file

@ -40,6 +40,7 @@
app:layout_constraintTop_toBottomOf="@id/tvTitle"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPIN"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_different_section"