Skip to content

Commit

Permalink
Merge pull request #119 from android/single_tap_sign_in
Browse files Browse the repository at this point in the history
Biometric(Single tap credential creation & sign-in) implementation in MyVault Provider
  • Loading branch information
niharika2810 authored Mar 3, 2025
2 parents 5829293 + ea78f1e commit 50788d1
Show file tree
Hide file tree
Showing 18 changed files with 819 additions and 241 deletions.
4 changes: 4 additions & 0 deletions CredentialProvider/MyVault/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The app demonstrates how to:
- Register as a `CredentialProviderService` so that users can store and retrieve passwords and passkeys using the app.
- Save passwords/passkeys to the app. These are stored locally in a database for demonstration purposes only. In a real app this data should be sent to a server to allow the user's credentials to be synchronized across all their devices.
- Retrieve credentials from the app to assist with user login in another app or website.
- Implement your own biometric prompts for single-tap credential creation and sign-in.
- Delete passkeys or passwords.

# Requirements
Expand Down Expand Up @@ -104,6 +105,9 @@ These additional activities are described below.

For more detailed information on how to create, save and retrieve credentials using the Credential Manager API, refer to the [official documentation]((https://developer.android.com/training/sign-in/credential-provider))

To implement your own biometrics prompt, refer to the [biometrics documentation](https://developer.android.com/identity/sign-in/single-tap-biometric)


## License

The **MyVault Sample** is distributed under the terms of the Apache License (Version 2.0).
Expand Down
4 changes: 2 additions & 2 deletions CredentialProvider/MyVault/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ plugins {
android {
namespace = "com.example.android.authentication.myvault"

compileSdkPreview = "VanillaIceCream"
compileSdk = 35

defaultConfig {
applicationId = "com.example.android.authentication.myvault"
minSdk = 34
targetSdkPreview = "VanillaIceCream"
targetSdk= 35
versionCode = 1
versionName = "1.0"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object AppDependencies {

var providerIcon: Icon? = null

lateinit var RPIconDataSource: RPIconDataSource
lateinit var rpIconDataSource: RPIconDataSource

/**
* Initializes the core components required for the application's data storage and icon handling.
Expand All @@ -63,7 +63,7 @@ object AppDependencies {
.fallbackToDestructiveMigration()
.build()

RPIconDataSource = RPIconDataSource(context.applicationInfo.dataDir)
rpIconDataSource = RPIconDataSource(context.applicationInfo.dataDir)
providerIcon = Icon.createWithResource(context, R.drawable.android_secure)

credentialsRepository =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.authentication.myvault

import android.annotation.SuppressLint
import android.content.Context
import androidx.credentials.provider.BiometricPromptResult

/**
* Utility class for handling biometric authentication errors.
*
* <p>This class provides a collection of static utility methods for managing
* and processing errors that may occur during biometric authentication flows.
* It encapsulates the logic for extracting error information from
* {@link BiometricPromptResult} objects and constructing user-friendly error
* messages.
*
* <p>The primary function of this class is to centralize the error-handling
* logic related to biometric authentication, promoting code reuse and
* maintainability.
*/
object BiometricErrorUtils {

/**
* Checks if there was an error during the biometric authentication flow and returns an error message if so.
*
* <p>This method determines whether the biometric authentication flow resulted in
* an error. It checks if the {@link BiometricPromptResult} is null or if the
* authentication was successful. If neither of these conditions is met, it
* extracts the error code and message from the {@link BiometricPromptResult},
* constructs an error message, and returns it.
*
* <p>The error message is built using the following format:
* "Biometric Error Code: [errorCode] [errorMessage] Other providers may be available."
*
* @param context The context used to retrieve string resources.
* @param biometricPromptResult The result of the biometric authentication prompt.
* @return An error message if there was an error during the biometric flow, or an empty string otherwise.
*/
@SuppressLint("StringFormatMatches")
fun getBiometricErrorMessage(
context: Context,
biometricPromptResult: BiometricPromptResult?,
): String {
// If the biometricPromptResult is null, there was no error.
if (biometricPromptResult == null) return context.getString(R.string.empty)

// If the biometricPromptResult indicates success, there was no error.
if (biometricPromptResult.isSuccessful) return context.getString(R.string.empty)

// Initialize default values for the error code and message.
var biometricAuthErrorCode = -1
var biometricAuthErrorMsg = context.getString(R.string.unknown_failure)

// Check if there is an authentication error in the biometricPromptResult.
if (biometricPromptResult.authenticationError != null) {
// Extract the error code and message from the authentication error.
biometricAuthErrorCode = biometricPromptResult.authenticationError!!.errorCode
biometricAuthErrorMsg = biometricPromptResult.authenticationError!!.errorMsg.toString()
}

// Build the error message to be sent to the client.
val errorMessage = buildString {
append(
context.getString(
R.string.biometric_error_code_with_message,
biometricAuthErrorCode,
),
)
append(biometricAuthErrorMsg)
append(context.getString(R.string.other_providers_error_message))
}

// Indicate that there was an error during the biometric flow.
return errorMessage
}
}
Loading

0 comments on commit 50788d1

Please sign in to comment.