4. Fingerprint recording process
The fingerprint recording activity implements the FingerprintEnrollSidecar.Listener interface for FingerprintEnrollEnrolling.
// Prompt during fingerprint recording (such as too fast, move your finger, etc.)
@Override
public void onEnrollmentHelp(CharSequence helpString) {
mErrorText.setText(helpString);
}
// Indicates that the fingerprint recording timed out or is not registered.
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
int msgId;
......
showErrorDialog(getText(msgId), errMsgId);
......
}
// Changes in progress during recording
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
updateProgress (true / * animate * /); // Update progress
updateDescription (); // Update description
animateFlash (); // Update animation
......
}
FingerprintEnrollSidecar's onStart method calls startEnrollment (), which calls the FingerrollManager's enroll method, and the EnrollmentCallback object is passed in. EnrollmentCallback is the callback of the fingerprint entry result, and the methods in the FingerprintEnrollSidecar.Listener interface are called separately so that they can be updated Fingerprint recording progress and recording results.
private void startEnrollment() {
......
mFingerprintManager.enroll(mToken, mEnrollmentCancel,
0 /* flags */, mUserId, mEnrollmentCallback);
mEnrolling = true;
}
private FingerprintManager.EnrollmentCallback mEnrollmentCallback
= new FingerprintManager.EnrollmentCallback() {
@Override
public void onEnrollmentProgress(int remaining) {
......
mListener.onEnrollmentProgressChange(mEnrollmentSteps, remaining);
}
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (mListener != null) {
mListener.onEnrollmentHelp(helpString);
}
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onEnrollmentError(errMsgId, errString);
}
mEnrolling = false;
}
};
public void enroll(byte [] token, CancellationSignal cancel, int flags,
int userId, EnrollmentCallback callback) {
......
mService.enroll(mToken, token, userId, mServiceReceiver, flags,
mContext.getOpPackageName ());
......
Pay attention to the incoming mServiceReceiver object. This object will send related messages through the handler to call the methods in EnrollmentCallback or AuthenticationCallback.
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
@Override // binder call
public void onAcquired(long deviceId, int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
}
@Override // binder call
public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
}
@Override // binder call
public void onAuthenticationFailed(long deviceId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
}
@Override // binder call
public void onError(long deviceId, int error) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
}
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
}
};
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_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
break;
case MSG_ERROR:
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
break;
case MSG_REMOVED:
sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
}
}
FingerprintManager and FingerprintService communicate directly through aidl. In FingerprintService, the internal class FingerprintServiceWrapper implements IFingerprintService.Stub. The Fingerroller enroll method we call is to call enroll () in FingerprintServiceWrapper class.
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
......
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken,
final int userId,final IFingerprintServiceReceiver receiver,
final int flags,
final String opPackageName) {
checkPermission(MANAGE_FINGERPRINT);
final int limit = mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
final int enrolled = FingerprintService.this.
getEnrolledFingerprints(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many fingerprints registered");
return;
}
......
mHandler.post(new Runnable() {
@Override
public void run() {
startEnrollment(token, cryptoToken, userId, receiver,
flags,restricted, opPackageName);
}
});
}
The start method of EnrollClient is called in the startEnrollment method. EnrollClient tracks the fingerprint recording status for a given client.
/**
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends ClientMonitor {
......
public EnrollClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken,
boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
......
}
@Override
public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
......
return sendEnrollResult(fingerId, groupId, remaining);
}
/*
* @return true if we're done.
*/
private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
IFingerprintServiceReceiver receiver = getReceiver();
......
receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining);
......
}
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
......
final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
......
return 0; // success
}
The start method will call fingerprintd and call the bottom fingerprint library. After the bottom library returns the result, it will call onEnrollResult to feed back the result to the receiver, and feedback to the upper layer. This is the fingerprint recording process.