学习笔记:
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图案锁分析,两者是一样的。