最近解了一個bug,覺得很有意思,拿出來和大家分享一下。
鎖屏密碼輸錯五次後出現倒計時,重啓設備不顯示倒計時。
首先,以圖案解鎖爲例,圖案解鎖的初始化和邏輯比對都在KeyguardPatternView.java中
倒計時方法用的是該類中的handleAttemptLockout(long elapsedRealtimeDeadline)方法,傳入一個獲取的系統休眠時間,該時間是設備啓動至現在的時間,再加上你所設置的休眠時間。
long mDeadline = mLockPatternUtils.setLockoutAttemptDeadline(
KeyguardUpdateMonitor.getCurrentUser(), 30000);//傳入的handleAttemptLockout的
//elapsedRealtimeDeadline就是這樣設置的,30000爲休眠的30秒
休眠方法知道了,我的整體思路是我在SettingsProvider裏存了一個值默認0,然後在倒計時的時候將這個值置爲1,倒計時結束再置爲0,在KeyguardPatternView.java的每次啓動方法中去讀取這個值,如果是0就什麼都不做,如果是1就開始倒計時。
OK,萬事具備,只欠東風,就是一個KeyguardPatternView.java的每次啓動都會運行的方法,剛開始我嘗試在KeyguardPatternView的構造方法中去做這些事,結果一直在報 mLockPatternView空指針,大家可以觀察handleAttemptLockout方法
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
mLockPatternView.clearPattern();//需要清除當前圖像
mLockPatternView.setEnabled(false);//設置不可點擊
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long secondsInFuture = (long) Math.ceil(
(elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
if (mCountdownTimer != null) {
mCountdownTimer.cancel();
}
mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
handleAttemptLockout方法需要清除當前圖像,並且設置不可點擊,所以我們需要在mLockPatternView創建好後去執行這些方法,後來我又嘗試在KeyguardPatternView.java的onFinishInflate()方法,但是發現它並不是每次的執行,所以也不行,最後我終於找到每次都會執行的方法就是KeyguardPatternView.java的 reset()方法,該方法每次加載PatternView都會執行
具體代碼實現如下:
@Override
public void reset() {
// reset lock pattern
mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
KeyguardUpdateMonitor.getCurrentUser()));
mLockPatternView.enableInput();
mLockPatternView.setEnabled(true);
mLockPatternView.clearPattern();
//add for count time at 2019-5-14 start 這裏開始
Log.v(TAG, "reset() COUNT_DOWNTIME_UNLOCK ="+Settings.System.getInt(mContext.getContentResolver(),Settings.System.COUNT_DOWNTIME_UNLOCK,0)+"mLockPatternView = "+mLockPatternView);
if (Settings.System.getInt(mContext.getContentResolver(),Settings.System.COUNT_DOWNTIME_UNLOCK,0) == 1 && mLockPatternView != null){//這裏去讀取存入值
long mDeadline = mLockPatternUtils.setLockoutAttemptDeadline(
KeyguardUpdateMonitor.getCurrentUser(), 30000);這裏去設置休眠時間
Log.v(TAG, "reset(inside) handleAttemptLockout(mDeadline)"+mDeadline);
}
//add for count time at 2019-5-14 end這裏結束
// if the user is currently locked out, enforce it.
long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
KeyguardUpdateMonitor.getCurrentUser());
if (deadline != 0) {
handleAttemptLockout(deadline);//這裏執行休眠方法
} else {
displayDefaultSecurityMessage();
}
}
接着需要修改倒計時handleAttemptLockout(deadline)方法,在倒計時的時候設爲1,停止的時候設置爲0
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
mLockPatternView.clearPattern();
mLockPatternView.setEnabled(false);
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long secondsInFuture = (long) Math.ceil(
(elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
if (mCountdownTimer != null) {
mCountdownTimer.cancel();
}
mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {//倒計時執行的地方
final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
R.plurals.kg_too_many_failed_attempts_countdown,
secondsRemaining, secondsRemaining));
//add for count time unlock start
Log.v(TAG, "handleAttemptLockout secondsRemaining = "+secondsRemaining);
if(secondsRemaining == 30){
Settings.System.putInt(mContext.getContentResolver(),Settings.System.COUNT_DOWNTIME_UNLOCK,1);
//在這裏置爲1
}
}
@Override
public void onFinish() {//倒計時結束的地方
mLockPatternView.setEnabled(true);
displayDefaultSecurityMessage();
Settings.System.putInt(mContext.getContentResolver(),Settings.System.COUNT_DOWNTIME_UNLOCK,0);
//在這裏置爲0
//add for count time unlock at 2019-end
}
}.start();
}
這樣就結束了,因爲password和pin碼都繼承自KeyguardAbsKeyInputView.java,所以我們只需要在KeyguardAbsKeyInputView.java做同樣的修改就OK了