6
votes

I recently moved my project to AndroidX and while implementing fingerprint for the app I am using the Biometric for AndroidX.

implementation 'androidx.biometric:biometric:1.0.0-alpha03'

When a dialog is displayed to use fingerprint for authentication, the dialog has "Cancel" option set as the negative button.

 final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
            .setTitle("Log into App")
            .setSubtitle("Please touch the fingerprint sensor to log you in")
            .setDescription("Touch Sensor")
            .setNegativeButtonText("Cancel".toUpperCase())
            .build();

As per the android documentation: https://developer.android.com/reference/androidx/biometric/BiometricPrompt.PromptInfo.Builder.html#setNegativeButtonText(java.lang.CharSequence)

Required: Set the text for the negative button. 
This would typically be used as a "Cancel" button, but may be also used
to show an alternative method for authentication, 
such as screen that asks for a backup password.

So instead of "Cancel" button I can say "Use Password" to provide an alternative method incase fingerprint fails, and when user clicks on it I can show another popup dialog where I can let user enter the device password to help retrieve the app password from the Keystore. Is this correct ?

But, what happens if I do not have password set to unlock my phone instead I use a pattern ?

I see that if I use android.hardware.biometrics.BiometricPrompt.Builder instead of androidx.biometric.BiometricPrompt.PromptInfo.Builder, it has a method https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt.Builder.html#setDeviceCredentialAllowed(boolean) for the same purpose, to let user authenticate using other means if fingerprint fails.

Can someone help me understand this ? How I could achieve this with AndroidX as my app is compatible from API 16 onwards. And why does AndroidX does not come back with this fallback method ?

4
I am using alpha04, but setDeviceCredentialAllowed() isn’t available. I thought the whole idea of using AndroidX components is to avoid using SDK level code... Maybe Google is planning to add that in the future?Takeshi Kaga

4 Answers

3
votes

The setDeviceCredentialAllowed API was recently added in beta01

See the release notes here

https://developer.android.com/jetpack/androidx/releases/biometric

1
votes

On SDK version Q and above using BiometricPrompt with authentication callback otherwise using createConfirmDeviceCredentialsIntent.

val km = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    val biometricPrompt = BiometricPrompt.Builder(this)
            .setTitle(getString(R.string.screen_lock_title))
            .setDescription(getString(R.string.screen_lock_desc))
            .setDeviceCredentialAllowed(true)
            .build()

    val cancellationSignal = CancellationSignal()
    cancellationSignal.setOnCancelListener {
        println("@Biometric cancellationSignal.setOnCancelListener")
        //handle cancellation
    }

    val executors = mainExecutor
    val authCallBack = object : BiometricPrompt.AuthenticationCallback() {
        override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
            super.onAuthenticationError(errorCode, errString)
            print("SecuritySetupActivity.onAuthenticationError ")
            println("@Biometric errorCode = [${errorCode}], errString = [${errString}]")
            //handle authentication error
        }

        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) {
            super.onAuthenticationSucceeded(result)
            print("SecuritySetupActivity.onAuthenticationSucceeded ")
            println("@Biometric result = [${result}]")

            //handle authentication success
        }

        override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence?) {
            super.onAuthenticationHelp(helpCode, helpString)
            print("SecuritySetupActivity.onAuthenticationHelp ")
            println("@Biometric helpCode = [${helpCode}], helpString = [${helpString}]")
        }

        override fun onAuthenticationFailed() {
            super.onAuthenticationFailed()
            print("SecuritySetupActivity.onAuthenticationFailed ")

            //handle authentication failed
        }
    }



    biometricPrompt.authenticate(cancellationSignal, executors, authCallBack)


} else {
    val i = km.createConfirmDeviceCredentialIntent(getString(R.string.screen_lock_title), getString(R.string.screen_lock_desc))
    startActivityForResult(i, 100)
}
-1
votes

Try setDeviceCredentialAllowed(true) on BiometricPromopt.

-4
votes

androidx 1.0.0 allows you to setup a fallback with ease - like this:

    // Allows user to authenticate using either a Class 3 biometric or
    // their lock screen credential (PIN, pattern, or password).
    promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        // Can't call setNegativeButtonText() and
        // setAllowedAuthenticators(... or DEVICE_CREDENTIAL) at the same time.
        // .setNegativeButtonText("Use account password")
        .setAllowedAuthenticators(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
        .build()

see this