3
votes

The documentation of BiometricPrompt.PromptInfo's setDeviceCredentialAllowed method states:

[...] Developers should first check KeyguardManager.isDeviceSecure() before enabling this. If the device is not secure, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL will be returned in BiometricPrompt.AuthenticationCallback.onAuthenticationError(int, CharSequence).

https://developer.android.com/reference/androidx/biometric/BiometricPrompt.PromptInfo.Builder.html#setDeviceCredentialAllowed(boolean)

However, in order to enable biometric authentication in the first place, you have to set up a device PIN or password. Isn't this check (which is only available on API 23+) therefore superfluous when we already have BiometricManager.canAuthenticate?

1

1 Answers

3
votes

This is a great question! It might be important to provide a step-wise response. First, let's separate what's happening on a particular device vs what's happening in your app. Then we'll address the more specific question.

Device

A device running API 23+ may or may not have device login credentials setup. The owner of a device is not required to setup device PIN, pattern, password, or biometric templates. It's a choice.

App

A user should be able to install your app whether or not device login credentials have been setup. Therefore your app must be written in a way that handles use cases where login credentials haven't been setup.

Answer to your more specific question

The recommendation is that you pass in a CryptoObject to authenticate() when implementing the biometrics API. If you follow that recommendation, then yes, you will check canAuthenticate() before calling authenticate(promptInfo, cryptoObject). There are a number of reasons for this, which you can get from reading the blog post pointed to above.

Since your question is specifically about setDeviceCredentialAllowed(true), it's important to recall what canAuthenticate() does. It checks for three things: whether there is biometric hardware available on the device, whether the user has enrolled templates, or whether the user has enabled biometric authentication.

Hence, you cannot use canAuthenticate() in your case since it's exclusively about biometrics whereas setDeviceCredentialAllowed(true) accepts device PIN, pattern or password.

Note that while the recommendation is that you use CryptoObject, setDeviceCredentialAllowed() is not compatible with CryptoObject nor with setNegativeButtonText().

P.S. You may also benefit from reading this blog post.