这篇文章会采用代码走读的方式,结合简单的流程图,和大家一起看下Android9.0 上的锁屏模块相关代码,其它android版本应该也差不多,不过这篇文件的讲解是基于android9.0上的代码。
在了解某个模块的之前,我们经常是有疑问才去了解,在这之前,我也是有下面几个疑问:
1)锁屏界面代码是包含在哪个模块的;
2)亮屏、灭屏操作,锁屏界面显示流程是怎样的;
3)锁屏界面上滑,显示登陆密码界面流程是怎样的;
4)按power键开机的时候,为啥没有显示锁屏界面;
5)我想修改锁屏界面内容,应该关注哪些类和布局可以快速修改;
6) 遇到的一些问题以及分析解决;
有疑问总是好事,这篇文章会针对上面的疑问来一步步展开讲解;
写在前面
在Android系统上,短按电源power键,会进入灭屏和亮屏。如果我们在设置中设置了屏幕锁定方式有密码的话,亮屏的时候,我们会看到如下图所示的锁屏界面,然后锁屏界面上滑,就是密码验证界面,输入正确密码后,才能进入系统界面。
image一、锁屏界面代码是包含在哪个模块的
答:是在SystemUI模块。
二、锁屏界面显示流程是怎样的
锁屏界面的处理是在SystemUI中进行处理。下图是系统开机后,涉及到锁屏相关逻辑的简单流程图,我们先来有个大概的了解,起码知道涉及到哪些重要的类。
KeyguardViewMediator.java
StatusBarKeyguardViewManager.java
StatusBarWindowManager.java
StatusBar.java
KeyguardBouncer.java
KeyguardHostView.java
KeyguardSecurityContainer.java
流程图-01面我们已经看到有一个很重要的类KeyguardViewMediator.java ,是的,我们首先就看下这个类的代码。
看代码之前,我们先看下这个类的最前面的注释吧,我们翻译下重要的来看下,方便整体的理解(本人英语水平有限,大伙可以直接看英文理解理解)。
/**
* Mediates requests related to the keyguard. This includes queries about the
* state of the keyguard, power management events that effect whether the keyguard
* should be shown or reset, callbacks to the phone window manager to notify
* it of when the keyguard is showing, and events from the keyguard view itself
* stating that the keyguard was succesfully unlocked.
*
* //Mediates(调解) 主要处理和锁屏相关的请求。这些内容包括查询锁屏的状态、根据Power 管理事
* 件决定锁屏是否显示或者重置、采用回调将当前是否是锁屏状态回调给phone window manager,以及
* 锁屏是否成功解锁这种来自锁屏自身的view的事件。
*
*
* Note that the keyguard view is shown when the screen is off (as appropriate)
* so that once the screen comes on, it will be ready immediately.
*
* //注意了:锁屏界面是在灭屏的时候就显示处理了(视情况而定),这样方便屏幕一亮的时候,锁屏界面
* 能快速的显示出来。
*
* Example external events that translate to keyguard view changes:
* - screen turned off -> reset the keyguard, and show it so it will be ready
* next time the screen turns on
* - keyboard is slid open -> if the keyguard is not secure, hide it
*
* //外部事件引起锁屏界面变化的例子:
* 灭屏->锁屏重置,然后显示,这样下次亮屏的时候,锁屏是准备好的。
*
* Events from the keyguard view:
* - user succesfully unlocked keyguard -> hide keyguard view, and no longer
* restrict input events.
*
* //锁屏试图的事件传递:
* 用户成功解锁锁屏->隐藏锁屏视图,不再限制输入事件
*
* Note: in addition to normal power managment events that effect the state of
* whether the keyguard should be showing, external apps and services may request
* that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When
* false, this will override all other conditions for turning on the keyguard.
*
* //注意:外部apps或者服务可能会使用setKeyguardEnabled(boolean)接口来设置是否需要显示锁屏,
* 为了使来自power management的关于锁屏是否应该显示的事件调用标准化,当setKeyguardEnabled设
* 的值为false的时候,这个会是推翻其它打开锁屏的条件
/
我们根据上面注释的描述,来走读下按键灭屏、亮屏这个流程:
screen turned off -> reset the keyguard, and show it so it will be ready next time the screen turns on
KeyguardViewMediator.java
----------------------------
/**
* 亮屏
**/
public void onScreenTurnedOn() {
Trace.beginSection("KeyguardViewMediator#onScreenTurnedOn");
notifyScreenTurnedOn();
mUpdateMonitor.dispatchScreenTurnedOn();
Trace.endSection();
}
/**
* 灭屏
**/
public void onScreenTurnedOff() {
notifyScreenTurnedOff();
mUpdateMonitor.dispatchScreenTurnedOff();
}
...
private void handleNotifyScreenTurnedOff() {
synchronized (this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
mStatusBarKeyguardViewManager.onScreenTurnedOff();
mDrawnCallback = null;
}
}
三、 长按power键开机后,为啥不会显示锁屏界面
没有显示,那就是Android本来就这样设计的呗,哈哈,做开发的,很喜欢的一句话应该是“设计就是这样的啊”,然后摊摊手,表示无能为力。是不是设计就是如此,我们来看代码确认下吧。
我们来看下 KeyguardViewMediator.java中的具体实现:
1)系统起来的时候,会走onSystemReady()方法,然后通话发送handler信息进行处理,真正的处理就是在handleSystemReady()里面;
2)handleSystemReady()里面,我们重点看下doKeyguardLocked()方法,doKeyguradLocked()里面会有一些条件判断,条件不符合,则直接return掉;条件符合,才会走showLocked(options)方法进行锁屏界面的显示;
/**
* 系统起来会调用该方法通知系统起来了
* 通过handler发送SYSTEM_READY信息进行一些事情的处理
*/
public void onSystemReady() {
Log.v(TAG,"--- onSystemReady();");
mHandler.obtainMessage(SYSTEM_READY).sendToTarget();
}
private Handler mHandler = new Handler(Looper.myLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
......
case SYSTEM_READY:
handleSystemReady();
break;
......
}
}
};
private void handleSystemReady() {
synchronized (this) {
if (DEBUG) Log.d(TAG, "onSystemReady");
mSystemReady = true;
doKeyguardLocked(null);
mUpdateMonitor.registerCallback(mUpdateCallback);
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
3)doKeyguardLocked()里面有个mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) 的判断,我们把这个的值打印下,会发现开机的时候,打印的值是false,lockedOrMissing和forceShow值默认为false,所以会直接return回去,没有继续走下面的流程了。
- 那我们现在知道了,是判断到lockScreen锁屏还没准备好,所以没有走显示锁屏的流程了。(这里具体没准备好的原因和判断条件,我还没有继续跟踪,我试过这里强制显示也是没有问题的,本来就是有个强制显示的参数forceShow,那说明这时需要强制显示也是可以的)
private void doKeyguardLocked(Bundle options) {
......
//------ 分析1
if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) && !lockedOrMissing && !forceShow) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
}
......
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
五、我想修改锁屏界面内容,应该关注哪些类和布局可以快速修改
1)登陆密码验证界面
i、这里涉及到2个重要的类 KeyguardAbsKeyInputView.java和 KeyguardPasswordView.java ,密码的授权验证在KeyguardAbsKeyInputView.java类中处理,界面的显示是在KeyguardPasswordView.java 中进行处理。 我们看下下图贴的代码 KeyguardPasswordView.java 里面的onEditorAction()里面的处理,有个verifyPasswordAndUnlock()的方法,就是跳转到KeyguardAbsKeyInputView.java中进行密码的验证了。
如果我们希望修改密码验证的逻辑的话,就可以修改KeyguardAbsKeyInputView.java中的verifyPasswordAndUnlock()里面的内容。
ii、密码验证对应的布局文件keyguard_password_view.xml,如果我们希望在布局上添加内容,就可以在这个布局文件上添加了。
--------KeyguardPasswordView.java --------
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// Check if this was the result of hitting the enter key
final boolean isSoftImeEvent = event == null
&& (actionId == EditorInfo.IME_NULL
|| actionId == EditorInfo.IME_ACTION_DONE
|| actionId == EditorInfo.IME_ACTION_NEXT);
final boolean isKeyboardEnterKey = event != null
&& KeyEvent.isConfirmKey(event.getKeyCode())
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (isSoftImeEvent || isKeyboardEnterKey) {
verifyPasswordAndUnlock();
return true;
}
return false;
}
六、遇到的问题以及分析解决
i、点击密码登录输入框,有时没有正常腾出输入法
这个问题发现和在KeyguardViewMediator.java 中调用mStatusBarKeyguardViewManager.setNeedsInput(needsInput); 有关系。需要正常腾出输入法,首先需要确保setNeedInput设置的值为true。我后面的修改是,在KeyguardViewMediator.java中,onSystemReady()方法中,根据自己需要,重新去设置了下setNeedInput的值。
还有个地方得修改下,KeyguardPasswordView.java中,resetState()里面,如下图所示,屏蔽掉了些代码。屏蔽掉的代码是自动调用输入法的,每次进入密码登录界面,会走resetState()的流程,不过很奇怪,主动去调用一次,反而是没有正常调用出来。
@Override
protected void resetState() {
mSecurityMessageDisplay.setMessage("");
final boolean wasDisabled = mUserNameEntry.isEnabled();
setPasswordEntryEnabled(true);
setPasswordEntryInputEnabled(true);
setUserNameEntryEnabled(true);
setUserNameEntryInputEnabled(true);
//屏蔽掉的代码
// if (wasDisabled) {
// mImm.showSoftInput(mUserNameEntry, InputMethodManager.SHOW_IMPLICIT);
// }
}
网友评论