最近解了一个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了