1、锁屏界面显示的流程
2、按键灭屏 —> 按键亮屏
对于Key事件,InputDispatcher在分发之前会先将事件上发到PhoneWindowManager中,可以进行拦截,故从PhoneWindowManager的interceptKeyBeforeQueueing()方法开始分析按键灭屏,其中根据keyCode处理各种类型的Key事件。
PhoneWindowManager.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
...
// Handle special keys.
switch (keyCode) {
...
case KeyEvent.KEYCODE_POWER: {
// Any activity on the power button stops the accessibility shortcut
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
//按下事件
interceptPowerKeyDown(event, interactive);
} else {
//抬起事件
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
...
}
}
因为power键组合完成多种任务,如长按出现GlobalActionDialog、双击进入camera、power+音量下完成截屏等,故在按下处理灭屏是不合适的,将抬起事件处理为灭屏
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
...
if (!handled) {
// Figure out how to handle the key now that it has been released.
mPowerKeyPressCounter += 1;
...
// No other actions. Handle it immediately.
powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
// Done. Reset our state.
finishPowerKeyPress();
}
private void powerPress(long eventTime, boolean interactive, int count) {
...
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
break;
...
}
}
}
这里的count是通过interceptPowerKeyUp()传递过来的,等于1。mShortPressOnPowerBehavior值是定义在config.xml中的,等于1,代表短按power键需要做的事
<!-- Control the behavior when the user short presses the power button.
0 - Nothing
1 - 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 home
5 - Dismiss IME if shown. Otherwise go to home
-->
<integer name="config_shortPressOnPowerBehavior">1</integer>
private void goToSleep(long eventTime, int reason, int flags) {
mRequestedOrGoingToSleep = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
导致灭屏的原因会有很多,定义在PowerManager中
PowerManager.java
/**
* Go to sleep reason code: Going to sleep due by application request.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_APPLICATION = 0;
/**
* Go to sleep reason code: Going to sleep due by request of the
* device administration policy.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1;
/**
* Go to sleep reason code: Going to sleep due to a screen timeout.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;
/**
* Go to sleep reason code: Going to sleep due to the lid switch being closed.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_LID_SWITCH = 3;
/**
* Go to sleep reason code: Going to sleep due to the power button being pressed.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_POWER_BUTTON = 4;
/**
* Go to sleep reason code: Going to sleep due to HDMI.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_HDMI = 5;
/**
* Go to sleep reason code: Going to sleep due to the sleep button being pressed.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6;
/**
* Go to sleep reason code: Going to sleep by request of an accessibility service
* @hide
*/
public static final int GO_TO_SLEEP_REASON_ACCESSIBILITY = 7;
public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
接着调用PowerManagerService的goToSleep( )方法
PowerManagerService.java
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
...
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
private void updatePowerStateLocked() {
...
// Phase 5: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
...
}
private void finishWakefulnessChangeIfNeededLocked() {
if (mWakefulnessChanging && mDisplayReady) {
...
mNotifier.onWakefulnessChangeFinished();
}
}
在这里调用到Notifier的onWakefulnessChangeFinished()方法
Notifier.java
/**
* Notifies that the device has finished changing wakefulness.
*/
public void onWakefulnessChangeFinished() {
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeFinished");
}
if (mInteractiveChanging) {
mInteractiveChanging = false;
handleLateInteractiveChange();
}
}
private void handleLateInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Finished waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.finishedWakingUp();
}
});
} else {
...
// Tell the policy we finished going to sleep.
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
...
mPolicy.finishedGoingToSleep(why);
}
});
// Send non-interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
mPendingGoToSleepBroadcast = true;
updatePendingBroadcastLocked();
}
}
}
当mInteractive为true时,点击power亮屏;为false时,灭屏;
最终调用到PhoneWindowManager的finishedGoingToSleep() 方法
PhoneWindowManager.java
// Called on the PowerManager's Notifier thread.
@Override
public void finishedGoingToSleep(int why) {
...
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onFinishedGoingToSleep(why,
mCameraGestureTriggeredDuringGoingToSleep);
}
mCameraGestureTriggeredDuringGoingToSleep = false;
}
接着调用KeyguardServiceDelegate的onFinishedGoingToSleep()方法
KeyguardServiceDelegate.java
public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
if (mKeyguardService != null) {
mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
}
mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
}
KeyguardService.java
@Override // Binder interface
public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
checkPermission();
mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);
mKeyguardLifecyclesDispatcher.dispatch(
KeyguardLifecyclesDispatcher.FINISHED_GOING_TO_SLEEP);
}
最终调用到我们所熟悉的KeyguardViewMediator.java中
KeyguardViewMediator.java
public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")");
synchronized (this) {
...
resetKeyguardDonePendingLocked();
//如果灭屏之前Bouncer正在显示则需要通知其进入onPause状态
notifyFinishedGoingToSleep();
//cameraGestureTriggered为true代表不会显示锁屏,而是启动camera
if (cameraGestureTriggered) {
Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking.");
// Just to make sure, make sure the device is awake.
mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
"com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
mPendingLock = false;
mPendingReset = false;
}
if (mPendingReset) {
resetStateLocked();
mPendingReset = false;
}
if (mPendingLock) {
doKeyguardLocked(null);
mPendingLock = false;
}
}
如果cameraGestureTriggered为false,则会调用resetStateLocked()和doKeyguardLocked(null)方法,而这两个方法最终都是通过StatusBarKeyguardViewManager的reset()方法进行锁屏。二者的区别是,resetStateLocked()因为已经在锁屏界面,不需要AMS、WMS修改锁屏窗口相关参数和Activity相关状态;doKeyguardLocked(null)会对是否显示进行一系列的条件判断,都验证通过才会show,比如第三方应用是否禁用了锁屏、是否在setup wizard界面等。
分析到doKeyguardLocked(null)方法后,接下来的流程就跟上述的锁屏界面显示流程一致。