为了实现组合键启动app的功能,参考了Android中截屏事件的处理流程,实现同时按下Power+音量增键启动电阻屏校准App的功能,下面是Android 代码中关于截屏按键部分的处理代码简要分析:
安卓5.0代码中,同时按住power键和音量-键一会可触发截屏事件
PhoneWindowManager.java (base\policy\src\com\android\internal\policy\impl)
public int interceptKeyBeforeQueueing(KeyEvent event, int 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();
}
} else {//key up
mScreenshotChordVolumeDownKeyTriggered = false;
cancelPendingScreenshotChordAction();
}
}
...
}
break;
}
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
return result;
}
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// 如果电源键是初次按下,记录时间,记录按键按下
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
}
}
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
mScreenshotChordPowerKeyTriggered = false;
}
private void interceptScreenshotChord() {
//如果电源键和音量- 键都被标记为按下状态
if (mScreenshotChordEnabled
&& mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
&& !mScreenshotChordVolumeUpKeyTriggered) {
final long now = SystemClock.uptimeMillis();
//第一个键按下150ms内,另一个键按下,被认为是同时按下,触发截屏操作
if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
&& now <= mScreenshotChordPowerKeyTime
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
//标志着截屏事件触发
mScreenshotChordVolumeDownKeyConsumed = true;
cancelPendingPowerKeyAction();
//发送广播给截屏组件
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}
}
}
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
//如果只按下了音量- 没有按下电源键且没有超过150ms,直接返回,不分发音量-事件
if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
final long now = SystemClock.uptimeMillis();
final long timeoutTime = mScreenshotChordVolumeDownKeyTime
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
if (now < timeoutTime) {
return timeoutTime - now;
}
}
//如果截屏事件触发且按键抬起,把截屏事件标记为未触发状态
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
&& mScreenshotChordVolumeDownKeyConsumed) {
if (!down) {
mScreenshotChordVolumeDownKeyConsumed = false;
}
//直接返回
return -1;
}
}
}
为何长按power和音量- 很长时间也只会触发一次截屏事件?
截屏事件触发一次后事假触发状态被设置为未触发,由于按键都没有抬起,因此记录的按键按下时间早已超过设定的150ms,因此不会再次触发?
那么 150 Ms 就有可能重复触发,还有条件保护?
interceptScreenshotChord 这个函数进入的条件为,Power键或者音量- 键首次按下,想再次进去的话得抬起,再按一次才行~