前言
涉及到的源码有
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\screenshot\TakeScreenshotService.java
vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\screenshot\GlobalScreenshot.java
按键处理都是在 PhoneWindowManager 中,真正截屏的功能实现在 GlobalScreenshot 中, PhoneWindowManager 和 systemui 通过 bind TakeScreenshotService 来实现截屏功能
流程
一般未经过特殊定制的 Android 系统,截屏都是通过同时按住音量下键和电源键来截屏,后来我们使用的一些华为、oppo等厂商的系统你会发现可以通过三指滑动来截屏,下一篇我们会定制此功能,而且截屏显示风格类似 iphone 在左下角显示截屏缩略图,点击可跳转放大查看,3s 无操作后向左自动滑动消失。
好了,现在我们先来理一下系统截屏的流程
system_process D/WindowManager: interceptKeyTi keyCode=25 down=true repeatCount=0 keyguardOn=false mHomePressed=false canceled=false metaState:0
system_process D/WindowManager: interceptKeyTq keycode=25 interactive=true keyguardActive=false policyFlags=22000000 down =false canceled = false isWakeKey=false mVolumeDownKeyTriggered =true result = 1 useHapticFeedback = false isInjected = false
system_process D/WindowManager: interceptKeyTi keyCode=25 down=false repeatCount=0 keyguardOn=false mHomePressed=false canceled=false metaState:0
system_process D/WindowManager: interceptKeyTq keycode=26 interactive=true keyguardActive=false policyFlags=22000000 down =false canceled = false isWakeKey=false mVolumeDownKeyTriggered =false result = 1 useHapticFeedback = false isInjected = false
上面是按下音量下键和电源键的日志,音量下键对应 keyCode=25 ,电源键对应 keyCode=26,来看到 PhoneWindowManager 中的 interceptKeyBeforeQueueing() 方法,在此处处理按键操作
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
.....
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " interactive=" + interactive + " keyguardActive=" + keyguardActive
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
.....
// Handle special keys.
switch (keyCode) {
.......
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordVolumeDownKeyTriggered = true;
mScreenshotChordVolumeDownKeyTime = event.getDownTime();
mScreenshotChordVolumeDownKeyConsumed = false;
cancelPendingPowerKeyAction();
interceptScreenshotChord();
interceptAccessibilityShortcutChord();
}
} else {
mScreenshotChordVolumeDownKeyTriggered = false;
cancelPendingScreenshotChordAction();
cancelPendingAccessibilityShortcutAction();
}
}
....
}
看到 KEYCODE_VOLUME_DOWN 中,记录当前按下音量下键的时间 mScreenshotChordVolumeDownKeyTime,cancelPendingPowerKeyAction() 移除电源键长按消息 MSG_POWER_LONG_PRESS,来看下核心方法 interceptScreenshotChord()
// Time to volume and power must be pressed within this interval of each other.
private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
private void interceptScreenshotChord() {
if (mScreenshotChordEnabled
&& mScreenshotChordVolumeDownKeyTriggered && mScreensho