Reputation: 1659
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
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