本篇接着分析锁屏相关流程,通常我们点击power键会灭屏,灭屏时就会加载锁屏,以便用户能在下次亮屏时第一时间看到锁屏,我们就来看看点击power键灭屏锁屏的流程

Android的事件分发流程大概是:InputReader读取dev/input设备节点的原始事件->通过封装传递给InputDispatcher->InputDispatcher找到对应处理事件的窗口并将事件分发到上层ViewRootImpl->ViewRootImpl再进行上层的事件分发…

对于Key事件,InputDispatcher在分发前会先将事件发到上层PhoneWindowManager中,有个提前拦截的机会:

InputDispatcher.notifyKey

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);needWake = enqueueInboundEventLocked(newEntry);...
}

所以我们就从PhoneWindowManager的interceptKeyBeforeQueueing方法作为起始点分析power按键的灭屏流程

interceptKeyBeforeQueueing

@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {if (!mSystemBooted) {return 0;}...switch (keyCode) {  ...case KeyEvent.KEYCODE_POWER: {...if (down) {//按下事件interceptPowerKeyDown(event, interactive);} else {//抬起事件interceptPowerKeyUp(event, interactive, canceled);}break;}...}}

根据keyCode处理各种类型的Key事件,我们这里只关心power事件,down为true代表按下,false代表抬起,灭屏是通过抬起事件完成的,这是因为power键组合需要完成多种任务,如长按出现GlobalActionDialog,双击进入camera,power+音量下完成截屏等,如果在按下处理灭屏肯定是不行的

interceptPowerKeyUp

    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {...mPowerKeyPressCounter += 1;powerPress(eventTime, interactive, mPowerKeyPressCounter);...// Done.  Reset our state.finishPowerKeyPress();
}

powerPress

private void powerPress(long eventTime, boolean interactive, int count) {...if (count == 2) {...} else if (count == 3) {...} else if (interactive && !mBeganFromNonInteractive) {switch (mShortPressOnPowerBehavior) {case SHORT_PRESS_POWER_NOTHING:break;case SHORT_PRESS_POWER_GO_TO_SLEEP:goToSleepFromPowerButton(eventTime, 0);break;....
}

这里的count是interceptPowerKeyUp传递过来的,等于1,mShortPressOnPowerBehavior值是定义在config.xml中的等于1,代表短按power键需要做的事,1 - Go to sleep (doze)

<!-- Control the behavior when the user short presses the power button.0 - Nothing1 - Go to sleep (doze)2 - Really go to sleep (don't doze)3 - Really go to sleep and go home (don't doze)4 - Go to home5 - Dismiss IME if shown. Otherwise go to home--><integer name="config_shortPressOnPowerBehavior">1</integer>

所以调用goToSleepFromPowerButton方法

goToSleepFromPowerButton

private boolean goToSleepFromPowerButton(long eventTime, int flags) {/*在我们真正进入睡眠之前,请检查最后一个唤醒原因。如果设备最近刚从手势中醒来(例如用户抬起设备)然后忽略睡眠指令。 这是因为用户倾向于在拿起设备时立即按下电源按钮,而在这种情况下我们不希望设备重新进入睡眠状态。*/final PowerManager.WakeData lastWakeUp = mPowerManagerInternal.getLastWakeup();if (lastWakeUp != null && lastWakeUp.wakeReason == PowerManager.WAKE_REASON_GESTURE) {final int gestureDelayMillis = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE,POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS);final long now = SystemClock.uptimeMillis();if (mPowerButtonSuppressionDelayMillis > 0&& (now < lastWakeUp.wakeTime + mPowerButtonSuppressionDelayMillis)) {return false;}}//这里传递了一个灭屏的原因,为点击power键灭屏goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);return true;}

灭屏的原因挺多的,定义在PowerManager中

public final class PowerManager {//某个应用调用灭屏相关APIpublic static final int GO_TO_SLEEP_REASON_APPLICATION = GO_TO_SLEEP_REASON_MIN;//通过设备管理策略设置灭屏public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1;//超时灭屏public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;//对于翻盖类型手机,关闭翻盖灭屏public static final int GO_TO_SLEEP_REASON_LID_SWITCH = 3;//点击power键灭屏public static final int GO_TO_SLEEP_REASON_POWER_BUTTON = 4;//因为HDMI灭屏public static final int GO_TO_SLEEP_REASON_HDMI = 5;//点击sleep键灭屏public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6;//无障碍服务请求灭屏public static final int GO_TO_SLEEP_REASON_ACCESSIBILITY = 7;//强制暂停灭屏public static final int GO_TO_SLEEP_REASON_FORCE_SUSPEND = 8;}

goToSleep

 private void goToSleep(long eventTime, int reason, int flags) {mRequestedOrGoingToSleep = true;mPowerManager.goToSleep(eventTime, reason, flags);}

接着调用到PowerManagerService的goToSleep方法

PowerManagerService.goToSleep

@Override // Binder callpublic void goToSleep(long eventTime, int reason, int flags) {...try {goToSleepInternal(eventTime, reason, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}}

goToSleepInternal

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {synchronized (mLock) {if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {updatePowerStateLocked();}}}

如果power键灭屏没有传入PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE,goToSleepNoUpdateLocked此方法会执行Doze相关策略,我们不去分析此方法返回false的情况,接着调用updatePowerStateLocked

updatePowerStateLocked

private void updatePowerStateLocked() {...// Phase 5: Send notifications, if needed.finishWakefulnessChangeIfNeededLocked();....}

finishWakefulnessChangeIfNeededLocked

private void finishWakefulnessChangeIfNeededLocked() {....  mNotifier.onWakefulnessChangeFinished();}}

这里调到Notifier的onWakefulnessChangeFinished去

Notifier.onWakefulnessChangeFinished

public void onWakefulnessChangeFinished() {if (mInteractiveChanging) {mInteractiveChanging = false;handleLateInteractiveChange();}}

handleLateInteractiveChange

private void handleLateInteractiveChange() {synchronized (mLock) {...if (mInteractive) {.....} else {...final int why = translateOffReason(mInteractiveChangeReason);mHandler.post(new Runnable() {@Overridepublic void run() {...mPolicy.finishedGoingToSleep(why);}});// 发送广播...}}}

点击power亮屏时mInteractive为true,灭屏时mInteractive为false,所以我们只看else分支
why是灭屏原因,我们这里获取到的是如下值为2

/** Screen turned off because of power button */int OFF_BECAUSE_OF_USER = 2;

最终调到了PhoneWindowManager的finishedGoingToSleep方法

finishedGoingToSleep

public void finishedGoingToSleep(int why) {......if (mKeyguardDelegate != null) {mKeyguardDelegate.onFinishedGoingToSleep(why,mCameraGestureTriggeredDuringGoingToSleep);}if (mDisplayFoldController != null) {mDisplayFoldController.finishedGoingToSleep();}mCameraGestureTriggeredDuringGoingToSleep = false;}

接着调用KeyguardServiceDelegate的onFinishedGoingToSleep方法,mCameraGestureTriggeredDuringGoingToSleep这个值代表点击的power键行为是否满足启动camera的要求

onFinishedGoingToSleep

public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {if (mKeyguardService != null) {mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);}mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;}

这里的mKeyguardService = new KeyguardServiceWrapper(mContext,
IKeyguardService.Stub.asInterface(service), mCallback);
这是一个binder调用,最终到了SystemUI进程中

KeyguardService.onFinishedGoingToSleep

@Override // Binder interfacepublic void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {checkPermission();mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);...}

调到了Keyguard的核心类KeyguardViewMediator中

onFinishedGoingToSleep

public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {synchronized (this) {...//移除KEYGUARD_DONE_PENDING_TIMEOUT消息resetKeyguardDonePendingLocked();//如果灭屏之前Bouncer正在显示则需要通知其进去onPause状态notifyFinishedGoingToSleep();//cameraGestureTriggered为true代表不会显示锁屏,而是启动cameraif (cameraGestureTriggered) {mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),PowerManager.WAKE_REASON_CAMERA_LAUNCH,"com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");mPendingLock = false;mPendingReset = false;}if (mPendingReset) {resetStateLocked();mPendingReset = false;}if (mPendingLock) {doKeyguardLocked(null);mPendingLock = false;}}

如果不走启动camera的分支则会调用resetStateLocked和doKeyguardLocked,这两个方法其实最终都是通过调用StatusBarKeyguardViewManager的reset方法而锁屏,二者的区别是,resetStateLocked因为已经在锁屏界面,所以不需要AMS,WMS修改锁屏窗口相关参数以及Activity先关状态改变

doKeyguardLocked则会对是否显示锁屏进行一系列条件判断,都验证通过才会真正去show,如是否三方应用禁用了锁屏,是否在Setup Wizard界面等

doKeyguardLocked这个方法其实在AndroidQ SystemUI之锁屏加载(上)滑动锁屏已经详细分析过了,我们再来看看

doKeyguardLocked

private void doKeyguardLocked(Bundle options) {if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {// 在半启动的cryptkeeper阶段不显示if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");return;}// 被三方应用禁用则不显示if (!mExternallyEnabled) {if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");mNeedToReshowWhenReenabled = true;return;}// Keyguard已经显示则不需要重新显示,reset一下就行了if (mStatusBarKeyguardViewManager.isShowing()) {if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");resetStateLocked();return;}....if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");showLocked(options);}

这个方法里面首先会对诸多条件进行验证,只有满足锁屏显示条件才调用showLocked显示锁屏

showLocked

private void showLocked(Bundle options) {...Message msg = mHandler.obtainMessage(SHOW, options);mHandler.sendMessage(msg);}

发送SHOW消息,调用handleShow

handleShow

private void handleShow(Bundle options) {.....mStatusBarKeyguardViewManager.show(options);......}

StatusBarKeyguardViewManager.show

 public void show(Bundle options) {mShowing = true;...//显示锁屏,隐藏bouncerreset(true /* hideBouncerWhenShowing */);}

reset

public void reset(boolean hideBouncerWhenShowing) {if (mShowing) {//锁屏被遮挡,如闹钟,来电界面if (mOccluded && !mDozing) {mStatusBar.hideKeyguard();if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {hideBouncer(false /* destroyView */);}} else {//否则走正常显示锁屏流程showBouncerOrKeyguard(hideBouncerWhenShowing);}}}

showBouncerOrKeyguard

protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {//执行显示bouncer的情况,插入带PIN或PUK码的SIM卡时走这里if (mBouncer.needsFullscreenBouncer() && !mDozing) {mStatusBar.hideKeyguard();mBouncer.show(true /* resetSecuritySelection */);} else {mStatusBar.showKeyguard();if (hideBouncerWhenShowing) {hideBouncer(shouldDestroyViewOnReset() /* destroyView */);mBouncer.prepare();}}updateStates();}

showBouncerOrKeyguard有两种情况,显示滑动锁屏还是bouncer,只有插入带PIN或PUK码的SIM卡时显示Bouncer,其他情况则showKeyguard并且hideBouncer

后面的流程就是AndroidQ SystemUI之锁屏加载(上)滑动锁屏 分析一样的,显示滑动锁屏的流程了

好了到此为止我们已经分析完了通过点击power键完成锁屏加载的大致流程,仅仅分析了方法的调用链,很多细节流程没有时间去看,也不用现在花时间去看,我们了解了整个流程后遇到这条链上的问题再顺着某一点分析是很容易的

总结一下:

  1. 首先PhoneWindowManager收到power Key的点击事件,并处理其按下和抬起事件
  2. 抬起事件会一步一步通过PowerManagerService->Notifier->PhoneWindowManager,再通过Binder调用到SystemUI进程的KeyguardViewMediator中
  3. KeyguardViewMediator的锁屏核心方法doKeyguardLocked为入口一步一步调用最后将滑动锁屏显示出来

AndroidQ SystemUI之power键灭屏锁屏流程相关推荐

  1. 解决Windows键+L不能锁屏的问题

    解决Windows键+L不能锁屏的问题 当时遇到windows+L不能锁屏的问题的时候,找了网上很多的解决办法,都是什么这边改改设置,那边改改配置.解决了还好说,解决不了的话,想撤销都没用. 我想说是 ...

  2. Windows无缝息屏锁屏

    Windows无缝息屏锁屏 背景 windows图形界面中需要在电源计划中设置息屏时间来达到息屏的效果,但这个不能够按照自己心意随时息屏,之前都是windows+L锁屏,但息屏却还需要等待至少1分钟时 ...

  3. 计算机键盘上怎么锁屏,锁屏快捷键,教您电脑锁屏键怎么用

    小可爱们知道我今天要说的内容是什么吗?小编大大我今天要说的对于小可爱们来说是有帮助的内容哟~那就是当我们不玩电脑时,为了节省电量,一般都会选择让电脑休眠.那么今天我要说的就是电脑的锁屏快捷键要怎么用. ...

  4. android 魔力锁屏,锁屏软件横评:锁屏功能PK_Android软件合辑_软件合辑_太平洋电脑网PConline...

    三.功能设置 GO锁屏:除了以上两个评测项目设计的设置之外,GO锁屏还可以设置开启锁屏提示音.解锁提示音及解锁震动.在设置中可以设置锁屏开启或关闭. 其他功能设置 魔力锁屏:魔力锁屏可以启用音量键唤醒 ...

  5. html页面锁屏,锁屏页面.html

     锁屏页面 $axure.utils.getTransparentGifPath = function() { return 'resources/images/transparent.gif'; ...

  6. opporeno5k怎样关闭乐划锁屏锁屏杂志

    许多手机都内置了锁屏杂志功能.当用户开启后壁纸会时不时更换一次.那opporeno5k怎么关闭锁屏杂志你知道吗?不清楚也没关系.快来看看换换带来的详细教程吧.希望对你有所帮助! opporeno5k关 ...

  7. Mac 电脑笔记本快速锁屏 锁屏快捷键

    有很多人把自己的 Mac 笔记本作为工作本,私人电脑的安全无比重要,但是 macOS 并没有直接锁屏的快捷键,设置屏幕保护程序又麻烦. 下面就介绍一种非常简单的锁屏方法, 只要一键设置,就可以一键锁屏 ...

  8. java 截屏 锁屏黑色_Appium 解决锁屏截屏问题(java篇)

    Promise与Defer认识 1.deffer对象:jquery的回掉函数解决方案:含义是延迟到未来某个点再执行: 2.$.ajax链式写法: $.ajax("test.php" ...

  9. Android 9.0 SystemUI 锁屏流程分析

    1.锁屏界面显示的流程 2.按键灭屏 -> 按键亮屏 对于Key事件,InputDispatcher在分发之前会先将事件上发到PhoneWindowManager中,可以进行拦截,故从Phone ...

  10. 【Mac使用系列】Mac锁屏及快捷键

    mac锁屏办法,我有所尝试,可用系统自带锁屏快捷键:Ctrl + Command + Q 或者参考方法2,直接设置TouchBar. 这两种办法,亲测可用.我直接设置了TouchBar,锁屏解锁离得很 ...

最新文章

  1. Appium定位元素的几种方法总结
  2. python下的scripts有什么用_python安装后无scripts内文件,无法使用pip
  3. vue-js 特殊变量$event常识
  4. 排序算法之快速排序(Java)
  5. vc给exe更改图标
  6. wps表格里面计算机在哪里,WPS的Word居然还有计算神器?在哪里能找到又是怎么进行计算呢?...
  7. 二叉树寻找祖先C语言,微软算法面试题:给定两个二叉树节点,寻找其最近共同祖先...
  8. 推荐系统实战第二部分 评价指标
  9. 中国内镜超声针市场趋势报告、技术动态创新及市场预测
  10. linux_grep操作
  11. linux安全加固技术--内核安全模块LSM
  12. echarts地图数据过旧,通过geojson自定义经纬度地图
  13. 移动GM220S光猫超级密码及改桥接模式方法
  14. 仿权重8高收录面包网pc+手机苹果cmsv8影视网站含迅雷下载N430模板
  15. C# GDI 手绘图片转化为电子版处理
  16. 项目1 设计简易灯箱画廊 实训要求: (1)利用超链接和图像标记设计简易灯箱画廊。 (2)给简易灯箱画廊增加背景音乐效果。
  17. Element ui 修改 <el-collapse 的 <el-collapse-item 标题字体大小
  18. 怎样在Word文档中插入GIF动画
  19. 电脑双屏下如何设置鼠标移动方向
  20. 服务器和交换机物理连接_利用Calico融合物理网络的云原生容器SDN方案

热门文章

  1. c语言程序设计基本模板,《C语言程序设计基础教程》试讲教案模板
  2. onkeyup+onafterpaste
  3. 手脱aspack变形壳
  4. 基于并查集的六度分隔理论的验证与实现
  5. css面试精讲之防止高度坍塌的4种方式
  6. 商品期货跨期套利实战笔记
  7. 计算机无法读取tf卡,教您电脑无法读取sd卡
  8. linux yum安装xz,CentOS 7 上安装 xz utils 解压缩工具
  9. Postman 接口神器
  10. QQ语音麦克风没声音,但其他地方能用麦克风(USB耳机麦克风)