From f3c85e8875c8efd535ed9e8a990aaa038a339ef9 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Thu, 14 Feb 2019 12:53:35 -0600 Subject: [PATCH] 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 --- .../fragments/BaseAccountFragment.kt | 2 +- .../fragments/BaseSecurityLockDialog.kt | 73 +++++++++++++++++-- .../fragments/FilterOptionsDialog.kt | 2 +- .../fragments/PINSecurityLockDialog.kt | 34 +++++++-- .../fragments/SettingsFragment.kt | 16 +++- .../res/layout/dialog_pin_security_lock.xml | 1 + 6 files changed, 111 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseAccountFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseAccountFragment.kt index 5a10ead..0a3521a 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseAccountFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseAccountFragment.kt @@ -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!!) 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 501549f..c32aa44 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/BaseSecurityLockDialog.kt @@ -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() } } \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt index ca7ed55..2029ee0 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt @@ -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, 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 acd6da9..f3e1dac 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/PINSecurityLockDialog.kt @@ -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 } + ) } } \ 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 d2c6d7a..9473d43 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt @@ -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. */ 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 e6756a2..c7f96a3 100644 --- a/app/src/main/res/layout/dialog_pin_security_lock.xml +++ b/app/src/main/res/layout/dialog_pin_security_lock.xml @@ -40,6 +40,7 @@ app:layout_constraintTop_toBottomOf="@id/tvTitle"/>