App'n'roll blog Menu

What is new in Android P — BiometricPrompt

This article was first published by Mariusz Dąbrowski in the App’n’roll Publication on Medium.

This is part of a series of articles about the new APIs available
in Android 9.0:

  1. BiometricPrompt
  2. ImageDecoder and AnimatedImageDrawable
  3. PrecomputedText

The sample application with source code used in this article can be found here.
Code snippets are written in Kotlin.


Fingerprint scanning

Using a fingerprint to unlock a phone or authenticate transactions in mobile applications is becoming more popular. It can be performed faster in comparison to using a password, pin or pattern and it still provides a similar level of security. Nowadays it is hard to imagine any new device released without a fingerprint scanner but let’s go back in time.

The first Android device with a fingerprint sensor was the Motorola Atrix released in 2011. However, developers had to wait until October 2015 in order to use this feature in their applications because the official API was introduced in Android 6.0 — FingerprintManager. Now in Android 9.0 it is deprecated and Google encourages us to use a new API — BiometricPrompt.

Let’s compare those components and see what’s changed.

FingerprintManager in action

FingerprintManager is a simple service. It is responsible for coordinating access to the fingerprint scanner hardware. In order to use it we need to:

Add permission to AndroidManifest.xml:

<uses-permission android:name="android.permission.USE_FINGERPRINT"/>

The permission has the protection level “normal” — so it is granted during app installation and not needed to be requested at runtime.

Obtain service instance from Context:

val fm = context.getSystemService(FingerprintManager::class.java)

FingerprintManager provides a simple API with just three public methods:

  • isHardwareDetected() — check if a device has a fingerprint scanner
  • hasEnrolledFingerprints() — check if a user has added at least one fingerprint
  • authenticate(crypto, cancel, flags, callback, handler)— start listening for the fingerprint authentication events

authenticate(...) method parameters description:

  • crypto — can be null, if a fingerprint is used in decryption then this object should contain a proper cipher
  • cancel— this object can stop the listening on the authentication events
  • flags — should be 0, optional flags
  • callback — this object will receive authentication events
  • handler — can be null, optional handler to handle authentication events

What is missing in FingerprintManager is the UI part — the app needs to build and manage its own UI in order to inform a user that they need to scan their fingerprint. Google has provided some guidelines on how the UI should look and they’ve even prepared a sample implementation. If you still want to use this feature in your app you need to:

  • Design UI, prepare icons, implement fingerprint dialog, manage its state, add custom error handling, add some animations
  • Find some 3rd party library which will make it for you
  • Copy and paste the code from Google sample

None of these solutions are perfect for implementing strictly specified and repeatable functionality such as fingerprint scanning.

Fingerprint dialog from Google sample — idle, error and success state

BiometricPrompt in action

Fortunately the new BiometricPrompt comes to the rescue here. This new component provides both access to fingerprint hardware and it displays the unified system UI. In order to use it we need to:

Add a new permission to AndroidManifest.xml (also protection level “normal”):

<uses-permission android:name="android.permission.USE_BIOMETRIC"/>

Create biometric prompt instance using builder pattern:

val executor = activity.mainExecutor
val cancelListener = DialogInterface.OnClickListener { _, _ -> })
val biometricPrompt = BiometricPrompt.Builder(context)
  .setTitle("Title")
  .setSubtitle("Subtitle")
  .setDescription("Description")
  .setNegativeButton("Cancel", executor, cancelListener)
  .build()

Builder methods:

  • setTitle(…) — required, sets title of the prompt
  • setSubtitle(…) — optionalsets subtitle of the prompt
  • setDescription(…) —optionalsets additional description
  • setNegativeButton(text, executor, listener) — required, label of dismiss button, executor to handle click callback (activity.maingExecutor for UI thread) and action to perform on click

BiometricPrompt provides only one public method:

  • authenticate(crypto, cancel, executor, callback) — display the fingerprint prompt and start listening on the fingerprint authentication events

Parameters are nearly the same as in FingerprintManager so it is very easy to refactor an app to use the new biometric component:

  • crypto— can be null, if a fingerprint is used in decryption then this object should contain a proper cipher
  • cancel— this object can stop listening on the authentication events, in this case it will also dismiss the prompt
  • executor— executor to handle callback events — activity.maingExecutorto handle callback events on UI thread
  • callback— this object will receive fingerprint authentication events
Biometric prompt — idle and error state (on success prompt is dismiss)

Authentication events are also handled very similarly to FingerprintManager — callback object can receive events through four methods:

onAuthenticationSucceeded(…)— scan was performed properly and user biometric was successfully recognized

onAuthenticationFailed()— scan was performed properly but user biometric was not recognized

onAuthenticationHelp(helpCode, helpString) — scan was not performed properly, help code describes what has gone wrong:

onAuthenticationError(errorCode, errString) — error occurred during scanning, error code describes what has gone wrong:

More about BiometricPrompt

The fact that the BiometricPrompt UI is provided by the framework (not by the developer) also implies its consistency across all Android applications.

It will be easier for the user to recognize that an app is requesting a fingerprint scan. If some devices are equipped with a fingerprint scanner built into the device screen, the BiometricPrompt on that device can be customized in order to indicate to the user in which place on the screen they should touch.

BiometricPrompt supports not only fingerprints but also Face and Iris authentication — but in order to test it we need to first wait for devices with proper hardware.

The biggest disadvantage at the moment is that the BiometricPrompt can be used only on Android P and above. In order to use it on older devices we need to wait for the release of a suitable component in the compat library.

Conclusion

BiometricPrompt provides its own unified UI so it is simpler to implement it than using the older approach with FingerprintManager. On the other hand it provides a similar API so refactoring is also very easy. I think that this is a step in the right direction and an example for all API designers, how they should introduce modification in their APIs, in order to make other developers happy.

If you’ve found this article useful please don’t hesitate to share it and if you have any further questions, feel free to comment below.



Close