设置指纹识别模块分析

Posted andy连长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设置指纹识别模块分析相关的知识,希望对你有一定的参考价值。

设置指纹识别模块分析

一,   指纹项的加载

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

首先我们应该从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 模块分析

模块分析

PyTorch 图像识别实战

OpenCV和Zbar两个Python模块实现二维码和条形码识别

口罩识别/安全帽识别/区域入侵检测/AI智能分析网关新增网口配置模块

电商系统登录模块需求分析