设置指纹识别模块分析

一,   指纹项的加载

首先我们从指纹项的布局加载开始分析,从手机设置下边直观的可以发现,指纹项是放在二级菜单安全菜单里边的,下面我们就从代码里边分析一下,指纹项是如何被加载进来的。

首先我们应该从SecuritySettings.java的加载开始分析,在该类起来之后,在它的

@Override
public void onResume() {
    super.onResume();
    // Make sure wereload the preference hierarchy since some of these settings
    // depend on others...
    createPreferenceHierarchy();

//省略代码
}

我们可以看到调用了createPreferenceHierarchy();方法,下面看看这个方法:

private PreferenceScreen createPreferenceHierarchy() {PreferenceScreen root = getPreferenceScreen();if (root != null) {root.removeAll();}addPreferencesFromResource(R.xml.security_settings);//通过布局文件加载一些基础的布局root = getPreferenceScreen();//代码省略
if (mProfileChallengeUserId != UserHandle.USER_NULL&& mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId)) {addPreferencesFromResource(R.xml.security_settings_profile);addPreferencesFromResource(R.xml.security_settings_unification);final int profileResid = getResIdForLockUnlockScreen(getActivity(), mLockPatternUtils, mManagedPasswordProvider,mProfileChallengeUserId);addPreferencesFromResource(profileResid);maybeAddFingerprintPreference(root, mProfileChallengeUserId);
               //从这里看到了我们想要的加载指纹的布局,下边看看这个方法内容:
               //代码省略
}  
                    
private void maybeAddFingerprintPreference(PreferenceGroup securityCategory, int userId) {Preference fingerprintPreference =FingerprintSettings.getFingerprintPreferenceForUser(securityCategory.getContext(), userId);if (fingerprintPreference != null) {securityCategory.addPreference(fingerprintPreference);}
}

这个方法看起来比较简单,首先是获取到这个fingerprintPreference,然后直接加载到securityCategory,从而让指纹项显示出来。但是点击事件却是在下边这个方法的,该方法getFingerprintPreferenceForUser()是在FingerprintSettings的一个全局方法,如下:

public static Preference getFingerprintPreferenceForUser(Context context, final int userId) {FingerprintManager fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);if (fpm == null || !fpm.isHardwareDetected()) {Log.v(TAG, "No fingerprint hardware detected!!");return null;}Preference fingerprintPreference = new Preference(context);fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);//设置点击的键fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title);final List<Fingerprint> items = fpm.getEnrolledFingerprints(userId);final int fingerprintCount = items != null ? items.size() : 0;final String clazz;
               //这个直接决定点击指纹项要启动的是哪个界面if (fingerprintCount > 0) {fingerprintPreference.setSummary(context.getResources().getQuantityString(R.plurals.security_settings_fingerprint_preference_summary,fingerprintCount, fingerprintCount));clazz = FingerprintSettings.class.getName();} else {fingerprintPreference.setSummary(R.string.security_settings_fingerprint_preference_summary_none);//slt yangxinzhao modified for lenovo UIclazz = FingerprintEnrollIntroduction.class.getName();}
               //这里是最关键的地方,为指纹项设置点击监听,
    fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {@Overridepublic boolean onPreferenceClick(Preference preference) {final Context context = preference.getContext();final UserManager userManager = UserManager.get(context); if (Utils.startQuietModeDialogIfNecessary(context, userManager,userId)) {return false;}Intent intent = new Intent();intent.setClassName("com.android.settings", clazz);intent.putExtra(Intent.EXTRA_USER_ID, userId);context.startActivity(intent);           return true;
}});return fingerprintPreference;
}

从这个方法中可以看出主要是做了一些指纹界面的初始化工作。其中有个比较关键的判断条件就是fingerprintCount,如果指纹的个数不为0,那么就点击菜单项打开的是指纹注册引导界面,即FingerprintEnrollIntroduction,否则打开的就是指纹项界面,即FingerprintSettings。到此,整个指纹界面的加载流程就梳理完了。

二,   指纹界面处理逻辑

1,首先来看一下指纹界面FingerprintSettings.java),该类继承SubSettings.java

而此类又是继承自SettingsActivity.java,首先我们从OnCreate()函数开始看:

@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);CharSequence msg = getText(R.string.security_settings_fingerprint_preference_title);setTitle(msg);
}

可以看到这个函数里边仅仅只是设置了这个activity的title。下边再看一个方法:

@Override
public Intent getIntent() {Intent modIntent = new Intent(super.getIntent());modIntent.putExtra(EXTRA_SHOW_FRAGMENT,
FingerprintSettingsFragment.class.getName());return modIntent;
}

从此方法可以看到这个activity是绑定的FingerprintSettingsFragment,所以我们接下来只需要分析这个fragment就可以了。

2,分析此fragment还是先从onCreate()函数开始分析:

@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (savedInstanceState != null) {mToken = savedInstanceState.getByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);mLaunchedConfirm = savedInstanceState.getBoolean(KEY_LAUNCHED_CONFIRM, false);}mUserId = getActivity().getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());Activity activity = getActivity();mFingerprintManager = (FingerprintManager) activity.getSystemService(Context.FINGERPRINT_SERVICE);// Need to authenticate a session token if noneif (mToken == null && mLaunchedConfirm == false) {mLaunchedConfirm = true;//当进入该界面,就把标志位置为truelaunchChooseOrConfirmLock();//启动密码确认界面}
}

从这个方法可以看到这里其实并没有做什么,只是进行了一些相关数据的初始化。但有一点需要注意,mLaunchedConfirm这变量表示是否需要进行密码确认,如果为false就需要进行密码确认,从而启动对应的密码确认界面,具体的方法如下:

private void launchChooseOrConfirmLock() {Intent intent = new Intent();long challenge = mFingerprintManager.preEnroll();ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this);if (!helper.launchConfirmationActivity(CONFIRM_REQUEST,getString(R.string.security_settings_fingerprint_preference_title),null, null, challenge, mUserId)) {intent.setClassName("com.android.settings", ChooseLockGeneric.class.getName());intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS,true);intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);intent.putExtra(Intent.EXTRA_USER_ID, mUserId);intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);intent.putExtra(Intent.EXTRA_USER_ID, mUserId);startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);}
}

接下来我们就看看这个fragment的onResume()方法:

@Override
public void onResume() {super.onResume();// Make sure we reload the preference hierarchy since fingerprints may be added,// deleted or renamed.updatePreferences();
}

从这里可以看到整个指纹界面就是从这里开始创建的,具体代码如下:

private void updatePreferences() {createPreferenceHierarchy();//进行界面的创建retryFingerprint();//认证指纹,也就是在这个activity起来之后就可以直接认证指纹了
}

下面我们具体看看指纹界面是如何创建的,指纹界面包含两个部分,一部分是最下边的指纹使用介绍,这部分仅仅是一个textview,还有一部分就是每个指纹选项和添加指纹选项,我们稍后介绍,先来看看指纹介绍是如何添加的,代码如下:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);TextView v = (TextView) LayoutInflater.from(view.getContext()).inflate(R.layout.fingerprint_settings_footer, null);EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(getActivity(), DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId);v.setText(getText(admin != null? R.string.security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled: R.string.security_settings_fingerprint_enroll_disclaimer));/*end of slt yangxinzhao modified for lenovo UI */setFooterView(v);
}

这部分代码很简单,仅仅是在onViewCreated()方法里边添加一个布局文件fingerprint_settings_footer.xml,这个布局文件仅仅是一个LinkTextView,仅作为显示文字之用,我们主要看看第二部分的指纹选项和添加指纹选项是如何加载的,代码如下:

private PreferenceScreen createPreferenceHierarchy() {PreferenceScreen root = getPreferenceScreen();if (root != null) {root.removeAll();}addPreferencesFromResource(R.xml.security_settings_fingerprint);//加载基础布局,实际上是一个空布局root = getPreferenceScreen();addFingerprintItemPreferences(root);//添加指纹条目,最多能够添加五个指纹setPreferenceScreen(root);return root;
}

我们从security_settings_fingerprint.xml可以看到这是一个空的布局文件,里边的选项都是通过动态加载进去的,具体代码可以看方法addFingerprintItemPreferences(root),

private void addFingerprintItemPreferences(PreferenceGroup root) {root.removeAll();final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);final int fingerprintCount = items.size();
               //通过for循环进行指纹条目的添加,同时设置各个属性已经点击监听for (int i = 0; i < fingerprintCount; i++) {final Fingerprint item = items.get(i);FingerprintPreference pref = new FingerprintPreference(root.getContext());pref.setKey(genKey(item.getFingerId()));pref.setTitle(item.getName());pref.setFingerprint(item);pref.setPersistent(false);pref.setIcon(R.drawable.ic_fingerprint_24dp);root.addPreference(pref);pref.setOnPreferenceChangeListener(this);/*slt yangxinzhao added for lenovo UI 20170118*/pref.setIcon(R.drawable.ic_fingerprint_list_icon);/*end of added*/}
               //添加指纹选项,并且设置对应的属性以及点击监听
    Preference addPreference = new Preference(root.getContext());addPreference.setKey(KEY_FINGERPRINT_ADD);addPreference.setTitle(R.string.fingerprint_add_title);addPreference.setIcon(R.drawable.ic_add_24dp);root.addPreference(addPreference);addPreference.setOnPreferenceChangeListener(this);updateAddPreference();
}

这部分其实主要也是分为两部分进行添加的,第一部分就是指纹条目,通过final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
将所有的指纹条目读取出来,使用for循环进行创建的条目,每一个条目包含了指纹条目的键,指纹的id,对应的图标等属性,同时为每个条目设置点击监听,pref.setOnPreferenceChangeListener(this);
同时在这个里边也添加了添加指纹选项,到此,整个指纹界面的的布局已经添加完成了,后边这个界面还会进行冬天更新,比如添加和删除指纹的操作都会更新这个界面,后面继续分析。

3,指纹的添加

我们前边说过为添加指纹选项设置了点击事件监听,我们看看这个点击事件:

@Overridepublic boolean onPreferenceTreeClick(Preference pref) {final String key = pref.getKey();if (KEY_FINGERPRINT_ADD.equals(key)) {Intent intent = new Intent();intent.setClassName("com.android.settings",FingerprintEnrollEnrolling.class.getName());intent.putExtra(Intent.EXTRA_USER_ID, mUserId);intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);} else if (pref instanceof FingerprintPreference) {FingerprintPreference fpref = (FingerprintPreference) pref;final Fingerprint fp =fpref.getFingerprint();showRenameDeleteDialog(fp);return super.onPreferenceTreeClick(pref);}return true;}

通过不同的Key判断,处理对应的事件,当点击添加指纹选项时,执行了如下代码:

Intent intent = new Intent();
intent.setClassName("com.android.settings",
FingerprintEnrollEnrolling.class.getName());
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
我们可以看到是启动了FingerprintEnrollEnrolling这个类进行指纹的添加,并且给返回了

ADD_FINGERPRINT_REQUEST这个结果。这个指纹注册的过程我们暂时不作关注,只要知道注册完指纹之后返回了结果就可以了,有兴趣的可以继续研究一下指纹的注册。

当添加完指纹返回之后,重新回到onResume()方法,执行界面更新,这时候新添加的指纹就会出现在指纹界面。

4,指纹的删除

前边也说过,添加指纹条目的时候已经为指纹条目设置了点击事件监听,当点击指纹条目的时候直接调用了方法showRenameDeleteDialog(fp);参数为传入的指纹,具体方法如下:

private void showRenameDeleteDialog(final Fingerprint fp) {RenameDeleteDialog renameDeleteDialog = new RenameDeleteDialog();Bundle args = new Bundle();args.putParcelable("fingerprint", fp);renameDeleteDialog.setArguments(args);renameDeleteDialog.setTargetFragment(this, 0);renameDeleteDialog.show(getFragmentManager(), RenameDeleteDialog.class.getName());
}

从代码中可以看到该方法主要是新建了一个RenameDeleteDialog,并且将指纹这个数据传进去了,那么我们就看看这个dialog,因为这个dialog的代码比较多,我们只关注他的删除按钮和确定按钮事件,先看确定按钮事件,也就是为指纹进行改名操作,其代码如下:

@Override
public void onClick(DialogInterface dialog, int which) {final String newName =mDialogTextField.getText().toString().trim();final CharSequence name = mFp.getName();if (!newName.equals(name)) {     if (DEBUG) {Log.v(TAG, "rename " + name + " to " + newName);}MetricsLogger.action(getContext(),MetricsEvent.ACTION_FINGERPRINT_RENAME,mFp.getFingerId());FingerprintSettingsFragment parent= (FingerprintSettingsFragment)getTargetFragment();parent.renameFingerPrint(mFp.getFingerId(),newName);}
}dialog.dismiss();
}

从这个代码中可以看到在修改指纹名称的时候会首先判断新的名称是否与旧的名称一致,如果一致不作操作,否则才会进行改名,具体调用了renameFingerPrint(),参数为对应的指纹ID和对应的新名称,具体看一下这个方法:

private void renameFingerPrint(int fingerId, String newName) {mFingerprintManager.rename(fingerId, mUserId, newName);updatePreferences();
}

这里方法比较简单,首先直接调用了指纹管理服务的rename接口进行改名的操作,然后又调用的界面更新方法对界面进行更新,指纹改名还是比较简单的。下面我们着重看一下指纹的删除逻辑,先看一下具体代码:

public void onClick(DialogInterface dialog, int which) {onDeleteClick(dialog);
}

点击事件很简单,仅仅调用了onDeleteClick()方法,接着往下追:

private void onDeleteClick(DialogInterface dialog) {if (DEBUG) Log.v(TAG, "Removing fpId=" + mFp.getFingerId());MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_DELETE,mFp.getFingerId());FingerprintSettingsFragment parent= (FingerprintSettingsFragment) getTargetFragment();final boolean isProfileChallengeUser =Utils.isManagedProfile(UserManager.get(getContext()), parent.mUserId);if (parent.mFingerprintManager.getEnrolledFingerprints(parent.mUserId).size() > 1) { parent.deleteFingerPrint(mFp);} else {ConfirmLastDeleteDialog lastDeleteDialog = new ConfirmLastDeleteDialog();Bundle args = new Bundle();args.putParcelable("fingerprint", mFp);args.putBoolean("isProfileChallengeUser", isProfileChallengeUser);lastDeleteDialog.setArguments(args);lastDeleteDialog.setTargetFragment(getTargetFragment(), 0);lastDeleteDialog.show(getFragmentManager(),ConfirmLastDeleteDialog.class.getName());}dialog.dismiss();
}

这个函数的代码稍微有点多,其实主要是分为两个逻辑,首先判断当前指纹是否大于一个,如果大于一个,则直接调用deleteFingerPrint()方法对指纹进行删除,否则新建一个确认删除最后一个指纹对话框,其实这个对话框主要是对删除最后一个指纹进行二次确认,其最终还是调用了deleteFingerPrint()这个方法,下面看一下删除指纹的方法:

private void deleteFingerPrint(Fingerprint fingerPrint) {mFingerprintManager.remove(fingerPrint, mUserId, mRemoveCallback);
}

一看这个代码更简单了,仅仅调用指纹管理服务的remove接口对指纹进行删除,但是这里就有一个问题了,对指纹进行删除,但是如何对指纹界面进行更新的呢?按照正常的逻辑来说,在指纹删除之后应该立即对界面进行更新的,从表面是看没有界面更新的操作,实际上我们可以看到删除指纹的接口有一个非常重要的参数,mRemoveCallback,为什么说这个参数非常重要呢,因为这个参数与界面的更新有关系,这个参数其实是一个回调接口,既然是一个回调接口,那么必然有地方对这个回调接口进行了注册,我们继续追代码就会找到这个地方:

我们可以看一下这个删除指纹的接口,在FingerprintManager.java中:

@RequiresPermission(MANAGE_FINGERPRINT)
public void remove(Fingerprint fp, int userId, RemovalCallback callback) {if (mService != null) try {mRemovalCallback = callback;mRemovalFingerprint = fp;mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);} catch (RemoteException e) {Log.w(TAG, "Remote exception in remove: ", e);if (callback != null) {callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));}}
}

从代码中可以看到,回调接口是通过参数传进来的,那么我们就看看这个回调接口注册指纹删除的地方:

private void sendRemovedResult(long deviceId, int fingerId, int groupId) {if (mRemovalCallback != null) {int reqFingerId = mRemovalFingerprint.getFingerId();int reqGroupId = mRemovalFingerprint.getGroupId();if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);return;}if (groupId != reqGroupId) {Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);return;}mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,deviceId));}
}

在这个方法中,我们可以看到对onRemovalSucceeded()这个方法进行了注册。所以在应用层我们就能够使用这个接口进行一些操作了,接来我们看看应用层是如何进行操作的。先看代码:

private RemovalCallback mRemoveCallback = new RemovalCallback() {@Overridepublic void onRemovalSucceeded(Fingerprint fingerprint) {mHandler.obtainMessage(MSG_REFRESH_FINGERPRINT_TEMPLATES,fingerprint.getFingerId(), 0).sendToTarget();}@Overridepublic void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {final Activity activity = getActivity();if (activity != null) {Toast.makeText(activity, errString, Toast.LENGTH_SHORT);}}
};

可以看到这边应用层仅仅是发送了一个消息MSG_REFRESH_FINGERPRINT_TEMPLATES,并且将对应的指纹ID传了过去,我们看一下消息处理的地方:

case MSG_REFRESH_FINGERPRINT_TEMPLATES:removeFingerprintPreference(msg.arg1);updateAddPreference();retryFingerprint();
break;

看到这里恍然大悟,原来是通过删除指纹的回调接口对指纹选项进行了界面更新,通过调用removeFingerprintPreference()这个方法将指纹选项删除掉了,具体可以看一下这个方法:

protected void removeFingerprintPreference(int fingerprintId) {String name = genKey(fingerprintId);Preference prefToRemove = findPreference(name);if (prefToRemove != null) {if (!getPreferenceScreen().removePreference(prefToRemove)) {Log.w(TAG, "Failed to remove preference with key " + name);}} else {Log.w(TAG, "Can't find preference to remove: " + name);}
}

这个方法也很简单,主要是调用getPreferenceScreen().removePreference(prefToRemove),这个方法删除了指纹选项,在删除的时候同时更新了界面,到这里删除指纹的逻辑与界面的同步我们已经明白了,下面还需要看一下指纹识别的逻辑:

5,指纹的识别

其实指纹的识别在刚开始界面更新的时候就进行了注册,我们现在返回去看一下界面更细你的代码:

private void updatePreferences() {createPreferenceHierarchy();retryFingerprint();
}

我们发现在新建界面的时候就对指纹识别进行了注册,retryFingerprint();看看这个方法:

private void retryFingerprint() {if (!mInFingerprintLockout) {mFingerprintCancel = new CancellationSignal();mFingerprintManager.authenticate(null, mFingerprintCancel, 0 /* flags */,mAuthCallback, null, mUserId);}
}

从这里可以看到直接调用了指纹认证的接口,其中有一个重要的参数mAuthCallback,指纹认证的回调接口,我们主要看看这个回调接口:

private AuthenticationCallback mAuthCallback = new AuthenticationCallback() {@Overridepublic void onAuthenticationSucceeded(AuthenticationResult result) {int fingerId = result.getFingerprint().getFingerId();mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget();}@Overridepublic void onAuthenticationFailed() {mHandler.obtainMessage(MSG_FINGER_AUTH_FAIL).sendToTarget();};@Overridepublic void onAuthenticationError(int errMsgId, CharSequence errString) {mHandler.obtainMessage(MSG_FINGER_AUTH_ERROR, errMsgId, 0, errString).sendToTarget();}@Overridepublic void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {mHandler.obtainMessage(MSG_FINGER_AUTH_HELP, helpMsgId, 0, helpString).sendToTarget();}
};

这个回调接口中主要注册了四种指纹认证的情况,认证成功,认证失败,认证错误和认证帮助,在这里我们只关注认证成功和失败的情况,先看认证成功:

@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {int fingerId = result.getFingerprint().getFingerId();mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget();
}

认证成功发送了消息MSG_FINGER_AUTH_SUCCESS,同时将指纹ID传了过去,看看消息处理的地方:

case MSG_FINGER_AUTH_SUCCESS:mFingerprintCancel = null;highlightFingerprintItem(msg.arg1);retryFingerprint();
break;

这里对指纹认证成功做了处理,看看到底做了什么处理?下面看看这个方法:

private void highlightFingerprintItem(int fpId) {String prefName = genKey(fpId);FingerprintPreference fpref = (FingerprintPreference) findPreference(prefName);final Drawable highlight = getHighlightDrawable();if (highlight != null) {      final View view = fpref.getView();final int centerX = view.getWidth() / 2;final int centerY = view.getHeight() / 2;highlight.setHotspot(centerX, centerY);view.setBackground(highlight);view.setPressed(true);view.setPressed(false);mHandler.postDelayed(new Runnable() {@Overridepublic void run() {view.setBackground(null);}}, RESET_HIGHLIGHT_DELAY_MS);}
}

其实这个处理主要是对对应的指纹选项做了高亮显示处理,延时500ms之后又将背景设置为空,也就是原生的颜色,这样就可以直观的看到哪个指纹对应哪个指纹选项,识别是否能够成功。

注意:在这里我们思考这么一个问题?当出现对应的指纹选项已经删除了,但是还是要通过该指纹去识别这个选项,会出现什么情况?  这里当然会出现空指针的报错,因为指纹的识别是通过指纹ID,找到对应的指纹选项,但是指纹已经被删除了,指纹选项也就为空了,这时候如果去识别这个指纹:

FingerprintPreference fpref =(FingerprintPreference) findPreference(prefName);
这个时候就fpref就为空,所以在finalView view = fpref.getView();这一行代码就会出现空指针的报错,导致整个设置奔溃。

下面看看指纹认证失败的情况,从应用层代码里边可以看到并没有对指纹认证失败的情况进行处理。但是我们在实际测试中可以发现,指纹认证失败最多能够执行5次,超过5次之后再进行指纹认证的时候就没有反应了。至于这个限制目前上层没有找到,应该是在底层进行验证的,有兴趣的同学可以进一步追一下代码,研究一下。

三,  总结:

到此我们梳理了整个设置下边指纹模块相关的一些逻辑,包括指纹的注册,指纹的重命名,指纹的删除已经界面的等,总体来说还是比较简单的,其实最难的应该是底层关于指纹的注册,读取,存储等。后边有时间在仔细研究一下。本次研究主要是针对上层关于指纹的处理作了一个比较深入的梳理。

设置指纹识别模块分析相关推荐

  1. vnr光学识别怎么打开_干货|指纹锁的指纹识别模块的前世今生,智能锁的指纹识别到底有多智能?...

    智能锁现在也有很多叫法:指纹锁.电子锁.可见指纹识别是智能锁的核心功能了,那我们今天来聊聊智能锁的指纹识别模块. 指纹识别的历史 指纹识别认证的流程 指纹识别技术的种类 指纹识别的历史 早在2000多 ...

  2. AS608光学指纹识别模块 智能锁/考勤门禁开发/指纹采集模块

    一.注册指纹 /*[Arduino]168种传感器模块系列实验(资料+代码+图形+仿真)实验一百五十:AS608光学指纹识别模块 智能锁/考勤门禁开发/指纹采集模块实验之二:输入序号,注册指纹示例安装 ...

  3. K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示

    K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示 一.资源说明 二.基本参数 参数 引脚说明 三.驱动说明 对应程序: 四.部分代码说明 1.接线引脚定义 ...

  4. AS608指纹识别模块+STM32实现指纹录入

    视频演示 d9148ed412b24119db81eef6c2c8e9ec 1.特性参数 (资料来自ALIENTEK文档) ATK-AS608 指纹识别模块是 ALIENTEK 推出的一款高性能的光学 ...

  5. YH-AS608指纹识别模块介绍

    前言 自小刺头深草里,而今渐觉出蓬蒿. 时人不识凌云木,直待凌云始道高.----杜荀鹤<小松> 一.YH-AS608简介 YH-AS608 是野火设计的高性能光学指纹识别模块.它采用了杭州 ...

  6. 【HaaS Python硬件积木】AS608指纹识别模块 打造指纹门禁 开门有手就行

    一.产品简介 ATK-AS608指纹识别模块是ALIENTEK推出的一款高性能的光学指纹识别模块.它采用的是指纹识别芯片公司杭州晟元芯片技术有限公司生产的AS608指纹识别芯片.该芯片内置DSP运算单 ...

  7. atk301指纹识别模块-stm32-串口实现

    连接 1.ATK-301 电容 指纹识别模块简介 ATK-301 电容 指纹识别模块(以下简称 LB301 模块)是 ALIENTEK 推出的一款高性 能的电容半导体指纹识别模块.LB301 采用了瑞 ...

  8. 电容指纹识别模块使用教程十分钟教会你使用指纹识别

    电容指纹识别模块使用教程十分钟教会你使用指纹识别 FPC1020A 引脚说明 使用前准备 接线说明 使用参考 总结 原文链接:https://www.yourcee.com/newsinfo/2923 ...

  9. 【雕爷学编程】Arduino动手做(141)---AS608光学指纹识别模块

    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...

最新文章

  1. 漫话:如何给女朋友解释什么是单例模式?
  2. Linux命令grep
  3. android 时间戳转换成日期_Matlab将Unix时间戳转为可读日期
  4. AngularJS 拦截器和好棒例子
  5. 爬虫工具篇 - 必会用的 6 款 Chrome 插件
  6. html流动海报css,海报网css代码怎样把模块移到右面?最好把代码直接给我!嘿嘿。...
  7. 如何才能一统编程语言的江湖?
  8. jquery根据滚动像素显示隐藏顶部导航条
  9. mysql 游戏背包_用sql实现背包问题
  10. Asp.Net MVC学习总结(三)——过滤器你怎么看?
  11. Nginx ssl证书部署方法
  12. 启动sqlserver服务时,总是出现“系统错误(126),指定驱动程序无法加载
  13. 我爱淘冲刺阶段站立会议2每天任务6
  14. 慢慢来,一切都来得及 2012-01-16 15:02:22
  15. Swift ——String 与 Array
  16. 【巨杉数据库SequoiaDB】巨杉再获企业级认可,分布式数据库领跑“一亿中流”
  17. 【Linux】万兆网卡82599驱动安装
  18. Linux C++ TCP编程
  19. JS实现 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
  20. Android 集成二维码扫描器

热门文章

  1. Python连接Twitter API读取用户画像及推特评论
  2. DA14580管脚唤醒配置
  3. OPENFILER操作
  4. 计算机视觉与深度学习第七章:经典网络分析
  5. 《乐高EV3机器人搭建与编程》一2.9 小结
  6. a按钮居中显示 bootstrap_Bootstrap提示冒泡样式
  7. 机器学习中的目标函数、损失函数、代价函数的区别
  8. 对数化绘制P值地形图
  9. 一级造价工程师(安装)- 计量笔记 - 第二章第二节除锈、防腐蚀和绝热工程
  10. 光伏逆变器的行业演进和格局分析