Android 5.1 截屏事件分析(Power + VolumeDown)组合键分析

来源:互联网 发布:买家可以开通淘宝客码 编辑:程序博客网 时间:2024/06/09 16:48

    为了实现组合键启动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键或者音量- 键首次按下,想再次进去的话得抬起,再按一次才行~
原创粉丝点击