在android 6.0 上Keyguard作为了SystemUI的一个库文件被引用,所以编译的时候不会出现Keyguard.apk这个文件,Keyguard也伴随着SystemUI的启动而启动,其中最重要的一个文件就是KeyguardViewMediator,这个文件负责SystemUI与Keyguard的交互,我们来看一下这个文件的启动。
一.KeyguardViewMediator的启动
KeyguardViewMediator.java作为SystemUIApplication.java中SERVICES[]中的一个元素,我们用一个流程图来说明这个文件的启动过程,这个数组中的其它元素启动顺序与这个类似,只是功能不同而已。
从上面的流程图中可以看到KeyguardViewMediator.java的启动分为两部分。
1.SystemUIApplication.java的onstart()
SystemUIApplication.java的onstart()调用,这个调用会初始化锁屏相关的工具类,但是需要注意这个步骤中没没有初始化任何锁屏界面相关的东西,只是进行一些Intent的注册以及一些必要的初始化工作。其中KeyguardDisplayManager.java会作为中间类去控制keyguard的show与hide,KeyguardUpdateMonitor.java中注册了绝大多数的广播,负责处理界面的一些刷新流程处理,还有一个需要特别注意一下就是FingerManager.java,这个类是android 6.0 新添加的,负责处理一些指纹相关的东西。
2.SystemUIApplication的onBootCompleted()
这个函数会去发送锁屏加载完成的广播,USER_PRESENT_INTENT,但是需要注意这个函数的调用时机。这个函数的调用是received到系统发送的ACTION_BOOT_COMPLETED,根据实际工作中的经验,
ACTION_BOOT_COMPLETED的发送比较偏后,在系统绝大多数的界面处理完成以后才会发送,在看到锁屏之后,也就是说,如果我们监听到
USER_PRESENT_INTENT,那么锁屏一般是肯定加载完成了的。
备注:锁屏界面的初始化是在SystemBar.java的onStart()方法中处理的,这个方法比较复杂,我们在SystemUI的分析中在细说。初始化是在onStart(),但是锁屏的加载需要经过一些特殊条件的触发与判断,由于开机第一次锁屏的加载是需要经过ActivityManagerService.java中界面的判断与WindowMnaagerService.java中界面绘制的处理才决定是否显示,牵扯的比较负责,暂时不分析,后续专门分析这部分。
二.SystemUI的启动
Keyguard是SystemUI的一个库文件,所以分析Keyguard我们需要先看一下SystemUI的启动。流程图简单分析如下:
PhoneStatusBar.java中的createAndAddWindows()会初始化并且加载SystemUI的绝大多数界面,包括statusbar与navigationbar,以及初始化QSHostView。这部分代码需要仔细阅读代码,注意细节,用到这些细节的时候我们再仔细分析。
至此,keyguard以及systemUI启动初始化加载完毕,SystemService.java中的startSystemUI()函数执行完毕。
三.POWER键灭屏时Keyguard的加载
我们知道用power键灭屏的时候会加载keyguard,这样可以保证亮屏的时候终端用户可以第一时间看到锁屏,保证良好的用户体验,我们用这个场景来分析锁屏的加载过程。
1.PowerManagerService亮屏流程
上述流程图从power按键的分发到PowerManagerService.java的处理,再到keyguard相关的代码处理,这条线路传到KeyguardViewMediator.java中以后就要开始锁屏界面的绘制了。稍后专门对锁屏界面的绘制进行说明。
备注:
亮屏过程中涉及到两条关键的线程,分别是PowerManager Notifier Thread 与DisplayManager Thread。
1.PowerManager Notifier Thread:power按键事件传到PowerManagerService.java中以后会分为两条线路进行事件处理,一条就是我们上面流程图上标注的,这条Thread(Notifier.java)主要负责亮屏或者灭屏广播的发送,以及锁屏界面的加载。
2.DisplayManager Thread:这条Thread会
传送到DisplayManagerService.java中去,会负责进行屏幕状态的设置以及屏幕的熄灭与点亮(真正的屏幕操作者),此外跟屏幕相关的一些可见性操作都是这条Thread(DisplayPowerController.java)进行处理,例如屏幕亮度的变化、屏幕亮度的设置、屏幕的显示时机等等,非常重要,有时间可以研究研究。
2.KeyguardManager.java的说明
APP侧开发锁屏应用,调用的接口是KeyguardManager.java或者内部类KeyguardManager.KeyguardLock,用这个manager来获取或者设置锁屏的一些状态,这样就可以控制锁屏的显示。需要添加对于的权限到AndroidMainfest.xml文件中,
android.permission.DISABLE_KEYGUARD。
对这个类的详细介绍以及用法介绍请参考如下网址:
http://blog.csdn.net/hudashi/article/details/7073373
我们简单的来分析一下这个调用过程,也用流程图来说明一下
从这个流程图不难发现,不管APP侧怎么调用KeyguardManager.java的接口,最终的实现都是在KeyguardViewMediator.java中。KeyguardService.java是Binder的服务器端,客户端是KeyguardServiceDelegate.java,
KeyguardServiceDelegate.java
这个文件在调用过程中只起到过渡的左右,在这里并没有深入研究。
KeyguardService.java会将所有的调用传递到
KeyguardViewMediator.java中。
备注:
Android 6.0 的Keyguard是在SystemUI中控制的,SystemUI是一个系统级的APK,要操作锁屏还是需要使用上述这些东西。所以如果需要改变锁屏的一些流程,我们可以在合适的位置调用KeyguardManager.java中接口,或者添加一些客制化的东西,直接在KeyguardViewMediator.java中进行操作,都是可以实现的。
3.锁屏的加载绘制过程
KeyguardViewMediator.java的onFinishedGoingToSleep()是加载锁屏的入口,接下来对这个过程进行分析。
这个过程是开机以后正常使用过程中,用power键灭屏的时候加载锁屏的流程,并且存在锁屏方式。还有其它方式的灭屏跟这个略有区别,例如亮屏超时的熄屏,但是大同小异,根本是一样的,有时间再仔细分析。
这样经过上述的流程以后,keyguard就在锁屏界面显示了,需要注意的是Android 6.0 上看到的锁屏实际上是一层通知panelview,也就是流程图上的17,如果去掉这个函数,那么界面上是不会出现通知界面的,但是锁屏也是不能用的,因为在这个函数执行之前已经通知了系统要加载锁屏,所以结果就是看上去去掉了notificationpanelview,但是实际上系统中的状态还是存在这个界面的,所以如果要从keyguard中用代码去掉这个界面,还需要其它的一些修改,需要保持界面状态的一致。
需要注意这个过程中的26:updateState(),这个函数会去更新keyguard以及systemUI的一些标志状态,保持系统状态的统一性,27会去设置更新后的这些状态值。