Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: biometric authentication in passcode activity #1455

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ ext {
lifecycleExtensionsVersion = '2.2.0'
activity_version = '1.5.0'
fragment_version = '1.5.0'
biometric = '1.1.0'

// App dependencies
supportLibraryVersion = '28.0.0'
Expand Down
2 changes: 2 additions & 0 deletions mifospay/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version")
implementation "androidx.compose.material:material-icons-extended:$compose_version"

// Biometric Authentication
implementation "androidx.biometric:biometric:$rootProject.biometric"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package org.mifos.mobilewallet.mifospay.passcode.ui
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AlertDialog
import android.view.View
import android.widget.Toast
import androidx.appcompat.widget.AppCompatButton
import butterknife.BindView
import butterknife.ButterKnife
import com.mifos.mobile.passcode.MifosPassCodeActivity
import com.mifos.mobile.passcode.utils.EncryptionUtil
Expand All @@ -19,6 +22,8 @@ import org.mifos.mobilewallet.mifospay.passcode.PassCodeContract
import org.mifos.mobilewallet.mifospay.passcode.PassCodeContract.PassCodeView
import org.mifos.mobilewallet.mifospay.passcode.presenter.PassCodePresenter
import org.mifos.mobilewallet.mifospay.receipt.ui.ReceiptActivity
import org.mifos.mobilewallet.mifospay.utils.BiometricAuthentication
import org.mifos.mobilewallet.mifospay.utils.BiometricCapability
import org.mifos.mobilewallet.mifospay.utils.Constants
import javax.inject.Inject

Expand All @@ -36,9 +41,16 @@ class PassCodeActivity : MifosPassCodeActivity(), PassCodeView {
private var currPass: String? = ""
private var updatePassword = false
private var isInitialScreen = false

@JvmField
@BindView(R.id.btn_save)
var btnSave: AppCompatButton? = null

private var biometricAuthentication: BiometricAuthentication? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

biometricAuthentication = BiometricAuthentication(this)
// can't call getActivityComponent b/c PassCodeActivity class does not extend BaseActivity

isInitialScreen = intent.getBooleanExtra(
Expand All @@ -50,6 +62,20 @@ class PassCodeActivity : MifosPassCodeActivity(), PassCodeView {
updatePassword = intent.getBooleanExtra(Constants.UPDATE_PASSCODE, false)
}
ButterKnife.bind(this)
if (btnSave?.text?.equals(getString(R.string.use_touch_id)) == true) {
biometricAuthentication?.authenticateWithBiometrics()
}
if (biometricAuthentication?.getBiometricCapabilities() == BiometricCapability.HAS_BIOMETRIC_AUTH) {
if (btnSave?.visibility == View.GONE) {
btnSave?.visibility = View.VISIBLE
btnSave?.text = getString(R.string.use_touch_id)
btnSave?.setOnClickListener {
biometricAuthentication?.authenticateWithBiometrics()
}
}
} else if (biometricAuthentication?.getBiometricCapabilities() == BiometricCapability.NOT_SUPPORTED) {
startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
}
deepLinkURI = intent.getStringExtra("uri")
}

Expand Down Expand Up @@ -115,6 +141,13 @@ class PassCodeActivity : MifosPassCodeActivity(), PassCodeView {
finish()
}

override fun onResume() {
if (btnSave?.text?.equals(getString(R.string.use_touch_id)) == true) {
biometricAuthentication?.authenticateWithBiometrics()
}
super.onResume()
}

override fun onBackPressed() {
super.onBackPressed()
saveCurrentPasscode()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.mifos.mobilewallet.mifospay.utils

import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED
import androidx.activity.result.ActivityResultLauncher
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.home.ui.MainActivity

open class BiometricAuthentication(
val context: FragmentActivity,
) {
private val executor = ContextCompat.getMainExecutor(context)
private val callback = object : BiometricPrompt.AuthenticationCallback() {

override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
context.startActivity(intent)
context.finish()
}
}

private val biometricPrompt = BiometricPrompt(context, executor, callback)

fun launchBiometricEnrollment(resultLauncher: ActivityResultLauncher<Intent>) {
val intent: Intent = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
Intent(Settings.ACTION_BIOMETRIC_ENROLL).putExtra(
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.BIOMETRIC_WEAK,
)
}

Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> {
Intent(Settings.ACTION_FINGERPRINT_ENROLL)
}

else -> {
Intent(Settings.ACTION_SECURITY_SETTINGS)
}
}
resultLauncher.launch(intent)
}

fun getBiometricCapabilities(): BiometricCapability {
val biometricManager = BiometricManager.from(context)
return when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK or BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
BiometricManager.BIOMETRIC_SUCCESS -> {
BiometricCapability.HAS_BIOMETRIC_AUTH
}

BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
BiometricCapability.NOT_ENROLLED
}

else -> {
BiometricCapability.NOT_SUPPORTED
}
}
}

fun authenticateWithBiometrics() {
val promptInfo = BiometricPrompt.PromptInfo.Builder().apply {
setTitle(context.getString(R.string.sign_in_fingerprint))
setDescription(context.getString(R.string.scan_your_fingerprint))
setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
}.build()

biometricPrompt.authenticate(promptInfo)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.mifos.mobilewallet.mifospay.utils

enum class BiometricCapability {
HAS_BIOMETRIC_AUTH, NOT_ENROLLED, NOT_SUPPORTED
}
3 changes: 3 additions & 0 deletions mifospay/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@
<string name="pay">Pay</string>
<string name="welcome_back">Welcome back!</string>
<string name="sign_up">Sign up.</string>
<string name="sign_in_fingerprint">Sign in using fingerprint</string>
<string name="scan_your_fingerprint">Scan your fingerprint</string>
<string name="use_touch_id">Use Touch Id</string>


</resources>
Loading