今天看源码的时候看到一个使用power键和音量下键来组合实现屏幕截图的功能,还挺有趣的,之前一直都不知道。。。
废话不多说,直接看过程吧
在android中由WindowManagerService这个系统服务来循环读取窗口获取的消息(包括按下,弹起,双击,单击等)然后分发到各个类接收,在这个过程中有一个类会进行消息过滤处理,就是PhoneWindowManager了,PhoneWindowManager中有两个方法interceptKeyBeforeDispatching和interceptKeyBeforeQueueing,其中包括了几乎所有按键的处理,interceptKeyBeforeDispatching主要处理Home键、Menu键、Search键等,
interceptKeyBeforeQueueing主要处理音量键、电源键、耳机键等。
截屏功能的代码就是在interceptKeyBeforeQueueing方法中,看两段代码
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
if (isScreenOn && !mVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeDownKeyTriggered = true;
mVolumeDownKeyTime = event.getDownTime();
mVolumeDownKeyConsumedByScreenshotChord = false;
cancelPendingPowerKeyAction();
interceptScreenshotChord();
}
} else {
mVolumeDownKeyTriggered = false;
cancelPendingScreenshotChordAction();
}
......
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
if (isScreenOn && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
mPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
}
......
可以看到正是这里(响应down事件)捕获是否按了音量下键和电源键,而且两个地方都会进入函数interceptScreenshotChord()中,接下来看看这个函数做了什么操作:
private void interceptScreenshotChord() {
if (mVolumeDownKeyTriggered && mPowerKeyTriggered
&& !mVolumeUpKeyTriggered) {
final long now = SystemClock.uptimeMillis();
if (now <= mVolumeDownKeyTime +
SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
&& now <= mPowerKeyTime +
SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mVolumeDownKeyConsumedByScreenshotChord = true;
cancelPendingPowerKeyAction();
mHandler.postDelayed(mScreenshotChordLongPress,
ViewConfiguration.getGlobalActionKeyTimeout());
}
}
}
在这个函数中,用两个布尔变量判断是否同时按了音量下键和电源键后,再计算两个按键响应Down事件之间的时间差不超过150毫秒,也就认为是同时按了这两个键后,算是真正的捕获到屏幕截屏的组合键。
调用函数interceptScreenshotChord,
private void interceptScreenshotChord() {
if (mScreenshotChordEnabled
&& mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {
final long now = SystemClock.uptimeMillis();
if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
&& now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mVolumeDownKeyConsumedByScreenshotChord = true;
cancelPendingPowerKeyAction();
mHandler.postDelayed(mScreenshotChordLongPress, getScreenshotChordLongPressDelay());
}
}
}
发送消息mScreenshotChordLongPress到消息队列里面,点进去可以看到
private final Runnable mScreenshotChordLongPress = new Runnable() {
public void run() {
takeScreenshot();
}
};
这个takeScreenshot一看就知道是实现截图功能的函数了,在takeScreenshot里面主要是绑定一个TakeScreenshotService的服务,还有一些返回的消息处理,再往下就是涉及到JNI调用底层服务的东西,在这就不作介绍了,也没仔细研究过 :oops: :oops: