On Android 15, Credential Manager supports a single tap flow for credential
creation and retrieval. In this flow, the information of the credential being
created, or being used, is displayed directly in the Biometric Prompt, along
with an entrypoint to more options. This simplified process creates a more
efficient and streamlined credential creation and retrieval process.

**Requirements:**

- Biometrics have been set up on the user's device and the user allows them for authentication into applications.
- For sign-in flows, this feature is enabled for single account scenarios only, even if there's multiple credentials (such as passkey and password) available for that account.

## Enable single tap on passkey creation flows

This method's creation steps match the [existing credential creation
process](https://developer.android.com/identity/sign-in/credential-provider#handle-passkey-creation). Within your `BeginCreatePublicKeyCredentialRequest`, use
`handleCreatePasskeyQuery()` to process the request if it is for a passkey.  

    is BeginCreatePublicKeyCredentialRequest -> {
        Log.i(TAG, "Request is passkey type")
        return handleCreatePasskeyQuery(request, passwordCount, passkeyCount)
    }

In your `handleCreatePasskeyQuery()`, include [`BiometricPromptData`](https://developer.android.com/reference/kotlin/androidx/credentials/provider/BiometricPromptData) with
the `CreateEntry` class:  

    val createEntry = CreateEntry(
        // Additional properties...
        biometricPromptData = BiometricPromptData(
            allowedAuthenticators = allowedAuthenticator
        ),
    )

Credential providers should explicitly set the `allowedAuthenticator` property
in the `BiometricPromptData` instance. If this property is not set, the value
defaults to `DEVICE_WEAK`. Set the optional `cryptoObject` property if needed
for your use case.
| **Note:** If the device is configured to use `DEVICE_CREDENTIALS` to require a PIN or passcode for authentication---regardless of whether biometrics are available or enabled---the standard credential manager flow will be used instead of the single-tap flow. This means the provider will always receive a `null` value for `biometricPromptResult` in these scenarios.

## Enable single tap on sign-in passkey flows

Similar to the passkey creation flow, this will follow the existing setup for
[handling user sign-in](https://developer.android.com/identity/sign-in/credential-provider#handle-user-sign-in). Under the `BeginGetPublicKeyCredentialOption`, use
`populatePasskeyData()` to gather the relevant information about the
authentication request:  

    is BeginGetPublicKeyCredentialOption -> {
        // ... other logic

        populatePasskeyData(
            origin,
            option,
            responseBuilder,
            autoSelectEnabled,
            allowedAuthenticator
        )

        // ... other logic as needed
    }

Similar to `CreateEntry`, a `BiometricPromptData` instance is set to the
`PublicKeyCredentialEntry` instance. If not explicitly set,
`allowedAuthenticator` defaults to `BIOMETRIC_WEAK`.  

    PublicKeyCredentialEntry(
        // other properties...

        biometricPromptData = BiometricPromptData(
            allowedAuthenticators = allowedAuthenticator
        )
    )

| **Note:** The user is presented with a biometric authentication option if their device supports it and they have granted permission for its use. The code is similar to the previous example, with the addition of a [`cryptoObject`](https://developer.android.com/reference/androidx/biometric/BiometricPrompt.CryptoObject).

## Handle credential entry selection

While handling the credential entry selection for [passkey creation](https://developer.android.com/identity/sign-in/credential-provider#handle-passkey-credential) or
[passkey selection during sign in](https://developer.android.com/identity/sign-in/credential-provider#passkeys-implement), call the `PendingIntentHandler's
retrieveProviderCreateCredentialRequest`, or
`retrieveProviderGetCredentialRequest`, as appropriate. These return objects
that contain the metadata needed for the provider. For example, when handling
passkey creation entry selection, update your code as shown:  

    val createRequest = PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
    if (createRequest == null) {
        Log.i(TAG, "request is null")
        setUpFailureResponseAndFinish("Unable to extract request from intent")
        return
    }
    // Other logic...

    val biometricPromptResult = createRequest.biometricPromptResult

    // Add your logic based on what needs to be done
    // after getting biometrics

    if (createRequest.callingRequest is CreatePublicKeyCredentialRequest) {
        val publicKeyRequest: CreatePublicKeyCredentialRequest =
            createRequest.callingRequest as CreatePublicKeyCredentialRequest

        if (biometricPromptResult == null) {
            // Do your own authentication flow, if needed
        } else if (biometricPromptResult.isSuccessful) {
            createPasskey(
                publicKeyRequest.requestJson,
                createRequest.callingAppInfo,
                publicKeyRequest.clientDataHash,
                accountId
            )
        } else {
            val error = biometricPromptResult.authenticationError
            // Process the error
        }

        // Other logic...
    }

This example contains information about the biometric flow's success. It also
contains other information about the credential. If the flow fails, use the
error code under `biometricPromptResult.authenticationError` to make decisions.
The error codes returned as part of
`biometricPromptResult.authenticationError.errorCode` are the same error codes
defined in the androidx.biometric library, such as
[androidx.biometric.BiometricPrompt.NO_SPACE](https://developer.android.com/reference/androidx/biometric/BiometricPrompt#ERROR_NO_SPACE()),
[androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS](https://developer.android.com/identity/sign-in/androidx.biometric.BiometricPrompt.NO_SPACE),
[androidx.biometric.BiometricPrompt.ERROR_TIMEOUT](https://developer.android.com/reference/androidx/biometric/BiometricPrompt#ERROR_TIMEOUT()), and similar. The
`authenticationError` will also contain an error message associated with the
`errorCode` that can be displayed on a UI.

Similarly, extract metadata during the `retrieveProviderGetCredentialRequest`.
Check if your biometric flow is `null`. If yes, configure your own biometrics to
authenticate. This is similar to how the [get operation](https://developer.android.com/identity/sign-in/credential-provider#passkeys-implement) is instrumented:  

    val getRequest =
        PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)

    if (getRequest == null) {
        Log.i(TAG, "request is null")
        setUpFailureResponseAndFinish("Unable to extract request from intent")
        return
    }

    // Other logic...

    val biometricPromptResult = getRequest.biometricPromptResult

    // Add your logic based on what needs to be done
    // after getting biometrics

    if (biometricPromptResult == null) {
        // Do your own authentication flow, if necessary
    } else if (biometricPromptResult.isSuccessful) {

        Log.i(TAG, "The response from the biometricPromptResult was ${biometricPromptResult.authenticationResult?.authenticationType}")

        validatePasskey(
            publicKeyRequest.requestJson,
            origin,
            packageName,
            uid,
            passkey.username,
            credId,
            privateKey
        )
    } else {
        val error = biometricPromptResult.authenticationError
        // Process the error
    }

    // Other logic...