| /* |
| * Copyright 2020 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 |
| * |
| * http://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 androidx.biometric; |
| |
| import android.os.Build; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.RequiresApi; |
| |
| /** |
| * Uses a common listener interface provided by the client to create and cache authentication |
| * callback objects that are compatible with {@link android.hardware.biometrics.BiometricPrompt} or |
| * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}. |
| */ |
| @SuppressWarnings("deprecation") |
| class AuthenticationCallbackProvider { |
| /** |
| * A listener object that can receive events from either |
| * {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} or |
| * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback}. |
| */ |
| static class Listener { |
| /** |
| * See {@link BiometricPrompt.AuthenticationCallback#onAuthenticationSucceeded( |
| * BiometricPrompt.AuthenticationResult)}. |
| * |
| * @param result An object containing authentication-related data. |
| */ |
| void onSuccess(@NonNull BiometricPrompt.AuthenticationResult result) {} |
| |
| /** |
| * See {@link BiometricPrompt.AuthenticationCallback#onAuthenticationError(int, |
| * CharSequence)}. |
| * |
| * @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) {} |
| |
| /** |
| * Called when a recoverable error/event has been encountered during authentication. |
| * |
| * @param helpMessage A human-readable message that describes the event. |
| */ |
| void onHelp(@Nullable CharSequence helpMessage) {} |
| |
| /** |
| * See {@link BiometricPrompt.AuthenticationCallback#onAuthenticationFailed()}. |
| */ |
| void onFailure() {} |
| } |
| |
| /** |
| * An authentication callback object that is compatible with |
| * {@link android.hardware.biometrics.BiometricPrompt}. |
| */ |
| @Nullable |
| private android.hardware.biometrics.BiometricPrompt.AuthenticationCallback mBiometricCallback; |
| |
| /** |
| * An authentication callback object that is compatible with |
| * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}. |
| */ |
| @Nullable |
| private androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback |
| mFingerprintCallback; |
| |
| /** |
| * A common listener object that will receive all authentication events. |
| */ |
| @SuppressWarnings("WeakerAccess") /* synthetic access */ |
| @NonNull |
| final Listener mListener; |
| |
| /** |
| * Constructs a callback provider that delegates events to the given listener. |
| * |
| * @param listener A listener that will receive authentication events. |
| */ |
| AuthenticationCallbackProvider(@NonNull Listener listener) { |
| mListener = listener; |
| } |
| |
| /** |
| * Provides a callback object that wraps the given listener and is compatible with |
| * {@link android.hardware.biometrics.BiometricPrompt}. |
| * |
| * <p>Subsequent calls to this method for the same provider instance will return the same |
| * callback object. |
| * |
| * @return A callback object that can be passed to |
| * {@link android.hardware.biometrics.BiometricPrompt}. |
| */ |
| @RequiresApi(Build.VERSION_CODES.P) |
| @NonNull |
| android.hardware.biometrics.BiometricPrompt.AuthenticationCallback getBiometricCallback() { |
| if (mBiometricCallback == null) { |
| mBiometricCallback = Api28Impl.createCallback(mListener); |
| } |
| return mBiometricCallback; |
| } |
| |
| /** |
| * Provides a callback object that wraps the given listener and is compatible with |
| * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}. |
| * |
| * <p>Subsequent calls to this method for the same provider instance will return the same |
| * callback object. |
| * |
| * @return A callback object that can be passed to |
| * {@link androidx.core.hardware.fingerprint.FingerprintManagerCompat}. |
| */ |
| @NonNull |
| androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback |
| getFingerprintCallback() { |
| if (mFingerprintCallback == null) { |
| mFingerprintCallback = new androidx.core.hardware.fingerprint.FingerprintManagerCompat |
| .AuthenticationCallback() { |
| @Override |
| public void onAuthenticationError(final int errMsgId, CharSequence errString) { |
| mListener.onError(errMsgId, errString); |
| } |
| |
| @Override |
| public void onAuthenticationHelp(int helpMsgId, final CharSequence helpString) { |
| mListener.onHelp(helpString); |
| } |
| |
| @Override |
| public void onAuthenticationSucceeded(final androidx.core.hardware.fingerprint |
| .FingerprintManagerCompat.AuthenticationResult result) { |
| |
| 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 |
| public void onAuthenticationFailed() { |
| mListener.onFailure(); |
| } |
| }; |
| } |
| return mFingerprintCallback; |
| } |
| |
| /** |
| * 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) |
| private static class Api28Impl { |
| // Prevent instantiation. |
| private Api28Impl() {} |
| |
| /** |
| * Creates a {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} that |
| * delegates events to the given listener. |
| * |
| * @param listener A listener object that will receive authentication events. |
| * @return A new instance of |
| * {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}. |
| */ |
| @NonNull |
| static android.hardware.biometrics.BiometricPrompt.AuthenticationCallback createCallback( |
| @NonNull final Listener listener) { |
| return new android.hardware.biometrics.BiometricPrompt.AuthenticationCallback() { |
| @Override |
| public void onAuthenticationError(int errorCode, CharSequence errString) { |
| listener.onError(errorCode, errString); |
| } |
| |
| @Override |
| public void onAuthenticationHelp( |
| final int helpCode, final CharSequence helpString) { |
| // Don't forward the result to the client, since the dialog takes care of it. |
| } |
| |
| @Override |
| public void onAuthenticationSucceeded( |
| android.hardware.biometrics.BiometricPrompt.AuthenticationResult result) { |
| |
| 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 |
| public void onAuthenticationFailed() { |
| listener.onFailure(); |
| } |
| }; |
| } |
| } |
| } |