设置指纹识别模块分析
一, 指纹项的加载
首先我们从指纹项的布局加载开始分析,从手机设置下边直观的可以发现,指纹项是放在二级菜单安全菜单里边的,下面我们就从代码里边分析一下,指纹项是如何被加载进来的。
首先我们应该从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 UI clazz = FingerprintEnrollIntroduction.class.getName(); }
//这里是最关键的地方,为指纹项设置点击监听, fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public 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 none if (mToken == null && mLaunchedConfirm == false) { mLaunchedConfirm = true;//当进入该界面,就把标志位置为true launchChooseOrConfirmLock();//启动密码确认界面 } }
从这个方法可以看到这里其实并没有做什么,只是进行了一些相关数据的初始化。但有一点需要注意,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,指纹的添加
我们前边说过为添加指纹选项设置了点击事件监听,我们看看这个点击事件:
@Override public 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() { @Override public void onRemovalSucceeded(Fingerprint fingerprint) { mHandler.obtainMessage(MSG_REFRESH_FINGERPRINT_TEMPLATES, fingerprint.getFingerId(), 0).sendToTarget(); } @Override public 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() { @Override public void onAuthenticationSucceeded(AuthenticationResult result) { int fingerId = result.getFingerprint().getFingerId(); mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget(); } @Override public void onAuthenticationFailed() { mHandler.obtainMessage(MSG_FINGER_AUTH_FAIL).sendToTarget(); }; @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { mHandler.obtainMessage(MSG_FINGER_AUTH_ERROR, errMsgId, 0, errString) .sendToTarget(); } @Override public 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() { @Override public void run() { view.setBackground(null); } }, RESET_HIGHLIGHT_DELAY_MS); } }
其实这个处理主要是对对应的指纹选项做了高亮显示处理,延时500ms之后又将背景设置为空,也就是原生的颜色,这样就可以直观的看到哪个指纹对应哪个指纹选项,识别是否能够成功。
注意:在这里我们思考这么一个问题?当出现对应的指纹选项已经删除了,但是还是要通过该指纹去识别这个选项,会出现什么情况? 这里当然会出现空指针的报错,因为指纹的识别是通过指纹ID,找到对应的指纹选项,但是指纹已经被删除了,指纹选项也就为空了,这时候如果去识别这个指纹:
FingerprintPreference fpref =(FingerprintPreference) findPreference(prefName);
这个时候就fpref就为空,所以在finalView view = fpref.getView();这一行代码就会出现空指针的报错,导致整个设置奔溃。
下面看看指纹认证失败的情况,从应用层代码里边可以看到并没有对指纹认证失败的情况进行处理。但是我们在实际测试中可以发现,指纹认证失败最多能够执行5次,超过5次之后再进行指纹认证的时候就没有反应了。至于这个限制目前上层没有找到,应该是在底层进行验证的,有兴趣的同学可以进一步追一下代码,研究一下。
三, 总结:
到此我们梳理了整个设置下边指纹模块相关的一些逻辑,包括指纹的注册,指纹的重命名,指纹的删除已经界面的等,总体来说还是比较简单的,其实最难的应该是底层关于指纹的注册,读取,存储等。后边有时间在仔细研究一下。本次研究主要是针对上层关于指纹的处理作了一个比较深入的梳理。