Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 991edb76 authored by Arthur Hung's avatar Arthur Hung Committed by Android (Google) Code Review
Browse files

Merge "Introduce SingleKeyGestureDetector to PhoneWindowManager" into sc-dev

parents 52e885a6 29f27e8d
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -102,9 +102,11 @@ public class KeyCombinationManager {
    }

    /**
     * Check if the key event could be triggered by combine key rule before dispatching to a window.
     * Check if the key event could be intercepted by combination key rule before it is dispatched
     * to a window.
     * Return true if any active rule could be triggered by the key event, otherwise false.
     */
    void interceptKey(KeyEvent event, boolean interactive) {
    boolean interceptKey(KeyEvent event, boolean interactive) {
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
        final int keyCode = event.getKeyCode();
        final int count = mActiveRules.size();
@@ -117,9 +119,9 @@ public class KeyCombinationManager {
                    // exceed time from first key down.
                    forAllRules(mActiveRules, (rule)-> rule.cancel());
                    mActiveRules.clear();
                    return;
                    return false;
                } else if (count == 0) { // has some key down but no active rule exist.
                    return;
                    return false;
                }
            }

@@ -127,7 +129,7 @@ public class KeyCombinationManager {
                mDownTimes.put(keyCode, eventTime);
            } else {
                // ignore old key, maybe a repeat key.
                return;
                return false;
            }

            if (mDownTimes.size() == 1) {
@@ -141,7 +143,7 @@ public class KeyCombinationManager {
            } else {
                // Ignore if rule already triggered.
                if (mTriggeredRule != null) {
                    return;
                    return true;
                }

                // check if second key can trigger rule, or remove the non-match rule.
@@ -156,6 +158,7 @@ public class KeyCombinationManager {
                mActiveRules.clear();
                if (mTriggeredRule != null) {
                    mActiveRules.add(mTriggeredRule);
                    return true;
                }
            }
        } else {
@@ -168,6 +171,7 @@ public class KeyCombinationManager {
                }
            }
        }
        return false;
    }

    /**
+163 −186
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;

import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -456,7 +458,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    volatile boolean mPowerKeyHandled;
    volatile boolean mBackKeyHandled;
    volatile boolean mBeganFromNonInteractive;
    volatile int mPowerKeyPressCounter;
    volatile boolean mEndCallKeyHandled;
    volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
    volatile boolean mGoingToSleep;
@@ -497,7 +498,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    boolean mHasSoftInput = false;
    boolean mHapticTextHandleEnabled;
    boolean mUseTvRouting;
    int mVeryLongPressTimeout;
    boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
    MetricsLogger mLogger;
    boolean mWakeOnDpadKeyPress;
@@ -597,14 +597,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
            = new LogDecelerateInterpolator(100, 0);

    private final MutableBoolean mTmpBoolean = new MutableBoolean(false);

    private boolean mPerDisplayFocusEnabled = false;
    private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;

    private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;

    private KeyCombinationManager mKeyCombinationManager;
    private SingleKeyGestureDetector mSingleKeyGestureDetector;

    private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
    private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
@@ -615,10 +614,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
    private static final int MSG_HIDE_BOOT_MESSAGE = 11;
    private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
    private static final int MSG_POWER_DELAYED_PRESS = 13;
    private static final int MSG_POWER_LONG_PRESS = 14;
    private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
    private static final int MSG_BACK_LONG_PRESS = 16;
    private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
    private static final int MSG_BUGREPORT_TV = 18;
    private static final int MSG_ACCESSIBILITY_TV = 19;
@@ -626,8 +622,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_SYSTEM_KEY_PRESS = 21;
    private static final int MSG_HANDLE_ALL_APPS = 22;
    private static final int MSG_LAUNCH_ASSIST = 23;
    private static final int MSG_POWER_VERY_LONG_PRESS = 25;
    private static final int MSG_RINGER_TOGGLE_CHORD = 26;
    private static final int MSG_RINGER_TOGGLE_CHORD = 24;

    private class PolicyHandler extends Handler {
        @Override
@@ -668,22 +663,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
                    launchVoiceAssistWithWakeLock();
                    break;
                case MSG_POWER_DELAYED_PRESS:
                    powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
                    finishPowerKeyPress();
                    break;
                case MSG_POWER_LONG_PRESS:
                    powerLongPress((Long) msg.obj /* eventTime */);
                    break;
                case MSG_POWER_VERY_LONG_PRESS:
                    powerVeryLongPress();
                    break;
                case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
                    showPictureInPictureMenuInternal();
                    break;
                case MSG_BACK_LONG_PRESS:
                    backLongPress();
                    break;
                case MSG_ACCESSIBILITY_SHORTCUT:
                    accessibilityShortcutActivated();
                    break;
@@ -794,13 +776,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    };

    private Runnable mPossibleVeryLongPressReboot = new Runnable() {
        @Override
        public void run() {
            mActivityManagerInternal.prepareForPossibleShutdown();
        }
    };

    private void handleRingerChordGesture() {
        if (mRingerToggleChord == VOLUME_HUSH_OFF) {
            return;
@@ -840,28 +815,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    private void interceptBackKeyDown() {
        mLogger.count("key_back_down", 1);
        // Reset back key state for long press
        mBackKeyHandled = false;

        if (hasLongPressOnBackBehavior()) {
            Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
            msg.setAsynchronous(true);
            mHandler.sendMessageDelayed(msg,
                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
        }
    }

    // returns true if the key was handled and should not be passed to the user
    private boolean interceptBackKeyUp(KeyEvent event) {
        mLogger.count("key_back_up", 1);
    private boolean backKeyPress() {
        mLogger.count("key_back_press", 1);
        // Cache handled state
        boolean handled = mBackKeyHandled;

        // Reset back long press state
        cancelPendingBackKeyAction();

        if (mHasFeatureWatch) {
            TelecomManager telecomManager = getTelecommService();

@@ -883,10 +843,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }

        if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        if (mAutofillManagerInternal != null) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL));
        }

        return handled;
    }

@@ -896,11 +855,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            mPowerKeyWakeLock.acquire();
        }

        // Cancel multi-press detection timeout.
        if (mPowerKeyPressCounter != 0) {
            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
        }

        mWindowManagerFuncs.onPowerKeyDown(interactive);

        // Stop ringing or end call if configured to do so when power is pressed.
@@ -922,71 +876,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {

        final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);

        GestureLauncherService gestureService = LocalServices.getService(
                GestureLauncherService.class);
        boolean gesturedServiceIntercepted = false;
        if (gestureService != null) {
            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
                    mTmpBoolean);
            if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
                mCameraGestureTriggeredDuringGoingToSleep = true;
            }
        }

        // Inform the StatusBar; but do not allow it to consume the event.
        sendSystemKeyToStatusBarAsync(event.getKeyCode());

        schedulePossibleVeryLongPressReboot();

        // If the power key has still not yet been handled, then detect short
        // press, long press, or multi press and decide what to do.
        mPowerKeyHandled = hungUp || gesturedServiceIntercepted
        mPowerKeyHandled = mPowerKeyHandled || hungUp
                || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
        if (!mPowerKeyHandled) {
            if (interactive) {
                // When interactive, we're already awake.
                // Wait for a long press or for the button to be released to decide what to do.
                if (hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress(event.getEventTime());
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
                                event.getEventTime());
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }
                }
            } else {
            if (!interactive) {
                wakeUpFromPowerKey(event.getDownTime());

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress(event.getEventTime());
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
                                event.getEventTime());
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }

                    mBeganFromNonInteractive = true;
                } else {
                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
                        mPowerKeyHandled = true;
                    } else {
@@ -994,68 +897,38 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    }
                }
            }
        } else {
            // handled by another power key policy.
            if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
                mSingleKeyGestureDetector.reset();
            }
        }
    }

    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
        final boolean handled = canceled || mPowerKeyHandled;
        cancelPendingPowerKeyAction();

        if (!handled) {
            if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
                // Abort possibly stuck animations only when power key up without long press case.
                mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
            }

            // Figure out how to handle the key now that it has been released.
            mPowerKeyPressCounter += 1;

            final int maxCount = getMaxMultiPressPowerCount();
            final long eventTime = event.getDownTime();
            if (mPowerKeyPressCounter < maxCount) {
                // This could be a multi-press.  Wait a little bit longer to confirm.
                // Continue holding the wake lock.
                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
                msg.setAsynchronous(true);
                mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
                return;
            }

            // No other actions.  Handle it immediately.
            powerPress(eventTime, interactive, mPowerKeyPressCounter);
        } else {
            // handled by single key or another power key policy.
            mSingleKeyGestureDetector.reset();
            finishPowerKeyPress();
        }

        // Done.  Reset our state.
        finishPowerKeyPress();
    }

    private void finishPowerKeyPress() {
        mBeganFromNonInteractive = false;
        mPowerKeyPressCounter = 0;
        mPowerKeyHandled = false;
        if (mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.release();
        }
    }

    private void cancelPendingPowerKeyAction() {
        if (!mPowerKeyHandled) {
            mPowerKeyHandled = true;
            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
        }
        if (hasVeryLongPressOnPowerBehavior()) {
            mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
        }
        cancelPossibleVeryLongPressReboot();
    }

    private void cancelPendingBackKeyAction() {
        if (!mBackKeyHandled) {
            mBackKeyHandled = true;
            mHandler.removeMessages(MSG_BACK_LONG_PRESS);
        }
    }

    private void powerPress(long eventTime, boolean interactive, int count) {
        if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {
            Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1206,6 +1079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    private void powerLongPress(long eventTime) {
        final int behavior = getResolvedLongPressOnPowerBehavior();

        switch (behavior) {
            case LONG_PRESS_POWER_NOTHING:
                break;
@@ -1844,8 +1718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                com.android.internal.R.integer.config_triplePressOnPowerBehavior);
        mShortPressOnSleepBehavior = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_shortPressOnSleepBehavior);
        mVeryLongPressTimeout = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_veryLongPressTimeout);
        mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);

@@ -1939,6 +1811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    }
                });
        initKeyCombinationRules();
        initSingleKeyGestureRules();
    }

    private void initKeyCombinationRules() {
@@ -1951,7 +1824,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
                        @Override
                        void execute() {
                            cancelPendingPowerKeyAction();
                            mPowerKeyHandled = true;
                            interceptScreenshotChord();
                        }
                        @Override
@@ -1986,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    }
                    @Override
                    void execute() {
                        cancelPendingPowerKeyAction();
                        mPowerKeyHandled = true;
                        interceptRingerToggleChord();
                    }
                    @Override
@@ -2000,7 +1873,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) {
                        @Override
                        void execute() {
                            cancelPendingBackKeyAction();
                            mBackKeyHandled = true;
                            interceptAccessibilityGestureTv();
                        }

@@ -2014,7 +1887,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) {
                        @Override
                        void execute() {
                            cancelPendingBackKeyAction();
                            mBackKeyHandled = true;
                            interceptBugreportGestureTv();
                        }

@@ -2026,6 +1899,84 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    /**
     * Rule for single power key gesture.
     */
    private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
        PowerKeyRule(int gestures) {
            super(KEYCODE_POWER, gestures);
        }

        @Override
        int getMaxMultiPressCount() {
            return getMaxMultiPressPowerCount();
        }

        @Override
        void onPress(long downTime) {
            powerPress(downTime, true, 1 /*count*/);
            finishPowerKeyPress();
        }

        @Override
        void onLongPress(long downTime) {
            powerLongPress(downTime);
        }

        @Override
        void onVeryLongPress(long downTime) {
            mActivityManagerInternal.prepareForPossibleShutdown();
            powerVeryLongPress();
        }

        @Override
        void onMultiPress(long downTime, int count) {
            powerPress(downTime, true, count);
            finishPowerKeyPress();
        }
    }

    /**
     * Rule for single back key gesture.
     */
    private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
        BackKeyRule(int gestures) {
            super(KEYCODE_BACK, gestures);
        }

        @Override
        int getMaxMultiPressCount() {
            return 1;
        }

        @Override
        void onPress(long downTime) {
            mBackKeyHandled |= backKeyPress();
        }

        @Override
        void onLongPress(long downTime) {
            backLongPress();
        }
    }

    private void initSingleKeyGestureRules() {
        mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);

        int powerKeyGestures = 0;
        if (hasVeryLongPressOnPowerBehavior()) {
            powerKeyGestures |= KEY_VERYLONGPRESS;
        }
        if (hasLongPressOnPowerBehavior()) {
            powerKeyGestures |= KEY_LONGPRESS;
        }
        mSingleKeyGestureDetector.addRule(new PowerKeyRule(powerKeyGestures));

        if (hasLongPressOnBackBehavior()) {
            mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS));
        }
    }

    /**
     * Read values from config.xml that may be overridden depending on
     * the configuration of the device.
@@ -3550,8 +3501,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return result;
        }

        // Alternate TV power to power key for Android TV device.
        final HdmiControlManager hdmiControlManager = getHdmiControlManager();
        if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
                && (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
            event = KeyEvent.obtain(
                    event.getDownTime(), event.getEventTime(),
                    event.getAction(), KeyEvent.KEYCODE_POWER,
                    event.getRepeatCount(), event.getMetaState(),
                    event.getDeviceId(), event.getScanCode(),
                    event.getFlags(), event.getSource(), event.getDisplayId(), null);
            return interceptKeyBeforeQueueing(event, policyFlags);
        }

        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            mKeyCombinationManager.interceptKey(event, interactive);
            handleKeyGesture(event, interactive);
        }

        // Enable haptics if down and virtual key without multiple repetitions. If this is a hard
@@ -3566,12 +3530,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK: {
                if (down) {
                    interceptBackKeyDown();
                    mBackKeyHandled = false;
                } else {
                    boolean handled = interceptBackKeyUp(event);

                    if (!hasLongPressOnBackBehavior()) {
                        mBackKeyHandled |= backKeyPress();
                    }
                    // Don't pass back press to app if we've already handled it via long press
                    if (handled) {
                    if (mBackKeyHandled) {
                        result &= ~ACTION_PASS_TO_USER;
                    }
                }
@@ -3683,33 +3648,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            case KeyEvent.KEYCODE_TV_POWER: {
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                HdmiControlManager hdmiControlManager = getHdmiControlManager();
                if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) {
                    if (down) {
                if (down && hdmiControlManager != null) {
                    hdmiControlManager.toggleAndFollowTvPower();
                }
                } else if (mHasFeatureLeanback) {
                    KeyEvent fallbackEvent = KeyEvent.obtain(
                            event.getDownTime(), event.getEventTime(),
                            event.getAction(), KeyEvent.KEYCODE_POWER,
                            event.getRepeatCount(), event.getMetaState(),
                            event.getDeviceId(), event.getScanCode(),
                            event.getFlags(), event.getSource(), event.getDisplayId(), null);
                    if (down) {
                        interceptPowerKeyDown(fallbackEvent, interactive);
                    } else {
                        interceptPowerKeyUp(fallbackEvent, interactive, canceled);
                    }
                }
                // Ignore this key for any device that is not connected to a TV via HDMI and
                // not an Android TV device.
                break;
            }

            case KeyEvent.KEYCODE_POWER: {
                EventLogTags.writeInterceptPower(
                        KeyEvent.actionToString(event.getAction()),
                        mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
                        mPowerKeyHandled ? 1 : 0,
                        mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
                // Any activity on the power button stops the accessibility shortcut
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
@@ -3890,6 +3839,43 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        return result;
    }

    private void handleKeyGesture(KeyEvent event, boolean interactive) {
        if (mKeyCombinationManager.interceptKey(event, interactive)) {
            // handled by combo keys manager.
            mSingleKeyGestureDetector.reset();
            return;
        }

        if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
            mPowerKeyHandled = handleCameraGesture(event, interactive);
            if (mPowerKeyHandled) {
                // handled by camera gesture.
                mSingleKeyGestureDetector.reset();
                return;
            }
        }

        mSingleKeyGestureDetector.interceptKey(event);
    }

    // The camera gesture will be detected by GestureLauncherService.
    private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
        // camera gesture.
        GestureLauncherService gestureService = LocalServices.getService(
                GestureLauncherService.class);
        if (gestureService == null) {
            return false;
        }

        final MutableBoolean outLaunched = new MutableBoolean(false);
        final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
                interactive, outLaunched);
        if (outLaunched.value && mRequestedOrGoingToSleep) {
            mCameraGestureTriggeredDuringGoingToSleep = true;
        }
        return gesturedServiceIntercepted;
    }

    /**
     * Handle statusbar expansion events.
     * @param event
@@ -4889,15 +4875,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    private void schedulePossibleVeryLongPressReboot() {
        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
        mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
    }

    private void cancelPossibleVeryLongPressReboot() {
        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
    }

    // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
    private void updateScreenOffSleepToken(boolean acquire) {
        if (acquire) {