summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2015-03-23 23:59:22 -0700
committerJim Miller <jaggies@google.com>2015-03-24 17:02:46 -0700
commit9f0753f5a378fc80da86305b33244acc6fc53f01 (patch)
treea86544b9552afaf5e332273dabc1684d9c40ff8a
parent9b58c85524675fd81cd093a8df5273a02f537661 (diff)
downloadframeworks_base-9f0753f5a378fc80da86305b33244acc6fc53f01.zip
frameworks_base-9f0753f5a378fc80da86305b33244acc6fc53f01.tar.gz
frameworks_base-9f0753f5a378fc80da86305b33244acc6fc53f01.tar.bz2
Refactor fingerprint API
- enroll() and authenticate() now take an explicit callback object. - better handling of strings - use framework resources for commonn error strings - add vendor-specific arrays to resources Bug 16487912 Change-Id: Idf34242fdd06bba1903cdb22bf20169d15d92b82
-rw-r--r--core/java/android/service/fingerprint/Fingerprint.aidl19
-rw-r--r--core/java/android/service/fingerprint/Fingerprint.java93
-rw-r--r--core/java/android/service/fingerprint/FingerprintManager.java566
-rw-r--r--core/java/android/service/fingerprint/FingerprintManagerReceiver.java76
-rw-r--r--core/java/android/service/fingerprint/FingerprintUtils.java2
-rw-r--r--core/java/android/service/fingerprint/IFingerprintService.aidl37
-rw-r--r--core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl10
-rw-r--r--core/jni/android_server_FingerprintManager.cpp42
-rw-r--r--core/res/res/values/strings.xml30
-rwxr-xr-xcore/res/res/values/symbols.xml13
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java108
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java2
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java210
15 files changed, 861 insertions, 369 deletions
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/service/fingerprint/Fingerprint.aidl
new file mode 100644
index 0000000..c9fd989
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+// @hide
+parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/service/fingerprint/Fingerprint.java
new file mode 100644
index 0000000..37552eb
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for fingerprint metadata.
+ * @hide
+ */
+public final class Fingerprint implements Parcelable {
+ private CharSequence mName;
+ private int mGroupId;
+ private int mFingerId;
+ private long mDeviceId; // physical device this is associated with
+
+ public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
+ mName = name;
+ mGroupId = groupId;
+ mFingerId = fingerId;
+ mDeviceId = deviceId;
+ }
+
+ private Fingerprint(Parcel in) {
+ mName = in.readString();
+ mGroupId = in.readInt();
+ mFingerId = in.readInt();
+ mDeviceId = in.readLong();
+ }
+
+ /**
+ * Gets the human-readable name for the given fingerprint.
+ * @return name given to finger
+ */
+ public CharSequence getName() { return mName; }
+
+ /**
+ * Gets the device-specific finger id. Used by Settings to map a name to a specific
+ * fingerprint template.
+ * @return device-specific id for this finger
+ * @hide
+ */
+ public int getFingerId() { return mFingerId; }
+
+ /**
+ * Gets the group id specified when the fingerprint was enrolled.
+ * @return group id for the set of fingerprints this one belongs to.
+ * @hide
+ */
+ public int getGroupId() { return mGroupId; }
+
+ /**
+ * Device this fingerprint belongs to.
+ * @hide
+ */
+ public long getDeviceId() { return mDeviceId; }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName.toString());
+ out.writeInt(mGroupId);
+ out.writeInt(mFingerId);
+ out.writeLong(mDeviceId);
+ }
+
+ public static final Parcelable.Creator<Fingerprint> CREATOR
+ = new Parcelable.Creator<Fingerprint>() {
+ public Fingerprint createFromParcel(Parcel in) {
+ return new Fingerprint(in);
+ }
+
+ public Fingerprint[] newArray(int size) {
+ return new Fingerprint[size];
+ }
+ };
+}; \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 6375668..26673ab 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -20,17 +20,25 @@ import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
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;
+
/**
* A class that coordinates access to the fingerprint hardware.
* @hide
@@ -45,9 +53,6 @@ public class FingerprintManager {
private static final int MSG_ERROR = 103;
private static final int MSG_REMOVED = 104;
- // Errors generated by layers above HAL
- public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
-
// Message types. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR = -1;
public static final int FINGERPRINT_ACQUIRED = 1;
@@ -60,254 +65,499 @@ public class FingerprintManager {
public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+ public static final int FINGERPRINT_ERROR_CANCELED = 5;
+ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
- // FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h)
+ // Image acquisition messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
- public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
- public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
- public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
private IFingerprintService mService;
- private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
private IBinder mToken = new Binder();
+ private AuthenticationCallback mAuthenticationCallback;
+ private EnrollmentCallback mEnrollmentCallback;
+ private RemovalCallback mRemovalCallback;
+ private CryptoObject mCryptoObject;
+ private Fingerprint mRemovalFingerprint;
+ private boolean mListening;
- private Handler mHandler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- if (mClientReceiver != null) {
- switch(msg.what) {
- case MSG_ENROLL_RESULT:
- mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
- break;
- case MSG_ACQUIRED:
- mClientReceiver.onAcquired(msg.arg1);
- break;
- case MSG_PROCESSED:
- mClientReceiver.onProcessed(msg.arg1);
- break;
- case MSG_ERROR:
- mClientReceiver.onError(msg.arg1);
- break;
- case MSG_REMOVED:
- mClientReceiver.onRemoved(msg.arg1);
- }
- }
- }
+ /**
+ * A wrapper class for a limited number of crypto objects supported by FingerprintManager.
+ */
+ public static class CryptoObject {
+ CryptoObject(Signature signature) { mSignature = signature; }
+ CryptoObject(Cipher cipher) { mCipher = cipher; }
+ private Signature mSignature;
+ private Cipher mCipher;
};
- public static final class FingerprintItem {
- public CharSequence name;
- public int id;
- FingerprintItem(CharSequence name, int id) {
- this.name = name;
- this.id = id;
+ /**
+ * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public static final class AuthenticationResult {
+ private Fingerprint mFingerprint;
+ private CryptoObject mCryptoObject;
+
+ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
+ mCryptoObject = crypto;
+ mFingerprint = fingerprint;
}
- }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public CryptoObject getCryptoObject() { return mCryptoObject; }
+
+ /**
+ * Obtain the Fingerprint associated with this operation. Applications are discouraged
+ * from associating specific fingers with specific applications or operations. Hence this
+ * is not public.
+ * @hide
+ */
+ public Fingerprint getFingerprint() { return mFingerprint; }
+ };
/**
- * @hide
+ * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}. Users of {@link #FingerprintManager()}
+ * must provide an implementation of this to {@link FingerprintManager#authenticate(
+ * CryptoObject, AuthenticationCallback, CancellationSignal, int) for listening to fingerprint
+ * events.
*/
- public FingerprintManager(Context context, IFingerprintService service) {
- mContext = context;
- mService = service;
- if (mService == null) {
- Slog.v(TAG, "FingerprintManagerService was null");
- }
- }
+ 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 errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onAuthenticationError(int errMsgId, CharSequence errString);
- private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+ /**
+ * 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 helpString a human-readible string that can be shown in UI.
+ */
+ public abstract void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
- public void onEnrollResult(int fingerprintId, int remaining) {
- mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
- }
+ /**
+ * Called when a fingerprint is recognized.
+ * @param result an object containing authentication-related data.
+ */
+ public abstract void onAuthenticationSucceeded(AuthenticationResult result);
+ };
- public void onAcquired(int acquireInfo) {
- mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
- }
+ /**
+ * 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,
+ * EnrollmentCallback, CancellationSignal, int) for listening to fingerprint events.
+ */
+ 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.
+ * @param errMsgId an integer identifying the error message.
+ * @param errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onEnrollmentError(int errMsgId, CharSequence errString);
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
- }
+ /**
+ * 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-readible string that can be shown in UI.
+ */
+ public abstract void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
- public void onError(int error) {
- mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
- }
+ /**
+ * 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 abstract void onEnrollmentProgress(int remaining);
+ };
- public void onRemoved(int fingerprintId) {
- mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
- }
+ /**
+ * Callback structure provided to {@link FingerprintManager#remove(int). Users of
+ * {@link #FingerprintManager()} may optionally provide an implementation of this to
+ * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
+ * fingerprint template removal events.
+ */
+ public static abstract class RemovalCallback {
+ /**
+ * Called when the given fingerprint can't be removed.
+ * @param fp the fingerprint that the call attempted to remove.
+ * @parame errMsgId an associated error message id.
+ * @param errString an error message indicating why the fingerprint id can't be removed.
+ */
+ public abstract void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
+
+ /**
+ * Called when a given fingerprint is successfully removed.
+ * @param fingerprint the fingerprint template that was removed.
+ */
+ public abstract void onRemovalSucceeded(Fingerprint fingerprint);
};
/**
- * Determine whether the user has at least one fingerprint enrolled and enabled.
+ * 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.
*
- * @return true if at least one is enrolled and enabled
+ * @param crypto object associated with the call or null if none required.
+ * @param callback an object to receive authentication events
+ * @param cancel an object that can be used to cancel authentication
+ * @param flags optional flags
*/
- public boolean enrolledAndEnabled() {
- ContentResolver res = mContext.getContentResolver();
- return Settings.Secure.getInt(res, "fingerprint_enabled", 0) != 0
- && FingerprintUtils.getFingerprintIdsForUser(res, getCurrentUserId()).length > 0;
+ public void authenticate(CryptoObject crypto, AuthenticationCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an authentication callback");
+ }
+
+ // TODO: handle cancel
+
+ if (mService != null) try {
+ mAuthenticationCallback = callback;
+ mCryptoObject = crypto;
+ long sessionId = 0; // TODO: get from crypto object
+ startListening();
+ mService.authenticate(mToken, sessionId, getCurrentUserId(), flags);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while authenticating: ", e);
+ stopListening();
+ }
}
/**
- * Start the enrollment process. Timeout dictates how long to wait for the user to
- * enroll a fingerprint.
- *
- * @param timeout
+ * 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 challenge a unique id provided by a recent verification of device credentials
+ * (e.g. pin, pattern or password).
+ * @param callback an object to receive enrollment events
+ * @param cancel an object that can be used to cancel enrollment
+ * @param flags optional flags
*/
- public void enroll(long timeout) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
+ public void enroll(long challenge, EnrollmentCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an enrollment callback");
}
+
+ // TODO: handle cancel
+
if (mService != null) try {
- mService.enroll(mToken, timeout, getCurrentUserId());
+ mEnrollmentCallback = callback;
+ startListening();
+ mService.enroll(mToken, getCurrentUserId(), flags);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception while enrolling: ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.v(TAG, "Remote exception in enroll: ", e);
+ stopListening();
}
}
/**
- * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
- * which is to delete all fingerprint data for the current user. Use with caution.
- * @param fingerprintId
+ * Remove given fingerprint template from fingerprint hardware and/or protected storage.
+ * @param fp the fingerprint item to remove
+ * @param callback an optional callback to verify that fingerprint templates have been
+ * successfully removed. May be null of no callback is required.
+ * @hide
*/
- public void remove(int fingerprintId) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
- }
- if (mService != null) {
- try {
- mService.remove(mToken, fingerprintId, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
- }
- } else {
- Log.w(TAG, "remove(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ public void remove(Fingerprint fp, RemovalCallback callback) {
+ if (mService != null) try {
+ mRemovalCallback = callback;
+ mRemovalFingerprint = fp;
+ startListening();
+ mService.remove(mToken, fp.getFingerId(), getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote in remove: ", e);
+ stopListening();
}
}
/**
- * Starts listening for fingerprint events. When a finger is scanned or recognized, the
- * client will be notified via the callback.
+ * Renames the given fingerprint template
+ * @param fpId the fingerprint id
+ * @param newName the new name
+ * @hide
*/
- public void startListening(FingerprintManagerReceiver receiver) {
- mClientReceiver = receiver;
+ public void rename(int fpId, String newName) {
+ // Renames the given fpId
if (mService != null) {
try {
- mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
+ mService.rename(fpId, getCurrentUserId(), newName);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in startListening(): ", e);
+ Log.v(TAG, "Remote exception in rename(): ", e);
}
} else {
- Log.w(TAG, "startListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.w(TAG, "rename(): Service not connected!");
}
}
- private int getCurrentUserId() {
- try {
- return ActivityManagerNative.getDefault().getCurrentUser().id;
+ /**
+ * Obtain the list of enrolled fingerprints templates.
+ * @return list of current fingerprint items
+ */
+ public List<Fingerprint> getEnrolledFingerprints() {
+ if (mService != null) try {
+ return mService.getEnrolledFingerprints(getCurrentUserId());
} catch (RemoteException e) {
- Log.w(TAG, "Failed to get current user id\n");
- return UserHandle.USER_NULL;
+ Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
}
+ return null;
}
/**
- * Stops the client from listening to fingerprint events.
+ * Determine if fingerprint hardware is present and functional.
+ * @return true if hardware is present and functional, false otherwise.
+ * @hide
*/
- public void stopListening() {
+ public boolean isHardwareDetected() {
if (mService != null) {
try {
- mService.stopListening(mToken, getCurrentUserId());
- mClientReceiver = null;
+ long deviceId = 0; /* TODO: plumb hardware id to FPMS */
+ return mService.isHardwareDetected(deviceId);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in stopListening(): ", e);
+ Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
}
} else {
- Log.w(TAG, "stopListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
}
+ return false;
}
- public void enrollCancel() {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
+ private Handler mHandler = new Handler() {
+ 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 */);
+ break;
+ case MSG_PROCESSED:
+ sendProcessedResult((Fingerprint) msg.obj);
+ break;
+ case MSG_ERROR:
+ sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
+ break;
+ case MSG_REMOVED:
+ sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
+ msg.arg2 /* groupId */);
+ }
}
- if (mService != null) {
- try {
- mService.enrollCancel(mToken, getCurrentUserId());
- mClientReceiver = null;
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception in enrollCancel(): ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+
+ private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
+ if (mRemovalCallback != null) {
+ int reqFingerId = mRemovalFingerprint.getFingerId();
+ int reqGroupId = mRemovalFingerprint.getGroupId();
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ }
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ }
+ mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
}
- } else {
- Log.w(TAG, "enrollCancel(): Service not connected!");
}
- }
- private void sendError(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(msg, arg1, arg2);
- }
+ private void sendErrorResult(long deviceId, int errMsgId) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
+ } else if (mRemovalCallback != null) {
+ mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
+ getErrorString(errMsgId));
+ }
+ }
+
+ private void sendEnrollResult(Fingerprint fp, int remaining) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentProgress(remaining);
+ }
+ }
+
+ private void sendProcessedResult(Fingerprint fp) {
+ if (mAuthenticationCallback != null) {
+ AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
+ mAuthenticationCallback.onAuthenticationSucceeded(result);
+ }
+ }
+
+ private void sendAcquiredResult(long deviceId, int acquireInfo) {
+ final String msg = getAcquiredString(acquireInfo);
+ if (msg == null) return;
+
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
+ }
+ }
+
+ private String getErrorString(int errMsg) {
+ 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);
+ default:
+ if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
+ int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_error_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
+ }
+ }
+
+ private String getAcquiredString(int acquireInfo) {
+ 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);
+ default:
+ if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+ int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_acquired_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
+ }
+ }
+ };
/**
- * @return list of current fingerprint items
* @hide
*/
- public List<FingerprintItem> getEnrolledFingerprints() {
- int[] ids = FingerprintUtils.getFingerprintIdsForUser(mContext.getContentResolver(),
- getCurrentUserId());
- List<FingerprintItem> result = new ArrayList<FingerprintItem>();
- for (int i = 0; i < ids.length; i++) {
- // TODO: persist names in Settings
- FingerprintItem item = new FingerprintItem("Finger" + ids[i], ids[i]);
- result.add(item);
+ public FingerprintManager(Context context, IFingerprintService service) {
+ mContext = context;
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FingerprintManagerService was null");
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get current user id\n");
+ return UserHandle.USER_NULL;
}
- return result;
}
/**
- * Determine if fingerprint hardware is present and functional.
- * @return true if hardware is present and functional, false otherwise.
- * @hide
+ * Stops the client from listening to fingerprint events.
*/
- public boolean isHardwareDetected() {
+ private void stopListening() {
if (mService != null) {
try {
- return mService.isHardwareDetected();
+ if (mListening) {
+ mService.removeListener(mToken, mServiceReceiver);
+ mListening = false;
+ }
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+ Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
- Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+ Log.w(TAG, "stopListening(): Service not connected!");
}
- return false;
}
/**
- * Renames the given fingerprint template
- * @param fpId the fingerprint id
- * @param newName the new name
- * @hide
+ * Starts listening for fingerprint events for this client.
*/
- public void rename(int fpId, String newName) {
- // Renames the given fpId
+ private void startListening() {
if (mService != null) {
try {
- mService.rename(fpId, newName);
+ if (!mListening) {
+ mService.addListener(mToken, mServiceReceiver, getCurrentUserId());
+ mListening = true;
+ }
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in rename(): ", e);
+ Log.v(TAG, "Remote exception in startListening(): ", e);
}
} else {
- Log.w(TAG, "rename(): Service not connected!");
+ Log.w(TAG, "startListening(): Service not connected!");
}
}
+
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ 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();
+ }
+
+ public void onAcquired(long deviceId, int acquireInfo) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
+ }
+
+ public void onProcessed(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_PROCESSED,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+ }
+
+ public void onError(long deviceId, int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
+ }
+
+ public void onRemoved(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
+ }
+ };
+
} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
deleted file mode 100644
index 85677ba..0000000
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package android.service.fingerprint;
-/**
- * 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.
- */
-
-/**
- * @hide
- */
-public class FingerprintManagerReceiver {
- /**
- * Fingerprint enrollment progress update. Enrollment is considered complete if
- * remaining hits 0 without {@link #onError(int)} being called.
- *
- * @param fingerprintId the fingerprint we're currently enrolling
- * @param remaining the number of samples required to complete enrollment. It's up to
- * the hardware to define what each step in enrollment means. Some hardware
- * requires multiple samples of the same part of the finger. Others require sampling of
- * different parts of the finger. The enrollment flow can use remaining to
- * mean "step x" of the process or "just need another sample."
- */
- public void onEnrollResult(int fingerprintId, int remaining) { }
-
- /**
- * Fingerprint touch detected, but not processed yet. Clients will use this message to
- * determine a good or bad scan before the fingerprint is processed. This is meant for the
- * client to provide feedback about the scan or alert the user that recognition is to follow.
- *
- * @param acquiredInfo one of:
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
- */
- public void onAcquired(int acquiredInfo) { }
-
- /**
- * Fingerprint has been detected and processed. A non-zero return indicates a valid
- * fingerprint was detected.
- *
- * @param fingerprintId the finger id, or 0 if not recognized.
- */
- public void onProcessed(int fingerprintId) { }
-
- /**
- * An error was detected during scan or enrollment. One of
- * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
- * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
- * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
- * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
- *
- * @param error one of the above error codes
- */
- public void onError(int error) { }
-
- /**
- * The given fingerprint template was successfully removed by the driver.
- * See {@link FingerprintManager#remove(int)}
- *
- * @param fingerprintId id of template to remove.
- */
- public void onRemoved(int fingerprintId) { }
-} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index cc17b99..62acbb9 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -67,7 +67,7 @@ class FingerprintUtils {
return toIntArray(tmp);
}
- public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ public static void addFingerprintIdForUser(ContentResolver res, int fingerId, int userId) {
// FingerId 0 has special meaning.
if (fingerId == 0) {
Log.w(TAG, "Tried to add fingerId 0");
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index 9b4750b..e5d3ad4 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -17,31 +17,42 @@ package android.service.fingerprint;
import android.os.Bundle;
import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.service.fingerprint.Fingerprint;
+import java.util.List;
/**
* Communication channel from client to the fingerprint service.
* @hide
*/
interface IFingerprintService {
- // Any errors resulting from this call will be returned to the listener
- void enroll(IBinder token, long timeout, int userId);
+ // Authenticate the given sessionId with a fingerprint
+ void authenticate(IBinder token, long sessionId, int groupId, int flags);
- // Any errors resulting from this call will be returned to the listener
- void enrollCancel(IBinder token, int userId);
+ // Start fingerprint enrollment
+ void enroll(IBinder token, int groupId, int flags);
// Any errors resulting from this call will be returned to the listener
- void remove(IBinder token, int fingerprintId, int userId);
+ void remove(IBinder token, int fingerId, int groupId);
+
+ // Rename the fingerprint specified by fingerId and groupId to the given name
+ void rename(int fingerId, int groupId, String name);
- // Start listening for fingerprint events. This has the side effect of starting
- // the hardware if not already started.
- void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+ // Get a list of enrolled fingerprints in the given group.
+ List<Fingerprint> getEnrolledFingerprints(int groupId);
- // Stops listening for fingerprints
- void stopListening(IBinder token, int userId);
+ // Register listener for an instance of FingerprintManager
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+
+ // Unregister listener for an instance of FingerprintManager
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected();
+ boolean isHardwareDetected(long deviceId);
+
+ // Gets the number of hardware devices
+ // int getHardwareDeviceCount();
+
+ // Gets the unique device id for hardware enumerated at i
+ // long getHardwareDevice(int i);
- // Rename the given fingerprint id
- void rename(int fpId, String name);
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index af4128f..f025064 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -23,9 +23,9 @@ import android.os.UserHandle;
* @hide
*/
oneway interface IFingerprintServiceReceiver {
- void onEnrollResult(int fingerprintId, int remaining);
- void onAcquired(int acquiredInfo);
- void onProcessed(int fingerprintId);
- void onError(int error);
- void onRemoved(int fingerprintId);
+ void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
+ void onAcquired(long deviceId, int acquiredInfo);
+ void onProcessed(long deviceId, int fingerId, int groupId);
+ void onError(long deviceId, int error);
+ void onRemoved(long deviceId, int fingerId, int groupId);
}
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index 853425c..f22c857 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -47,14 +47,15 @@ static jobject gCallback;
class CallbackHandler : public MessageHandler {
int type;
- int arg1, arg2;
+ int arg1, arg2, arg3;
public:
- CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { }
+ CallbackHandler(int type, int arg1, int arg2, int arg3)
+ : type(type), arg1(arg1), arg2(arg2), arg3(arg3) { }
virtual void handleMessage(const Message& message) {
//ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2);
+ env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2, arg3);
}
};
@@ -62,6 +63,7 @@ public:
static void hal_notify_callback(fingerprint_msg_t msg) {
uint32_t arg1 = 0;
uint32_t arg2 = 0;
+ uint32_t arg3 = 0;
switch (msg.type) {
case FINGERPRINT_ERROR:
arg1 = msg.data.error;
@@ -71,13 +73,16 @@ static void hal_notify_callback(fingerprint_msg_t msg) {
break;
case FINGERPRINT_PROCESSED:
arg1 = msg.data.processed.finger.fid;
+ arg2 = msg.data.processed.finger.gid;
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
arg1 = msg.data.enroll.finger.fid;
- arg2 = msg.data.enroll.samples_remaining;
+ arg2 = msg.data.enroll.finger.gid;
+ arg3 = msg.data.enroll.samples_remaining;
break;
case FINGERPRINT_TEMPLATE_REMOVED:
arg1 = msg.data.removed.finger.fid;
+ arg2 = msg.data.removed.finger.gid;
break;
default:
ALOGE("fingerprint: invalid msg: %d", msg.type);
@@ -86,7 +91,7 @@ static void hal_notify_callback(fingerprint_msg_t msg) {
// This call potentially comes in on a thread not owned by us. Hand it off to our
// looper so it runs on our thread when calling back to FingerprintService.
// CallbackHandler object is reference-counted, so no cleanup necessary.
- gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message());
+ gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2, arg3), Message());
}
static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) {
@@ -95,9 +100,15 @@ static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callb
gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
}
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
- int ret = gContext.device->enroll(gContext.device, 0, timeout);
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout);
+ int ret = gContext.device->enroll(gContext.device, groupId, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeAuthenticate(sid=%ld, gid=%d)\n", sessionId, groupId);
+ int ret = gContext.device->authenticate(gContext.device, sessionId, groupId);
return reinterpret_cast<jint>(ret);
}
@@ -107,11 +118,11 @@ static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
return reinterpret_cast<jint>(ret);
}
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(fid=%d, gid=%d)\n", fingerId, groupId);
fingerprint_finger_id_t finger;
- finger.gid = 0;
- finger.fid = fingerprintId;
+ finger.fid = fingerId;
+ finger.gid = groupId;
int ret = gContext.device->remove(gContext.device, finger);
return reinterpret_cast<jint>(ret);
}
@@ -172,9 +183,10 @@ static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
// TODO: clean up void methods
static const JNINativeMethod g_methods[] = {
- { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate },
+ { "nativeEnroll", "(II)I", (void*)nativeEnroll },
{ "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel },
- { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeRemove", "(II)I", (void*)nativeRemove },
{ "nativeOpenHal", "()I", (void*)nativeOpenHal },
{ "nativeCloseHal", "()I", (void*)nativeCloseHal },
{ "nativeInit","(Landroid/os/MessageQueue;"
@@ -185,7 +197,7 @@ int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE);
gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gFingerprintServiceClassInfo.notify =
- GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V");
+ GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(IIII)V");
int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
return result;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 19cae03..3478ee3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2226,6 +2226,36 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_useFingerprint">Allows the app to use fingerprint hardware for authentication</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
+ <string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
+ <string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
+ <string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
+ <!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_acquired_vendor">
+ <item>Vendor-specific acquisition error message 0</item>
+ </string-array>
+
+ <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
+ <string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware can't be accessed -->
+ <string name="fingerprint_error_hw_not_available">Hardware not available.</string>
+ <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
+ <string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_vendor">Fingerprint time out reached. Try again.</string>
+ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_error_vendor">
+ <item>Vendor-specifc error message.</item>
+ </string-array>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readSyncSettings">read sync settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 203b017..13f78c5 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2059,6 +2059,19 @@
<!-- From KeyguardServiceDelegate -->
<java-symbol type="string" name="config_keyguardComponent" />
+ <!-- Fingerprint messages -->
+ <java-symbol type="string" name="fingerprint_error_unable_to_process" />
+ <java-symbol type="string" name="fingerprint_error_hw_not_available" />
+ <java-symbol type="string" name="fingerprint_error_no_space" />
+ <java-symbol type="string" name="fingerprint_error_timeout" />
+ <java-symbol type="array" name="fingerprint_error_vendor" />
+ <java-symbol type="string" name="fingerprint_acquired_partial" />
+ <java-symbol type="string" name="fingerprint_acquired_insufficient" />
+ <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
+ <java-symbol type="string" name="fingerprint_acquired_too_slow" />
+ <java-symbol type="string" name="fingerprint_acquired_too_fast" />
+ <java-symbol type="array" name="fingerprint_acquired_vendor" />
+
<!-- From various Material changes -->
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 396fe4f..52e3699 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -40,6 +40,7 @@ import static android.os.BatteryManager.EXTRA_HEALTH;
import android.media.AudioManager;
import android.os.BatteryManager;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
@@ -51,9 +52,11 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.FingerprintManager.AuthenticationResult;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -109,10 +112,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_SCREEN_TURNED_ON = 319;
private static final int MSG_SCREEN_TURNED_OFF = 320;
private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
- private static final int MSG_FINGERPRINT_PROCESSED = 323;
- private static final int MSG_FINGERPRINT_ACQUIRED = 324;
- private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325;
- private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326;
+ private static final int MSG_FINGERPRINT_AUTHENTICATED = 323;
+ private static final int MSG_FINGERPRINT_ERROR = 324;
+ private static final int MSG_FINGERPRINT_HELP = 325;
+ private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 326;
+ private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 327;
private static KeyguardUpdateMonitor sInstance;
@@ -201,11 +205,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_SCREEN_TURNED_ON:
handleScreenTurnedOn();
break;
- case MSG_FINGERPRINT_ACQUIRED:
- handleFingerprintAcquired(msg.arg1);
+ case MSG_FINGERPRINT_AUTHENTICATED:
+ handleFingerprintAuthenticated(msg.arg1, msg.arg2);
+ break;
+ case MSG_FINGERPRINT_HELP:
+ handleFingerprintHelp(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
break;
- case MSG_FINGERPRINT_PROCESSED:
- handleFingerprintProcessed(msg.arg1);
+ case MSG_FINGERPRINT_ERROR:
+ handleFingerprintError(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
break;
case MSG_FACE_UNLOCK_STATE_CHANGED:
handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
@@ -227,7 +234,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
- private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
+ private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
@Override
@@ -314,18 +321,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- private void onFingerprintRecognized(int userId) {
- mUserFingerprintRecognized.put(userId, true);
+ private void onFingerprintAuthenticated(int userId) {
+ mUserFingerprintAuthenticated.put(userId, true);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintRecognized(userId);
+ cb.onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintProcessed(int fingerprintId) {
- if (fingerprintId == 0) return; // not a valid fingerprint
+ private void handleFingerprintAuthenticated(int fingerId, int groupId) {
+ if (fingerId == 0) return; // not a valid fingerprint
final int userId;
try {
@@ -341,17 +348,28 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
final ContentResolver res = mContext.getContentResolver();
final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
for (int i = 0; i < ids.length; i++) {
- if (ids[i] == fingerprintId) {
- onFingerprintRecognized(userId);
+ // TODO: fix once HAL supports storing group id
+ final boolean isCorrectUser = true || (groupId == userId);
+ if (ids[i] == fingerId && isCorrectUser) {
+ onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintAcquired(int info) {
+ private void handleFingerprintHelp(int msgId, String helpString) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAcquired(info);
+ cb.onFingerprintHelp(msgId, helpString);
+ }
+ }
+ }
+
+ private void handleFingerprintError(int msgId, String errString) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFingerprintError(msgId, errString);
}
}
}
@@ -387,7 +405,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
public boolean getUserHasTrust(int userId) {
return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
- || mUserFingerprintRecognized.get(userId);
+ || mUserFingerprintAuthenticated.get(userId);
}
public boolean getUserTrustIsManaged(int userId) {
@@ -464,23 +482,29 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
};
- private FingerprintManagerReceiver mFingerprintManagerReceiver =
- new FingerprintManagerReceiver() {
+
+ private FingerprintManager.AuthenticationCallback mAuthenticationCallback
+ = new AuthenticationCallback() {
+
@Override
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
- };
+ public void onAuthenticationSucceeded(AuthenticationResult result) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED,
+ result.getFingerprint().getFingerId(),
+ result.getFingerprint().getGroupId()).sendToTarget();
+ }
@Override
- public void onAcquired(int info) {
- mHandler.obtainMessage(MSG_FINGERPRINT_ACQUIRED, info, 0).sendToTarget();
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_HELP, helpMsgId, 0, helpString).sendToTarget();
}
@Override
- public void onError(int error) {
- if (DEBUG) Log.w(TAG, "FingerprintManager reported error: " + error);
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString);
}
};
+ private CancellationSignal mFingerprintCancelSignal;
+ private FingerprintManager mFpm;
/**
* When we receive a
@@ -606,6 +630,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOn();
}
}
+ startListeningForFingerprint(mContext);
}
protected void handleScreenTurnedOff(int arg1) {
@@ -617,6 +642,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOff(arg1);
}
}
+ stopListeningForFingerprint();
}
/**
@@ -705,9 +731,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
trustManager.registerTrustListener(this);
- FingerprintManager fpm;
- fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
- fpm.startListening(mFingerprintManagerReceiver);
+ mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+ startListeningForFingerprint(context);
+ }
+
+ private void startListeningForFingerprint(Context context) {
+ if (mFpm != null && mFpm.isHardwareDetected()) {
+ if (mFingerprintCancelSignal == null) {
+ mFingerprintCancelSignal = new CancellationSignal();
+ } else {
+ mFingerprintCancelSignal.cancel();
+ }
+ mFpm.authenticate(null, mAuthenticationCallback, mFingerprintCancelSignal, 0);
+ }
+ }
+
+ private void stopListeningForFingerprint() {
+ if (mFingerprintCancelSignal != null) {
+ mFingerprintCancelSignal.cancel();
+ }
}
private boolean isDeviceProvisionedInSettingsDb() {
@@ -1152,7 +1194,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
public void clearFingerprintRecognized() {
- mUserFingerprintRecognized.clear();
+ mUserFingerprintAuthenticated.clear();
}
public void reportFailedUnlockAttempt() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index f0e2389..c2462e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@ import android.app.admin.DevicePolicyManager;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.SystemClock;
+import android.service.fingerprint.FingerprintManager;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicy;
@@ -176,14 +177,24 @@ public class KeyguardUpdateMonitorCallback {
/**
* Called when a fingerprint is recognized.
- * @param userId
+ * @param userId the user id for which the fingerprint was authenticated
*/
- public void onFingerprintRecognized(int userId) { }
+ public void onFingerprintAuthenticated(int userId) { }
/**
- * Called when fingerprint is acquired but not yet recognized
+ * Called when fingerprint provides help string (e.g. "Try again")
+ * @param msgId
+ * @param helpString
*/
- public void onFingerprintAcquired(int info) { }
+ public void onFingerprintHelp(int msgId, String helpString) { }
+
+ /**
+ * Called when fingerprint provides an semi-permanent error message
+ * (e.g. "Hardware not available").
+ * @param msgId one of the error messages listed in {@link FingerprintManager}
+ * @param errString
+ */
+ public void onFingerprintError(int msgId, String errString) { }
/**
* Called when the state of face unlock changed.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 275a6be..001d660 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -436,7 +436,8 @@ public class KeyguardViewMediator extends SystemUI {
}
}
- public void onFingerprintRecognized(int userId) {
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mViewMediatorCallback.keyguardDone(true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 5ef345b..65cd268 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -125,7 +125,7 @@ public class UnlockMethodCache {
}
@Override
- public void onFingerprintRecognized(int userId) {
+ public void onFingerprintAuthenticated(int userId) {
update(false /* updateAlways */);
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b398f41..ab56b34 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,6 +16,7 @@
package com.android.server.fingerprint;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -29,12 +30,16 @@ import android.util.Slog;
import com.android.server.SystemService;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.Fingerprint;
import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.IFingerprintServiceReceiver;
+
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.USE_FINGERPRINT;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -50,11 +55,14 @@ public class FingerprintService extends SystemService {
private static final int MSG_NOTIFY = 10;
+ private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NOTIFY:
- handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ FpHalMsg m = (FpHalMsg) msg.obj;
+ handleNotify(m.type, m.arg1, m.arg2, m.arg3);
break;
default:
@@ -66,7 +74,7 @@ public class FingerprintService extends SystemService {
private int mHalDeviceId;
private static final int STATE_IDLE = 0;
- private static final int STATE_LISTENING = 1;
+ private static final int STATE_AUTHENTICATING = 1;
private static final int STATE_ENROLLING = 2;
private static final int STATE_REMOVING = 3;
private static final long MS_PER_SEC = 1000;
@@ -76,7 +84,10 @@ public class FingerprintService extends SystemService {
int state;
int userId;
public TokenWatcher tokenWatcher;
- IBinder getToken() { return tokenWatcher.getToken(); }
+
+ IBinder getToken() {
+ return tokenWatcher.getToken();
+ }
}
private class TokenWatcher implements IBinder.DeathRecipient {
@@ -86,7 +97,10 @@ public class FingerprintService extends SystemService {
this.token = new WeakReference<IBinder>(token);
}
- IBinder getToken() { return token.get(); }
+ IBinder getToken() {
+ return token.get();
+ }
+
public void binderDied() {
mClients.remove(token);
this.token = null;
@@ -112,21 +126,42 @@ public class FingerprintService extends SystemService {
// TODO: Move these into separate process
// JNI methods to communicate from FingerprintManagerService to HAL
- static native int nativeEnroll(int timeout);
+ static native int nativeEnroll(int timeout, int groupId);
+
+ static native int nativeAuthenticate(long sessionId, int groupId);
+
static native int nativeEnrollCancel();
- static native int nativeRemove(int fingerprintId);
+
+ static native int nativeRemove(int fingerId, int groupId);
+
static native int nativeOpenHal();
+
static native int nativeCloseHal();
+
static native void nativeInit(MessageQueue queue, FingerprintService service);
+ static final class FpHalMsg {
+ int type; // Type of the message. One of the constants in fingerprint.h
+ int arg1; // optional arguments
+ int arg2;
+ int arg3;
+
+ FpHalMsg(int type, int arg1, int arg2, int arg3) {
+ this.type = type;
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+ }
+
// JNI methods for communicating from HAL to clients
- void notify(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ void notify(int type, int arg1, int arg2, int arg3) {
+ mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget();
}
- void handleNotify(int msg, int arg1, int arg2) {
- Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
- + ", " + mClients.size() + " clients");
+ void handleNotify(int type, int arg1, int arg2, int arg3) {
+ Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", "
+ + mClients.size() + " clients");
for (int i = 0; i < mClients.size(); i++) {
if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i));
ClientData clientData = mClients.valueAt(i);
@@ -134,21 +169,20 @@ public class FingerprintService extends SystemService {
if (DEBUG) Slog.v(TAG, "clientData is invalid!!");
continue;
}
- switch (msg) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ switch (type) {
case FingerprintManager.FINGERPRINT_ERROR: {
- final int error = arg1;
try {
- clientData.receiver.onError(error);
+ clientData.receiver.onError(mHalDeviceId, arg1 /* error */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- break;
+ break;
case FingerprintManager.FINGERPRINT_ACQUIRED: {
- final int acquireInfo = arg1;
try {
- clientData.receiver.onAcquired(acquireInfo);
+ clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -156,9 +190,9 @@ public class FingerprintService extends SystemService {
break;
}
case FingerprintManager.FINGERPRINT_PROCESSED: {
- final int fingerId = arg1;
try {
- clientData.receiver.onProcessed(fingerId);
+ clientData.receiver
+ .onProcessed(mHalDeviceId, arg1 /* fingerId */, arg2 /* groupId */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -167,11 +201,13 @@ public class FingerprintService extends SystemService {
}
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
final int fingerId = arg1;
- final int remaining = arg2;
+ final int groupId = arg2;
+ final int remaining = arg3;
if (clientData.state == STATE_ENROLLING) {
// Only send enroll updates to clients that are actually enrolling
try {
- clientData.receiver.onEnrollResult(fingerId, remaining);
+ clientData.receiver.onEnrollResult(mHalDeviceId, fingerId, groupId,
+ remaining);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -179,8 +215,8 @@ public class FingerprintService extends SystemService {
// Update the database with new finger id.
// TODO: move to client code (Settings)
if (remaining == 0) {
- FingerprintUtils.addFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId,
+ clientData.userId);
clientData.state = STATE_IDLE; // Nothing left to do
}
} else {
@@ -191,30 +227,50 @@ public class FingerprintService extends SystemService {
}
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
int fingerId = arg1;
- if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
- FingerprintUtils.removeFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ int groupId = arg2;
+ if (fingerId == 0) {
+ throw new IllegalStateException("Got illegal id from HAL");
+ }
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver,
+ clientData.userId);
if (clientData.receiver != null) {
try {
- clientData.receiver.onRemoved(fingerId);
+ clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
}
- break;
+ break;
}
}
}
- void startEnroll(IBinder token, long timeout, int userId) {
+ void startEnroll(IBinder token, int groupId, int flags) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
clientData.state = STATE_ENROLLING;
- nativeEnroll((int) (timeout / MS_PER_SEC));
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeEnroll(timeout, groupId);
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startAuthenticate(IBinder token, long sessionId, int groupId, int flags) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
+ clientData.state = STATE_AUTHENTICATING;
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeAuthenticate(sessionId, groupId);
} else {
Slog.w(TAG, "enroll(): No listener registered");
}
@@ -224,7 +280,7 @@ public class FingerprintService extends SystemService {
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
nativeEnrollCancel();
} else {
Slog.w(TAG, "enrollCancel(): No listener registered");
@@ -238,7 +294,7 @@ public class FingerprintService extends SystemService {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_REMOVING;
// The fingerprint id will be removed when we get confirmation from the HAL
- int result = nativeRemove(fingerId);
+ int result = nativeRemove(fingerId, userId);
if (result != 0) {
Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
}
@@ -251,7 +307,7 @@ public class FingerprintService extends SystemService {
if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
if (mClients.get(token) == null) {
ClientData clientData = new ClientData();
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
clientData.receiver = receiver;
clientData.userId = userId;
clientData.tokenWatcher = new TokenWatcher(token);
@@ -266,7 +322,7 @@ public class FingerprintService extends SystemService {
}
}
- void removeListener(IBinder token, int userId) {
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
ClientData clientData = mClients.get(token);
if (clientData != null) {
@@ -278,61 +334,91 @@ public class FingerprintService extends SystemService {
mClients.remove(token);
}
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ ContentResolver resolver = mContext.getContentResolver();
+ int[] ids = FingerprintUtils.getFingerprintIdsForUser(resolver, groupId);
+ List<Fingerprint> result = new ArrayList<Fingerprint>();
+ for (int i = 0; i < ids.length; i++) {
+ // TODO: persist names in Settings
+ CharSequence name = "Finger" + ids[i];
+ final int group = 0; // TODO
+ final int fingerId = ids[i];
+ final long deviceId = 0; // TODO
+ Fingerprint item = new Fingerprint(name, 0, ids[i], 0);
+ result.add(item);
+ }
+ return result;
+ }
+
void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission, "Must have "
- + permission + " permission.");
+ getContext().enforceCallingOrSelfPermission(permission,
+ "Must have " + permission + " permission.");
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- @Override // Binder call
- public void enroll(IBinder token, long timeout, int userId) {
+ @Override
+ // Binder call
+ public void enroll(IBinder token, int groupId, int flags) {
checkPermission(MANAGE_FINGERPRINT);
- startEnroll(token, timeout, userId);
+ startEnroll(token, groupId, flags);
}
- @Override // Binder call
- public void enrollCancel(IBinder token,int userId) {
- checkPermission(MANAGE_FINGERPRINT);
- startEnrollCancel(token, userId);
+ @Override
+ // Binder call
+ public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
+ checkPermission(USE_FINGERPRINT);
+ startAuthenticate(token, sessionId, groupId, flags);
}
- @Override // Binder call
- public void remove(IBinder token, int fingerprintId, int userId) {
+ @Override
+ // Binder call
+ public void remove(IBinder token, int fingerId, int groupId) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
- startRemove(token, fingerprintId, userId);
+ startRemove(token, fingerId, groupId);
}
- @Override // Binder call
- public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
- {
+ @Override
+ // Binder call
+ public void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
checkPermission(USE_FINGERPRINT);
- addListener(token, receiver, userId);
+ FingerprintService.this.addListener(token, receiver, userId);
}
- @Override // Binder call
- public void stopListening(IBinder token, int userId) {
+ @Override
+ // Binder call
+ public void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
checkPermission(USE_FINGERPRINT);
- removeListener(token, userId);
+ FingerprintService.this.removeListener(token, receiver);
}
- @Override // Binder call
- public boolean isHardwareDetected() {
+ @Override
+ // Binder call
+ public boolean isHardwareDetected(long deviceId) {
checkPermission(USE_FINGERPRINT);
- return mHalDeviceId != 0;
+ return mHalDeviceId != 0; // TODO
}
@Override
- public void rename(int fpId, String name) {
+ // Binder call
+ public void rename(int fingerId, int groupId, String name) {
checkPermission(MANAGE_FINGERPRINT);
+ Slog.w(TAG, "rename id=" + fingerId + ",gid=" + groupId + ",name=" + name);
// TODO
}
+
+ @Override
+ // Binder call
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ checkPermission(USE_FINGERPRINT);
+ return FingerprintService.this.getEnrolledFingerprints(groupId);
+ }
}
@Override
public void onStart() {
- publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
- mHalDeviceId = nativeOpenHal();
- if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ mHalDeviceId = nativeOpenHal();
+ if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
}
}