Maulik Dodia
Maulik Dodia

Reputation: 1659

Android Biometric API Issue

What I want to achieve: Provide options to login with different biometrics like FingerPrint, FaceId and Iris. I want to give option of using PIN, Password or Pattern incase any biometric sensor doesn't work.

Problem: While user clicks on "Use Password" option it directly goes to the "onAuthenticationError" callback where I'm checking error code for BiometricPrompt.ERROR_NEGATIVE_BUTTON. My concern is, do I need to handle it by myself? I mean do I need to show a dialogPopUp where I will ask user to enter his/her email/username and password and then he/she can login in my app?

What I have done:

dependency:

implementation 'androidx.biometric:biometric:1.2.0-alpha01'

MainActivity.kt

    class MainActivity : AppCompatActivity() {

    private lateinit var executor: Executor
    private lateinit var biometricPrompt: BiometricPrompt

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        executor = ContextCompat.getMainExecutor(this)
        biometricPrompt = createBiometricObject()
    }

    private fun createBiometricObject(): BiometricPrompt {

        return BiometricPrompt(this, executor, object : AuthenticationCallback() {

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)

                if (errorCode == ERROR_NEGATIVE_BUTTON && errString == "Use Password") {
                    // Do I need to create my own DialogPopUp?
                }
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
            }
        })
    }

    fun loginWithBiometrics(view: View) {
        when (BiometricManager.from(this).canAuthenticate(BIOMETRIC_STRONG)) {
            BiometricManager.BIOMETRIC_SUCCESS -> biometricPrompt.authenticate(
                createPromptInfoForBiometrics()
            )
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> Toast.makeText(
                this,
                "Please enroll your biometrics",
                Toast.LENGTH_LONG
            ).show()
            BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> Toast.makeText(
                this,
                "Device not compatible",
                Toast.LENGTH_LONG
            ).show()
            BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> Toast.makeText(
                this,
                "Sensors are available as off now, please try again later!",
                Toast.LENGTH_LONG
            ).show()
            BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> {
                TODO()
            }
            BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> {
                TODO()
            }
            BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> {
                biometricPrompt.authenticate(createPromptInfoForBiometrics())
            }
        }
    }

    private fun createPromptInfoForBiometrics(): BiometricPrompt.PromptInfo {
        return BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric Login")
            .setSubtitle("Please login with your biometrics")
            .setNegativeButtonText("Use Password")
            .setAllowedAuthenticators(BIOMETRIC_STRONG)
            .build()
    }
}

Any help would be appreciated.

Upvotes: 2

Views: 1917

Answers (1)

Ivan Syabro
Ivan Syabro

Reputation: 155

You should try pass DEVICE_CREDENTIAL flag to setAllowedAuthenticators()

BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                //..
                .setAllowedAuthenticators(DEVICE_CREDENTIAL or BIOMETRIC_STRONG)
                .build()

But also make sure you use it with appropriate android API level. According to docs:

Note that not all combinations of authenticator types are supported prior to Android 11 (API 30). Specifically, DEVICE_CREDENTIAL alone is unsupported prior to API 30, and BIOMETRIC_STRONG | DEVICE_CREDENTIAL is unsupported on API 28-29. Setting an unsupported value on an affected Android version will result in an error when calling build().

Upvotes: 3

Related Questions