Copyright (C) 2014 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.
/** * Copyright (C) 2014 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.fingerprint; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.USE_BIOMETRIC; import static android.Manifest.permission.USE_FINGERPRINT; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricPromptReceiver; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal.OnCancelListener; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import java.security.Signature; import java.util.List; import java.util.concurrent.Executor; import javax.crypto.Cipher; import javax.crypto.Mac;
A class that coordinates access to the fingerprint hardware.
Deprecated:See BiometricPrompt which shows a system-provided dialog upon starting authentication. In a world where devices may have different types of biometric authentication, it's much more realistic to have a system-provided authentication dialog since the method may vary by vendor/device.
/** * A class that coordinates access to the fingerprint hardware. * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting * authentication. In a world where devices may have different types of biometric authentication, * it's much more realistic to have a system-provided authentication dialog since the method may * vary by vendor/device. */
@Deprecated @SystemService(Context.FINGERPRINT_SERVICE) @RequiresFeature(PackageManager.FEATURE_FINGERPRINT) public class FingerprintManager implements BiometricFingerprintConstants { private static final String TAG = "FingerprintManager"; private static final boolean DEBUG = true; private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; private static final int MSG_AUTHENTICATION_FAILED = 103; private static final int MSG_ERROR = 104; private static final int MSG_REMOVED = 105; private static final int MSG_ENUMERATED = 106; private IFingerprintService mService; private Context mContext; private IBinder mToken = new Binder(); private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback; private EnrollmentCallback mEnrollmentCallback; private RemovalCallback mRemovalCallback; private EnumerateCallback mEnumerateCallback; private android.hardware.biometrics.CryptoObject mCryptoObject; private Fingerprint mRemovalFingerprint; private Handler mHandler; private Executor mExecutor; private class OnEnrollCancelListener implements OnCancelListener { @Override public void onCancel() { cancelEnrollment(); } } private class OnAuthenticationCancelListener implements OnCancelListener { private android.hardware.biometrics.CryptoObject mCrypto; public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { mCrypto = crypto; } @Override public void onCancel() { cancelAuthentication(mCrypto); } }
A wrapper class for the crypto objects supported by FingerprintManager. Currently the framework supports Signature, Cipher and Mac objects.
Deprecated:See CryptoObject
/** * A wrapper class for the crypto objects supported by FingerprintManager. Currently the * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} */
@Deprecated public static final class CryptoObject extends android.hardware.biometrics.CryptoObject { public CryptoObject(@NonNull Signature signature) { super(signature); } public CryptoObject(@NonNull Cipher cipher) { super(cipher); } public CryptoObject(@NonNull Mac mac) { super(mac); }
Get Signature object.
Returns:Signature object or null if this doesn't contain one.
/** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. */
public Signature getSignature() { return super.getSignature(); }
Get Cipher object.
Returns:Cipher object or null if this doesn't contain one.
/** * Get {@link Cipher} object. * @return {@link Cipher} object or null if this doesn't contain one. */
public Cipher getCipher() { return super.getCipher(); }
Get Mac object.
Returns:Mac object or null if this doesn't contain one.
/** * Get {@link Mac} object. * @return {@link Mac} object or null if this doesn't contain one. */
public Mac getMac() { return super.getMac(); } }
Deprecated:See AuthenticationResult
/** * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult} */
@Deprecated public static class AuthenticationResult { private Fingerprint mFingerprint; private CryptoObject mCryptoObject; private int mUserId;
Authentication result
Params:
  • crypto – the crypto object
  • fingerprint – the recognized fingerprint data, if allowed.
@hide
/** * Authentication result * * @param crypto the crypto object * @param fingerprint the recognized fingerprint data, if allowed. * @hide */
public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) { mCryptoObject = crypto; mFingerprint = fingerprint; mUserId = userId; }
Obtain the crypto object associated with this transaction
Returns:crypto object provided to FingerprintManager.authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler).
/** * Obtain the crypto object associated with this transaction * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. */
public CryptoObject getCryptoObject() { return mCryptoObject; }
Obtain the Fingerprint associated with this operation. Applications are strongly discouraged from associating specific fingers with specific applications or operations.
@hide
/** * Obtain the Fingerprint associated with this operation. Applications are strongly * discouraged from associating specific fingers with specific applications or operations. * * @hide */
public Fingerprint getFingerprint() { return mFingerprint; }
Obtain the userId for which this fingerprint was authenticated.
@hide
/** * Obtain the userId for which this fingerprint was authenticated. * @hide */
public int getUserId() { return mUserId; } };
Deprecated:See AuthenticationCallback
/** * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link * FingerprintManager#authenticate(CryptoObject, CancellationSignal, * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to * fingerprint events. * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} */
@Deprecated public static abstract class AuthenticationCallback extends BiometricAuthenticator.AuthenticationCallback {
Called when an unrecoverable error has been encountered and the operation is complete. No further callbacks will be made on this object.
Params:
  • errorCode – An integer identifying the error message
  • errString – A human-readable error string that can be shown in UI
/** * Called when an unrecoverable error has been encountered and the operation is complete. * No further callbacks will be made on this object. * @param errorCode An integer identifying the error message * @param errString A human-readable error string that can be shown in UI */
@Override public void onAuthenticationError(int errorCode, CharSequence errString) { }
Called when a recoverable error has been encountered during authentication. The help string is provided to give the user guidance for what went wrong, such as "Sensor dirty, please clean it."
Params:
  • helpCode – An integer identifying the error message
  • helpString – A human-readable string that can be shown in UI
/** * Called when a recoverable error has been encountered during authentication. The help * string is provided to give the user guidance for what went wrong, such as * "Sensor dirty, please clean it." * @param helpCode An integer identifying the error message * @param helpString A human-readable string that can be shown in UI */
@Override public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
Called when a fingerprint is recognized.
Params:
  • result – An object containing authentication-related data
/** * Called when a fingerprint is recognized. * @param result An object containing authentication-related data */
public void onAuthenticationSucceeded(AuthenticationResult result) { }
Called when a fingerprint is valid but not recognized.
/** * Called when a fingerprint is valid but not recognized. */
@Override public void onAuthenticationFailed() { }
Called when a fingerprint image has been acquired, but wasn't processed yet.
Params:
  • acquireInfo – one of FINGERPRINT_ACQUIRED_* constants
@hide
/** * Called when a fingerprint image has been acquired, but wasn't processed yet. * * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants * @hide */
@Override public void onAuthenticationAcquired(int acquireInfo) {}
Params:
  • result –
@hide
/** * @hide * @param result */
@Override public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) { onAuthenticationSucceeded(new AuthenticationResult( (CryptoObject) result.getCryptoObject(), (Fingerprint) result.getId(), result.getUserId())); } };
Callback structure provided to FingerprintManager#enroll(long, EnrollmentCallback, * CancellationSignal, int). Users of FingerprintManager() must provide an implementation of this to for listening to fingerprint events.
@hide
/** * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback, * CancellationSignal, int). Users of {@link #FingerprintManager()} * must provide an implementation of this to {@link FingerprintManager#enroll(long, * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events. * * @hide */
public static abstract class EnrollmentCallback {
Called when an unrecoverable error has been encountered and the operation is complete. No further callbacks will be made on this object.
Params:
  • errMsgId – An integer identifying the error message
  • errString – A human-readable error string that can be shown in UI
/** * Called when an unrecoverable error has been encountered and the operation is complete. * No further callbacks will be made on this object. * @param errMsgId An integer identifying the error message * @param errString A human-readable error string that can be shown in UI */
public void onEnrollmentError(int errMsgId, CharSequence errString) { }
Called when a recoverable error has been encountered during enrollment. The help string is provided to give the user guidance for what went wrong, such as "Sensor dirty, please clean it" or what they need to do next, such as "Touch sensor again."
Params:
  • helpMsgId – An integer identifying the error message
  • helpString – A human-readable string that can be shown in UI
/** * Called when a recoverable error has been encountered during enrollment. The help * string is provided to give the user guidance for what went wrong, such as * "Sensor dirty, please clean it" or what they need to do next, such as * "Touch sensor again." * @param helpMsgId An integer identifying the error message * @param helpString A human-readable string that can be shown in UI */
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
Called as each enrollment step progresses. Enrollment is considered complete when remaining reaches 0. This function will not be called if enrollment fails. See onEnrollmentError(int, CharSequence)
Params:
  • remaining – The number of remaining steps
/** * Called as each enrollment step progresses. Enrollment is considered complete when * remaining reaches 0. This function will not be called if enrollment fails. See * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} * @param remaining The number of remaining steps */
public void onEnrollmentProgress(int remaining) { } };
Callback structure provided to remove. Users of FingerprintManager may optionally provide an implementation of this to FingerprintManager.remove(Fingerprint, int, RemovalCallback) for listening to fingerprint template removal events.
@hide
/** * Callback structure provided to {@link #remove}. Users of {@link FingerprintManager} may * optionally provide an implementation of this to * {@link #remove(Fingerprint, int, RemovalCallback)} for listening to fingerprint template * removal events. * * @hide */
public static abstract class RemovalCallback {
Called when the given fingerprint can't be removed.
Params:
  • fp – The fingerprint that the call attempted to remove
  • errMsgId – An associated error message id
  • errString – An error message indicating why the fingerprint id can't be removed
/** * Called when the given fingerprint can't be removed. * @param fp The fingerprint that the call attempted to remove * @param errMsgId An associated error message id * @param errString An error message indicating why the fingerprint id can't be removed */
public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
Called when a given fingerprint is successfully removed.
Params:
  • fp – The fingerprint template that was removed.
  • remaining – The number of fingerprints yet to be removed in this operation. If remove is called on one fingerprint, this should be 0. If remove is called on a group, this should be the number of remaining fingerprints in the group, and 0 after the last fingerprint is removed.
/** * Called when a given fingerprint is successfully removed. * @param fp The fingerprint template that was removed. * @param remaining The number of fingerprints yet to be removed in this operation. If * {@link #remove} is called on one fingerprint, this should be 0. If * {@link #remove} is called on a group, this should be the number of remaining * fingerprints in the group, and 0 after the last fingerprint is removed. */
public void onRemovalSucceeded(Fingerprint fp, int remaining) { } };
Callback structure provided to FingerprintManager#enumerate(int). Users of {FingerprintManager() may optionally provide an implementation of this to FingerprintManager.enumerate(int, EnumerateCallback, EnumerateCallback) for listening to fingerprint template removal events.
@hide
/** * Callback structure provided to {@link FingerprintManager#enumerate(int). Users of * {@link #FingerprintManager()} may optionally provide an implementation of this to * {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to * fingerprint template removal events. * * @hide */
public static abstract class EnumerateCallback {
Called when the given fingerprint can't be removed.
Params:
  • errMsgId – An associated error message id
  • errString – An error message indicating why the fingerprint id can't be removed
/** * Called when the given fingerprint can't be removed. * @param errMsgId An associated error message id * @param errString An error message indicating why the fingerprint id can't be removed */
public void onEnumerateError(int errMsgId, CharSequence errString) { }
Called when a given fingerprint is successfully removed.
Params:
  • fingerprint – the fingerprint template that was removed.
/** * Called when a given fingerprint is successfully removed. * @param fingerprint the fingerprint template that was removed. */
public void onEnumerate(Fingerprint fingerprint) { } };
@hide
/** * @hide */
public static abstract class LockoutResetCallback {
Called when lockout period expired and clients are allowed to listen for fingerprint again.
/** * Called when lockout period expired and clients are allowed to listen for fingerprint * again. */
public void onLockoutReset() { } };
Request authentication of a crypto object. This call warms up the fingerprint hardware and starts scanning for a fingerprint. It terminates when AuthenticationCallback.onAuthenticationError(int, CharSequence) or AuthenticationCallback.onAuthenticationSucceeded(AuthenticationResult) is called, at which point the object is no longer valid. The operation can be canceled by using the provided cancel object.
Params:
  • crypto – object associated with the call or null if none required.
  • cancel – an object that can be used to cancel authentication
  • flags – optional flags; should be 0
  • callback – an object to receive authentication events
  • handler – an optional handler to handle callback events
Throws:
Deprecated:See BiometricPrompt.authenticate(CancellationSignal, Executor, AuthenticationCallback) and BiometricPrompt.authenticate(CryptoObject, CancellationSignal, Executor, AuthenticationCallback)
/** * Request authentication of a crypto object. This call warms up the fingerprint hardware * and starts scanning for a fingerprint. It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * * @param crypto object associated with the call or null if none required. * @param cancel an object that can be used to cancel authentication * @param flags optional flags; should be 0 * @param callback an object to receive authentication events * @param handler an optional handler to handle callback events * * @throws IllegalArgumentException if the crypto operation is not supported or is not backed * by <a href="{@docRoot}training/articles/keystore.html">Android Keystore * facility</a>. * @throws IllegalStateException if the crypto primitive is not initialized. * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor, * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate( * BiometricPrompt.CryptoObject, CancellationSignal, Executor, * BiometricPrompt.AuthenticationCallback)} */
@Deprecated @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId()); }
Use the provided handler thread for events.
Params:
  • handler –
/** * Use the provided handler thread for events. * @param handler */
private void useHandler(Handler handler) { if (handler != null) { mHandler = new MyHandler(handler.getLooper()); } else if (mHandler.getLooper() != mContext.getMainLooper()){ mHandler = new MyHandler(mContext.getMainLooper()); } }
Params:
  • userId – the user ID that the fingerprint hardware will authenticate for.
@hide
/** * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)} * @param userId the user ID that the fingerprint hardware will authenticate for. * @hide */
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } if (cancel != null) { if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled"); return; } else { cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); } } if (mService != null) try { useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, mContext.getOpPackageName(), null /* bundle */, null /* receiver */); } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or try // again later. callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); } } }
Params:
  • userId – the user ID that the fingerprint hardware will authenticate for.
/** * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, Bundle, Executor, IBiometricPromptReceiver, AuthenticationCallback)} * @param userId the user ID that the fingerprint hardware will authenticate for. */
private void authenticate(int userId, @Nullable android.hardware.biometrics.CryptoObject crypto, @NonNull CancellationSignal cancel, @NonNull Bundle bundle, @NonNull @CallbackExecutor Executor executor, @NonNull IBiometricPromptReceiver receiver, @NonNull BiometricAuthenticator.AuthenticationCallback callback) { mCryptoObject = crypto; if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled"); return; } else { cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); } if (mService != null) { try { mExecutor = executor; mAuthenticationCallback = callback; final long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, 0 /* flags */, mContext.getOpPackageName(), bundle, receiver); } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating", e); mExecutor.execute(() -> { callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); }); } } }
Params:
  • cancel –
  • executor –
  • callback –
@hide
/** * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor, * BiometricPrompt.AuthenticationCallback)} * @param cancel * @param executor * @param callback * @hide */
public void authenticate( @NonNull CancellationSignal cancel, @NonNull Bundle bundle, @NonNull @CallbackExecutor Executor executor, @NonNull IBiometricPromptReceiver receiver, @NonNull BiometricAuthenticator.AuthenticationCallback callback) { if (cancel == null) { throw new IllegalArgumentException("Must supply a cancellation signal"); } if (bundle == null) { throw new IllegalArgumentException("Must supply a bundle"); } if (executor == null) { throw new IllegalArgumentException("Must supply an executor"); } if (receiver == null) { throw new IllegalArgumentException("Must supply a receiver"); } if (callback == null) { throw new IllegalArgumentException("Must supply a calback"); } authenticate(mContext.getUserId(), null, cancel, bundle, executor, receiver, callback); }
Params:
  • crypto –
  • cancel –
  • executor –
  • callback –
@hide
/** * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject, * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)} * @param crypto * @param cancel * @param executor * @param callback * @hide */
public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto, @NonNull CancellationSignal cancel, @NonNull Bundle bundle, @NonNull @CallbackExecutor Executor executor, @NonNull IBiometricPromptReceiver receiver, @NonNull BiometricAuthenticator.AuthenticationCallback callback) { if (crypto == null) { throw new IllegalArgumentException("Must supply a crypto object"); } if (cancel == null) { throw new IllegalArgumentException("Must supply a cancellation signal"); } if (bundle == null) { throw new IllegalArgumentException("Must supply a bundle"); } if (executor == null) { throw new IllegalArgumentException("Must supply an executor"); } if (receiver == null) { throw new IllegalArgumentException("Must supply a receiver"); } if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } authenticate(mContext.getUserId(), crypto, cancel, bundle, executor, receiver, callback); }
Request fingerprint enrollment. This call warms up the fingerprint hardware and starts scanning for fingerprints. Progress will be indicated by callbacks to the EnrollmentCallback object. It terminates when EnrollmentCallback.onEnrollmentError(int, CharSequence) or is called with remaining == 0, at which point the object is no longer valid. The operation can be canceled by using the provided cancel object.
Params:
  • token – a unique token provided by a recent creation or verification of device credentials (e.g. pin, pattern or password).
  • cancel – an object that can be used to cancel enrollment
  • flags – optional flags
  • userId – the user to whom this fingerprint will belong to
  • callback – an object to receive enrollment events
@hide
/** * Request fingerprint enrollment. This call warms up the fingerprint hardware * and starts scanning for fingerprints. Progress will be indicated by callbacks to the * {@link EnrollmentCallback} object. It terminates when * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * @param token a unique token provided by a recent creation or verification of device * credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment * @param flags optional flags * @param userId the user to whom this fingerprint will belong to * @param callback an object to receive enrollment events * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public void enroll(byte [] token, CancellationSignal cancel, int flags, int userId, EnrollmentCallback callback) { if (userId == UserHandle.USER_CURRENT) { userId = getCurrentUserId(); } if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); } if (cancel != null) { if (cancel.isCanceled()) { Slog.w(TAG, "enrollment already canceled"); return; } else { cancel.setOnCancelListener(new OnEnrollCancelListener()); } } if (mService != null) try { mEnrollmentCallback = callback; mService.enroll(mToken, token, userId, mServiceReceiver, flags, mContext.getOpPackageName()); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enroll: ", e); if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or try // again later. callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); } } }
Requests a pre-enrollment auth token to tie enrollment to the confirmation of existing device credentials (e.g. pin/pattern/password).
@hide
/** * Requests a pre-enrollment auth token to tie enrollment to the confirmation of * existing device credentials (e.g. pin/pattern/password). * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public long preEnroll() { long result = 0; if (mService != null) try { result = mService.preEnroll(mToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return result; }
Finishes enrollment and cancels the current auth token.
@hide
/** * Finishes enrollment and cancels the current auth token. * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public int postEnroll() { int result = 0; if (mService != null) try { result = mService.postEnroll(mToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return result; }
Sets the active user. This is meant to be used to select the current profile for enrollment to allow separate enrolled fingers for a work profile
Params:
  • userId –
@hide
/** * Sets the active user. This is meant to be used to select the current profile for enrollment * to allow separate enrolled fingers for a work profile * @param userId * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public void setActiveUser(int userId) { if (mService != null) try { mService.setActiveUser(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
Remove given fingerprint template from fingerprint hardware and/or protected storage.
Params:
  • fp – the fingerprint item to remove
  • userId – the user who this fingerprint belongs to
  • callback – an optional callback to verify that fingerprint templates have been successfully removed. May be null of no callback is required.
@hide
/** * Remove given fingerprint template from fingerprint hardware and/or protected storage. * @param fp the fingerprint item to remove * @param userId the user who this fingerprint belongs to * @param callback an optional callback to verify that fingerprint templates have been * successfully removed. May be null of no callback is required. * * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public void remove(Fingerprint fp, int userId, RemovalCallback callback) { if (mService != null) try { mRemovalCallback = callback; mRemovalFingerprint = fp; mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in remove: ", e); if (callback != null) { callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); } } }
Enumerate all fingerprint templates stored in hardware and/or protected storage.
Params:
  • userId – the user who this fingerprint belongs to
  • callback – an optional callback to verify that fingerprint templates have been successfully removed. May be null of no callback is required.
@hide
/** * Enumerate all fingerprint templates stored in hardware and/or protected storage. * @param userId the user who this fingerprint belongs to * @param callback an optional callback to verify that fingerprint templates have been * successfully removed. May be null of no callback is required. * * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public void enumerate(int userId, @NonNull EnumerateCallback callback) { if (mService != null) try { mEnumerateCallback = callback; mService.enumerate(mToken, userId, mServiceReceiver); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enumerate: ", e); if (callback != null) { callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); } } }
Renames the given fingerprint template
Params:
  • fpId – the fingerprint id
  • userId – the user who this fingerprint belongs to
  • newName – the new name
@hide
/** * Renames the given fingerprint template * @param fpId the fingerprint id * @param userId the user who this fingerprint belongs to * @param newName the new name * * @hide */
@RequiresPermission(MANAGE_FINGERPRINT) public void rename(int fpId, int userId, String newName) { // Renames the given fpId if (mService != null) { try { mService.rename(fpId, userId, newName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "rename(): Service not connected!"); } }
Obtain the list of enrolled fingerprints templates.
Returns:list of current fingerprint items
@hide
/** * Obtain the list of enrolled fingerprints templates. * @return list of current fingerprint items * * @hide */
@RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints(int userId) { if (mService != null) try { return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return null; }
Obtain the list of enrolled fingerprints templates.
Returns:list of current fingerprint items
@hide
/** * Obtain the list of enrolled fingerprints templates. * @return list of current fingerprint items * * @hide */
@RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints() { return getEnrolledFingerprints(mContext.getUserId()); }
Determine if there is at least one fingerprint enrolled.
Returns:true if at least one fingerprint is enrolled, false otherwise
Deprecated:See BiometricPrompt and BiometricFingerprintConstants.FINGERPRINT_ERROR_NO_FINGERPRINTS
/** * Determine if there is at least one fingerprint enrolled. * * @return true if at least one fingerprint is enrolled, false otherwise * @deprecated See {@link BiometricPrompt} and * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS} */
@Deprecated @RequiresPermission(USE_FINGERPRINT) public boolean hasEnrolledFingerprints() { if (mService != null) try { return mService.hasEnrolledFingerprints( mContext.getUserId(), mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return false; }
@hide
/** * @hide */
@RequiresPermission(allOf = { USE_FINGERPRINT, INTERACT_ACROSS_USERS}) public boolean hasEnrolledFingerprints(int userId) { if (mService != null) try { return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return false; }
Determine if fingerprint hardware is present and functional.
Returns:true if hardware is present and functional, false otherwise.
Deprecated:See BiometricPrompt and BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE
/** * Determine if fingerprint hardware is present and functional. * * @return true if hardware is present and functional, false otherwise. * @deprecated See {@link BiometricPrompt} and * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE} */
@Deprecated @RequiresPermission(USE_FINGERPRINT) public boolean isHardwareDetected() { if (mService != null) { try { long deviceId = 0; /* TODO: plumb hardware id to FPMS */ return mService.isHardwareDetected(deviceId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "isFingerprintHardwareDetected(): Service not connected!"); } return false; }
Retrieves the authenticator token for binding keys to the lifecycle of the calling user's fingerprints. Used only by internal clients.
@hide
/** * Retrieves the authenticator token for binding keys to the lifecycle * of the calling user's fingerprints. Used only by internal clients. * * @hide */
public long getAuthenticatorId() { if (mService != null) { try { return mService.getAuthenticatorId(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "getAuthenticatorId(): Service not connected!"); } return 0; }
Reset the lockout timer when asked to do so by keyguard.
Params:
  • token – an opaque token returned by password confirmation.
@hide
/** * Reset the lockout timer when asked to do so by keyguard. * * @param token an opaque token returned by password confirmation. * * @hide */
public void resetTimeout(byte[] token) { if (mService != null) { try { mService.resetTimeout(token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "resetTimeout(): Service not connected!"); } }
@hide
/** * @hide */
public void addLockoutResetCallback(final LockoutResetCallback callback) { if (mService != null) { try { final PowerManager powerManager = mContext.getSystemService(PowerManager.class); mService.addLockoutResetCallback( new IFingerprintServiceLockoutResetCallback.Stub() { @Override public void onLockoutReset(long deviceId, IRemoteCallback serverCallback) throws RemoteException { try { final PowerManager.WakeLock wakeLock = powerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback"); wakeLock.acquire(); mHandler.post(() -> { try { callback.onLockoutReset(); } finally { wakeLock.release(); } }); } finally { serverCallback.sendResult(null /* data */); } } }); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "addLockoutResetCallback(): Service not connected!"); } } private class MyHandler extends Handler { private MyHandler(Context context) { super(context.getMainLooper()); } private MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); break; case MSG_ACQUIRED: sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */, msg.arg2 /* vendorCode */); break; case MSG_AUTHENTICATION_SUCCEEDED: sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */); break; case MSG_AUTHENTICATION_FAILED: sendAuthenticatedFailed(); break; case MSG_ERROR: sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */, msg.arg2 /* vendorCode */); break; case MSG_REMOVED: sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); break; case MSG_ENUMERATED: sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */, msg.arg2 /* groupId */); break; } } private void sendRemovedResult(Fingerprint fingerprint, int remaining) { if (mRemovalCallback == null) { return; } if (fingerprint == null) { Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null"); return; } int fingerId = fingerprint.getFingerId(); int reqFingerId = mRemovalFingerprint.getFingerId(); if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) { Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); return; } int groupId = fingerprint.getGroupId(); int reqGroupId = mRemovalFingerprint.getGroupId(); if (groupId != reqGroupId) { Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); return; } mRemovalCallback.onRemovalSucceeded(fingerprint, remaining); } private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) { if (mEnumerateCallback != null) { mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId)); } } private void sendEnrollResult(Fingerprint fp, int remaining) { if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentProgress(remaining); } } }; private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) { if (mAuthenticationCallback != null) { final BiometricAuthenticator.AuthenticationResult result = new BiometricAuthenticator.AuthenticationResult(mCryptoObject, fp, userId); mAuthenticationCallback.onAuthenticationSucceeded(result); } } private void sendAuthenticatedFailed() { if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationFailed(); } } private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) { if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); } final String msg = getAcquiredString(acquireInfo, vendorCode); if (msg == null) { return; } // emulate HAL 2.1 behavior and send real acquiredInfo final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo; if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg); } else if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg); } } private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) { // emulate HAL 2.1 behavior and send real errMsgId final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId; if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentError(clientErrMsgId, getErrorString(errMsgId, vendorCode)); } else if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationError(clientErrMsgId, getErrorString(errMsgId, vendorCode)); } else if (mRemovalCallback != null) { mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId, getErrorString(errMsgId, vendorCode)); } else if (mEnumerateCallback != null) { mEnumerateCallback.onEnumerateError(clientErrMsgId, getErrorString(errMsgId, vendorCode)); } }
@hide
/** * @hide */
public FingerprintManager(Context context, IFingerprintService service) { mContext = context; mService = service; if (mService == null) { Slog.v(TAG, "FingerprintManagerService was null"); } mHandler = new MyHandler(context); } private int getCurrentUserId() { try { return ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private void cancelEnrollment() { if (mService != null) try { mService.cancelEnrollment(mToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { if (mService != null) try { mService.cancelAuthentication(mToken, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
@hide
/** * @hide */
public String getErrorString(int errMsg, int vendorCode) { switch (errMsg) { case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: return mContext.getString( com.android.internal.R.string.fingerprint_error_unable_to_process); case FINGERPRINT_ERROR_HW_UNAVAILABLE: return mContext.getString( com.android.internal.R.string.fingerprint_error_hw_not_available); case FINGERPRINT_ERROR_NO_SPACE: return mContext.getString( com.android.internal.R.string.fingerprint_error_no_space); case FINGERPRINT_ERROR_TIMEOUT: return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout); case FINGERPRINT_ERROR_CANCELED: return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled); case FINGERPRINT_ERROR_LOCKOUT: return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout); case FINGERPRINT_ERROR_LOCKOUT_PERMANENT: return mContext.getString( com.android.internal.R.string.fingerprint_error_lockout_permanent); case FINGERPRINT_ERROR_USER_CANCELED: return mContext.getString( com.android.internal.R.string.fingerprint_error_user_canceled); case FINGERPRINT_ERROR_NO_FINGERPRINTS: return mContext.getString( com.android.internal.R.string.fingerprint_error_no_fingerprints); case FINGERPRINT_ERROR_HW_NOT_PRESENT: return mContext.getString( com.android.internal.R.string.fingerprint_error_hw_not_present); case FINGERPRINT_ERROR_VENDOR: { String[] msgArray = mContext.getResources().getStringArray( com.android.internal.R.array.fingerprint_error_vendor); if (vendorCode < msgArray.length) { return msgArray[vendorCode]; } } } Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); return null; }
@hide
/** * @hide */
public String getAcquiredString(int acquireInfo, int vendorCode) { switch (acquireInfo) { case FINGERPRINT_ACQUIRED_GOOD: return null; case FINGERPRINT_ACQUIRED_PARTIAL: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_partial); case FINGERPRINT_ACQUIRED_INSUFFICIENT: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_insufficient); case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_imager_dirty); case FINGERPRINT_ACQUIRED_TOO_SLOW: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_too_slow); case FINGERPRINT_ACQUIRED_TOO_FAST: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_too_fast); case FINGERPRINT_ACQUIRED_VENDOR: { String[] msgArray = mContext.getResources().getStringArray( com.android.internal.R.array.fingerprint_acquired_vendor); if (vendorCode < msgArray.length) { return msgArray[vendorCode]; } } } Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode); return null; } private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { @Override // binder call public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); } @Override // binder call public void onAcquired(long deviceId, int acquireInfo, int vendorCode) { if (mExecutor != null) { mExecutor.execute(() -> { sendAcquiredResult(deviceId, acquireInfo, vendorCode); }); } else { mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget(); } } @Override // binder call public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) { if (mExecutor != null) { mExecutor.execute(() -> { sendAuthenticatedSucceeded(fp, userId); }); } else { mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget(); } } @Override // binder call public void onAuthenticationFailed(long deviceId) { if (mExecutor != null) { mExecutor.execute(() -> { sendAuthenticatedFailed(); }); } else { mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget(); } } @Override // binder call public void onError(long deviceId, int error, int vendorCode) { if (mExecutor != null) { // BiometricPrompt case if (error == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED || error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { // User tapped somewhere to cancel, or authentication was cancelled by the app // or got kicked out. The prompt is already gone, so send the error immediately. mExecutor.execute(() -> { sendErrorResult(deviceId, error, vendorCode); }); } else { // User got an error that needs to be displayed on the dialog, post a delayed // runnable on the FingerprintManager handler that sends the error message after // FingerprintDialog.HIDE_DIALOG_DELAY to send the error to the application. mHandler.postDelayed(() -> { mExecutor.execute(() -> { sendErrorResult(deviceId, error, vendorCode); }); }, BiometricPrompt.HIDE_DIALOG_DELAY); } } else { mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget(); } } @Override // binder call public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) { mHandler.obtainMessage(MSG_REMOVED, remaining, 0, new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); } @Override // binder call public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) { // TODO: propagate remaining mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget(); } }; }