diff options
author | Jim Miller <jaggies@google.com> | 2015-03-23 23:59:22 -0700 |
---|---|---|
committer | Jim Miller <jaggies@google.com> | 2015-03-24 17:02:46 -0700 |
commit | 9f0753f5a378fc80da86305b33244acc6fc53f01 (patch) | |
tree | a86544b9552afaf5e332273dabc1684d9c40ff8a | |
parent | 9b58c85524675fd81cd093a8df5273a02f537661 (diff) | |
download | frameworks_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
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); } } |