一、前言

前面几篇文章大致介绍了SystemUI的两个模块,StatusBar和QuickSetting,这篇文章开始分析Keyguard模块。
对于锁屏呢,需要有个基本认知,它分为两类,一是滑动锁屏,一是安全锁屏。滑动锁屏是指通过手指滑动即可解锁的锁屏,安全锁屏是指密码锁,图案锁,PIN码锁等等。这两种锁屏是在不同的地方创建的,不可一概而论,而本文只分析滑动锁屏。
https://blog.csdn.net/omnispace/article/details/78566838
https://juejin.cn/user/2805609401693943/posts

二、滑动锁屏视图

1、根据SystemUI之StatusBar创建可知,整个SystemUI视图是由super_status_bar.xml创建的

<!--根布局继承自FrameLayout的StatusBarWindowView-->
<com.android.systemui.statusbar.phone.StatusBarWindowViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:sysui="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><com.android.systemui.statusbar.BackDropViewandroid:id="@+id/backdrop"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"sysui:ignoreRightInset="true"><ImageView android:id="@+id/backdrop_back"android:layout_width="match_parent"android:scaleType="centerCrop"android:layout_height="match_parent" /><ImageView android:id="@+id/backdrop_front"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"android:visibility="invisible" /></com.android.systemui.statusbar.BackDropView><com.android.systemui.statusbar.ScrimViewandroid:id="@+id/scrim_behind"android:layout_width="match_parent"android:layout_height="match_parent"android:importantForAccessibility="no"sysui:ignoreRightInset="true"/>状态栏容器<FrameLayoutandroid:id="@+id/status_bar_container"android:layout_width="match_parent"android:layout_height="wrap_content" />车载模式的布局 <ViewStub android:id="@+id/fullscreen_user_switcher_stub"android:layout="@layout/car_fullscreen_user_switcher"android:layout_width="match_parent"android:layout_height="match_parent"/>整个下拉通知面版,包括滑动锁屏界面<include layout="@layout/status_bar_expanded"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="invisible" />这里亮度调节bar<include layout="@layout/brightness_mirror" />状态栏下拉后,背景,半透明灰色<com.android.systemui.statusbar.ScrimViewandroid:id="@+id/scrim_in_front"android:layout_width="match_parent"android:layout_height="match_parent"android:importantForAccessibility="no"sysui:ignoreRightInset="true"/></com.android.systemui.statusbar.phone.StatusBarWindowView>

2、在这个布局中,include了一个status_bar_expanded.xml布局,这是整个下拉通知面版,包括滑动锁屏的各种控件,来看看这个布局:

<com.android.systemui.statusbar.phone.NotificationPanelViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:systemui="http://schemas.android.com/apk/res-auto"android:id="@+id/notification_panel"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/transparent" >滑动锁屏界面状态视图: 时间,日期<includelayout="@layout/keyguard_status_view"android:visibility="gone" /><com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainerandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="@integer/notification_panel_layout_gravity"android:id="@+id/notification_container_parent"android:clipToPadding="false"android:clipChildren="false">QS界面<FrameLayoutandroid:id="@+id/qs_frame"android:layout="@layout/qs_panel"android:layout_width="@dimen/qs_panel_width"android:layout_height="match_parent"android:layout_gravity="@integer/notification_panel_layout_gravity"android:clipToPadding="false"android:clipChildren="false"systemui:viewType="com.android.systemui.plugins.qs.QS" />显示通知的容器<com.android.systemui.statusbar.stack.NotificationStackScrollLayoutandroid:id="@+id/notification_stack_scroller"android:layout_marginTop="@dimen/notification_panel_margin_top"android:layout_width="@dimen/notification_panel_width"android:layout_height="match_parent"android:layout_gravity="@integer/notification_panel_layout_gravity"android:layout_marginBottom="@dimen/close_handle_underlap" /><include layout="@layout/ambient_indication"android:id="@+id/ambient_indication_container" /><ViewStubandroid:id="@+id/keyguard_user_switcher"android:layout="@layout/keyguard_user_switcher"android:layout_height="match_parent"android:layout_width="match_parent" />滑动锁屏状态栏<includelayout="@layout/keyguard_status_bar"android:visibility="invisible" /><Buttonandroid:id="@+id/report_rejected_touch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="@dimen/status_bar_header_height_keyguard"android:text="@string/report_rejected_touch"android:visibility="gone" /></com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>这里锁屏底部图标, 填充整个父布局,例如左下角的图标,右下角的图标Camera<includelayout="@layout/keyguard_bottom_area"android:visibility="gone" /><com.android.systemui.statusbar.AlphaOptimizedViewandroid:id="@+id/qs_navbar_scrim"android:layout_height="96dp"android:layout_width="match_parent"android:layout_gravity="bottom"android:visibility="invisible"android:background="@drawable/qs_navbar_scrim" /></com.android.systemui.statusbar.phone.NotificationPanelView>

可以看到,滑动锁屏的各个部分比较分散,并不是在同一容器中集中创建的。

三、滑动锁屏的显示

1、一般我们通过电源键的开关来锁屏的,本文来分析下,从开机到滑动锁屏显示的过程。

在开机的过程中,当ActivityManagerService启动完毕后,会创建SystemUI

frameworks/base/services/java/com/android/server/SystemServer.java

    static final void startSystemUi(Context context, WindowManagerService windowManager) {//启动SystemUIServiceIntent intent = new Intent();intent.setComponent(new ComponentName("com.android.systemui","com.android.systemui.SystemUIService"));intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);context.startServiceAsUser(intent, UserHandle.SYSTEM);// 2. 通知WMS,SystemUI已经启动windowManager.onSystemUiStarted();}

2、前面的文章已经分析了SystemUI的启动,这个过程创建了整个SystemUI的视图,包括滑动锁屏的视图。现在来看看WindowManagerService在SystemUI启动后,做了什么

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public void onSystemUiStarted() {mPolicy.onSystemUiStarted();}

3、Window Manager 通知了 PhoneWindowManager , SystemUI 已经启动。

public class PhoneWindowManager implements WindowManagerPolicy {...private void bindKeyguard() {synchronized (mLock) {if (mKeyguardBound) {return;}mKeyguardBound = true;}mKeyguardDelegate.bindService(mContext);}@Overridepublic void onSystemUiStarted() {//绑定锁屏服务KeyguardServicebindKeyguard();} ...
}

4、策略类 PhoneWindowManager 通过一个代理类 KeyguardServiceDelegate 来绑定了 KeyguardService。

KeyguardService 是一个标准的 Service,在绑定它的时候会返回一个 IBinder 对象,也就是服务端接口。我们在后面直接称 KeyguardService 为锁屏服务端。

锁屏组件所对应的服务名称:

<string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
public class KeyguardServiceDelegate {...public void bindService(Context context) {Intent intent = new Intent();final Resources resources = context.getApplicationContext().getResources();final ComponentName keyguardComponent = ComponentName.unflattenFromString(resources.getString(com.android.internal.R.string.config_keyguardComponent));intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);intent.setComponent(keyguardComponent);//绑定服务if (!context.bindServiceAsUser(intent, mKeyguardConnection,Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);mKeyguardState.showing = false;mKeyguardState.showingAndNotOccluded = false;mKeyguardState.secure = false;synchronized (mKeyguardState) {mKeyguardState.deviceHasKeyguard = false;}} else {if (DEBUG) Log.v(TAG, "*** Keyguard started");}}...}

5、这就是一个标准的绑定 Service 流程,通过绑定时传入的参数 mKeyguardConnection 可以查看成功绑定后的操作,而ServiceConnection 是服务绑定成功后返回的对象。

public class KeyguardServiceDelegate {...private final ServiceConnection mKeyguardConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mKeyguardService = new KeyguardServiceWrapper(mContext,IKeyguardService.Stub.asInterface(service), mCallback);if (mKeyguardState.systemIsReady) {// If the system is ready, it means keyguard crashed and restarted.mKeyguardService.onSystemReady();}...}@Overridepublic void onServiceDisconnected(ComponentName name) {if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");mKeyguardService = null;mKeyguardState.reset();mHandler.post(() -> {try {// There are no longer any keyguard windows on secondary displays, so pass// INVALID_DISPLAY. All that means is that showWhenLocked activities on// secondary displays now get to show.ActivityManager.getService().setLockScreenShown(true /* keyguardShowing */,false /* aodShowing */, INVALID_DISPLAY);} catch (RemoteException e) {// Local call.}});}};...}

6、通过查询各种状态,然后按顺序向锁屏服务端发送指令。这里我们只分析服务端的onSystemReady()的实现

代理类 KeyguardServiceDelegate 内部通过 KeyguardState 对象保存锁屏的状态,从而控制 KeyguardService 的行为。

    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {...@Override // Binder interfacepublic void onSystemReady() {// SYSTEM 用户或者有 android.Manifest.permission.CONTROL_KEYGUARD 权限checkPermission();mKeyguardViewMediator.onSystemReady();}...};

7、锁屏服务端又辗转通知了 KeyguardViewMediator,KeyguardViewMediator 向 Handler 发送了一个 SYSTEM_READY 事件来处理,最终会调用 handleSystemReady()

frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

public class KeyguardViewMediator extends SystemUI {...public void onSystemReady() {mHandler.obtainMessage(SYSTEM_READY).sendToTarget();}...private Handler mHandler = new Handler(Looper.myLooper(), null, true) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {...case SYSTEM_READY:handleSystemReady();break;...        }}
}
  • KeyguardViewMediator是典型的中介者模式的应用,它综合了各方面的信息来控制锁屏。
  • KeyguardViewMediator有一个与主线程 Looper 关联的 Handlder,事件和处理都是通过这个 Handler,因此保证了事件处理的有序性,这样就不会导致界面刷新混乱。
    private void handleSystemReady() {synchronized (this) {mSystemReady = true;// 开启锁屏, 这里参数为 nulldoKeyguardLocked(null);// KeyguardUpdateMonitor 通过监听数据库Uri, 注册广播接收器,向各种服务注册监听,从而获取到与锁屏有关的更新// KeyguardViewMediator 这个中介者关心的回调如下// 1. onClockVisibilityChanged// 2. onDeviceProvisioned// 3. onSimStateChanged// 4. onBiometricAuthFailed, onBiometricAuthenticated// 5. onHasLockscreenWallpaperChangedmUpdateMonitor.registerCallback(mUpdateCallback);}maybeSendUserPresentBroadcast();}

8、doKeyguardLocked方法又会调用showLocked方法,showLocked方法通过Handler发送SHOW类型的消息,最终调用handleShow方法,handleShow方法会继续调用KeyguardDisplayManager的show方法。

  private void doKeyguardLocked(Bundle options) {...showLocked(options);}...//显示锁屏private void showLocked(Bundle options) {...mShowKeyguardWakeLock.acquire();Message msg = mHandler.obtainMessage(SHOW, options);mHandler.sendMessage(msg);}...//处理消息的Handlerprivate Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case SHOW://处理显示锁屏的消息handleShow((Bundle) msg.obj);break;...}}private void handleShow(Bundle options) {...//继续调用KeyguardDisplayManager的show方法mKeyguardDisplayManager.show();}

9、KeyguardDisplayManager的show方法又会继续调用updateDisplays方法,

public class KeyguardDisplayManager {...public void show() {if (!mShowing) {if (DEBUG) Slog.v(TAG, "show");mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);updateDisplays(true);}mShowing = true;}...protected void updateDisplays(boolean showing) {Presentation originalPresentation = mPresentation;if (showing) {MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);boolean useDisplay = route != null&& route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());mPresentation.dismiss();mPresentation = null;}if (mPresentation == null && presentationDisplay != null) {if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);mPresentation = new KeyguardPresentation(mContext, presentationDisplay,R.style.keyguard_presentation_theme);mPresentation.setOnDismissListener(mOnDismissListener);try {mPresentation.show();} catch (WindowManager.InvalidDisplayException ex) {Slog.w(TAG, "Invalid display:", ex);mPresentation = null;}}} else {if (mPresentation != null) {mPresentation.dismiss();mPresentation = null;}}// mPresentation is only updated when the display changesif (mPresentation != originalPresentation) {final int displayId = mPresentation != null? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;mCallback.onSecondaryDisplayShowingChanged(displayId);}}...}

Android 9.0系统源码_SystemUI(六)滑动锁屏的创建相关推荐

  1. Android 9.0系统源码_SystemUI(一)SystemUI的启动流程

    一.SystemUI 介绍 1.初步认识SystemUI Android 的 SystemUI 其实就是 Android 的系统界面,它包括了界面上方的状态栏 status bar,下方的导航栏Nav ...

  2. Android 9.0系统源码_SystemUI(四)通知图标控制器

    前言 上一篇我们具体分析了状态栏上状态图标,例如 wifi.蓝牙等图标的控制流程,本篇文章我们继续来分析下状态栏上通知图标的控制流程.主要分析当一个新通知来临时,新通知的图标是如何一步步显示到状态栏上 ...

  3. Android 9.0系统源码_SystemUI(二)StatusBar系统状态栏的创建流程

    前言 上一篇我们具体分析了SystemUI的启动流程,在SystemServer的startOtherServices方法中,会启动SystemUIService服务,SystemUIService服 ...

  4. Android 9.0系统源码_SystemUI(九)PhoneWindowManager构建状态栏和导航栏视图窗口区域坐标的流程解析

    前言 NavigationBar 和 StatusBar 都属于 SystemBar,也叫做 decor,就是说给 App 装饰的意思.一般的 window 的布局是在 PhoneWindowMana ...

  5. Android 9.0系统源码_SystemUI(三)系统状态图标控制

    前言 上一篇我们具体分析了系统状态栏StatusBar的创建过程,其中状态栏视图就存储在CollapsedStatusBarFragment中,这个视图被添加到id为status_bar_contai ...

  6. android 系统源码调试 局部变量值_如何方便快速的整编Android 9.0系统源码?

    点击上方"刘望舒",选择"星标" 多点在看,就是真爱! 作者 :  刘望舒  |  来源 :刘望舒的博客地址:http://liuwangshu.cn/fram ...

  7. Android 8.0系统源码分析--开篇

    个人分类: Android框架总结Android源码解析android framework 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sinat ...

  8. Android 8.0系统源码分析--Camera processCaptureResult结果回传源码分析

    相机,从上到下概览一下,真是太大了,上面的APP->Framework->CameraServer->CameraHAL,HAL进程中Pipeline.接各种算法的Node.再往下的 ...

  9. android微信电话锁屏,解决 Android 7.0 系统中,微信无法在锁屏画面显示

    文章版块:HTC One A9 在 Android 7.0 系统中htc手机微信怎么截屏htc手机微信怎么截屏,会出现微信无法在锁屏画面显示的状况.建议您进行下面修改就可以解决: 进入"HT ...

最新文章

  1. 强大的shell常用命令集锦
  2. 【markdown】图片的处理
  3. 玩转UITableView
  4. 分享一个简单程序(webApi+castle+Automapper+Ef+angular)
  5. leetcode--872. 叶子相似的树
  6. 记一次某APK的恶意WIFI攻击
  7. python观察日志(part9)--数据库与pickle模块
  8. 关于Git使用的一些心得
  9. 分布式系统的那些事儿(六) - SOA架构体系
  10. 详尽kmp_详尽的分步指南,用于数据准备
  11. java 注解入门 简书_Java基础-注解
  12. 树莓派 python_树莓派笔记08—Python流水灯
  13. ider中的html元素背景操作,idea怎么设置背景颜色
  14. matlab 二元函数 定义,实验五用matlab求二元函数及极值.doc
  15. Matlab图窗保存为pdf文件
  16. 对比分析163VIP邮箱费用,原来有这么多的好处!
  17. golang 定时任务处理
  18. java热敏POS打印机编程
  19. (3)数仓建设-数据仓库设计方案
  20. 如何用ajax实现页面自动刷新,Ajax实现页面自动刷新实例解析

热门文章

  1. 如何将matlab设置为默认打开方式,如何设置默认打开方式
  2. MySQL Workbench 8.0 默认没有开启Metadata and internal Schemas
  3. ios 视频选择封面功能
  4. mtk处理器和骁龙对比_联发科(MTK)智能手机处理器平台汇总(含基本参数对比)一览...
  5. HDU1847:Good Luck in CET-4 Everybody!(SG博弈)
  6. java构建树状结构工具类
  7. urllib库爬取拍信创意图片(post请求)json传参
  8. 亚马逊云科技发布“云拓计划”赋能企业加速上云及数字化转型
  9. python中的请求方法_Python爬虫HTPP请求方法有哪些
  10. 【MySQL 面试系列】索引原理