BiometricManager
has a canAuthenticate
method that can return either of 4 flags:
when (biometricManager.canAuthenticate()) {
BiometricManager.BIOMETRIC_SUCCESS ->
Log.d("MY_APP_TAG", "App can authenticate using biometrics.")
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
Log.e("MY_APP_TAG", "No biometric features available on this device.")
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
Log.e("MY_APP_TAG", "Biometric features are currently unavailable.")
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
Log.e("MY_APP_TAG", "The user hasn't associated " +
"any biometric credentials with their account.")
}
Now it seems logical to only trigger the BiometricPrompt
if the result of that call is BIOMETRIC_SUCCESS
and otherwise fall back to a different authentication method (i.e. app-specific password).
But if I set setDeviceCredentialAllowed(true)
on the BiometricPrompt, it can still use the device password even if the canAuthenticate
check does not return BIOMETRIC_SUCCESS
(I think in this case it returns BIOMETRIC_ERROR_NONE_ENROLLED
).
I could additionally use KeyguardManager
to check if a pin/password/pattern is set:
val kgm = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (kgm.isDeviceSecure) {
[...]
}
But this only works on API 23+. However, setDeviceCredentialAllowed
works on API levels below 23. But there seems to be no real alternative to check if a device password is set on these older devices
So my question is: With all these different options, what is the correct flow to show the user the appropriate authentication method? How should canAuthenticate
and isDeviceSecure
be used together and what check should be used for API levels below 23?