6

I am looking to get started with the Marshmallow Fingerprint Authentication API. I understand that to ask for permission, I must use the following method:

ContextCompat.checkSelfPermission(getContext(), Manifest.permission.USE_FINGERPRINT);

And I must check if the device is running API level 23 or higher. But before I ask for permission, I would like to check if the device actually has a fingerprint scanner to begin with. I found the following two methods to do this check:

FingerprintManager manager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);

manager.isHardwareDetected();

manager.hasEnrolledFingerprints();

But both methods require USE_FINGERPRINT permission to be called at all. Why would I want to ask for permission to use a fingerprint scanner that I do not even know exists? Are there any other methods to find out if a scanner exists? Or is the only way to ask for permission first?

Bryan
  • 14,756
  • 10
  • 70
  • 125
  • 2
    `USE_FINGERPRINT` is a normal permission - once it is in your manifest you will always have it and you don't need to use `ContextCompat.checkSelfPermission()`. – ianhanniballake Feb 09 '16 at 21:10
  • @ianhanniballake Oh, that seems to be true. Why then would it throw a `SecurityException`? Shouldn't it just be a compiler error or something? The `VIBRATOR_SERVICE` requires a normal permission as well, and it doesn't throw any exceptions. – Bryan Feb 09 '16 at 21:17

4 Answers4

11

I just found the class FingerprintManagerCompat, which does exactly what you would expect:

A class that coordinates access to the fingerprint hardware.

On platforms before M, this class behaves as there would be no fingerprint hardware available.

The same methods from FingerprintManager in this class do not require USE_FINGERPRINT permission, enabling you to call them before you ask for USE_FINGERPRINT permission.

FingerprintManagerCompat manager = FingerprintManagerCompat.from(mContext);

manager.isHardwareDetected();
manager.hasEnrolledFingerprints();

These methods will also yield the expected false results on pre-Marshmallow devices.

Community
  • 1
  • 1
Bryan
  • 14,756
  • 10
  • 70
  • 125
  • FingerprintManagerCompat is decprecated. – Rohit Singh Jan 29 '22 at 15:36
  • @RohitSingh That it is. My team has moved away from using biometrics since this post, so I haven't kept up with the relevant APIs. I hope they're a bit easier to use by now. – Bryan Jan 31 '22 at 15:15
6

Try hasSystemFeature(PackageManager.FEATURE_FINGERPRINT) on a PackageManager instance (you can get one from calling getPackageManager() on any handy Context).

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • This looks promising, but I am a little wary considering this method does not require API level 23. Will this return true if the device has a pre-Marshmallow scanner (say, on a Samsung device), or a scanner that is not interoperable with the Fingerprint Authentication API? If so, then on those devices I would be in the same predicament I am in now. – Bryan Feb 09 '16 at 21:10
  • 1
    @Bryan: "I am a little wary considering this method does not require API level 23" -- the method doesn't, but `FEATURE_FINGERPRINT` does. Only call it on API Level 23+ devices; I have no idea what happens if you pass in an unrecognized feature name to `hasSystemFeature()`. – CommonsWare Feb 09 '16 at 21:11
  • 1
    @Bryan: "or a scanner that is not interoperable with the Fingerprint Authentication API?" -- that, I can't say. That's what the `FingerprintManager` methods are for. Your objective should be to filter out cases where you clearly don't need the `USE_FINGERPRINT` permission. If it's conceivable that you have fingerprint capability, then ask for the permission and reconfirm availability with `FingerprintManager`. – CommonsWare Feb 09 '16 at 21:15
  • Ah, I see. This should work, though unfortunately I don't have any of the said devices to test on. If I can get my hands on one, I will test it out and report back. For now I will plan for the worst-case scenario. – Bryan Feb 09 '16 at 21:27
  • see my comment answer below – simplatek Jul 09 '18 at 18:28
  • This always returns false for API 23. Works fine for API 24 and above. – Rohit Singh Jan 29 '22 at 15:35
  • @RohitSingh: "This always returns false for API 23" -- that will depend on the hardware. It should only return `true` for devices where the fingerprint sensor is available to apps via the Android SDK. Particularly for devices that shipped with an earlier version of Android and were upgraded to Android 6.0 (API Level 23), I would not be at all surprised for the device to have a fingerprint sensor but not have it available to apps. – CommonsWare Jan 29 '22 at 15:48
  • But when I use an Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null); the biometric prompt is shown. \ – Rohit Singh Jan 29 '22 at 15:57
  • @RohitSingh: Yes, but that does not necessarily involve biometrics. It happens to do so on your device as you have it set up. I would expect `FingerprintManager` to not work on a device where `FEATURE_FINGERPRINT` is unavailable. – CommonsWare Jan 29 '22 at 16:06
1

FingerprintManager class supports Android devices running on API 23 or higher and throws an exception on devices running lower Android versions.

FingerprintManagerCompat class give backward compatibility of isHardwareDetected method in lower Android Version but it always returns false for API 23 or higher

I picked best of both and created this method to check for FingerPrint Sensor hardware support in all Android version.

  private boolean isSensorAvialable() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return ActivityCompat.checkSelfPermission(AppContext, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED &&
                    AppContext.getSystemService(FingerprintManager.class).isHardwareDetected();
        } else {
            return FingerprintManagerCompat.from(AppContext).isHardwareDetected();
        }
    }
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
1

@CommonsWare mentioned something important, hasSystemFeature. To be on the safe side, if your using Java, make sure you call hasSystemFeature or check for null FingerprintManager return value when calling getSystermService even on devices running API 23 or higher. For Kotlin, use an optional variable and do a smart cast when calling getSystemService to avoid unpredictable crashes in the wild for devices without the Fingerprint hardware but running API 23 or greater.

simplatek
  • 637
  • 7
  • 7