Loading core/java/android/hardware/biometrics/BiometricPrompt.java +50 −117 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ import android.content.DialogInterface; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.security.identity.IdentityCredential; Loading @@ -56,70 +56,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private static final String TAG = "BiometricPrompt"; /** * @hide */ public static final String KEY_TITLE = "title"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_USE_DEFAULT_TITLE = "use_default_title"; /** * @hide */ public static final String KEY_SUBTITLE = "subtitle"; /** * @hide */ public static final String KEY_DESCRIPTION = "description"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_TITLE = "device_credential_title"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_SUBTITLE = "device_credential_subtitle"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_DESCRIPTION = "device_credential_description"; /** * @hide */ public static final String KEY_NEGATIVE_TEXT = "negative_text"; /** * @hide */ public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation"; /** * This is deprecated. Internally we should use {@link #KEY_AUTHENTICATORS_ALLOWED} * @hide */ public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential"; /** * If this key is set, we will ignore {@link #KEY_ALLOW_DEVICE_CREDENTIAL} * @hide */ public static final String KEY_AUTHENTICATORS_ALLOWED = "authenticators_allowed"; /** * If this is set, check the Device Policy Manager for allowed biometrics. * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; /** * Request to receive system events, such as back gesture/button. See * {@link AuthenticationCallback#onSystemEvent(int)} * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_RECEIVE_SYSTEM_EVENTS = "receive_system_events"; /** * Error/help message will show for this amount of time. * For error messages, the dialog will also be dismissed after this amount of time. Loading Loading @@ -197,8 +133,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * A builder that collects arguments to be shown on the system-provided biometric dialog. */ public static class Builder { private final Bundle mBundle; private ButtonInfo mPositiveButtonInfo; private PromptInfo mPromptInfo; private ButtonInfo mNegativeButtonInfo; private Context mContext; Loading @@ -207,7 +142,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @param context The {@link Context} that will be used to build the prompt. */ public Builder(Context context) { mBundle = new Bundle(); mPromptInfo = new PromptInfo(); mContext = context; } Loading @@ -218,7 +153,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mBundle.putCharSequence(KEY_TITLE, title); mPromptInfo.setTitle(title); return this; } Loading @@ -231,7 +166,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @RequiresPermission(USE_BIOMETRIC_INTERNAL) @NonNull public Builder setUseDefaultTitle() { mBundle.putBoolean(KEY_USE_DEFAULT_TITLE, true); mPromptInfo.setUseDefaultTitle(true); return this; } Loading @@ -242,7 +177,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setSubtitle(@NonNull CharSequence subtitle) { mBundle.putCharSequence(KEY_SUBTITLE, subtitle); mPromptInfo.setSubtitle(subtitle); return this; } Loading @@ -253,7 +188,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setDescription(@NonNull CharSequence description) { mBundle.putCharSequence(KEY_DESCRIPTION, description); mPromptInfo.setDescription(description); return this; } Loading @@ -270,13 +205,13 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Nullable CharSequence subtitle, @Nullable CharSequence description) { if (title != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_TITLE, title); mPromptInfo.setDeviceCredentialTitle(title); } if (subtitle != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_SUBTITLE, subtitle); mPromptInfo.setDeviceCredentialSubtitle(subtitle); } if (description != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_DESCRIPTION, description); mPromptInfo.setDeviceCredentialDescription(description); } return this; } Loading Loading @@ -308,7 +243,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (listener == null) { throw new IllegalArgumentException("Listener must not be null"); } mBundle.putCharSequence(KEY_NEGATIVE_TEXT, text); mPromptInfo.setNegativeButtonText(text); mNegativeButtonInfo = new ButtonInfo(executor, listener); return this; } Loading @@ -335,7 +270,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setConfirmationRequired(boolean requireConfirmation) { mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation); mPromptInfo.setConfirmationRequested(requireConfirmation); return this; } Loading @@ -360,7 +295,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Deprecated @NonNull public Builder setDeviceCredentialAllowed(boolean allowed) { mBundle.putBoolean(KEY_ALLOW_DEVICE_CREDENTIAL, allowed); mPromptInfo.setDeviceCredentialAllowed(allowed); return this; } Loading Loading @@ -390,7 +325,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setAllowedAuthenticators(@Authenticators.Types int authenticators) { mBundle.putInt(KEY_AUTHENTICATORS_ALLOWED, authenticators); mPromptInfo.setAuthenticators(authenticators); return this; } Loading @@ -403,8 +338,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setDisallowBiometricsIfPolicyExists(boolean checkDevicePolicyManager) { mBundle.putBoolean(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, checkDevicePolicyManager); mPromptInfo.setDisallowBiometricsIfPolicyExists(checkDevicePolicyManager); return this; } Loading @@ -416,7 +350,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setReceiveSystemEvents(boolean set) { mBundle.putBoolean(KEY_RECEIVE_SYSTEM_EVENTS, set); mPromptInfo.setReceiveSystemEvents(set); return this; } Loading @@ -430,12 +364,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public BiometricPrompt build() { final CharSequence title = mBundle.getCharSequence(KEY_TITLE); final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT); final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE, false); final boolean deviceCredentialAllowed = mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL); final @Authenticators.Types int authenticators = mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, 0); final CharSequence title = mPromptInfo.getTitle(); final CharSequence negative = mPromptInfo.getNegativeButtonText(); final boolean useDefaultTitle = mPromptInfo.isUseDefaultTitle(); final boolean deviceCredentialAllowed = mPromptInfo.isDeviceCredentialAllowed(); final @Authenticators.Types int authenticators = mPromptInfo.getAuthenticators(); final boolean willShowDeviceCredentialButton = deviceCredentialAllowed || (authenticators & Authenticators.DEVICE_CREDENTIAL) != 0; Loading @@ -447,7 +380,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Can't have both negative button behavior" + " and device credential enabled"); } return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo); return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo); } } Loading @@ -461,8 +394,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private final IBinder mToken = new Binder(); private final Context mContext; private final IAuthService mService; private final Bundle mBundle; private final ButtonInfo mPositiveButtonInfo; private final PromptInfo mPromptInfo; private final ButtonInfo mNegativeButtonInfo; private CryptoObject mCryptoObject; Loading Loading @@ -545,14 +477,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Override public void onDialogDismissed(int reason) { // Check the reason and invoke OnClickListener(s) if necessary if (reason == DISMISSED_REASON_BIOMETRIC_CONFIRMED) { mPositiveButtonInfo.executor.execute(() -> { mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE); }); } else if (reason == DISMISSED_REASON_NEGATIVE) { if (reason == DISMISSED_REASON_NEGATIVE) { mNegativeButtonInfo.executor.execute(() -> { mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE); }); } else { Log.e(TAG, "Unknown reason: " + reason); } } Loading @@ -564,11 +494,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } }; private BiometricPrompt(Context context, Bundle bundle, ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) { private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo) { mContext = context; mBundle = bundle; mPositiveButtonInfo = positiveButtonInfo; mPromptInfo = promptInfo; mNegativeButtonInfo = negativeButtonInfo; mService = IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)); Loading @@ -580,7 +508,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public CharSequence getTitle() { return mBundle.getCharSequence(KEY_TITLE, ""); return mPromptInfo.getTitle(); } /** Loading @@ -590,7 +518,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public boolean shouldUseDefaultTitle() { return mBundle.getBoolean(KEY_USE_DEFAULT_TITLE, false); return mPromptInfo.isUseDefaultTitle(); } /** Loading @@ -599,7 +527,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getSubtitle() { return mBundle.getCharSequence(KEY_SUBTITLE); return mPromptInfo.getSubtitle(); } /** Loading @@ -608,7 +536,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getDescription() { return mBundle.getCharSequence(KEY_DESCRIPTION); return mPromptInfo.getDescription(); } /** Loading @@ -618,7 +546,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getNegativeButtonText() { return mBundle.getCharSequence(KEY_NEGATIVE_TEXT); return mPromptInfo.getNegativeButtonText(); } /** Loading @@ -628,7 +556,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @return true if explicit user confirmation is required, or false otherwise. */ public boolean isConfirmationRequired() { return mBundle.getBoolean(KEY_REQUIRE_CONFIRMATION, true); return mPromptInfo.isConfirmationRequested(); } /** Loading @@ -640,7 +568,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public int getAllowedAuthenticators() { return mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, 0); return mPromptInfo.getAuthenticators(); } /** Loading Loading @@ -893,8 +821,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } // Disallow explicitly setting any non-Strong biometric authenticator types. final @Authenticators.Types int authenticators = mBundle.getInt( KEY_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_STRONG); @Authenticators.Types int authenticators = mPromptInfo.getAuthenticators(); if (authenticators == Authenticators.EMPTY_SET) { authenticators = Authenticators.BIOMETRIC_STRONG; } final int biometricStrength = authenticators & Authenticators.BIOMETRIC_WEAK; if ((biometricStrength & ~Authenticators.BIOMETRIC_STRONG) != 0) { throw new IllegalArgumentException("Only Strong biometrics supported with crypto"); Loading Loading @@ -974,22 +904,25 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan mAuthenticationCallback = callback; final long operationId = crypto != null ? crypto.getOpId() : 0; final Bundle bundle; final PromptInfo promptInfo; if (crypto != null) { // Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth. // Note that we use a new bundle here so as to not overwrite the application's // 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 // without a crypto object later. bundle = new Bundle(mBundle); bundle.putInt(KEY_AUTHENTICATORS_ALLOWED, mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_STRONG)); Parcel parcel = Parcel.obtain(); mPromptInfo.writeToParcel(parcel, 0 /* flags */); parcel.setDataPosition(0); promptInfo = new PromptInfo(parcel); if (promptInfo.getAuthenticators() == Authenticators.EMPTY_SET) { promptInfo.setAuthenticators(Authenticators.BIOMETRIC_STRONG); } } else { bundle = mBundle; promptInfo = mPromptInfo; } mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, mContext.getOpPackageName(), bundle); mContext.getOpPackageName(), promptInfo); } catch (RemoteException e) { Log.e(TAG, "Remote exception while authenticating", e); Loading core/java/android/hardware/biometrics/IAuthService.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package android.hardware.biometrics; import android.os.Bundle; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.PromptInfo; /** * Communication channel from BiometricPrompt and BiometricManager to AuthService. The Loading @@ -31,7 +31,7 @@ interface IAuthService { // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. void authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); Loading core/java/android/hardware/biometrics/IBiometricService.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,10 @@ package android.hardware.biometrics; import android.os.Bundle; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.PromptInfo; /** * Communication channel from AuthService to BiometricService. Loading @@ -29,7 +29,7 @@ interface IBiometricService { // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. void authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo, int callingUid, int callingPid, int callingUserId); // Cancel authentication for the given session. Loading core/java/android/hardware/biometrics/PromptInfo.aidl 0 → 100644 +18 −0 Original line number Diff line number Diff line /* * Copyright (C) 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 android.hardware.biometrics; parcelable PromptInfo; core/java/android/hardware/biometrics/PromptInfo.java 0 → 100644 +229 −0 Original line number Diff line number Diff line /* * Copyright (C) 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 android.hardware.biometrics; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; /** * Contains the information set/requested by the caller of the {@link BiometricPrompt} * @hide */ public class PromptInfo implements Parcelable { @NonNull private CharSequence mTitle; private boolean mUseDefaultTitle; @Nullable private CharSequence mSubtitle; @Nullable private CharSequence mDescription; @Nullable private CharSequence mDeviceCredentialTitle; @Nullable private CharSequence mDeviceCredentialSubtitle; @Nullable private CharSequence mDeviceCredentialDescription; @Nullable private CharSequence mNegativeButtonText; private boolean mConfirmationRequested = true; // default to true private boolean mDeviceCredentialAllowed; private @BiometricManager.Authenticators.Types int mAuthenticators; private boolean mDisallowBiometricsIfPolicyExists; private boolean mReceiveSystemEvents; public PromptInfo() { } PromptInfo(Parcel in) { mTitle = in.readCharSequence(); mUseDefaultTitle = in.readBoolean(); mSubtitle = in.readCharSequence(); mDescription = in.readCharSequence(); mDeviceCredentialTitle = in.readCharSequence(); mDeviceCredentialSubtitle = in.readCharSequence(); mDeviceCredentialDescription = in.readCharSequence(); mNegativeButtonText = in.readCharSequence(); mConfirmationRequested = in.readBoolean(); mDeviceCredentialAllowed = in.readBoolean(); mAuthenticators = in.readInt(); mDisallowBiometricsIfPolicyExists = in.readBoolean(); mReceiveSystemEvents = in.readBoolean(); } public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() { @Override public PromptInfo createFromParcel(Parcel in) { return new PromptInfo(in); } @Override public PromptInfo[] newArray(int size) { return new PromptInfo[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mTitle); dest.writeBoolean(mUseDefaultTitle); dest.writeCharSequence(mSubtitle); dest.writeCharSequence(mDescription); dest.writeCharSequence(mDeviceCredentialTitle); dest.writeCharSequence(mDeviceCredentialSubtitle); dest.writeCharSequence(mDeviceCredentialDescription); dest.writeCharSequence(mNegativeButtonText); dest.writeBoolean(mConfirmationRequested); dest.writeBoolean(mDeviceCredentialAllowed); dest.writeInt(mAuthenticators); dest.writeBoolean(mDisallowBiometricsIfPolicyExists); dest.writeBoolean(mReceiveSystemEvents); } public boolean containsPrivateApiConfigurations() { if (mDisallowBiometricsIfPolicyExists) { return true; } else if (mUseDefaultTitle) { return true; } else if (mDeviceCredentialTitle != null) { return true; } else if (mDeviceCredentialSubtitle != null) { return true; } else if (mDeviceCredentialDescription != null) { return true; } else if (mReceiveSystemEvents) { return true; } return false; } // Setters public void setTitle(CharSequence title) { mTitle = title; } public void setUseDefaultTitle(boolean useDefaultTitle) { mUseDefaultTitle = useDefaultTitle; } public void setSubtitle(CharSequence subtitle) { mSubtitle = subtitle; } public void setDescription(CharSequence description) { mDescription = description; } public void setDeviceCredentialTitle(CharSequence deviceCredentialTitle) { mDeviceCredentialTitle = deviceCredentialTitle; } public void setDeviceCredentialSubtitle(CharSequence deviceCredentialSubtitle) { mDeviceCredentialSubtitle = deviceCredentialSubtitle; } public void setDeviceCredentialDescription(CharSequence deviceCredentialDescription) { mDeviceCredentialDescription = deviceCredentialDescription; } public void setNegativeButtonText(CharSequence negativeButtonText) { mNegativeButtonText = negativeButtonText; } public void setConfirmationRequested(boolean confirmationRequested) { mConfirmationRequested = confirmationRequested; } public void setDeviceCredentialAllowed(boolean deviceCredentialAllowed) { mDeviceCredentialAllowed = deviceCredentialAllowed; } public void setAuthenticators(int authenticators) { mAuthenticators = authenticators; } public void setDisallowBiometricsIfPolicyExists(boolean disallowBiometricsIfPolicyExists) { mDisallowBiometricsIfPolicyExists = disallowBiometricsIfPolicyExists; } public void setReceiveSystemEvents(boolean receiveSystemEvents) { mReceiveSystemEvents = receiveSystemEvents; } // Getters public CharSequence getTitle() { return mTitle; } public boolean isUseDefaultTitle() { return mUseDefaultTitle; } public CharSequence getSubtitle() { return mSubtitle; } public CharSequence getDescription() { return mDescription; } public CharSequence getDeviceCredentialTitle() { return mDeviceCredentialTitle; } public CharSequence getDeviceCredentialSubtitle() { return mDeviceCredentialSubtitle; } public CharSequence getDeviceCredentialDescription() { return mDeviceCredentialDescription; } public CharSequence getNegativeButtonText() { return mNegativeButtonText; } public boolean isConfirmationRequested() { return mConfirmationRequested; } /** * This value is read once by {@link com.android.server.biometrics.BiometricService} and * combined into {@link #getAuthenticators()}. * @deprecated * @return */ @Deprecated public boolean isDeviceCredentialAllowed() { return mDeviceCredentialAllowed; } public int getAuthenticators() { return mAuthenticators; } public boolean isDisallowBiometricsIfPolicyExists() { return mDisallowBiometricsIfPolicyExists; } public boolean isReceiveSystemEvents() { return mReceiveSystemEvents; } } Loading
core/java/android/hardware/biometrics/BiometricPrompt.java +50 −117 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ import android.content.DialogInterface; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.security.identity.IdentityCredential; Loading @@ -56,70 +56,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private static final String TAG = "BiometricPrompt"; /** * @hide */ public static final String KEY_TITLE = "title"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_USE_DEFAULT_TITLE = "use_default_title"; /** * @hide */ public static final String KEY_SUBTITLE = "subtitle"; /** * @hide */ public static final String KEY_DESCRIPTION = "description"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_TITLE = "device_credential_title"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_SUBTITLE = "device_credential_subtitle"; /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_DEVICE_CREDENTIAL_DESCRIPTION = "device_credential_description"; /** * @hide */ public static final String KEY_NEGATIVE_TEXT = "negative_text"; /** * @hide */ public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation"; /** * This is deprecated. Internally we should use {@link #KEY_AUTHENTICATORS_ALLOWED} * @hide */ public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential"; /** * If this key is set, we will ignore {@link #KEY_ALLOW_DEVICE_CREDENTIAL} * @hide */ public static final String KEY_AUTHENTICATORS_ALLOWED = "authenticators_allowed"; /** * If this is set, check the Device Policy Manager for allowed biometrics. * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; /** * Request to receive system events, such as back gesture/button. See * {@link AuthenticationCallback#onSystemEvent(int)} * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public static final String KEY_RECEIVE_SYSTEM_EVENTS = "receive_system_events"; /** * Error/help message will show for this amount of time. * For error messages, the dialog will also be dismissed after this amount of time. Loading Loading @@ -197,8 +133,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * A builder that collects arguments to be shown on the system-provided biometric dialog. */ public static class Builder { private final Bundle mBundle; private ButtonInfo mPositiveButtonInfo; private PromptInfo mPromptInfo; private ButtonInfo mNegativeButtonInfo; private Context mContext; Loading @@ -207,7 +142,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @param context The {@link Context} that will be used to build the prompt. */ public Builder(Context context) { mBundle = new Bundle(); mPromptInfo = new PromptInfo(); mContext = context; } Loading @@ -218,7 +153,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mBundle.putCharSequence(KEY_TITLE, title); mPromptInfo.setTitle(title); return this; } Loading @@ -231,7 +166,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @RequiresPermission(USE_BIOMETRIC_INTERNAL) @NonNull public Builder setUseDefaultTitle() { mBundle.putBoolean(KEY_USE_DEFAULT_TITLE, true); mPromptInfo.setUseDefaultTitle(true); return this; } Loading @@ -242,7 +177,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setSubtitle(@NonNull CharSequence subtitle) { mBundle.putCharSequence(KEY_SUBTITLE, subtitle); mPromptInfo.setSubtitle(subtitle); return this; } Loading @@ -253,7 +188,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setDescription(@NonNull CharSequence description) { mBundle.putCharSequence(KEY_DESCRIPTION, description); mPromptInfo.setDescription(description); return this; } Loading @@ -270,13 +205,13 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Nullable CharSequence subtitle, @Nullable CharSequence description) { if (title != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_TITLE, title); mPromptInfo.setDeviceCredentialTitle(title); } if (subtitle != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_SUBTITLE, subtitle); mPromptInfo.setDeviceCredentialSubtitle(subtitle); } if (description != null) { mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_DESCRIPTION, description); mPromptInfo.setDeviceCredentialDescription(description); } return this; } Loading Loading @@ -308,7 +243,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (listener == null) { throw new IllegalArgumentException("Listener must not be null"); } mBundle.putCharSequence(KEY_NEGATIVE_TEXT, text); mPromptInfo.setNegativeButtonText(text); mNegativeButtonInfo = new ButtonInfo(executor, listener); return this; } Loading @@ -335,7 +270,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setConfirmationRequired(boolean requireConfirmation) { mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation); mPromptInfo.setConfirmationRequested(requireConfirmation); return this; } Loading @@ -360,7 +295,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Deprecated @NonNull public Builder setDeviceCredentialAllowed(boolean allowed) { mBundle.putBoolean(KEY_ALLOW_DEVICE_CREDENTIAL, allowed); mPromptInfo.setDeviceCredentialAllowed(allowed); return this; } Loading Loading @@ -390,7 +325,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setAllowedAuthenticators(@Authenticators.Types int authenticators) { mBundle.putInt(KEY_AUTHENTICATORS_ALLOWED, authenticators); mPromptInfo.setAuthenticators(authenticators); return this; } Loading @@ -403,8 +338,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setDisallowBiometricsIfPolicyExists(boolean checkDevicePolicyManager) { mBundle.putBoolean(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, checkDevicePolicyManager); mPromptInfo.setDisallowBiometricsIfPolicyExists(checkDevicePolicyManager); return this; } Loading @@ -416,7 +350,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public Builder setReceiveSystemEvents(boolean set) { mBundle.putBoolean(KEY_RECEIVE_SYSTEM_EVENTS, set); mPromptInfo.setReceiveSystemEvents(set); return this; } Loading @@ -430,12 +364,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public BiometricPrompt build() { final CharSequence title = mBundle.getCharSequence(KEY_TITLE); final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT); final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE, false); final boolean deviceCredentialAllowed = mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL); final @Authenticators.Types int authenticators = mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, 0); final CharSequence title = mPromptInfo.getTitle(); final CharSequence negative = mPromptInfo.getNegativeButtonText(); final boolean useDefaultTitle = mPromptInfo.isUseDefaultTitle(); final boolean deviceCredentialAllowed = mPromptInfo.isDeviceCredentialAllowed(); final @Authenticators.Types int authenticators = mPromptInfo.getAuthenticators(); final boolean willShowDeviceCredentialButton = deviceCredentialAllowed || (authenticators & Authenticators.DEVICE_CREDENTIAL) != 0; Loading @@ -447,7 +380,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Can't have both negative button behavior" + " and device credential enabled"); } return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo); return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo); } } Loading @@ -461,8 +394,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private final IBinder mToken = new Binder(); private final Context mContext; private final IAuthService mService; private final Bundle mBundle; private final ButtonInfo mPositiveButtonInfo; private final PromptInfo mPromptInfo; private final ButtonInfo mNegativeButtonInfo; private CryptoObject mCryptoObject; Loading Loading @@ -545,14 +477,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Override public void onDialogDismissed(int reason) { // Check the reason and invoke OnClickListener(s) if necessary if (reason == DISMISSED_REASON_BIOMETRIC_CONFIRMED) { mPositiveButtonInfo.executor.execute(() -> { mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE); }); } else if (reason == DISMISSED_REASON_NEGATIVE) { if (reason == DISMISSED_REASON_NEGATIVE) { mNegativeButtonInfo.executor.execute(() -> { mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE); }); } else { Log.e(TAG, "Unknown reason: " + reason); } } Loading @@ -564,11 +494,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } }; private BiometricPrompt(Context context, Bundle bundle, ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) { private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo) { mContext = context; mBundle = bundle; mPositiveButtonInfo = positiveButtonInfo; mPromptInfo = promptInfo; mNegativeButtonInfo = negativeButtonInfo; mService = IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)); Loading @@ -580,7 +508,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @NonNull public CharSequence getTitle() { return mBundle.getCharSequence(KEY_TITLE, ""); return mPromptInfo.getTitle(); } /** Loading @@ -590,7 +518,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public boolean shouldUseDefaultTitle() { return mBundle.getBoolean(KEY_USE_DEFAULT_TITLE, false); return mPromptInfo.isUseDefaultTitle(); } /** Loading @@ -599,7 +527,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getSubtitle() { return mBundle.getCharSequence(KEY_SUBTITLE); return mPromptInfo.getSubtitle(); } /** Loading @@ -608,7 +536,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getDescription() { return mBundle.getCharSequence(KEY_DESCRIPTION); return mPromptInfo.getDescription(); } /** Loading @@ -618,7 +546,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public CharSequence getNegativeButtonText() { return mBundle.getCharSequence(KEY_NEGATIVE_TEXT); return mPromptInfo.getNegativeButtonText(); } /** Loading @@ -628,7 +556,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @return true if explicit user confirmation is required, or false otherwise. */ public boolean isConfirmationRequired() { return mBundle.getBoolean(KEY_REQUIRE_CONFIRMATION, true); return mPromptInfo.isConfirmationRequested(); } /** Loading @@ -640,7 +568,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ @Nullable public int getAllowedAuthenticators() { return mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, 0); return mPromptInfo.getAuthenticators(); } /** Loading Loading @@ -893,8 +821,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } // Disallow explicitly setting any non-Strong biometric authenticator types. final @Authenticators.Types int authenticators = mBundle.getInt( KEY_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_STRONG); @Authenticators.Types int authenticators = mPromptInfo.getAuthenticators(); if (authenticators == Authenticators.EMPTY_SET) { authenticators = Authenticators.BIOMETRIC_STRONG; } final int biometricStrength = authenticators & Authenticators.BIOMETRIC_WEAK; if ((biometricStrength & ~Authenticators.BIOMETRIC_STRONG) != 0) { throw new IllegalArgumentException("Only Strong biometrics supported with crypto"); Loading Loading @@ -974,22 +904,25 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan mAuthenticationCallback = callback; final long operationId = crypto != null ? crypto.getOpId() : 0; final Bundle bundle; final PromptInfo promptInfo; if (crypto != null) { // Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth. // Note that we use a new bundle here so as to not overwrite the application's // 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 // without a crypto object later. bundle = new Bundle(mBundle); bundle.putInt(KEY_AUTHENTICATORS_ALLOWED, mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_STRONG)); Parcel parcel = Parcel.obtain(); mPromptInfo.writeToParcel(parcel, 0 /* flags */); parcel.setDataPosition(0); promptInfo = new PromptInfo(parcel); if (promptInfo.getAuthenticators() == Authenticators.EMPTY_SET) { promptInfo.setAuthenticators(Authenticators.BIOMETRIC_STRONG); } } else { bundle = mBundle; promptInfo = mPromptInfo; } mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, mContext.getOpPackageName(), bundle); mContext.getOpPackageName(), promptInfo); } catch (RemoteException e) { Log.e(TAG, "Remote exception while authenticating", e); Loading
core/java/android/hardware/biometrics/IAuthService.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package android.hardware.biometrics; import android.os.Bundle; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.PromptInfo; /** * Communication channel from BiometricPrompt and BiometricManager to AuthService. The Loading @@ -31,7 +31,7 @@ interface IAuthService { // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. void authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); Loading
core/java/android/hardware/biometrics/IBiometricService.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,10 @@ package android.hardware.biometrics; import android.os.Bundle; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.PromptInfo; /** * Communication channel from AuthService to BiometricService. Loading @@ -29,7 +29,7 @@ interface IBiometricService { // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. void authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo, int callingUid, int callingPid, int callingUserId); // Cancel authentication for the given session. Loading
core/java/android/hardware/biometrics/PromptInfo.aidl 0 → 100644 +18 −0 Original line number Diff line number Diff line /* * Copyright (C) 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 android.hardware.biometrics; parcelable PromptInfo;
core/java/android/hardware/biometrics/PromptInfo.java 0 → 100644 +229 −0 Original line number Diff line number Diff line /* * Copyright (C) 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 android.hardware.biometrics; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; /** * Contains the information set/requested by the caller of the {@link BiometricPrompt} * @hide */ public class PromptInfo implements Parcelable { @NonNull private CharSequence mTitle; private boolean mUseDefaultTitle; @Nullable private CharSequence mSubtitle; @Nullable private CharSequence mDescription; @Nullable private CharSequence mDeviceCredentialTitle; @Nullable private CharSequence mDeviceCredentialSubtitle; @Nullable private CharSequence mDeviceCredentialDescription; @Nullable private CharSequence mNegativeButtonText; private boolean mConfirmationRequested = true; // default to true private boolean mDeviceCredentialAllowed; private @BiometricManager.Authenticators.Types int mAuthenticators; private boolean mDisallowBiometricsIfPolicyExists; private boolean mReceiveSystemEvents; public PromptInfo() { } PromptInfo(Parcel in) { mTitle = in.readCharSequence(); mUseDefaultTitle = in.readBoolean(); mSubtitle = in.readCharSequence(); mDescription = in.readCharSequence(); mDeviceCredentialTitle = in.readCharSequence(); mDeviceCredentialSubtitle = in.readCharSequence(); mDeviceCredentialDescription = in.readCharSequence(); mNegativeButtonText = in.readCharSequence(); mConfirmationRequested = in.readBoolean(); mDeviceCredentialAllowed = in.readBoolean(); mAuthenticators = in.readInt(); mDisallowBiometricsIfPolicyExists = in.readBoolean(); mReceiveSystemEvents = in.readBoolean(); } public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() { @Override public PromptInfo createFromParcel(Parcel in) { return new PromptInfo(in); } @Override public PromptInfo[] newArray(int size) { return new PromptInfo[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mTitle); dest.writeBoolean(mUseDefaultTitle); dest.writeCharSequence(mSubtitle); dest.writeCharSequence(mDescription); dest.writeCharSequence(mDeviceCredentialTitle); dest.writeCharSequence(mDeviceCredentialSubtitle); dest.writeCharSequence(mDeviceCredentialDescription); dest.writeCharSequence(mNegativeButtonText); dest.writeBoolean(mConfirmationRequested); dest.writeBoolean(mDeviceCredentialAllowed); dest.writeInt(mAuthenticators); dest.writeBoolean(mDisallowBiometricsIfPolicyExists); dest.writeBoolean(mReceiveSystemEvents); } public boolean containsPrivateApiConfigurations() { if (mDisallowBiometricsIfPolicyExists) { return true; } else if (mUseDefaultTitle) { return true; } else if (mDeviceCredentialTitle != null) { return true; } else if (mDeviceCredentialSubtitle != null) { return true; } else if (mDeviceCredentialDescription != null) { return true; } else if (mReceiveSystemEvents) { return true; } return false; } // Setters public void setTitle(CharSequence title) { mTitle = title; } public void setUseDefaultTitle(boolean useDefaultTitle) { mUseDefaultTitle = useDefaultTitle; } public void setSubtitle(CharSequence subtitle) { mSubtitle = subtitle; } public void setDescription(CharSequence description) { mDescription = description; } public void setDeviceCredentialTitle(CharSequence deviceCredentialTitle) { mDeviceCredentialTitle = deviceCredentialTitle; } public void setDeviceCredentialSubtitle(CharSequence deviceCredentialSubtitle) { mDeviceCredentialSubtitle = deviceCredentialSubtitle; } public void setDeviceCredentialDescription(CharSequence deviceCredentialDescription) { mDeviceCredentialDescription = deviceCredentialDescription; } public void setNegativeButtonText(CharSequence negativeButtonText) { mNegativeButtonText = negativeButtonText; } public void setConfirmationRequested(boolean confirmationRequested) { mConfirmationRequested = confirmationRequested; } public void setDeviceCredentialAllowed(boolean deviceCredentialAllowed) { mDeviceCredentialAllowed = deviceCredentialAllowed; } public void setAuthenticators(int authenticators) { mAuthenticators = authenticators; } public void setDisallowBiometricsIfPolicyExists(boolean disallowBiometricsIfPolicyExists) { mDisallowBiometricsIfPolicyExists = disallowBiometricsIfPolicyExists; } public void setReceiveSystemEvents(boolean receiveSystemEvents) { mReceiveSystemEvents = receiveSystemEvents; } // Getters public CharSequence getTitle() { return mTitle; } public boolean isUseDefaultTitle() { return mUseDefaultTitle; } public CharSequence getSubtitle() { return mSubtitle; } public CharSequence getDescription() { return mDescription; } public CharSequence getDeviceCredentialTitle() { return mDeviceCredentialTitle; } public CharSequence getDeviceCredentialSubtitle() { return mDeviceCredentialSubtitle; } public CharSequence getDeviceCredentialDescription() { return mDeviceCredentialDescription; } public CharSequence getNegativeButtonText() { return mNegativeButtonText; } public boolean isConfirmationRequested() { return mConfirmationRequested; } /** * This value is read once by {@link com.android.server.biometrics.BiometricService} and * combined into {@link #getAuthenticators()}. * @deprecated * @return */ @Deprecated public boolean isDeviceCredentialAllowed() { return mDeviceCredentialAllowed; } public int getAuthenticators() { return mAuthenticators; } public boolean isDisallowBiometricsIfPolicyExists() { return mDisallowBiometricsIfPolicyExists; } public boolean isReceiveSystemEvents() { return mReceiveSystemEvents; } }