Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e3a96cf authored by Kevin Chyn's avatar Kevin Chyn Committed by Automerger Merge Worker
Browse files

Merge "Make FingerprintManager show BiometricPrompt for UDFPS" into sc-dev am: b92e7e8a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13501293

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ibde25c97f0f75342a940ee532393ed81c494eabe
parents f25b09f2 b92e7e8a
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Slog;

@@ -46,6 +45,13 @@ public class BiometricManager {

    private static final String TAG = "BiometricManager";

    /**
     * An ID that should match any biometric sensor on the device.
     *
     * @hide
     */
    public static final int SENSOR_ID_ANY = -1;

    /**
     * No error detected.
     */
@@ -139,7 +145,7 @@ public class BiometricManager {
         *
         * <p>This corresponds to {@link KeyProperties#AUTH_BIOMETRIC_STRONG} during key generation.
         *
         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
         * @see android.security.keystore.KeyGenParameterSpec.Builder
         */
        int BIOMETRIC_STRONG = 0x000F;

@@ -182,7 +188,7 @@ public class BiometricManager {
         * <p>This corresponds to {@link KeyProperties#AUTH_DEVICE_CREDENTIAL} during key
         * generation.
         *
         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
         * @see android.security.keystore.KeyGenParameterSpec.Builder
         */
        int DEVICE_CREDENTIAL = 1 << 15;
    }
+65 −12
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.security.identity.IdentityCredential;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -325,7 +324,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
         * request authentication with the proper set of authenticators (e.g. match the
         * authenticators specified during key generation).
         *
         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
         * @see android.security.keystore.KeyGenParameterSpec.Builder
         * @see KeyProperties#AUTH_BIOMETRIC_STRONG
         * @see KeyProperties#AUTH_DEVICE_CREDENTIAL
         *
@@ -364,6 +363,21 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            return this;
        }

        /**
         * If set, authenticate using the biometric sensor with the given ID.
         *
         * @param sensorId The ID of a biometric sensor, or -1 to allow any sensor (default).
         * @return This builder.
         *
         * @hide
         */
        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
        @NonNull
        public Builder setSensorId(int sensorId) {
            mPromptInfo.setSensorId(sensorId);
            return this;
        }

        /**
         * Creates a {@link BiometricPrompt}.
         *
@@ -589,7 +603,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
     *
     * <p>Cryptographic operations in Android can be split into two categories: auth-per-use and
     * time-based. This is specified during key creation via the timeout parameter of the
     * {@link KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)} API.
     * {@code setUserAuthenticationParameters(int, int)} method of {@link
     * android.security.keystore.KeyGenParameterSpec.Builder}.
     *
     * <p>CryptoObjects are used to unlock auth-per-use keys via
     * {@link BiometricPrompt#authenticate(CryptoObject, CancellationSignal, Executor,
@@ -778,6 +793,27 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AuthenticationCallback callback,
            int userId) {
        authenticateUserForOperation(cancel, executor, callback, userId, 0 /* operationId */);
    }

    /**
     * Authenticates for the given user and keystore operation.
     *
     * @param cancel An object that can be used to cancel authentication
     * @param executor An executor to handle callback events
     * @param callback An object to receive authentication events
     * @param userId The user to authenticate
     * @param operationId The keystore operation associated with authentication
     *
     * @hide
     */
    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
    public void authenticateUserForOperation(
            @NonNull CancellationSignal cancel,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AuthenticationCallback callback,
            int userId,
            long operationId) {
        if (cancel == null) {
            throw new IllegalArgumentException("Must supply a cancellation signal");
        }
@@ -787,7 +823,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        if (callback == null) {
            throw new IllegalArgumentException("Must supply a callback");
        }
        authenticateInternal(null /* crypto */, cancel, executor, callback, userId);
        authenticateInternal(operationId, cancel, executor, callback, userId);
    }

    /**
@@ -912,11 +948,31 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        }
    }

    private void authenticateInternal(@Nullable CryptoObject crypto,
    private void authenticateInternal(
            @Nullable CryptoObject crypto,
            @NonNull CancellationSignal cancel,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AuthenticationCallback callback,
            int userId) {

        mCryptoObject = crypto;
        final long operationId = crypto != null ? crypto.getOpId() : 0L;
        authenticateInternal(operationId, cancel, executor, callback, userId);
    }

    private void authenticateInternal(
            long operationId,
            @NonNull CancellationSignal cancel,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AuthenticationCallback callback,
            int userId) {

        // Ensure we don't return the wrong crypto object as an auth result.
        if (mCryptoObject != null && mCryptoObject.getOpId() != operationId) {
            Log.w(TAG, "CryptoObject operation ID does not match argument; setting field to null");
            mCryptoObject = null;
        }

        try {
            if (cancel.isCanceled()) {
                Log.w(TAG, "Authentication already canceled");
@@ -925,13 +981,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
                cancel.setOnCancelListener(new OnAuthenticationCancelListener());
            }

            mCryptoObject = crypto;
            mExecutor = executor;
            mAuthenticationCallback = callback;
            final long operationId = crypto != null ? crypto.getOpId() : 0;

            final PromptInfo promptInfo;
            if (crypto != null) {
            if (operationId != 0L) {
                // Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
                // Note that we use a new PromptInfo here so as to not overwrite the application's
                // preference, since it is possible that the same prompt configuration be used
@@ -952,10 +1006,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan

        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception while authenticating", e);
            mExecutor.execute(() -> {
                callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                        mContext.getString(R.string.biometric_error_hw_unavailable));
            });
            mExecutor.execute(() -> callback.onAuthenticationError(
                    BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                    mContext.getString(R.string.biometric_error_hw_unavailable)));
        }
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ public class PromptInfo implements Parcelable {
    private @BiometricManager.Authenticators.Types int mAuthenticators;
    private boolean mDisallowBiometricsIfPolicyExists;
    private boolean mReceiveSystemEvents;
    private int mSensorId = -1;

    public PromptInfo() {

@@ -59,6 +60,7 @@ public class PromptInfo implements Parcelable {
        mAuthenticators = in.readInt();
        mDisallowBiometricsIfPolicyExists = in.readBoolean();
        mReceiveSystemEvents = in.readBoolean();
        mSensorId = in.readInt();
    }

    public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -93,6 +95,7 @@ public class PromptInfo implements Parcelable {
        dest.writeInt(mAuthenticators);
        dest.writeBoolean(mDisallowBiometricsIfPolicyExists);
        dest.writeBoolean(mReceiveSystemEvents);
        dest.writeInt(mSensorId);
    }

    public boolean containsPrivateApiConfigurations() {
@@ -166,6 +169,10 @@ public class PromptInfo implements Parcelable {
        mReceiveSystemEvents = receiveSystemEvents;
    }

    public void setSensorId(int sensorId) {
        mSensorId = sensorId;
    }

    // Getters

    public CharSequence getTitle() {
@@ -226,4 +233,8 @@ public class PromptInfo implements Parcelable {
    public boolean isReceiveSystemEvents() {
        return mReceiveSystemEvents;
    }

    public int getSensorId() {
        return mSensorId;
    }
}
+22 −29
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
@@ -56,8 +55,6 @@ import android.security.identity.IdentityCredential;
import android.util.Slog;
import android.view.Surface;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.Signature;
import java.util.ArrayList;
import java.util.List;
@@ -98,13 +95,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    public static final int SENSOR_ID_ANY = -1;

    /**
     * @hide
     */
    @IntDef({SENSOR_ID_ANY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SensorId {}

    private IFingerprintService mService;
    private Context mContext;
    private IBinder mToken = new Binder();
@@ -508,8 +498,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
            @NonNull AuthenticationCallback callback, Handler handler, @SensorId int sensorId,
            int userId) {
            @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId) {

        if (callback == null) {
            throw new IllegalArgumentException("Must supply an authentication callback");
        }
@@ -653,15 +643,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void generateChallenge(int userId, GenerateChallengeCallback callback) {
        final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
                getSensorPropertiesInternal();
        if (fingerprintSensorProperties.isEmpty()) {
        final FingerprintSensorPropertiesInternal sensorProps = getFirstFingerprintSensor();
        if (sensorProps == null) {
            Slog.e(TAG, "No sensors");
            return;
        }

        final int sensorId = fingerprintSensorProperties.get(0).sensorId;
        generateChallenge(sensorId, userId, callback);
        generateChallenge(sensorProps.sensorId, userId, callback);
    }

    /**
@@ -681,20 +668,20 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void revokeChallenge(int userId, long challenge) {
        if (mService != null) try {
            final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
                    getSensorPropertiesInternal();
            if (fingerprintSensorProperties.isEmpty()) {
        if (mService != null) {
            try {
                final FingerprintSensorPropertiesInternal sensorProps = getFirstFingerprintSensor();
                if (sensorProps == null) {
                    Slog.e(TAG, "No sensors");
                    return;
                }
            final int sensorId = fingerprintSensorProperties.get(0).sensorId;
            mService.revokeChallenge(mToken, sensorId, userId, mContext.getOpPackageName(),
                    challenge);
                mService.revokeChallenge(mToken, sensorProps.sensorId, userId,
                        mContext.getOpPackageName(), challenge);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

    /**
     * Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
@@ -1161,6 +1148,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        }
    }

    @Nullable
    private FingerprintSensorPropertiesInternal getFirstFingerprintSensor() {
        final List<FingerprintSensorPropertiesInternal> allSensors = getSensorPropertiesInternal();
        return allSensors.isEmpty() ? null : allSensors.get(0);
    }

    private void cancelEnrollment() {
        if (mService != null) try {
            mService.cancelEnrollment(mToken);
+2 −0
Original line number Diff line number Diff line
@@ -1585,6 +1585,8 @@

    <!-- Template to be used to name enrolled fingerprints by default. -->
    <string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint. [CHAR LIMIT=70] -->
    <string name="fingerprint_dialog_default_subtitle">Use your fingerprint to continue</string>

    <!-- Array containing custom error messages from vendor.  Vendor is expected to add and translate these strings -->
    <string-array name="fingerprint_error_vendor">
Loading