指纹使用(FingerprintManager)

思路

开始条件

  1. 判断系统版本是否在6.0之后
  2. 判断手机是否支持指纹
  3. 判断手机中是否已经录入相关指纹(锁屏)
  4. 以上条件全部满足后,可以进行指纹验证

指纹验证的情况分为3中:

  1. 验证通过(success),之后进行用户登录、跳转界面等操作
  2. 验证失败(failed),次数内的失败,例如一次失败后的提示(倒计次数)、震动等操作
  3. 验证失败(failed),达到五次后,提示次数过多,跳转到密码登录(要么30秒后指纹登录,要么提示这一次只能密码登录)

注:

  • 8.0之前,指纹只能错误5次,达到5次时会禁止指纹认证,同时开启30秒倒计时,等待结束后重置错误计数,继续认证
  • 8.0之后,依然是每错误5次就会倒计时30秒,然而30秒结束后错误计数并不会被清空,
  • 8.0上加入了最大20次的限制,累计错误20次之后就无法使用指纹认证功能了,只能用密码的方式才能重置错误计数
  • 9.0之后它。。。。。。被抛弃了 -.-||
  • ic_fp_40px.png
  • 本文参考了郭霖大神的文章

根据官方demo修改代码如下:

FingerprintDialogFragment 代码:

@TargetApi(23)
public class FingerprintDialogFragment extends DialogFragment {
    private RelativeLayout fingerprintContainer;
    private TextView fingerprintDescription, fingerprintStatus;
    private ImageView fingerprintIcon;
    private RelativeLayout backupContainer;
    private FrameLayout description;
    private TextView passwordDescription, newFingerprintEnrolledDescription;
    private EditText password;
    private CheckBox useFingerprintInFutureCheck;
    private LinearLayout buttonPanel;
    private Button cancelButton, secondDialogButton;

    private FingerprintManager fingerprintManager;
    private CancellationSignal mCancellationSignal;
    private Cipher mCipher;
    private static final String DEFAULT_KEY_NAME = "default_key";
    private KeyStore keyStore;
    private Stage mStage = Stage.FINGERPRINT;
    private int flag = 5;           // 验证次数
    private int countdown = 1;      // 时间倒计时
    private boolean isSelfCancelled;// 标识是否是用户主动取消的认证

    // 是否支持指纹
    public boolean supportFingerprint() {
        if (Build.VERSION.SDK_INT < 23) {
            Toast.makeText(getContext(), "您的系统版本过低,不支持指纹功能", Toast.LENGTH_SHORT).show();
            return false;
        } else {
            KeyguardManager keyguardManager = getContext().getSystemService(KeyguardManager.class);
            FingerprintManager fingerprintManager = getContext().getSystemService(FingerprintManager.class);
            if (fingerprintManager != null) {
                if (!fingerprintManager.isHardwareDetected()) {
                    Toast.makeText(getContext(), "您的手机不支持指纹功能", Toast.LENGTH_SHORT).show();
                    return false;
                } else if (keyguardManager != null) {
                    if (!keyguardManager.isKeyguardSecure()) {
                        Toast.makeText(getContext(), "您还未设置锁屏,请先设置锁屏并添加一个指纹", Toast.LENGTH_SHORT).show();
                        return false;
                    } else if (!fingerprintManager.hasEnrolledFingerprints()) {
                        Toast.makeText(getContext(), "您至少需要在系统设置中添加一个指纹", Toast.LENGTH_SHORT).show();
                        return false;
                    }
                } else {
                    Toast.makeText(getContext(), "键盘管理初始化失败", Toast.LENGTH_SHORT).show();
                    return false;
                }
            } else {
                Toast.makeText(getContext(), "指纹管理初始化失败", Toast.LENGTH_SHORT).show();
                return false;
            }
        }
        return true;
    }

    // 初始化密钥库
    private void initKey() {
        try {
            keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
                    KeyProperties.PURPOSE_ENCRYPT |
                            KeyProperties.PURPOSE_DECRYPT)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
            keyGenerator.init(builder.build());
            keyGenerator.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 初始化密钥
    private void initCipher() {
        try {
            SecretKey key = (SecretKey) keyStore.getKey(DEFAULT_KEY_NAME, null);
            Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                    + KeyProperties.BLOCK_MODE_CBC + "/"
                    + KeyProperties.ENCRYPTION_PADDING_PKCS7);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            setCipher(cipher);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void setCipher(Cipher cipher) {
        mCipher = cipher;
    }

    // 向Activity传值的接口
    public interface FragmentInteraction {
        void onEditPassword(String strPassword);//输入的密码

        void onAuthenticated();//验证成功
    }

    private FragmentInteraction listener;

    private void initView(View view) {
        // 指纹登录
        fingerprintContainer = (RelativeLayout) view.findViewById(R.id.fingerprint_container);
        fingerprintDescription = (TextView) view.findViewById(R.id.fingerprint_description);
        fingerprintIcon = (ImageView) view.findViewById(R.id.fingerprint_icon);
        fingerprintStatus = (TextView) view.findViewById(R.id.fingerprint_status);
        // 密码登录
        backupContainer = (RelativeLayout) view.findViewById(R.id.backup_container);
        description = (FrameLayout) view.findViewById(R.id.description);
        passwordDescription = (TextView) view.findViewById(R.id.password_description);
        newFingerprintEnrolledDescription = (TextView) view.findViewById(R.id.new_fingerprint_enrolled_description);
        password = (EditText) view.findViewById(R.id.password);
        useFingerprintInFutureCheck = (CheckBox) view.findViewById(R.id.use_fingerprint_in_future_check);
        // 下方按钮
        buttonPanel = (LinearLayout) view.findViewById(R.id.buttonPanel);
        cancelButton = (Button) view.findViewById(R.id.cancel_button);
        secondDialogButton = (Button) view.findViewById(R.id.second_dialog_button);

        getDialog().setCancelable(false);
        getDialog().setCanceledOnTouchOutside(false);
    }

    private void initEvent() {
        cancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mStage == Stage.FINGERPRINT) {
                    stopListening();
                    dismiss();
                } else if (mStage == Stage.PASSWORD) {
                    password.setText("");
                    dismiss();
                }
            }
        });

        secondDialogButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mStage == Stage.FINGERPRINT) {
                    goToPassword();
                } else if (mStage == Stage.PASSWORD) {
                    //LogUtil( "输入密码是:" + password.getText().toString());
                    listener.onEditPassword(password.getText().toString());
                    dismiss();
                }
            }
        });
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        listener = (FragmentInteraction) context;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);

        if (supportFingerprint()) {
            fingerprintManager = getContext().getSystemService(FingerprintManager.class);
            initKey();
            initCipher();
        } else {
            LogUtil("关闭dialog");
            dismiss();
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        getDialog().setTitle("指纹验证");
        View v = inflater.inflate(R.layout.dialog_fingerprint, container, false);

        initView(v);
        initEvent();
        LogUtil("Fragment名字:" + getTag());
        return v;
    }

    @Override
    public void onResume() {
        super.onResume();
        // 开始指纹认证监听
        startListening(mCipher);
    }

    @Override
    public void onPause() {
        super.onPause();
        // 停止指纹认证监听
        stopListening();
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;//把传递进来的activity对象释放掉
    }

    private void startListening(Cipher cipher) {
        isSelfCancelled = false;
        mCancellationSignal = new CancellationSignal();
        fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), mCancellationSignal, 0, new FingerprintManager.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errorCode, CharSequence errString) {
                if (!isSelfCancelled) {
                    fingerprintStatus.setText(errString);
                    if (errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                        //多次指纹密码验证错误后,进入此方法;并且,不能短时间内调用指纹验证
                        Message message = new Message();
                        message.what = -1;
                        message.obj = errString;
                        myHandler.sendMessage(message);
                    }
                }
            }

            @Override
            public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
                fingerprintStatus.setText(helpString);
            }

            @Override
            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
                Message message = new Message();
                message.what = 1;
                myHandler.sendMessage(message);
            }

            @Override
            public void onAuthenticationFailed() {
                Message message = new Message();
                message.what = 0;
                myHandler.sendMessage(message);
            }

        }, null);
    }

    private void stopListening() {
        if (mCancellationSignal != null) {
            mCancellationSignal.cancel();
            mCancellationSignal = null;
            isSelfCancelled = true;
        }
    }

    @SuppressLint("HandlerLeak")
    private Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case -1:
                    LogUtil("handleMessage---多次失败");
                    /*if (flag == 0) {
                        // 传值失败时的系统时间,用来判断是否可以再次开启指纹
                        DateFormat dateFormat = DateFormat.getDateInstance(R.string.data_format);
                        listener.process(dateFormat.format(new Date(System.currentTimeMillis())));
                    }*/
                    Toast.makeText(getContext(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
                    goToPassword();
                    //dismiss();
                    break;

                case 1:
                    LogUtil("handleMessage---成功");
                    fingerprintIcon.setImageResource(R.drawable.ic_fingerprint_success);
                    fingerprintStatus.setText("成功");
                    fingerprintStatus.setTextColor(fingerprintStatus.getResources().getColor(R.color.success_color));
                    fingerprintStatus.postDelayed(mSucceedFingerRunnable, countdown * 1000);
                    break;

                case 0:
                    flag--;
                    LogUtil("指纹识别失败,还剩下" + flag + "次机会");
                    fingerprintIcon.setImageResource(R.drawable.ic_fingerprint_error);
                    fingerprintStatus.setText("指纹识别失败,还剩下" + flag + "次机会");
                    fingerprintStatus.setTextColor(fingerprintStatus.getResources().getColor(R.color.red));
                    fingerprintStatus.postDelayed(mResetFingerRunnable, countdown * 1000);
                    break;

                default:
                    break;
            }
        }
    };

    private Runnable mResetFingerRunnable = new Runnable() {
        @Override
        public void run() {
            fingerprintStatus.setText("重新验证");
            fingerprintStatus.setTextColor(fingerprintStatus.getResources().getColor(R.color.grey));
            fingerprintIcon.setImageResource(R.mipmap.ic_fp_40px);
        }
    };

    private Runnable mSucceedFingerRunnable = new Runnable() {
        @Override
        public void run() {
            listener.onAuthenticated();
            dismiss();
        }
    };

    private void goToPassword() {
        cancelButton.setText(R.string.s_btn_cancel);
        secondDialogButton.setText(R.string.s_btn_ok);
        fingerprintContainer.setVisibility(View.GONE);
        backupContainer.setVisibility(View.VISIBLE);

        mStage = Stage.PASSWORD;
        password.requestFocus();
        stopListening();

    }

    private void LogUtil(String msg) {
        Log.e("指纹界面:", msg);
    }

    public enum Stage {
        FINGERPRINT,
        NEW_FINGERPRINT_ENROLLED,
        PASSWORD
    }
}

dialog_fingerprint布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <include
            layout="@layout/fingerprint_dialog_content" />

        <include
            layout="@layout/fingerprint_dialog_backup"
            android:visibility="gone"/>

    </FrameLayout>

    <LinearLayout
        android:id="@+id/buttonPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingStart="12dp"
        android:paddingEnd="12dp"
        android:paddingTop="4dp"
        android:paddingBottom="4dp"
        android:gravity="bottom">

        <Space
            android:id="@+id/spacer"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:visibility="invisible" />
        <Button
            android:id="@+id/cancel_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="取消"/>

        <Button
            android:id="@+id/second_dialog_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码登陆"/>
    </LinearLayout>

</LinearLayout>

fingerprint_dialog_backup布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/backup_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="16dp"
    android:paddingBottom="8dp">

    <FrameLayout
        android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp"
        android:layout_alignParentLeft="true">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="输入你的密码"
            android:id="@+id/password_description"
            android:textSize="18sp"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A new fingerprint was added to this device, so your password is required."
            android:id="@+id/new_fingerprint_enrolled_description"
            android:visibility="gone"
            android:textColor="?android:attr/textColorSecondary" />
    </FrameLayout>

    <EditText
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:ems="10"
        android:hint="密码"
        android:imeOptions="actionGo"
        android:layout_below="@+id/description"
        android:layout_marginTop="16dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true" />

    <CheckBox
        android:id="@+id/use_fingerprint_in_future_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/password"
        android:layout_alignParentStart="true"
        android:layout_marginTop="16dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:checked="true"
        android:visibility="gone"
        android:text="Use fingerprint in the future"
        android:layout_alignParentLeft="true" />

</RelativeLayout>

fingerprint_dialog_content布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fingerprint_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="8dp"
    android:paddingStart="24dp"
    android:paddingEnd="24dp"
    android:paddingTop="16dp">

    <TextView
        android:id="@+id/fingerprint_description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:textSize="18sp"
        android:text="请确认指纹" />


    <ImageView
        android:id="@+id/fingerprint_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/fingerprint_description"
        android:layout_marginTop="20dp"
        android:src="@mipmap/ic_fp_40px"/>

    <TextView
        android:id="@+id/fingerprint_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/fingerprint_icon"
        android:layout_alignTop="@+id/fingerprint_icon"
        android:gravity="center_vertical"
        android:text="请进行指纹验证"
        android:textColor="@color/darkgray"
        android:layout_marginLeft="16dp"
        android:layout_toRightOf="@+id/fingerprint_icon" />

</RelativeLayout>
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值