Merge "Update and cleanup FingerprintManager API to new spec" into mnc-dev

This commit is contained in:
Jim Miller
2015-06-09 01:46:15 +00:00
committed by Android (Google) Code Review
8 changed files with 155 additions and 129 deletions

View File

@@ -13942,16 +13942,8 @@ package android.hardware.display {
package android.hardware.fingerprint { package android.hardware.fingerprint {
public final class Fingerprint implements android.os.Parcelable {
ctor public Fingerprint(java.lang.CharSequence, int, int, long);
method public int describeContents();
method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.fingerprint.Fingerprint> CREATOR;
}
public class FingerprintManager { public class FingerprintManager {
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, int); method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
method public boolean hasEnrolledFingerprints(); method public boolean hasEnrolledFingerprints();
method public boolean isHardwareDetected(); method public boolean isHardwareDetected();
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0 field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
@@ -13960,14 +13952,12 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1 field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5 field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4 field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
field public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; // 0x3e8
field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5 field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1 field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7 field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4 field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3 field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; // 0x3e8
} }
public static abstract class FingerprintManager.AuthenticationCallback { public static abstract class FingerprintManager.AuthenticationCallback {
@@ -13979,11 +13969,10 @@ package android.hardware.fingerprint {
} }
public static final class FingerprintManager.AuthenticationResult { public static final class FingerprintManager.AuthenticationResult {
ctor public FingerprintManager.AuthenticationResult(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.hardware.fingerprint.Fingerprint);
method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject(); method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
} }
public static class FingerprintManager.CryptoObject { public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature); ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher); ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac); ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);

View File

@@ -14260,16 +14260,8 @@ package android.hardware.display {
package android.hardware.fingerprint { package android.hardware.fingerprint {
public final class Fingerprint implements android.os.Parcelable {
ctor public Fingerprint(java.lang.CharSequence, int, int, long);
method public int describeContents();
method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.fingerprint.Fingerprint> CREATOR;
}
public class FingerprintManager { public class FingerprintManager {
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, int); method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
method public boolean hasEnrolledFingerprints(); method public boolean hasEnrolledFingerprints();
method public boolean isHardwareDetected(); method public boolean isHardwareDetected();
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0 field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
@@ -14278,14 +14270,12 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1 field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5 field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4 field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
field public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; // 0x3e8
field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5 field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1 field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7 field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4 field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3 field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; // 0x3e8
} }
public static abstract class FingerprintManager.AuthenticationCallback { public static abstract class FingerprintManager.AuthenticationCallback {
@@ -14297,11 +14287,10 @@ package android.hardware.fingerprint {
} }
public static final class FingerprintManager.AuthenticationResult { public static final class FingerprintManager.AuthenticationResult {
ctor public FingerprintManager.AuthenticationResult(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.hardware.fingerprint.Fingerprint);
method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject(); method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
} }
public static class FingerprintManager.CryptoObject { public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature); ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher); ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac); ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);

View File

@@ -18,32 +18,30 @@ package android.hardware.fingerprint;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManagerNative; import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.os.Binder; import android.os.Binder;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener; import android.os.CancellationSignal.OnCancelListener;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.AndroidKeyStoreProvider;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
import java.security.Signature; import java.security.Signature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.Mac; import javax.crypto.Mac;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
/** /**
* A class that coordinates access to the fingerprint hardware. * A class that coordinates access to the fingerprint hardware.
* <p> * <p>
@@ -57,9 +55,10 @@ public class FingerprintManager {
private static final boolean DEBUG = true; private static final boolean DEBUG = true;
private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101; private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATED = 102; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
private static final int MSG_ERROR = 103; private static final int MSG_AUTHENTICATION_FAILED = 103;
private static final int MSG_REMOVED = 104; private static final int MSG_ERROR = 104;
private static final int MSG_REMOVED = 105;
// //
// Error messages from fingerprint hardware during initilization, enrollment, authentication or // Error messages from fingerprint hardware during initilization, enrollment, authentication or
@@ -112,6 +111,7 @@ public class FingerprintManager {
/** /**
* Hardware vendors may extend this list if there are conditions that do not fall under one of * Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors. * the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/ */
public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
@@ -162,6 +162,7 @@ public class FingerprintManager {
/** /**
* Hardware vendors may extend this list if there are conditions that do not fall under one of * Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors. * the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/ */
public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
@@ -173,6 +174,7 @@ public class FingerprintManager {
private RemovalCallback mRemovalCallback; private RemovalCallback mRemovalCallback;
private CryptoObject mCryptoObject; private CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint; private Fingerprint mRemovalFingerprint;
private Handler mHandler;
private class OnEnrollCancelListener implements OnCancelListener { private class OnEnrollCancelListener implements OnCancelListener {
@Override @Override
@@ -198,72 +200,71 @@ public class FingerprintManager {
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/ */
public static class CryptoObject { public static final class CryptoObject {
public CryptoObject(@NonNull Signature signature) { public CryptoObject(@NonNull Signature signature) {
mSignature = signature; mCrypto = signature;
mCipher = null;
mMac = null;
} }
public CryptoObject(@NonNull Cipher cipher) { public CryptoObject(@NonNull Cipher cipher) {
mCipher = cipher; mCrypto = cipher;
mSignature = null;
mMac = null;
} }
public CryptoObject(@NonNull Mac mac) { public CryptoObject(@NonNull Mac mac) {
mMac = mac; mCrypto = mac;
mCipher = null;
mSignature = null;
} }
/** /**
* Get {@link Signature} object. * Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one. * @return {@link Signature} object or null if this doesn't contain one.
*/ */
public Signature getSignature() { return mSignature; } public Signature getSignature() {
return mCrypto instanceof Signature ? (Signature) mCrypto : null;
}
/** /**
* Get {@link Cipher} object. * Get {@link Cipher} object.
* @return {@link Cipher} object or null if this doesn't contain one. * @return {@link Cipher} object or null if this doesn't contain one.
*/ */
public Cipher getCipher() { return mCipher; } public Cipher getCipher() {
return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
}
/** /**
* Get {@link Mac} object. * Get {@link Mac} object.
* @return {@link Mac} object or null if this doesn't contain one. * @return {@link Mac} object or null if this doesn't contain one.
*/ */
public Mac getMac() { return mMac; } public Mac getMac() {
return mCrypto instanceof Mac ? (Mac) mCrypto : null;
}
/** /**
* @hide * @hide
* @return the opId associated with this object or 0 if none * @return the opId associated with this object or 0 if none
*/ */
public long getOpId() { public long getOpId() {
if (mSignature != null) { return mCrypto != null ?
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature); AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
} else if (mCipher != null) {
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher);
} else if (mMac != null) {
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac);
}
return 0;
} }
private final Signature mSignature; private final Object mCrypto;
private final Cipher mCipher;
private final Mac mMac;
}; };
/** /**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}. * CancellationSignal, int, AuthenticationCallback, Handler)}.
*/ */
public static final class AuthenticationResult { public static final class AuthenticationResult {
private Fingerprint mFingerprint; private Fingerprint mFingerprint;
private CryptoObject mCryptoObject; private CryptoObject mCryptoObject;
/**
* Authentication result
*
* @param crypto the crypto object
* @param fingerprint the recognized fingerprint data, if allowed.
* @hide
*/
public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) { public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
mCryptoObject = crypto; mCryptoObject = crypto;
mFingerprint = fingerprint; mFingerprint = fingerprint;
@@ -272,7 +273,7 @@ public class FingerprintManager {
/** /**
* Obtain the crypto object associated with this transaction * Obtain the crypto object associated with this transaction
* @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}. * CancellationSignal, int, AuthenticationCallback, Handler)}.
*/ */
public CryptoObject getCryptoObject() { return mCryptoObject; } public CryptoObject getCryptoObject() { return mCryptoObject; }
@@ -287,28 +288,28 @@ public class FingerprintManager {
/** /**
* Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}. Users of {@link * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
* FingerprintManager#authenticate(CryptoObject, CancellationSignal, * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* AuthenticationCallback, int) } must provide an implementation of this for listening to * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events. * fingerprint events.
*/ */
public static abstract class AuthenticationCallback { public static abstract class AuthenticationCallback {
/** /**
* Called when an unrecoverable error has been encountered and the operation is complete. * Called when an unrecoverable error has been encountered and the operation is complete.
* No further callbacks will be made on this object. * No further callbacks will be made on this object.
* @param errMsgId An integer identifying the error message * @param errorCode An integer identifying the error message
* @param errString A human-readable error string that can be shown in UI * @param errString A human-readable error string that can be shown in UI
*/ */
public void onAuthenticationError(int errMsgId, CharSequence errString) { } public void onAuthenticationError(int errorCode, CharSequence errString) { }
/** /**
* Called when a recoverable error has been encountered during authentication. The help * 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 * string is provided to give the user guidance for what went wrong, such as
* "Sensor dirty, please clean it." * "Sensor dirty, please clean it."
* @param helpMsgId An integer identifying the error message * @param helpCode An integer identifying the error message
* @param helpString A human-readable string that can be shown in UI * @param helpString A human-readable string that can be shown in UI
*/ */
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { } public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
/** /**
* Called when a fingerprint is recognized. * Called when a fingerprint is recognized.
@@ -326,7 +327,7 @@ public class FingerprintManager {
* Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback, * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
* CancellationSignal, int). Users of {@link #FingerprintManager()} * CancellationSignal, int). Users of {@link #FingerprintManager()}
* must provide an implementation of this to {@link FingerprintManager#enroll(long, * must provide an implementation of this to {@link FingerprintManager#enroll(long,
* CancellationSignal, EnrollmentCallback, int) for listening to fingerprint events. * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
* *
* @hide * @hide
*/ */
@@ -392,31 +393,35 @@ public class FingerprintManager {
* *
* @param crypto object associated with the call or null if none required. * @param crypto object associated with the call or null if none required.
* @param cancel an object that can be used to cancel authentication * @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param flags optional flags; should be 0 * @param flags optional flags; should be 0
* @param callback an object to receive authentication events
* @param handler an optional handler to handle callback events
*/ */
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, int flags) { int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, callback, flags, UserHandle.myUserId()); authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
} }
/** /**
* Request authentication of a crypto object. This call warms up the fingerprint hardware * Use the provided handler thread for events.
* and starts scanning for a fingerprint. It terminates when * @param handler
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or */
* {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at private void useHandler(Handler handler) {
* which point the object is no longer valid. The operation can be canceled by using the if (handler != null) {
* provided cancel object. mHandler = new MyHandler(handler.getLooper());
* } else if (mHandler.getLooper() != mContext.getMainLooper()){
* @param crypto object associated with the call or null if none required. mHandler = new MyHandler(mContext.getMainLooper());
* @param cancel an object that can be used to cancel authentication }
* @param callback an object to receive authentication events }
* @param flags optional flags; should be 0
* @param userId the userId the fingerprint belongs to /**
* Per-user version
* @hide * @hide
*/ */
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, int flags, int userId) { int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
if (callback == null) { if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback"); throw new IllegalArgumentException("Must supply an authentication callback");
} }
@@ -431,6 +436,7 @@ public class FingerprintManager {
} }
if (mService != null) try { if (mService != null) try {
useHandler(handler);
mAuthenticationCallback = callback; mAuthenticationCallback = callback;
mCryptoObject = crypto; mCryptoObject = crypto;
long sessionId = crypto != null ? crypto.getOpId() : 0; long sessionId = crypto != null ? crypto.getOpId() : 0;
@@ -458,12 +464,13 @@ public class FingerprintManager {
* @param token a unique token provided by a recent creation or verification of device * @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password). * credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment * @param cancel an object that can be used to cancel enrollment
* @param callback an object to receive enrollment events
* @param flags optional flags * @param flags optional flags
* @param callback an object to receive enrollment events
* @hide * @hide
*/ */
public void enroll(byte [] token, CancellationSignal cancel, EnrollmentCallback callback, @RequiresPermission(MANAGE_FINGERPRINT)
int flags) { public void enroll(byte [] token, CancellationSignal cancel, int flags,
EnrollmentCallback callback) {
if (callback == null) { if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback"); throw new IllegalArgumentException("Must supply an enrollment callback");
} }
@@ -496,6 +503,7 @@ public class FingerprintManager {
* existing device credentials (e.g. pin/pattern/password). * existing device credentials (e.g. pin/pattern/password).
* @hide * @hide
*/ */
@RequiresPermission(MANAGE_FINGERPRINT)
public long preEnroll() { public long preEnroll() {
long result = 0; long result = 0;
if (mService != null) try { if (mService != null) try {
@@ -514,6 +522,7 @@ public class FingerprintManager {
* *
* @hide * @hide
*/ */
@RequiresPermission(MANAGE_FINGERPRINT)
public void remove(Fingerprint fp, RemovalCallback callback) { public void remove(Fingerprint fp, RemovalCallback callback) {
if (mService != null) try { if (mService != null) try {
mRemovalCallback = callback; mRemovalCallback = callback;
@@ -535,6 +544,7 @@ public class FingerprintManager {
* *
* @hide * @hide
*/ */
@RequiresPermission(MANAGE_FINGERPRINT)
public void rename(int fpId, String newName) { public void rename(int fpId, String newName) {
// Renames the given fpId // Renames the given fpId
if (mService != null) { if (mService != null) {
@@ -554,6 +564,7 @@ public class FingerprintManager {
* *
* @hide * @hide
*/ */
@RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints(int userId) { public List<Fingerprint> getEnrolledFingerprints(int userId) {
if (mService != null) try { if (mService != null) try {
return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
@@ -569,6 +580,7 @@ public class FingerprintManager {
* *
* @hide * @hide
*/ */
@RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints() { public List<Fingerprint> getEnrolledFingerprints() {
return getEnrolledFingerprints(UserHandle.myUserId()); return getEnrolledFingerprints(UserHandle.myUserId());
} }
@@ -578,6 +590,7 @@ public class FingerprintManager {
* *
* @return true if at least one fingerprint is enrolled, false otherwise * @return true if at least one fingerprint is enrolled, false otherwise
*/ */
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() { public boolean hasEnrolledFingerprints() {
if (mService != null) try { if (mService != null) try {
return mService.hasEnrolledFingerprints(UserHandle.myUserId(), return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
@@ -593,6 +606,7 @@ public class FingerprintManager {
* *
* @return true if hardware is present and functional, false otherwise. * @return true if hardware is present and functional, false otherwise.
*/ */
@RequiresPermission(USE_FINGERPRINT)
public boolean isHardwareDetected() { public boolean isHardwareDetected() {
if (mService != null) { if (mService != null) {
try { try {
@@ -626,13 +640,15 @@ public class FingerprintManager {
return 0; return 0;
} }
private Handler mHandler;
private class MyHandler extends Handler { private class MyHandler extends Handler {
private MyHandler(Context context) { private MyHandler(Context context) {
super(context.getMainLooper()); super(context.getMainLooper());
} }
private MyHandler(Looper looper) {
super(looper);
}
public void handleMessage(android.os.Message msg) { public void handleMessage(android.os.Message msg) {
switch(msg.what) { switch(msg.what) {
case MSG_ENROLL_RESULT: case MSG_ENROLL_RESULT:
@@ -641,8 +657,11 @@ public class FingerprintManager {
case MSG_ACQUIRED: case MSG_ACQUIRED:
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */); sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
break; break;
case MSG_AUTHENTICATED: case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedResult((Fingerprint) msg.obj); sendAuthenticatedSucceeded((Fingerprint) msg.obj);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
break; break;
case MSG_ERROR: case MSG_ERROR:
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */); sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
@@ -684,15 +703,16 @@ public class FingerprintManager {
} }
} }
private void sendAuthenticatedResult(Fingerprint fp) { private void sendAuthenticatedSucceeded(Fingerprint fp) {
if (mAuthenticationCallback != null) { if (mAuthenticationCallback != null) {
if (fp.getFingerId() == 0) { final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
// Fingerprint template valid but doesn't match one in database mAuthenticationCallback.onAuthenticationSucceeded(result);
mAuthenticationCallback.onAuthenticationFailed(); }
} else { }
final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
mAuthenticationCallback.onAuthenticationSucceeded(result); private void sendAuthenticatedFailed() {
} if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationFailed();
} }
} }
@@ -809,24 +829,33 @@ public class FingerprintManager {
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
} }
@Override // binder call
public void onAcquired(long deviceId, int acquireInfo) { public void onAcquired(long deviceId, int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget(); mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
} }
public void onAuthenticated(long deviceId, int fingerId, int groupId) { @Override // binder call
mHandler.obtainMessage(MSG_AUTHENTICATED, public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
} }
@Override // binder call
public void onAuthenticationFailed(long deviceId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
}
@Override // binder call
public void onError(long deviceId, int error) { public void onError(long deviceId, int error) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget(); mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
} }
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) { public void onRemoved(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget(); mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
} }

View File

@@ -15,6 +15,7 @@
*/ */
package android.hardware.fingerprint; package android.hardware.fingerprint;
import android.hardware.fingerprint.Fingerprint;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
@@ -25,7 +26,8 @@ import android.os.UserHandle;
oneway interface IFingerprintServiceReceiver { oneway interface IFingerprintServiceReceiver {
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining); void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
void onAcquired(long deviceId, int acquiredInfo); void onAcquired(long deviceId, int acquiredInfo);
void onAuthenticated(long deviceId, int fingerId, int groupId); void onAuthenticationSucceeded(long deviceId, in Fingerprint fp);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error); void onError(long deviceId, int error);
void onRemoved(long deviceId, int fingerId, int groupId); void onRemoved(long deviceId, int fingerId, int groupId);
} }

View File

@@ -197,7 +197,7 @@ of the two modes:
reset (e.g. by a Device Admin).</li> reset (e.g. by a Device Admin).</li>
<li>User authentication is required for every use of the key. In this mode, a specific operation <li>User authentication is required for every use of the key. In this mode, a specific operation
involving a specific key is authorized by the user. Currently, the only means of such involving a specific key is authorized by the user. Currently, the only means of such
authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, int) FingerprintManager.authenticate}. authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) FingerprintManager.authenticate}.
Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}). Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}).
These keys become permanently invalidated once all fingerprints are unenrolled.</li> These keys become permanently invalidated once all fingerprints are unenrolled.</li>
</ul> </ul>

View File

@@ -796,7 +796,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFingerprintCancelSignal.cancel(); mFingerprintCancelSignal.cancel();
} }
mFingerprintCancelSignal = new CancellationSignal(); mFingerprintCancelSignal = new CancellationSignal();
mFpm.authenticate(null, mFingerprintCancelSignal, mAuthenticationCallback, 0, userId); mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
setFingerprintRunningDetectionRunning(true); setFingerprintRunningDetectionRunning(true);
} }
} }

View File

@@ -22,6 +22,7 @@ import android.app.AppOpsManager;
import android.app.IUserSwitchObserver; import android.app.IUserSwitchObserver;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder; import android.os.Binder;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
@@ -73,13 +74,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private ClientMonitor mRemoveClient = null; private ClientMonitor mRemoveClient = null;
private final AppOpsManager mAppOps; private final AppOpsManager mAppOps;
// Message types. Used internally to dispatch messages to the correct callback.
// Must agree with the list in fingerprint.h
private static final int FINGERPRINT_ERROR = -1;
private static final int FINGERPRINT_ACQUIRED = 1;
private static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
private static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
private static final int FINGERPRINT_AUTHENTICATED = 5;
private static final long MS_PER_SEC = 1000; private static final long MS_PER_SEC = 1000;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5; private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -207,7 +201,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (mEnrollClient != null) { if (mEnrollClient != null) {
if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) { if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
if (remaining == 0) { if (remaining == 0) {
ContentResolver res = mContext.getContentResolver();
addTemplateForUser(mEnrollClient, fingerId); addTemplateForUser(mEnrollClient, fingerId);
removeClient(mEnrollClient); removeClient(mEnrollClient);
} }
@@ -262,14 +255,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
} }
void startEnrollment(IBinder token, byte[] cryptoToken, int groupId, void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
IFingerprintServiceReceiver receiver, int flags) { IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon(); IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) { if (daemon == null) {
Slog.w(TAG, "enroll: no fingeprintd!"); Slog.w(TAG, "enroll: no fingeprintd!");
return; return;
} }
stopPendingOperations(); stopPendingOperations();
mEnrollClient = new ClientMonitor(token, receiver, groupId); mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try { try {
final int result = daemon.enroll(cryptoToken, groupId, timeout); final int result = daemon.enroll(cryptoToken, groupId, timeout);
@@ -328,14 +321,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
} }
void startAuthentication(IBinder token, long opId, int groupId, void startAuthentication(IBinder token, long opId, int groupId,
IFingerprintServiceReceiver receiver, int flags) { IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon(); IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) { if (daemon == null) {
Slog.w(TAG, "startAuthentication: no fingeprintd!"); Slog.w(TAG, "startAuthentication: no fingeprintd!");
return; return;
} }
stopPendingOperations(); stopPendingOperations();
mAuthClient = new ClientMonitor(token, receiver, groupId); mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
if (inLockoutMode()) { if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication"); Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -344,7 +337,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mAuthClient = null; mAuthClient = null;
return; return;
} }
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try { try {
final int result = daemon.authenticate(opId, groupId); final int result = daemon.authenticate(opId, groupId);
if (result != 0) { if (result != 0) {
@@ -378,13 +370,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
} }
void startRemove(IBinder token, int fingerId, int userId, void startRemove(IBinder token, int fingerId, int userId,
IFingerprintServiceReceiver receiver) { IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon(); IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) { if (daemon == null) {
Slog.w(TAG, "startRemove: no fingeprintd!"); Slog.w(TAG, "startRemove: no fingeprintd!");
return; return;
} }
mRemoveClient = new ClientMonitor(token, receiver, userId);
mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
// The fingerprint template ids will be removed when we get confirmation from the HAL // The fingerprint template ids will be removed when we get confirmation from the HAL
try { try {
final int result = daemon.remove(fingerId, userId); final int result = daemon.remove(fingerId, userId);
@@ -404,6 +397,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return mFingerprintUtils.getFingerprintsForUser(mContext, groupId).size() > 0; return mFingerprintUtils.getFingerprintsForUser(mContext, groupId).size() > 0;
} }
boolean hasPermission(String permission) {
return getContext().checkCallingOrSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}
void checkPermission(String permission) { void checkPermission(String permission) {
getContext().enforceCallingOrSelfPermission(permission, getContext().enforceCallingOrSelfPermission(permission,
"Must have " + permission + " permission."); "Must have " + permission + " permission.");
@@ -420,11 +418,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
IBinder token; IBinder token;
IFingerprintServiceReceiver receiver; IFingerprintServiceReceiver receiver;
int userId; int userId;
boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId) { public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
boolean restricted) {
this.token = token; this.token = token;
this.receiver = receiver; this.receiver = receiver;
this.userId = userId; this.userId = userId;
this.restricted = restricted;
try { try {
token.linkToDeath(this, 0); token.linkToDeath(this, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -498,7 +499,13 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
boolean result = false; boolean result = false;
if (receiver != null) { if (receiver != null) {
try { try {
receiver.onAuthenticated(mHalDeviceId, fpId, groupId); if (fpId == 0) {
receiver.onAuthenticationFailed(mHalDeviceId);
} else {
Fingerprint fp = !restricted ?
new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
}
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Failed to notify Authenticated:", e); Slog.w(TAG, "Failed to notify Authenticated:", e);
result = true; // client failed result = true; // client failed
@@ -592,14 +599,22 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
final IFingerprintServiceReceiver receiver, final int flags) { final IFingerprintServiceReceiver receiver, final int flags) {
checkPermission(MANAGE_FINGERPRINT); checkPermission(MANAGE_FINGERPRINT);
final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length); final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
final boolean restricted = isRestricted();
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
startEnrollment(token, cryptoClone, groupId, receiver, flags); startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted);
} }
}); });
} }
private boolean isRestricted() {
// Only give privileged apps (like Settings) access to fingerprint info
final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
return restricted;
}
@Override // Binder call @Override // Binder call
public void cancelEnrollment(final IBinder token) { public void cancelEnrollment(final IBinder token) {
checkPermission(MANAGE_FINGERPRINT); checkPermission(MANAGE_FINGERPRINT);
@@ -614,14 +629,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override // Binder call @Override // Binder call
public void authenticate(final IBinder token, final long opId, final int groupId, public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) { final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) {
checkPermission(USE_FINGERPRINT);
if (!canUseFingerprint(opPackageName)) { if (!canUseFingerprint(opPackageName)) {
return; return;
} }
final boolean restricted = isRestricted();
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
startAuthentication(token, opId, groupId, receiver, flags); startAuthentication(token, opId, groupId, receiver, flags, restricted);
} }
}); });
} }
@@ -643,10 +659,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
public void remove(final IBinder token, final int fingerId, final int groupId, public void remove(final IBinder token, final int fingerId, final int groupId,
final IFingerprintServiceReceiver receiver) { final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
startRemove(token, fingerId, groupId, receiver); startRemove(token, fingerId, groupId, receiver, restricted);
} }
}); });

View File

@@ -57,7 +57,7 @@ class FingerprintsUserState {
private final File mFile; private final File mFile;
@GuardedBy("this") @GuardedBy("this")
private final ArrayList<Fingerprint> mFingerprints = new ArrayList<>(); private final ArrayList<Fingerprint> mFingerprints = new ArrayList<Fingerprint>();
private final Context mCtx; private final Context mCtx;
public FingerprintsUserState(Context ctx, int userId) { public FingerprintsUserState(Context ctx, int userId) {
@@ -127,7 +127,7 @@ class FingerprintsUserState {
} }
private ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) { private ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) {
ArrayList<Fingerprint> result = new ArrayList<>(array.size()); ArrayList<Fingerprint> result = new ArrayList<Fingerprint>(array.size());
for (int i = 0; i < array.size(); i++) { for (int i = 0; i < array.size(); i++) {
Fingerprint fp = array.get(i); Fingerprint fp = array.get(i);
result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(), result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(),