Add support for AuthenticationResult#getAuthenticationType()
Updates the AndroidX implementation of BiometricPrompt to add
backwards-compatible support for the
AuthenticationResult#getAuthenticationType() method add in Android 11
(API 30).
Relnote: "Added support for
BiometricPrompt.AuthenticationResult#getAuthenticationType()"
Test: Biometric integration test app on API 27-30.
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Bug: 148223669
Change-Id: Icfad54cdf7baa5719e54464e0d33fc6757bb12c2
diff --git a/biometric/biometric/api/1.1.0-alpha02.txt b/biometric/biometric/api/1.1.0-alpha02.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/1.1.0-alpha02.txt
+++ b/biometric/biometric/api/1.1.0-alpha02.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/api/current.txt b/biometric/biometric/api/current.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/current.txt
+++ b/biometric/biometric/api/current.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/api/public_plus_experimental_1.1.0-alpha02.txt b/biometric/biometric/api/public_plus_experimental_1.1.0-alpha02.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/public_plus_experimental_1.1.0-alpha02.txt
+++ b/biometric/biometric/api/public_plus_experimental_1.1.0-alpha02.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/api/public_plus_experimental_current.txt b/biometric/biometric/api/public_plus_experimental_current.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/public_plus_experimental_current.txt
+++ b/biometric/biometric/api/public_plus_experimental_current.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/api/restricted_1.1.0-alpha02.txt b/biometric/biometric/api/restricted_1.1.0-alpha02.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/restricted_1.1.0-alpha02.txt
+++ b/biometric/biometric/api/restricted_1.1.0-alpha02.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/api/restricted_current.txt b/biometric/biometric/api/restricted_current.txt
index c5d2b64..9a3ee13 100644
--- a/biometric/biometric/api/restricted_current.txt
+++ b/biometric/biometric/api/restricted_current.txt
@@ -28,6 +28,9 @@
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo, androidx.biometric.BiometricPrompt.CryptoObject);
method public void authenticate(androidx.biometric.BiometricPrompt.PromptInfo);
method public void cancelAuthentication();
+ field public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2; // 0x2
+ field public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1; // 0x1
+ field public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1; // 0xffffffff
field public static final int ERROR_CANCELED = 5; // 0x5
field public static final int ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int ERROR_HW_UNAVAILABLE = 1; // 0x1
@@ -51,6 +54,7 @@
}
public static class BiometricPrompt.AuthenticationResult {
+ method public int getAuthenticationType();
method public androidx.biometric.BiometricPrompt.CryptoObject? getCryptoObject();
}
diff --git a/biometric/biometric/src/main/java/androidx/biometric/AuthenticationCallbackProvider.java b/biometric/biometric/src/main/java/androidx/biometric/AuthenticationCallbackProvider.java
index d5dad84..db6e9f0 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/AuthenticationCallbackProvider.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/AuthenticationCallbackProvider.java
@@ -47,7 +47,7 @@
* See {@link BiometricPrompt.AuthenticationCallback#onAuthenticationError(int,
* CharSequence)}.
*
- * @param errorCode An integer ID associated with the error.
+ * @param errorCode An integer ID associated with the error.
* @param errorMessage A human-readable message that describes the error.
*/
void onError(int errorCode, @Nullable CharSequence errorMessage) {}
@@ -104,7 +104,7 @@
* callback object.
*
* @return A callback object that can be passed to
- * {@link android.hardware.biometrics.BiometricPrompt}.
+ * {@link android.hardware.biometrics.BiometricPrompt}.
*/
@RequiresApi(Build.VERSION_CODES.P)
@NonNull
@@ -123,7 +123,7 @@
* callback object.
*
* @return A callback object that can be passed to
- * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}.
+ * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}.
*/
@NonNull
androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback
@@ -144,13 +144,17 @@
@Override
public void onAuthenticationSucceeded(final androidx.core.hardware.fingerprint
.FingerprintManagerCompat.AuthenticationResult result) {
- final BiometricPrompt.AuthenticationResult unwrappedResult =
- result != null
- ? new BiometricPrompt.AuthenticationResult(
- CryptoObjectUtils.unwrapFromFingerprintManager(
- result.getCryptoObject()))
- : new BiometricPrompt.AuthenticationResult(null /* crypto */);
- mListener.onSuccess(unwrappedResult);
+
+ final BiometricPrompt.CryptoObject crypto = result != null
+ ? CryptoObjectUtils.unwrapFromFingerprintManager(
+ result.getCryptoObject())
+ : null;
+
+ final BiometricPrompt.AuthenticationResult resultCompat =
+ new BiometricPrompt.AuthenticationResult(
+ crypto, BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
+
+ mListener.onSuccess(resultCompat);
}
@Override
@@ -163,6 +167,30 @@
}
/**
+ * Nested class to avoid verification errors for methods introduced in Android 11 (API 30).
+ */
+ @RequiresApi(Build.VERSION_CODES.R)
+ private static class Api30Impl {
+ // Prevent instantiation.
+ private Api30Impl() {}
+
+ /**
+ * Gets the authentication type from the given framework authentication result.
+ *
+ * @param result An instance of
+ * {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}.
+ * @return The value returned by calling {@link
+ * android.hardware.biometrics.BiometricPrompt.AuthenticationResult#getAuthenticationType()}
+ * for the given result object.
+ */
+ @BiometricPrompt.AuthenticationResultType
+ static int getAuthenticationType(
+ @NonNull android.hardware.biometrics.BiometricPrompt.AuthenticationResult result) {
+ return result.getAuthenticationType();
+ }
+ }
+
+ /**
* Nested class to avoid verification errors for methods introduced in Android 9.0 (API 28).
*/
@RequiresApi(Build.VERSION_CODES.P)
@@ -176,7 +204,7 @@
*
* @param listener A listener object that will receive authentication events.
* @return A new instance of
- * {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}.
+ * {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}.
*/
@NonNull
static android.hardware.biometrics.BiometricPrompt.AuthenticationCallback createCallback(
@@ -196,13 +224,26 @@
@Override
public void onAuthenticationSucceeded(
android.hardware.biometrics.BiometricPrompt.AuthenticationResult result) {
- final BiometricPrompt.AuthenticationResult unwrappedResult =
- new BiometricPrompt.AuthenticationResult(
- result != null
- ? CryptoObjectUtils.unwrapFromBiometricPrompt(
- result.getCryptoObject())
- : null);
- listener.onSuccess(unwrappedResult);
+
+ final BiometricPrompt.CryptoObject crypto = result != null
+ ? CryptoObjectUtils.unwrapFromBiometricPrompt(result.getCryptoObject())
+ : null;
+
+ @BiometricPrompt.AuthenticationResultType final int authenticationType;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ authenticationType = result != null
+ ? Api30Impl.getAuthenticationType(result)
+ : BiometricPrompt.AUTHENTICATION_RESULT_TYPE_UNKNOWN;
+ } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
+ authenticationType = BiometricPrompt.AUTHENTICATION_RESULT_TYPE_UNKNOWN;
+ } else {
+ authenticationType = BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC;
+ }
+
+ final BiometricPrompt.AuthenticationResult resultCompat =
+ new BiometricPrompt.AuthenticationResult(crypto, authenticationType);
+
+ listener.onSuccess(resultCompat);
}
@Override
diff --git a/biometric/biometric/src/main/java/androidx/biometric/AuthenticatorUtils.java b/biometric/biometric/src/main/java/androidx/biometric/AuthenticatorUtils.java
index db2bbaa..0d380b7 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/AuthenticatorUtils.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/AuthenticatorUtils.java
@@ -26,6 +26,12 @@
* Utilities related to {@link BiometricManager.Authenticators} constants.
*/
class AuthenticatorUtils {
+ /**
+ * A bitmask for the portion of an {@link BiometricManager.AuthenticatorTypes} value related to
+ * biometric sensor class.
+ */
+ private static final int BIOMETRIC_CLASS_MASK = 0x7FFF;
+
// Prevent instantiation.
private AuthenticatorUtils() {}
@@ -128,6 +134,16 @@
}
/**
+ * Checks if any biometric class is included in the given set of allowed authenticator types.
+ *
+ * @param authenticators A bit field representing a set of allowed authenticator types.
+ * @return Whether the allowed authenticator types include one or more biometric classes.
+ */
+ static boolean isSomeBiometricAllowed(@BiometricManager.AuthenticatorTypes int authenticators) {
+ return (authenticators & BIOMETRIC_CLASS_MASK) != 0;
+ }
+
+ /**
* Checks if a <strong>Class 2</strong> (formerly <strong>Weak</strong>) biometric is included
* in the given set of allowed authenticator types.
*
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
index 60c17c7..51831b0 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
@@ -654,9 +654,11 @@
*/
private void handleConfirmCredentialResult(int resultCode) {
if (resultCode == Activity.RESULT_OK) {
- // Device credential auth succeeded. This is incompatible with crypto.
+ // Device credential auth succeeded. This is incompatible with crypto for API <30.
sendSuccessAndDismiss(
- new BiometricPrompt.AuthenticationResult(null /* crypto */));
+ new BiometricPrompt.AuthenticationResult(
+ null /* crypto */,
+ BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL));
} else {
// Device credential auth failed. Assume this is due to the user canceling.
sendErrorAndDismiss(
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java
index 0d75cca..1ada95a 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java
@@ -78,6 +78,40 @@
@interface AuthenticationError {}
/**
+ * Authentication type reported by {@link AuthenticationResult} when the user authenticated via
+ * an unknown method.
+ *
+ * <p>This value may be returned on older Android versions due to partial incompatibility
+ * with a newer API. It does NOT necessarily imply that the user authenticated with a method
+ * other than those represented by {@link #AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL} and
+ * {@link #AUTHENTICATION_RESULT_TYPE_BIOMETRIC}.
+ */
+ public static final int AUTHENTICATION_RESULT_TYPE_UNKNOWN = -1;
+
+ /**
+ * Authentication type reported by {@link AuthenticationResult} when the user authenticated by
+ * entering their device PIN, pattern, or password.
+ */
+ public static final int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 1;
+
+ /**
+ * Authentication type reported by {@link AuthenticationResult} when the user authenticated by
+ * presenting some form of biometric (e.g. fingerprint or face).
+ */
+ public static final int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 2;
+
+ /**
+ * The authentication type that was used, as reported by {@link AuthenticationResult}.
+ */
+ @IntDef({
+ AUTHENTICATION_RESULT_TYPE_UNKNOWN,
+ AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL,
+ AUTHENTICATION_RESULT_TYPE_BIOMETRIC
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AuthenticationResultType {}
+
+ /**
* Tag used to identify the {@link BiometricFragment} attached to the client activity/fragment.
*/
private static final String BIOMETRIC_FRAGMENT_TAG = "androidx.biometric.BiometricFragment";
@@ -161,9 +195,12 @@
*/
public static class AuthenticationResult {
private final CryptoObject mCryptoObject;
+ @AuthenticationResultType private final int mAuthenticationType;
- AuthenticationResult(CryptoObject crypto) {
+ AuthenticationResult(
+ CryptoObject crypto, @AuthenticationResultType int authenticationType) {
mCryptoObject = crypto;
+ mAuthenticationType = authenticationType;
}
/**
@@ -175,6 +212,21 @@
public CryptoObject getCryptoObject() {
return mCryptoObject;
}
+
+ /**
+ * Gets the type of authentication (e.g. device credential or biometric) that was
+ * requested from and successfully provided by the user.
+ *
+ * @return An integer representing the type of authentication that was used.
+ *
+ * @see #AUTHENTICATION_RESULT_TYPE_UNKNOWN
+ * @see #AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL
+ * @see #AUTHENTICATION_RESULT_TYPE_BIOMETRIC
+ */
+ @AuthenticationResultType
+ public int getAuthenticationType() {
+ return mAuthenticationType;
+ }
}
/**
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java
index d7fbdee..f403a81 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java
@@ -302,6 +302,14 @@
@Override
void onSuccess(@NonNull BiometricPrompt.AuthenticationResult result) {
if (isAwaitingResult()) {
+ // Try to infer the authentication type if unknown.
+ if (result.getAuthenticationType()
+ == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_UNKNOWN) {
+ result = new BiometricPrompt.AuthenticationResult(
+ result.getCryptoObject(),
+ getInferredAuthenticationResultType());
+ }
+
setAuthenticationResult(result);
}
}
@@ -544,4 +552,21 @@
liveData.postValue(value);
}
}
+
+ /**
+ * Attempts to infer the type of authenticator that was used to authenticate the user.
+ *
+ * @return The inferred authentication type, or
+ * {@link BiometricPrompt#AUTHENTICATION_RESULT_TYPE_UNKNOWN} if unknown.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ @BiometricPrompt.AuthenticationResultType
+ int getInferredAuthenticationResultType() {
+ @BiometricManager.AuthenticatorTypes final int authenticators = getAllowedAuthenticators();
+ if (AuthenticatorUtils.isSomeBiometricAllowed(authenticators)
+ && !AuthenticatorUtils.isDeviceCredentialAllowed(authenticators)) {
+ return BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC;
+ }
+ return BiometricPrompt.AUTHENTICATION_RESULT_TYPE_UNKNOWN;
+ }
}
diff --git a/biometric/biometric/src/test/java/androidx/biometric/AuthenticatorUtilsTest.java b/biometric/biometric/src/test/java/androidx/biometric/AuthenticatorUtilsTest.java
index 0fa80d7..ef9355c 100644
--- a/biometric/biometric/src/test/java/androidx/biometric/AuthenticatorUtilsTest.java
+++ b/biometric/biometric/src/test/java/androidx/biometric/AuthenticatorUtilsTest.java
@@ -144,6 +144,21 @@
}
@Test
+ public void testIsSomeBiometricAllowed() {
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(0)).isFalse();
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(Authenticators.BIOMETRIC_STRONG))
+ .isTrue();
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(Authenticators.BIOMETRIC_WEAK))
+ .isTrue();
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(Authenticators.DEVICE_CREDENTIAL))
+ .isFalse();
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(
+ Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL)).isTrue();
+ assertThat(AuthenticatorUtils.isSomeBiometricAllowed(
+ Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL)).isTrue();
+ }
+
+ @Test
public void testIsWeakBiometricAllowed() {
assertThat(AuthenticatorUtils.isWeakBiometricAllowed(0)).isFalse();
assertThat(AuthenticatorUtils.isWeakBiometricAllowed(Authenticators.BIOMETRIC_STRONG))
diff --git a/biometric/biometric/src/test/java/androidx/biometric/BiometricFragmentTest.java b/biometric/biometric/src/test/java/androidx/biometric/BiometricFragmentTest.java
index 7c490e7..df7ede4 100644
--- a/biometric/biometric/src/test/java/androidx/biometric/BiometricFragmentTest.java
+++ b/biometric/biometric/src/test/java/androidx/biometric/BiometricFragmentTest.java
@@ -84,7 +84,9 @@
mViewModel.setClientCallback(mAuthenticationCallback);
mViewModel.setAwaitingResult(true);
- mFragment.onAuthenticationSucceeded(new BiometricPrompt.AuthenticationResult(null));
+ mFragment.onAuthenticationSucceeded(
+ new BiometricPrompt.AuthenticationResult(
+ null /* crypto */, BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC));
verify(mAuthenticationCallback).onAuthenticationSucceeded(mResultCaptor.capture());
assertThat(mResultCaptor.getValue().getCryptoObject()).isNull();
diff --git a/biometric/integration-tests/testapp/src/main/java/androidx/biometric/integration/testapp/BiometricTestActivity.kt b/biometric/integration-tests/testapp/src/main/java/androidx/biometric/integration/testapp/BiometricTestActivity.kt
index 617d86b..f3fe670 100644
--- a/biometric/integration-tests/testapp/src/main/java/androidx/biometric/integration/testapp/BiometricTestActivity.kt
+++ b/biometric/integration-tests/testapp/src/main/java/androidx/biometric/integration/testapp/BiometricTestActivity.kt
@@ -120,7 +120,7 @@
result: BiometricPrompt.AuthenticationResult
) {
super.onAuthenticationSucceeded(result)
- log("onAuthenticationSucceeded: crypto = ${result.cryptoObject}")
+ log("onAuthenticationSucceeded: ${result.toDataString()}")
// Encrypt a test payload using the result of crypto-based auth.
if (useCryptoAuthCheckbox.isChecked) {
@@ -256,6 +256,14 @@
private const val PAYLOAD = "hello"
/**
+ * Converts an authentication result object to a string that represents its contents.
+ */
+ private fun BiometricPrompt.AuthenticationResult.toDataString(): String {
+ val typeString = authenticationType.toAuthenticationTypeString()
+ return "crypto = $cryptoObject, type = $typeString"
+ }
+
+ /**
* Converts an authentication status code to a string that represents the status.
*/
private fun Int.toAuthenticationStatusString(): String = when (this) {
@@ -267,7 +275,18 @@
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> "ERROR_NO_HARDWARE"
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED ->
"ERROR_SECURITY_UPDATE_REQUIRED"
- else -> "Unknown error: $this"
+ else -> "Unrecognized error: $this"
+ }
+
+ /**
+ * Converts an authentication result type to a string that represents the method of
+ * authentication.
+ */
+ private fun Int.toAuthenticationTypeString(): String = when (this) {
+ BiometricPrompt.AUTHENTICATION_RESULT_TYPE_UNKNOWN -> "UNKNOWN"
+ BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC -> "BIOMETRIC"
+ BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL -> "DEVICE_CREDENTIAL"
+ else -> "Unrecognized type: $this"
}
/**