diff options
author | Jeff Brown <jeffbrown@google.com> | 2014-11-01 14:10:50 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-11-01 14:10:50 +0000 |
commit | a71601a98c7f37004e1b86757cdbf552564a2e8c (patch) | |
tree | 3cd9e39d32d267659dc69c6801a496617af26b02 /policy/src | |
parent | 0ed053ef537daa11659e70c91974cded7c9bddc6 (diff) | |
parent | 13f00f07d69f087cf186c23ae6c6fc938e2be561 (diff) | |
download | frameworks_base-a71601a98c7f37004e1b86757cdbf552564a2e8c.zip frameworks_base-a71601a98c7f37004e1b86757cdbf552564a2e8c.tar.gz frameworks_base-a71601a98c7f37004e1b86757cdbf552564a2e8c.tar.bz2 |
am 13f00f07: Implement multi-press behavior for power key.
* commit '13f00f07d69f087cf186c23ae6c6fc938e2be561':
Implement multi-press behavior for power key.
Diffstat (limited to 'policy/src')
-rw-r--r-- | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 510 |
1 files changed, 348 insertions, 162 deletions
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index d418ffb..1195ac8 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -159,6 +159,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int LONG_PRESS_POWER_SHUT_OFF = 2; static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; + static final int MULTI_PRESS_POWER_NOTHING = 0; + static final int MULTI_PRESS_POWER_THEATER_MODE = 1; + static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2; + // These need to match the documentation/constant in // core/res/res/values/config.xml static final int LONG_PRESS_HOME_NOTHING = 0; @@ -301,12 +305,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { }; GlobalActions mGlobalActions; - volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread - boolean mPendingPowerKeyUpCanceled; Handler mHandler; WindowState mLastInputMethodWindow = null; WindowState mLastInputMethodTargetWindow = null; + // FIXME This state is shared between the input reader and handler thread. + // Technically it's broken and buggy but it has been like this for many years + // and we have not yet seen any problems. Someday we'll rewrite this logic + // so that only one thread is involved in handling input policy. Unfortunately + // it's on a critical path for power management so we can't just post the work to the + // handler thread. We'll need to resolve this someday by teaching the input dispatcher + // to hold wakelocks during dispatch and eliminating the critical path. + volatile boolean mPowerKeyHandled; + volatile int mPowerKeyPressCounter; + volatile boolean mEndCallKeyHandled; + boolean mRecentsVisible; int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; @@ -346,8 +359,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidKeyboardAccessibility; int mLidNavigationAccessibility; boolean mLidControlsSleep; - int mShortPressOnPowerBehavior = -1; - int mLongPressOnPowerBehavior = -1; + int mShortPressOnPowerBehavior; + int mLongPressOnPowerBehavior; + int mDoublePressOnPowerBehavior; + int mTriplePressOnPowerBehavior; boolean mAwake; boolean mScreenOnEarly; boolean mScreenOnFully; @@ -518,12 +533,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Increase the chord delay when taking a screenshot from the keyguard private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f; private boolean mScreenshotChordEnabled; - private boolean mVolumeDownKeyTriggered; - private long mVolumeDownKeyTime; - private boolean mVolumeDownKeyConsumedByScreenshotChord; - private boolean mVolumeUpKeyTriggered; - private boolean mPowerKeyTriggered; - private long mPowerKeyTime; + private boolean mScreenshotChordVolumeDownKeyTriggered; + private long mScreenshotChordVolumeDownKeyTime; + private boolean mScreenshotChordVolumeDownKeyConsumed; + private boolean mScreenshotChordVolumeUpKeyTriggered; + private boolean mScreenshotChordPowerKeyTriggered; + private long mScreenshotChordPowerKeyTime; /* The number of steps between min and max brightness */ private static final int BRIGHTNESS_STEPS = 10; @@ -531,6 +546,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { SettingsObserver mSettingsObserver; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; + PowerManager.WakeLock mPowerKeyWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; private int mCurrentUserId; @@ -556,6 +572,8 @@ 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 class PolicyHandler extends Handler { @Override @@ -597,6 +615,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK: launchVoiceAssistWithWakeLock(msg.arg1 != 0); break; + case MSG_POWER_DELAYED_PRESS: + powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2); + finishPowerKeyPress(); + break; + case MSG_POWER_LONG_PRESS: + powerLongPress(); + break; } } } @@ -790,38 +815,239 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void interceptPowerKeyDown(boolean handled) { - mPowerKeyHandled = handled; + private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { + // Hold a wake lock until the power key is released. + if (!mPowerKeyWakeLock.isHeld()) { + mPowerKeyWakeLock.acquire(); + } + + // Cancel multi-press detection timeout. + if (mPowerKeyPressCounter != 0) { + mHandler.removeMessages(MSG_POWER_DELAYED_PRESS); + } + + // Detect user pressing the power button in panic when an application has + // taken over the whole screen. + boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, + event.getDownTime(), isImmersiveMode(mLastSystemUiFlags)); + if (panic) { + mHandler.post(mRequestTransientNav); + } + + // Latch power key state to detect screenshot chord. + if (interactive && !mScreenshotChordPowerKeyTriggered + && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + mScreenshotChordPowerKeyTriggered = true; + mScreenshotChordPowerKeyTime = event.getDownTime(); + interceptScreenshotChord(); + } + + // Stop ringing or end call if configured to do so when power is pressed. + TelecomManager telecomManager = getTelecommService(); + boolean hungUp = false; + if (telecomManager != null) { + if (telecomManager.isRinging()) { + // Pressing Power while there's a ringing incoming + // call should silence the ringer. + telecomManager.silenceRinger(); + } else if ((mIncallPowerBehavior + & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 + && telecomManager.isInCall() && interactive) { + // Otherwise, if "Power button ends call" is enabled, + // the Power button will hang up any current active call. + hungUp = telecomManager.endCall(); + } + } + + // 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 || mScreenshotChordVolumeDownKeyTriggered + || mScreenshotChordVolumeUpKeyTriggered; + 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()) { + Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + } + } else { + // When non-interactive, we ordinarily wake up immediately and + // consume the key. However on some devices we need to support multi-press + // without waking so we will delay handling for later in that case + // (at the cost of increased latency). + final int maxCount = getMaxMultiPressPowerCount(); + if (maxCount <= 1) { + // No other actions. We can wake immediately. + wakeUpFromPowerKey(event.getDownTime()); + mPowerKeyHandled = true; + } + } + } + } + + private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) { + final boolean handled = canceled || mPowerKeyHandled; + mScreenshotChordPowerKeyTriggered = false; + cancelPendingScreenshotChordAction(); + cancelPendingPowerKeyAction(); + if (!handled) { - mHandler.postDelayed(mPowerLongPress, - ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + // 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.getDoubleTapTimeout()); + return; + } + + // No other actions. Handle it immediately. + powerPress(eventTime, interactive, mPowerKeyPressCounter); } + + // Done. Reset our state. + finishPowerKeyPress(); } - private boolean interceptPowerKeyUp(boolean canceled) { - if (!mPowerKeyHandled) { - mHandler.removeCallbacks(mPowerLongPress); - return !canceled; + private void finishPowerKeyPress() { + mPowerKeyPressCounter = 0; + if (mPowerKeyWakeLock.isHeld()) { + mPowerKeyWakeLock.release(); } - return false; } private void cancelPendingPowerKeyAction() { if (!mPowerKeyHandled) { - mHandler.removeCallbacks(mPowerLongPress); + mPowerKeyHandled = true; + mHandler.removeMessages(MSG_POWER_LONG_PRESS); } - if (mPowerKeyTriggered) { - mPendingPowerKeyUpCanceled = true; + } + + private void powerPress(long eventTime, boolean interactive, int count) { + if (mScreenOnEarly && !mScreenOnFully) { + Slog.i(TAG, "Suppressed redundant power key press while " + + "already in the process of turning the screen on."); + return; + } + + if (count == 2) { + powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); + } else if (count == 3) { + powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); + } else if (!interactive) { + wakeUpFromPowerKey(eventTime); + } else { + switch (mShortPressOnPowerBehavior) { + case SHORT_PRESS_POWER_NOTHING: + break; + case SHORT_PRESS_POWER_GO_TO_SLEEP: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + break; + case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + break; + case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + launchHomeFromHotKey(); + break; + } } } + private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) { + switch (behavior) { + case MULTI_PRESS_POWER_NOTHING: + break; + case MULTI_PRESS_POWER_THEATER_MODE: + if (isTheaterModeEnabled()) { + Slog.i(TAG, "Toggling theater mode off."); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0); + if (!interactive) { + wakeUpFromPowerKey(eventTime); + } + } else { + Slog.i(TAG, "Toggling theater mode on."); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 1); + if (interactive) { + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + } + } + break; + case MULTI_PRESS_POWER_BRIGHTNESS_BOOST: + mPowerManager.boostScreenBrightness(eventTime); + break; + } + } + + private int getMaxMultiPressPowerCount() { + if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { + return 3; + } + if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { + return 2; + } + return 1; + } + + private void powerLongPress() { + final int behavior = getResolvedLongPressOnPowerBehavior(); + switch (behavior) { + case LONG_PRESS_POWER_NOTHING: + break; + case LONG_PRESS_POWER_GLOBAL_ACTIONS: + mPowerKeyHandled = true; + if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { + performAuditoryFeedbackForAccessibilityIfNeed(); + } + showGlobalActionsInternal(); + break; + case LONG_PRESS_POWER_SHUT_OFF: + case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: + mPowerKeyHandled = true; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF); + break; + } + } + + private int getResolvedLongPressOnPowerBehavior() { + if (FactoryTest.isLongPressOnPowerOffEnabled()) { + return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; + } + return mLongPressOnPowerBehavior; + } + + private boolean hasLongPressOnPowerBehavior() { + return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING; + } + private void interceptScreenshotChord() { if (mScreenshotChordEnabled - && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { + && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered + && !mScreenshotChordVolumeUpKeyTriggered) { final long now = SystemClock.uptimeMillis(); - if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS - && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { - mVolumeDownKeyConsumedByScreenshotChord = true; + if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS + && now <= mScreenshotChordPowerKeyTime + + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { + mScreenshotChordVolumeDownKeyConsumed = true; cancelPendingPowerKeyAction(); mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay()); @@ -842,64 +1068,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.removeCallbacks(mScreenshotRunnable); } - private void powerShortPress(long eventTime) { - if (mShortPressOnPowerBehavior < 0) { - mShortPressOnPowerBehavior = mContext.getResources().getInteger( - com.android.internal.R.integer.config_shortPressOnPowerBehavior); - } - - switch (mShortPressOnPowerBehavior) { - case SHORT_PRESS_POWER_NOTHING: - break; - case SHORT_PRESS_POWER_GO_TO_SLEEP: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); - break; - case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, - PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - break; - case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, - PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - launchHomeFromHotKey(); - break; - } - } - - private final Runnable mPowerLongPress = new Runnable() { + private final Runnable mEndCallLongPress = new Runnable() { @Override public void run() { - // The context isn't read - if (mLongPressOnPowerBehavior < 0) { - mLongPressOnPowerBehavior = mContext.getResources().getInteger( - com.android.internal.R.integer.config_longPressOnPowerBehavior); - } - int resolvedBehavior = mLongPressOnPowerBehavior; - if (FactoryTest.isLongPressOnPowerOffEnabled()) { - resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; - } - - switch (resolvedBehavior) { - case LONG_PRESS_POWER_NOTHING: - break; - case LONG_PRESS_POWER_GLOBAL_ACTIONS: - mPowerKeyHandled = true; - if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { - performAuditoryFeedbackForAccessibilityIfNeed(); - } - showGlobalActionsInternal(); - break; - case LONG_PRESS_POWER_SHUT_OFF: - case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: - mPowerKeyHandled = true; - performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF); - break; + mEndCallKeyHandled = true; + if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { + performAuditoryFeedbackForAccessibilityIfNeed(); } + showGlobalActionsInternal(); } }; @@ -940,6 +1116,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; } + private void handleShortPressOnHome() { + // If there's a dream running then use home to escape the dream + // but don't actually go home. + if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { + mDreamManagerInternal.stopDream(false /*immediate*/); + return; + } + + // Go home! + launchHomeFromHotKey(); + } + private void handleLongPressOnHome() { if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { mHomeConsumed = true; @@ -965,7 +1153,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void run() { if (mHomeDoubleTapPending) { mHomeDoubleTapPending = false; - launchHomeFromHotKey(); + handleShortPressOnHome(); } } }; @@ -1008,6 +1196,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); + mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "PhoneWindowManager.mPowerKeyWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mSupportAutoRotation = mContext.getResources().getBoolean( com.android.internal.R.bool.config_supportAutoRotation); @@ -1046,6 +1236,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture); + mShortPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_shortPressOnPowerBehavior); + mLongPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior); + mDoublePressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_doublePressOnPowerBehavior); + mTriplePressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_triplePressOnPowerBehavior); + readConfigurationDependentBehaviors(); mAccessibilityManager = (AccessibilityManager) context.getSystemService( @@ -2189,17 +2388,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // but we're not sure, then tell the dispatcher to wait a little while and // try again later before dispatching. if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) { - if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) { + if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) { final long now = SystemClock.uptimeMillis(); - final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; + final long timeoutTime = mScreenshotChordVolumeDownKeyTime + + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; if (now < timeoutTime) { return timeoutTime - now; } } if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN - && mVolumeDownKeyConsumedByScreenshotChord) { + && mScreenshotChordVolumeDownKeyConsumed) { if (!down) { - mVolumeDownKeyConsumedByScreenshotChord = false; + mScreenshotChordVolumeDownKeyConsumed = false; } return -1; } @@ -2242,15 +2442,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } - // If there's a dream running then use home to escape the dream - // but don't actually go home. - if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { - mDreamManagerInternal.stopDream(false /*immediate*/); - return -1; - } - - // Go home! - launchHomeFromHotKey(); + handleShortPressOnHome(); return -1; } @@ -2524,7 +2716,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } - if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { + if (isValidGlobalKey(keyCode) + && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return -1; } @@ -4290,10 +4483,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the key would be handled globally, just return the result, don't worry about special // key processing. - if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { + if (isValidGlobalKey(keyCode) + && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { if (isWakeKey) { - wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER - ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); } return result; } @@ -4309,28 +4502,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_VOLUME_MUTE: { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if (down) { - if (interactive && !mVolumeDownKeyTriggered + if (interactive && !mScreenshotChordVolumeDownKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mVolumeDownKeyTriggered = true; - mVolumeDownKeyTime = event.getDownTime(); - mVolumeDownKeyConsumedByScreenshotChord = false; + mScreenshotChordVolumeDownKeyTriggered = true; + mScreenshotChordVolumeDownKeyTime = event.getDownTime(); + mScreenshotChordVolumeDownKeyConsumed = false; cancelPendingPowerKeyAction(); interceptScreenshotChord(); } } else { - mVolumeDownKeyTriggered = false; + mScreenshotChordVolumeDownKeyTriggered = false; cancelPendingScreenshotChordAction(); } } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { if (down) { - if (interactive && !mVolumeUpKeyTriggered + if (interactive && !mScreenshotChordVolumeUpKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mVolumeUpKeyTriggered = true; + mScreenshotChordVolumeUpKeyTriggered = true; cancelPendingPowerKeyAction(); cancelPendingScreenshotChordAction(); } } else { - mVolumeUpKeyTriggered = false; + mScreenshotChordVolumeUpKeyTriggered = false; cancelPendingScreenshotChordAction(); } } @@ -4387,20 +4580,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (telecomManager != null) { hungUp = telecomManager.endCall(); } - interceptPowerKeyDown(!interactive || hungUp); + if (interactive && !hungUp) { + mEndCallKeyHandled = false; + mHandler.postDelayed(mEndCallLongPress, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + } else { + mEndCallKeyHandled = true; + } } else { - if (interceptPowerKeyUp(canceled)) { - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { - if (goHome()) { - break; + if (!mEndCallKeyHandled) { + mHandler.removeCallbacks(mEndCallLongPress); + if (!canceled) { + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { + if (goHome()) { + break; + } + } + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { + mPowerManager.goToSleep(event.getEventTime(), + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + isWakeKey = false; } - } - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { - mPowerManager.goToSleep(event.getEventTime(), - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); - isWakeKey = false; } } } @@ -4409,49 +4611,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; + isWakeKey = false; // wake-up will be handled separately if (down) { - boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, - event.getDownTime(), isImmersiveMode(mLastSystemUiFlags)); - if (panic) { - mHandler.post(mRequestTransientNav); - } - if (interactive && !mPowerKeyTriggered - && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mPowerKeyTriggered = true; - mPowerKeyTime = event.getDownTime(); - interceptScreenshotChord(); - } - - TelecomManager telecomManager = getTelecommService(); - boolean hungUp = false; - if (telecomManager != null) { - if (telecomManager.isRinging()) { - // Pressing Power while there's a ringing incoming - // call should silence the ringer. - telecomManager.silenceRinger(); - } else if ((mIncallPowerBehavior - & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 - && telecomManager.isInCall() && interactive) { - // Otherwise, if "Power button ends call" is enabled, - // the Power button will hang up any current active call. - hungUp = telecomManager.endCall(); - } - } - interceptPowerKeyDown(!interactive || hungUp - || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered); + interceptPowerKeyDown(event, interactive); } else { - mPowerKeyTriggered = false; - cancelPendingScreenshotChordAction(); - if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) { - if (mScreenOnEarly && !mScreenOnFully) { - Slog.i(TAG, "Suppressed redundant power key press while " - + "already in the process of turning the screen on."); - } else { - powerShortPress(event.getEventTime()); - } - isWakeKey = false; - } - mPendingPowerKeyUpCanceled = false; + interceptPowerKeyUp(event, interactive, canceled); } break; } @@ -4542,14 +4706,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (isWakeKey) { - wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER - ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); } return result; } /** + * Returns true if the key can have global actions attached to it. + * We reserve all power management keys for the system since they require + * very careful handling. + */ + private static boolean isValidGlobalKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_POWER: + case KeyEvent.KEYCODE_WAKEUP: + case KeyEvent.KEYCODE_SLEEP: + return false; + default: + return true; + } + } + + /** * When the screen is off we ignore some keys that might otherwise typically * be considered wake keys. We filter them out here. * @@ -4766,6 +4945,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void wakeUpFromPowerKey(long eventTime) { + wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey); + } + private void wakeUp(long wakeTime, boolean wakeInTheaterMode) { if (!wakeInTheaterMode && isTheaterModeEnabled()) { return; @@ -5986,6 +6169,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior); pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior); + pw.print(prefix); + pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior); + pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior); pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput); pw.print(prefix); pw.print("mAwake="); pw.println(mAwake); pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); |