【 Android 10 生物识别 】系列 -- Fingerprint_指纹录入流程

# 前言

由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 Thinking in Android 》 来阅读这边文章(也可以点击 RSS 订阅查看代码更方便),希望这篇文章能帮你梳理清楚“指纹注册流程”

# 核心源码

UerIv8.png 

 

一、FingerprintEnrollIntroduction
接下来我们就从指纹引导界面开始源码分析,图 1 的逻辑就在 FingerprintEnrollIntroduction 类,点击 Next 执行下一步,会执行 onNextButtonClick() 方法。

1.1 FingerprintEnrollIntroduction.onNextButtonClick()
 

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java

public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFingerprintManager = Utils.getFingerprintManagerOrNull(this);

        mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
		
        // Cancel Button
        mFooterBarMixin.setSecondaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.security_settings_face_enroll_introduction_cancel)
                        .setListener(this::onCancelButtonClick)
                        .setButtonType(FooterButton.ButtonType.SKIP)
                        .setTheme(R.style.SudGlifButton_Secondary)
                        .build()
        );

        // Next Button
        mFooterBarMixin.setPrimaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.wizard_next)
                        .setListener(this::onNextButtonClick)    // 点击 "下一步" 的处理流程
                        .setButtonType(FooterButton.ButtonType.NEXT)
                        .setTheme(R.style.SudGlifButton_Primary)
                        .build()
        );
    }

}

我们可以发现:FingerprintEnrollIntroduction 继承自 BiometricEnrollIntroduction,onNextButtonClick() 方法在其父类 BiometricEnrollIntroduction 中处理。
二、BiometricEnrollIntroduction
2.1 BiometricEnrollIntroduction.onNextButtonClick()

 

// packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java

public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
        implements LinkSpan.OnClickListener {

    @Override
    protected void onNextButtonClick(View view) {
        mNextClicked = true;
        if (checkMaxEnrolled() == 0) {
            // Lock thingy is already set up, launch directly to the next page
            launchNextEnrollingActivity(mToken);    // 接下来就要拉起指纹录入界面
        } else {
            setResult(RESULT_FINISHED);
            finish();
        }
    }
		
}

2.2 BiometricEnrollIntroduction.launchNextEnrollingActivity()

// packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java

public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
        implements LinkSpan.OnClickListener {

    private void launchNextEnrollingActivity(byte[] token) {
        Intent intent = getEnrollingIntent();    // 获取 FingerprintEnrollFindSensor
        if (token != null) {
            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
        }
        if (mUserId != UserHandle.USER_NULL) {
            intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
        }
        intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
        startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST);    // 跳转 FingerprintEnrollFindSensor
    }
		
}

我们看下 getEnrollingIntent() 方法:

// packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java

public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
        implements LinkSpan.OnClickListener {

    protected abstract Intent getEnrollingIntent();    // 抽象方法,由子类 FingerprintEnrollIntroduction 实现
	
}

所以我们跳转到 FingerprintEnrollIntroduction

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java

public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {

    @Override
    protected Intent getEnrollingIntent() {
        return new Intent(this, FingerprintEnrollFindSensor.class);    // 获取 FingerprintEnrollFindSensor
    }
	
}

三、FingerprintEnrollFindSensor

我们把上面的图再拿过来,此时就进入了图 2 界面的逻辑,我们接着往下看。

UerIv8.png

3.1 FingerprintEnrollFindSensor.onCreate() 

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getContentView());
        mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
        // Skip button
        mFooterBarMixin.setSecondaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.skip_label)
                        .setListener(this::onSkipButtonClick)
                        .setButtonType(FooterButton.ButtonType.SKIP)
                        .setTheme(R.style.SudGlifButton_Secondary)
                        .build()
        );

        // Touch the sensor
        setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);

        // 执行 startLookingForFingerprint() 方法
        startLookingForFingerprint(); // already confirmed, so start looking for fingerprint

        // 演示动画
        View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
        if (animationView instanceof FingerprintFindSensorAnimation) {
            mAnimation = (FingerprintFindSensorAnimation) animationView;
        } else {
            mAnimation = null;
        }
    }

}

到这里都只是涉及到 UI 界面的相关逻辑,接下来的代码逻辑就稍微复杂一点了,我们仔细深挖研究。

3.2 FingerprintEnrollFindSensor.startLookingForFingerprint()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    private FingerprintEnrollSidecar mSidecar;
    private boolean mNextClicked;

    private void startLookingForFingerprint() {
        // FingerprintEnrollSidecar 这个 fragment 的生命周期正式开启
        mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
                FingerprintEnrollEnrolling.TAG_SIDECAR);
        if (mSidecar == null) {
            mSidecar = new FingerprintEnrollSidecar();
            // 添加 FingerprintEnrollEnrolling
            getSupportFragmentManager().beginTransaction()
                    .add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
                    .commitAllowingStateLoss();
        }

        // FingerprintEnrollEnrolling 实现了 BiometricEnrollSidecar.Listener 接口
        mSidecar.setListener(new Listener() {    // 匿名内部类的方式实现接口方法
            @Override
            public void onEnrollmentProgressChange(int steps, int remaining) {
                mNextClicked = true;
                proceedToEnrolling(true /* cancelEnrollment */);
            }

            @Override
            public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
            }

            @Override
            public void onEnrollmentError(int errMsgId, CharSequence errString) {
                if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                    mNextClicked = false;
                    proceedToEnrolling(false /* cancelEnrollment */);
                }
            }
        });
    }

}

这里面有个重点方法:onEnrollmentProgressChange(),如果我们此时用手指贴在指纹传感器上,会产生反馈信息的回调,此时 onEnrollmentProgressChange() 方法被执行,进入执行 proceedToEnrolling() 方法,我们看下这个方法:
 

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    private void proceedToEnrolling(boolean cancelEnrollment) {
        if (mSidecar != null) {
            if (cancelEnrollment) {
                if (mSidecar.cancelEnrollment()) {
                    // Enrollment cancel requested. When the cancellation is successful,
                    // onEnrollmentError will be called with FINGERPRINT_ERROR_CANCELED, calling
                    // this again.
                    return;
                }
            }
            getSupportFragmentManager().beginTransaction().remove(mSidecar).
                    commitAllowingStateLoss();
            mSidecar = null;
            // getFingerprintEnrollingIntent() 方法会返回一个包含 FingerprintEnrollEnrolling 的 Intent
            startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
        }
    }

}

正常流程会走到 startActivityForResult() 方法,跳转到 FingerprintEnrollEnrolling 界面。

四、FingerprintEnrollEnrolling

我们把上面的图再拿过来,此时就进入了图 3 界面的逻辑,我们接着往下看。

UerIv8.png

 

4.1 FingerprintEnrollEnrolling.onStart()

我们重点关注 onStart() 方法:

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

/**
 * Activity which handles the actual enrolling for fingerprint.
 */
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    @Override
    protected void onStart() {
        super.onStart();    // 调用父类 BiometricEnrollSidecar 的 onStart() 方法
        updateProgress(false /* animate */);    // 更新录入进度
        updateDescription();
        if (mRestoring) {
            startIconAnimation();
        }
    }

}

FingerprintEnrollEnrolling 类继承自 BiometricsEnrollEnrolling 类,而 BiometricsEnrollEnrolling 类实现了 BiometricEnrollSidecar.Listener 接口,所以 FingerprintEnrollEnrolling 也实现了 BiometricEnrollSidecar.Listener 接口。
 

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

/**
 * Activity which handles the actual enrolling for fingerprint.
 */
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    // 指纹录制时提示(比如太快,移动手指之类)
    @Override
    public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
        if (!TextUtils.isEmpty(helpString)) {
            mErrorText.removeCallbacks(mTouchAgainRunnable);
            showError(helpString);
        }
    }

    // 提示指纹录制过程中超时,或者未注册
    @Override
    public void onEnrollmentError(int errMsgId, CharSequence errString) {
        int msgId;
        switch (errMsgId) {
            case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
                msgId = R.string.security_settings_fingerprint_enroll_error_timeout_dialog_message;
                break;
            default:
                msgId = R.string.security_settings_fingerprint_enroll_error_generic_dialog_message;
                break;
        }
        showErrorDialog(getText(msgId), errMsgId);
        stopIconAnimation();
        mErrorText.removeCallbacks(mTouchAgainRunnable);
    }

    // 录制过程中进度的变化(手指按压指纹传感区,onEnrollmentProgressChange() 会被触发,执行一系列处理工作)
    @Override
    public void onEnrollmentProgressChange(int steps, int remaining) {
        updateProgress(true /* animate */);    // 更新进度
        updateDescription();    // 更新描述
        clearError();
        animateFlash();    // 更新动画
        mErrorText.removeCallbacks(mTouchAgainRunnable);
        mErrorText.postDelayed(mTouchAgainRunnable, HINT_TIMEOUT_DURATION);
    }

}

五、BiometricsEnrollEnrolling

5.1 BiometricsEnrollEnrolling.onStart()

// packages/apps/Settings/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java

public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
        implements BiometricEnrollSidecar.Listener {

    @Override
    protected void onStart() {
        super.onStart();
        if (shouldStartAutomatically()) {    // 恒定为 true
            startEnrollment();    // 调用 startEnrollment() 方法
        }
    }
		
}

5.2 BiometricsEnrollEnrolling.startEnrollment()

// packages/apps/Settings/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java

public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
        implements BiometricEnrollSidecar.Listener {

    protected BiometricEnrollSidecar mSidecar;

    protected abstract BiometricEnrollSidecar getSidecar();    // 抽象方法,由子类实现

    public void startEnrollment() {
        // 调用 BiometricEnrollSidecar 的 onStart() 方法
        mSidecar = (BiometricEnrollSidecar) getSupportFragmentManager()
                .findFragmentByTag(TAG_SIDECAR);
        if (mSidecar == null) {
            mSidecar = getSidecar();    // 获取 mSidecar
            getSupportFragmentManager().beginTransaction().add(mSidecar, TAG_SIDECAR)
                    .commitAllowingStateLoss();
        }
        mSidecar.setListener(this);
    }
		
}

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    @Override
    protected BiometricEnrollSidecar getSidecar() {
        // 返回了一个继承自 BiometricEnrollSidecar 的 FingerprintEnrollSidecar 对象
        return new FingerprintEnrollSidecar();
    }

}

六、FingerprintEnrollSidecar

6.1 FingerprintEnrollSidecar.startEnrollment()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java

/**
 * Sidecar fragment to handle the state around fingerprint enrollment.
 */
public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {

    private FingerprintManager mFingerprintManager;

    @Override
    protected void startEnrollment() {
        super.startEnrollment();
        if (mUserId != UserHandle.USER_NULL) {
            mFingerprintManager.setActiveUser(mUserId);
        }
        /*
         * 调用 FingeprintManager 的 enroll() 方法开始录入,并且传入了 EnrollmentCallback 对象
         * EnrollmentCallback 是指纹录入结果的回调,分别调用了 BiometricEnrollSidecar.Listener 接口中的方法,
         * 这样就能更新指纹录制的进度和录制结果。
         */
        mFingerprintManager.enroll(mToken, mEnrollmentCancel, 0 /* flags */, mUserId, mEnrollmentCallback);
    }

我们看下 EnrollmentCallback 对象是什么:

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java

public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {

    private FingerprintManager.EnrollmentCallback mEnrollmentCallback
            = new FingerprintManager.EnrollmentCallback() {

        @Override
        public void onEnrollmentProgress(int remaining) {
            FingerprintEnrollSidecar.super.onEnrollmentProgress(remaining);
        }

        @Override
        public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
            FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
        }

        @Override
        public void onEnrollmentError(int errMsgId, CharSequence errString) {
            FingerprintEnrollSidecar.super.onEnrollmentError(errMsgId, errString);
        }
    };

}

七、FingerprintManager

7.1 FingerprintManager.enroll()

// frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private IFingerprintService mService;

    // CancellationSignal 类提供删除信号类,提供终止操作的能力
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = getCurrentUserId();
        }
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Slog.w(TAG, "enrollment already canceled");
                return;
            } else {
                cancel.setOnCancelListener(new OnEnrollCancelListener());
            }
        }

        if (mService != null) try {
            mEnrollmentCallback = callback;
            // 调用 FingerprintServiceWrapper 的 enroll() 方法
            mService.enroll(mToken, token, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception in enroll: ", e);
            if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or try
                // again later.
                callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
                            0 /* vendorCode */));
            }
        }
    }

}

八、FingerprintService
8.1 FingerprintServiceWrapper.enroll()

FingerprintManager 与 FingerprintService 直接通过 aidl 进行通信,在 FingerprintService 中内部类 FingerprintServiceWrapper 实现了 IFingerprintService.Stub,我们调用的 FingerManger 的 enroll() 方法就是调用 FingerprintServiceWrapper 类中的 enroll() 方法。
 

// frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java

public class FingerprintService extends BiometricServiceBase {

    /**
     * Receives the incoming binder calls from FingerprintManager.
     */
    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 boolean restricted = isRestricted();
            final int groupId = userId; // default group for fingerprint enrollment
            final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                    mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
                    ENROLL_TIMEOUT_SEC) {
                @Override
                public boolean shouldVibrate() {
                    return true;
                }

                @Override
                protected int statsModality() {
                    return FingerprintService.this.statsModality();
                }
            };

            enrollInternal(client, userId);    // 调用 BiometricServiceBase 的 enrollInternal() 方法
        }

	}

}

九、BiometricServiceBase

9.1 BiometricServiceBase.enrollInternal()

// frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    protected void enrollInternal(EnrollClientImpl client, int userId) {
        if (hasReachedEnrollmentLimit(userId)) {
            return;
        }

        // Group ID is arbitrarily set to parent profile user ID. It just represents
        // the default biometrics for the user.
        if (!isCurrentUserOrProfile(userId)) {
            return;
        }

        mHandler.post(() -> {
            startClient(client, true /* initiatedByClient */);    // 调用 startClient() 方法
        });
    }		

}

9.2 BiometricServiceBase.startClient()

// frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
        ClientMonitor currentClient = mCurrentClient;
        if (currentClient != null) {
            if (DEBUG) Slog.v(getTag(), "request stop current client " +
                    currentClient.getOwnerString());
            if (currentClient instanceof InternalEnumerateClient
                    || currentClient instanceof InternalRemovalClient) {
                if (newClient != null) {
                    Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
                            + newClient.getClass().getSuperclass().getSimpleName()
                            + "(" + newClient.getOwnerString() + ")"
                            + ", initiatedByClient = " + initiatedByClient);
                }
            } else {
                currentClient.stop(initiatedByClient);

                mHandler.removeCallbacks(mResetClientState);
                mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
            }
            mPendingClient = newClient;
        } else if (newClient != null) {
            if (newClient instanceof AuthenticationClient) {
                AuthenticationClient client = (AuthenticationClient) newClient;
                if (client.isBiometricPrompt()) {
                    if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
                    mCurrentClient = newClient;
                    if (mBiometricService == null) {
                        mBiometricService = IBiometricService.Stub.asInterface(
                                ServiceManager.getService(Context.BIOMETRIC_SERVICE));
                    }
                    try {
                        mBiometricService.onReadyForAuthentication(client.getCookie(),
                                client.getRequireConfirmation(), client.getTargetUserId());
                    } catch (RemoteException e) {
                        Slog.e(getTag(), "Remote exception", e);
                    }
                    return;
                }
            }

            // We are not a BiometricPrompt client, start the client immediately
            mCurrentClient = newClient;
            startCurrentClient(mCurrentClient.getCookie());    // 调用 startCurrentClient() 方法
        }
    }
		
}

9.3 BiometricServiceBase.startCurrentClient()

// frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    private ClientMonitor mCurrentClient;

    protected void startCurrentClient(int cookie) {
        if (mCurrentClient == null) {
            Slog.e(getTag(), "Trying to start null client!");
            return;
        }
        if (DEBUG) Slog.v(getTag(), "starting client "
                + mCurrentClient.getClass().getSuperclass().getSimpleName()
                + "(" + mCurrentClient.getOwnerString() + ")"
                + " targetUserId: " + mCurrentClient.getTargetUserId()
                + " currentUserId: " + mCurrentUserId
                + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
        if (cookie != mCurrentClient.getCookie()) {
            Slog.e(getTag(), "Mismatched cookie");
            return;
        }
        notifyClientActiveCallbacks(true);
        mCurrentClient.start();    // 调用 EnrollClient 的 start() 方法
    }

}

十、EnrollClient

10.1 EnrollClient.start()

// frameworks/base/services/core/java/com/android/server/biometrics/EnrollClient.java

// EnrollClient 是为给定的客户端跟踪指纹录制状态
public abstract class EnrollClient extends ClientMonitor {

    // start 方法会调用 fingerprintd,调用底层的指纹库,底层库返回结果后会调用 onEnrollResult 来反馈结果给 receiver,再往上层反馈。
    @Override
    public int start() {
        mEnrollmentStartTimeMs = System.currentTimeMillis();
        try {
            final ArrayList<Integer> disabledFeatures = new ArrayList<>();
            for (int i = 0; i < mDisabledFeatures.length; i++) {
                disabledFeatures.add(mDisabledFeatures[i]);
            }

            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
                    disabledFeatures);
            if (result != 0) {
                Slog.w(getLogTag(), "startEnroll failed, result=" + result);
                mMetricsLogger.histogram(mConstants.tagEnrollStartError(), result);
                onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                        0 /* vendorCode */);
                return result;
            }
        } catch (RemoteException e) {
            Slog.e(getLogTag(), "startEnroll failed", e);
        }
        return 0; // success
    }

}

getDaemonWrapper().enroll() 会调用 fingerprintd,调用底层的指纹库,底层库返回结果后会调用 onEnrollResult 来反馈结果给 receiver,在往上层反馈。这就是指纹的录制流程。

// frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private Handler mHandler;

    // mServiceReceiver 对象会通过 handler 发送相关消息去调用 EnrollmentCallback 或者 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, int vendorCode) {
            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
                    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, int vendorCode) {
            mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
        }

        @Override // binder call
        public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
            mHandler.obtainMessage(MSG_REMOVED, remaining, 0,
                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
        }

        @Override // binder call
        public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
            // TODO: propagate remaining
            mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget();
        }
    };
	
    private class MyHandler extends Handler {
        private MyHandler(Context context) {
            super(context.getMainLooper());
        }

        private MyHandler(Looper looper) {
            super(looper);
        }

        @Override
        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 */,
                            msg.arg2 /* vendorCode */);
                    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 */,
                            msg.arg2 /* vendorCode */);
                    break;
                case MSG_REMOVED:
                    sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                    break;
                case MSG_ENUMERATED:
                    sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
                            msg.arg2 /* groupId */);
                    break;
            }
        }
    };
}

看下 MSG_ENROLL_RESULT

// frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private void sendEnrollResult(Fingerprint fp, int remaining) {
        if (mEnrollmentCallback != null) {
            // 调用 EnrollmentCallback 的 onEnrollmentProgress 方法
            mEnrollmentCallback.onEnrollmentProgress(remaining);
        }
    }

}

# Enroll 流程图

UKXCTS.png

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个项目包含了指纹图像增强和指纹图像识别两个部分。在指纹图像增强部分,主要使用了以下公式: 1. 方向图像计算 首先,通过计算梯度图像的方向和大小,得到梯度方向图像和梯度大小图像。具体的公式如下: $$G_{x}=\begin{bmatrix}-1&0&1\\-2&0&2\\-1&0&1\end{bmatrix}*I$$ $$G_{y}=\begin{bmatrix}-1&-2&-1\\0&0&0\\1&2&1\end{bmatrix}*I$$ $$M=\sqrt{G_{x}^2+G_{y}^2}$$ $$\theta=\tan^{-1}\left(\frac{G_{y}}{G_{x}}\right)$$ 其中,$G_{x}$和$G_{y}$分别表示图像在水平和垂直方向的梯度,$I$为原始图像,$M$表示梯度大小图像,$\theta$表示梯度方向图像。 2. 统计局部方向直方图 对于每个像素点,计算其周围一定范围内的梯度方向直方图,得到一个局部方向直方图。具体的公式如下: $$h_i=\sum_{(x,y)\in N_i}\omega_{x,y}\delta(\theta_{x,y}-\theta_i)$$ 其中,$N_i$表示以当前像素点为中心的一个固定大小的邻域,$\omega_{x,y}$为权重系数,$\delta$为Kronecker delta函数,$\theta_i$为当前像素点的梯度方向。 3. 估计全局方向 通过计算所有局部方向直方图的峰值位置,得到一个全局方向。具体的公式如下: $$\theta_{global}=\frac{1}{2}\left(\max_i(h_i)+\min_i(h_i)\right)$$ 4. 旋转图像 根据估计的全局方向,对原始图像进行旋转,使得所有指纹纹线的方向与x轴平行。具体的公式如下: $$I_{rot}(x,y)=I(x\cos(\theta_{global})+y\sin(\theta_{global}),-x\sin(\theta_{global})+y\cos(\theta_{global}))$$ 在指纹图像识别部分,主要使用了以下公式: 1. 计算指纹特征向量 将指纹图像分成多个小块,对于每个小块,计算其局部方向直方图,并将直方图转换成一个特征向量。具体的公式和方法可以参考论文《Fingerprint Minutiae Recognition based on Local Features》。 2. 计算指纹相似度 通过计算两个指纹特征向量之间的距离,来判断两个指纹的相似度。常用的距离度量有欧氏距离、曼哈顿距离、余弦距离等。具体的公式可以参考论文《Fingerprint Minutiae Recognition based on Local Features》。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值