summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt15
-rw-r--r--api/system-current.txt15
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java183
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl4
-rw-r--r--docs/html/training/articles/keystore.jd2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java2
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java59
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintsUserState.java4
8 files changed, 155 insertions, 129 deletions
diff --git a/api/current.txt b/api/current.txt
index 8680c49..4c775a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13942,16 +13942,8 @@ package android.hardware.display {
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 {
- 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 isHardwareDetected();
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_TOO_FAST = 5; // 0x5
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_HW_UNAVAILABLE = 1; // 0x1
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_TIMEOUT = 3; // 0x3
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 {
@@ -13979,11 +13969,10 @@ package android.hardware.fingerprint {
}
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();
}
- public static class FingerprintManager.CryptoObject {
+ public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);
diff --git a/api/system-current.txt b/api/system-current.txt
index 44baba2..5184825 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -14260,16 +14260,8 @@ package android.hardware.display {
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 {
- 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 isHardwareDetected();
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_TOO_FAST = 5; // 0x5
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_HW_UNAVAILABLE = 1; // 0x1
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_TIMEOUT = 3; // 0x3
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 {
@@ -14297,11 +14287,10 @@ package android.hardware.fingerprint {
}
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();
}
- public static class FingerprintManager.CryptoObject {
+ public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index caf21d5..e61813c 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -18,32 +18,30 @@ package android.hardware.fingerprint;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManagerNative;
-import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
-import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.security.keystore.AndroidKeyStoreProvider;
import android.util.Log;
import android.util.Slog;
import java.security.Signature;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import javax.crypto.Cipher;
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.
* <p>
@@ -57,9 +55,10 @@ public class 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_AUTHENTICATED = 102;
- private static final int MSG_ERROR = 103;
- private static final int MSG_REMOVED = 104;
+ 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;
//
// 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
* the above categories. Vendors are responsible for providing error strings for these errors.
+ * @hide
*/
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
* the above categories. Vendors are responsible for providing error strings for these errors.
+ * @hide
*/
public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
@@ -173,6 +174,7 @@ public class FingerprintManager {
private RemovalCallback mRemovalCallback;
private CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint;
+ private Handler mHandler;
private class OnEnrollCancelListener implements OnCancelListener {
@Override
@@ -198,72 +200,71 @@ public class FingerprintManager {
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/
- public static class CryptoObject {
+ public static final class CryptoObject {
public CryptoObject(@NonNull Signature signature) {
- mSignature = signature;
- mCipher = null;
- mMac = null;
+ mCrypto = signature;
}
public CryptoObject(@NonNull Cipher cipher) {
- mCipher = cipher;
- mSignature = null;
- mMac = null;
+ mCrypto = cipher;
}
public CryptoObject(@NonNull Mac mac) {
- mMac = mac;
- mCipher = null;
- mSignature = null;
+ mCrypto = mac;
}
/**
* Get {@link Signature} object.
* @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.
* @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.
* @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
* @return the opId associated with this object or 0 if none
*/
public long getOpId() {
- if (mSignature != null) {
- return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature);
- } else if (mCipher != null) {
- return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher);
- } else if (mMac != null) {
- return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac);
- }
- return 0;
+ return mCrypto != null ?
+ AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
}
- private final Signature mSignature;
- private final Cipher mCipher;
- private final Mac mMac;
+ private final Object mCrypto;
};
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, AuthenticationCallback, int)}.
+ * CancellationSignal, int, AuthenticationCallback, Handler)}.
*/
public static final class AuthenticationResult {
private Fingerprint mFingerprint;
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) {
mCryptoObject = crypto;
mFingerprint = fingerprint;
@@ -272,7 +273,7 @@ public class FingerprintManager {
/**
* Obtain the crypto object associated with this transaction
* @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, AuthenticationCallback, int)}.
+ * CancellationSignal, int, AuthenticationCallback, Handler)}.
*/
public CryptoObject getCryptoObject() { return mCryptoObject; }
@@ -287,28 +288,28 @@ public class FingerprintManager {
/**
* 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,
- * 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.
*/
public static abstract class AuthenticationCallback {
/**
* 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 errorCode An integer identifying the error message
* @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
* string is provided to give the user guidance for what went wrong, such as
* "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
*/
- public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
/**
* Called when a fingerprint is recognized.
@@ -326,7 +327,7 @@ public class FingerprintManager {
* 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, EnrollmentCallback, int) for listening to fingerprint events.
+ * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
*
* @hide
*/
@@ -392,31 +393,35 @@ public class FingerprintManager {
*
* @param crypto object associated with the call or null if none required.
* @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 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,
- @NonNull AuthenticationCallback callback, int flags) {
- authenticate(crypto, cancel, callback, flags, UserHandle.myUserId());
+ int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
+ authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
}
/**
- * 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 callback an object to receive authentication events
- * @param flags optional flags; should be 0
- * @param userId the userId the fingerprint belongs to
+ * 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());
+ }
+ }
+
+ /**
+ * Per-user version
* @hide
*/
+ @RequiresPermission(USE_FINGERPRINT)
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) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -431,6 +436,7 @@ public class FingerprintManager {
}
if (mService != null) try {
+ useHandler(handler);
mAuthenticationCallback = callback;
mCryptoObject = crypto;
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
* credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
- * @param callback an object to receive enrollment events
* @param flags optional flags
+ * @param callback an object to receive enrollment events
* @hide
*/
- public void enroll(byte [] token, CancellationSignal cancel, EnrollmentCallback callback,
- int flags) {
+ @RequiresPermission(MANAGE_FINGERPRINT)
+ public void enroll(byte [] token, CancellationSignal cancel, int flags,
+ EnrollmentCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
@@ -496,6 +503,7 @@ public class FingerprintManager {
* existing device credentials (e.g. pin/pattern/password).
* @hide
*/
+ @RequiresPermission(MANAGE_FINGERPRINT)
public long preEnroll() {
long result = 0;
if (mService != null) try {
@@ -514,6 +522,7 @@ public class FingerprintManager {
*
* @hide
*/
+ @RequiresPermission(MANAGE_FINGERPRINT)
public void remove(Fingerprint fp, RemovalCallback callback) {
if (mService != null) try {
mRemovalCallback = callback;
@@ -535,6 +544,7 @@ public class FingerprintManager {
*
* @hide
*/
+ @RequiresPermission(MANAGE_FINGERPRINT)
public void rename(int fpId, String newName) {
// Renames the given fpId
if (mService != null) {
@@ -554,6 +564,7 @@ public class FingerprintManager {
*
* @hide
*/
+ @RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints(int userId) {
if (mService != null) try {
return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
@@ -569,6 +580,7 @@ public class FingerprintManager {
*
* @hide
*/
+ @RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints() {
return getEnrolledFingerprints(UserHandle.myUserId());
}
@@ -578,6 +590,7 @@ public class FingerprintManager {
*
* @return true if at least one fingerprint is enrolled, false otherwise
*/
+ @RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
if (mService != null) try {
return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
@@ -593,6 +606,7 @@ public class FingerprintManager {
*
* @return true if hardware is present and functional, false otherwise.
*/
+ @RequiresPermission(USE_FINGERPRINT)
public boolean isHardwareDetected() {
if (mService != null) {
try {
@@ -626,13 +640,15 @@ public class FingerprintManager {
return 0;
}
- private Handler mHandler;
-
private class MyHandler extends Handler {
private MyHandler(Context context) {
super(context.getMainLooper());
}
+ private MyHandler(Looper looper) {
+ super(looper);
+ }
+
public void handleMessage(android.os.Message msg) {
switch(msg.what) {
case MSG_ENROLL_RESULT:
@@ -641,8 +657,11 @@ public class FingerprintManager {
case MSG_ACQUIRED:
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
break;
- case MSG_AUTHENTICATED:
- sendAuthenticatedResult((Fingerprint) msg.obj);
+ case MSG_AUTHENTICATION_SUCCEEDED:
+ sendAuthenticatedSucceeded((Fingerprint) msg.obj);
+ break;
+ case MSG_AUTHENTICATION_FAILED:
+ sendAuthenticatedFailed();
break;
case MSG_ERROR:
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 (fp.getFingerId() == 0) {
- // Fingerprint template valid but doesn't match one in database
- mAuthenticationCallback.onAuthenticationFailed();
- } else {
- final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
- mAuthenticationCallback.onAuthenticationSucceeded(result);
- }
+ 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() {
+ @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) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
}
- public void onAuthenticated(long deviceId, int fingerId, int groupId) {
- mHandler.obtainMessage(MSG_AUTHENTICATED,
- new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+ @Override // binder call
+ public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
+ 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) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
}
+ @Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index a2d74b8..57a429f 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.fingerprint.Fingerprint;
import android.os.Bundle;
import android.os.UserHandle;
@@ -25,7 +26,8 @@ import android.os.UserHandle;
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
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 onRemoved(long deviceId, int fingerId, int groupId);
}
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index 20963f5..fca958e 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -197,7 +197,7 @@ of the two modes:
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
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}).
These keys become permanently invalidated once all fingerprints are unenrolled.</li>
</ul>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3c30d8c..d889d0c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -796,7 +796,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
- mFpm.authenticate(null, mFingerprintCancelSignal, mAuthenticationCallback, 0, userId);
+ mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
setFingerprintRunningDetectionRunning(true);
}
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index fd36b7e..b0d5765 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -22,6 +22,7 @@ import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -73,13 +74,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private ClientMonitor mRemoveClient = null;
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 FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
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.sendEnrollResult(fingerId, groupId, remaining)) {
if (remaining == 0) {
- ContentResolver res = mContext.getContentResolver();
addTemplateForUser(mEnrollClient, fingerId);
removeClient(mEnrollClient);
}
@@ -262,14 +255,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
- IFingerprintServiceReceiver receiver, int flags) {
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll: no fingeprintd!");
return;
}
stopPendingOperations();
- mEnrollClient = new ClientMonitor(token, receiver, groupId);
+ mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
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,
- IFingerprintServiceReceiver receiver, int flags) {
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
stopPendingOperations();
- mAuthClient = new ClientMonitor(token, receiver, groupId);
+ mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -344,7 +337,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mAuthClient = null;
return;
}
- final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.authenticate(opId, groupId);
if (result != 0) {
@@ -378,13 +370,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startRemove(IBinder token, int fingerId, int userId,
- IFingerprintServiceReceiver receiver) {
+ IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startRemove: no fingeprintd!");
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
try {
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;
}
+ boolean hasPermission(String permission) {
+ return getContext().checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
void checkPermission(String permission) {
getContext().enforceCallingOrSelfPermission(permission,
"Must have " + permission + " permission.");
@@ -420,11 +418,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
IBinder token;
IFingerprintServiceReceiver receiver;
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.receiver = receiver;
this.userId = userId;
+ this.restricted = restricted;
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -498,7 +499,13 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
boolean result = false;
if (receiver != null) {
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) {
Slog.w(TAG, "Failed to notify Authenticated:", e);
result = true; // client failed
@@ -592,14 +599,22 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
final IFingerprintServiceReceiver receiver, final int flags) {
checkPermission(MANAGE_FINGERPRINT);
final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
+
+ final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
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
public void cancelEnrollment(final IBinder token) {
checkPermission(MANAGE_FINGERPRINT);
@@ -614,14 +629,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override // Binder call
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) {
- checkPermission(USE_FINGERPRINT);
+
if (!canUseFingerprint(opPackageName)) {
return;
}
+ final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
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,
final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
+ final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
- startRemove(token, fingerId, groupId, receiver);
+ startRemove(token, fingerId, groupId, receiver, restricted);
}
});
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
index 33177b4..902d970 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
@@ -57,7 +57,7 @@ class FingerprintsUserState {
private final File mFile;
@GuardedBy("this")
- private final ArrayList<Fingerprint> mFingerprints = new ArrayList<>();
+ private final ArrayList<Fingerprint> mFingerprints = new ArrayList<Fingerprint>();
private final Context mCtx;
public FingerprintsUserState(Context ctx, int userId) {
@@ -127,7 +127,7 @@ class FingerprintsUserState {
}
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++) {
Fingerprint fp = array.get(i);
result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(),