当前位置:
首页
文章
移动端
详情

Android10.0 锁屏分析——KeyguardPINView PIN锁分析

学习笔记:

PIN 解锁流程跟Android10.0 锁屏分析——KeyguardPatternView图案锁分析一样,这里就不过多讲解了。

在这里主要分析下 PIN 键盘的按钮事件。

1. 确认按钮

// KeyguardPinBasedInputView.java
    @Override
    protected void onFinishInflate() {

    // 省略部分代码......

        mOkButton = findViewById(R.id.key_enter);
        if (mOkButton != null) {
            mOkButton.setOnTouchListener(this);
            mOkButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "mOkButton onClick");
                    if (mPasswordEntry.isEnabled()) {
                        Log.d(TAG, "mOkButton onClick verifyPasswordAndUnlock");
                        verifyPasswordAndUnlock();
                    }
                }
            });
            mOkButton.setOnHoverListener(new LiftToActivateListener(getContext()));
        }

     // 省略部分代码......
   }

在这里主要看verifyPasswordAndUnlock()方法,

// KeyguardAbsKeyInputView.java
protected void verifyPasswordAndUnlock() {
        Log.d(TAG, "verifyPasswordAndUnlock mDismissing=" + mDismissing);
        // 判断是否正在进行解锁,如果在则返回,
        if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.

        // 创建一个表示给定数字 PIN 的 LockscreenCredential 对象。如果提供的密码为空,则创建一个空的凭证对象。
        final LockscreenCredential password = getEnteredCredential();
       // 禁止输入
        setPasswordEntryInputEnabled(false);
        if (mPendingLockCheck != null) {
            mPendingLockCheck.cancel(false);
        }

        final int userId = KeyguardUpdateMonitor.getCurrentUser();
        // 比对最小密码长度
        if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
            // to avoid accidental lockout, only count attempts that are long enough to be a
            // real password. This may require some tweaking.
            setPasswordEntryInputEnabled(true);
            onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
            password.zeroize();
            return;
        }

        if (LatencyTracker.isEnabled(mContext)) {
            LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
            LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
        }

        mKeyguardUpdateMonitor.setCredentialAttempted();
        // 这里跟图案解锁流程一样,就不过多讲解。 
        mPendingLockCheck = LockPatternChecker.checkCredential(
                mLockPatternUtils,
                password,
                userId,
                new LockPatternChecker.OnCheckCallback() {

                    @Override
                    public void onEarlyMatched() {
                        if (LatencyTracker.isEnabled(mContext)) {
                            LatencyTracker.getInstance(mContext).onActionEnd(
                                    ACTION_CHECK_CREDENTIAL);
                        }
                        onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
                                true /* isValidPassword */);
                        password.zeroize();
                    }

                    @Override
                    public void onChecked(boolean matched, int timeoutMs) {
                        Log.d(TAG, "verifyPasswordAndUnlock onChecked");
                        if (LatencyTracker.isEnabled(mContext)) {
                            LatencyTracker.getInstance(mContext).onActionEnd(
                                    ACTION_CHECK_CREDENTIAL_UNLOCKED);
                        }
                        setPasswordEntryInputEnabled(true);
                        mPendingLockCheck = null;
                        if (!matched) {
                            onPasswordChecked(userId, false /* matched */, timeoutMs,
                                    true /* isValidPassword */);
                        }
                        password.zeroize();
                    }

                    @Override
                    public void onCancelled() {
                        Log.d(TAG, "verifyPasswordAndUnlock onCancelled");
                        // We already got dismissed with the early matched callback, so we cancelled
                        // the check. However, we still need to note down the latency.
                        if (LatencyTracker.isEnabled(mContext)) {
                            LatencyTracker.getInstance(mContext).onActionEnd(
                                    ACTION_CHECK_CREDENTIAL_UNLOCKED);
                        }
                        password.zeroize();
                    }
                });
    }

2. 删除回退按钮

// KeyguardPinBasedInputView.java
    @Override
    protected void onFinishInflate() {

    // 省略部分代码......

        mDeleteButton = findViewById(R.id.delete_button);
        mDeleteButton.setVisibility(View.VISIBLE);
        mDeleteButton.setOnTouchListener(this);
        mDeleteButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // check for time-based lockouts
                if (mPasswordEntry.isEnabled()) {
                    mPasswordEntry.deleteLastChar();
                }
            }
        });
        mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                // check for time-based lockouts
                if (mPasswordEntry.isEnabled()) {
                    resetPasswordText(true /* animate */, true /* announce */);
                }
                doHapticKeyClick();
                return true;
            }
        });

     // 省略部分代码......
   }

这里主要看mPasswordEntry.deleteLastChar()这句话,mPasswordEntry是PasswordTextView的对象。调用其方法deleteLastChar()进行字符串的删除回退。

// PasswordTextView.java
    public void deleteLastChar() {
        int length = mText.length();
        CharSequence textbefore = getTransformedText();
        if (length > 0) {
            mText = mText.substring(0, length - 1);
            CharState charState = mTextChars.get(length - 1);
            charState.startRemoveAnimation(0, 0);
            sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
        }
        userActivity();
    }

看到这里,在接着看数字按钮。
3. 数字按钮
数字按钮是一个自定义布局。

// NumPadKey.java
    private View.OnClickListener mListener = new View.OnClickListener() {
        @Override
        public void onClick(View thisView) {
            Log.d("jiangshufeng","yexiao:"+Character.forDigit(mDigit, 10));

            if (mTextView == null && mTextViewResId > 0) {
                final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId);
                if (v != null && v instanceof PasswordTextView) {
                    mTextView = (PasswordTextView) v;
                }
            }
            if (mTextView != null && mTextView.isEnabled()) {
                mTextView.append(Character.forDigit(mDigit, 10));
            }
            userActivity();
        }
    };

在该自定义布局里有点击事件的实现,mDigit其实就是数字键盘对应的数字,mTextView为PasswordTextView的对象,调用其append(char c)方法进行字符串的拼接。

PIN到此分析结束,如果要看解锁流程,即参考Android10.0 锁屏分析——KeyguardPatternView图案锁分析,两者是一样的。

参考:Android中锁屏密码加密算法分析

免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。