am 13f00f07: Implement multi-press behavior for power key. automerge: a71601a

automerge: 634ffc4

* commit '634ffc4211de6bfbc06d6f67084b2d664c2f4f2a':
  Implement multi-press behavior for power key.
This commit is contained in:
Jeff Brown
2014-11-01 15:05:45 +00:00
committed by android-build-merger
3 changed files with 366 additions and 163 deletions

View File

@@ -586,6 +586,7 @@
0 - Nothing 0 - Nothing
1 - Global actions menu 1 - Global actions menu
2 - Power off (with confirmation) 2 - Power off (with confirmation)
3 - Power off (without confirmation)
--> -->
<integer name="config_longPressOnPowerBehavior">1</integer> <integer name="config_longPressOnPowerBehavior">1</integer>
@@ -597,6 +598,20 @@
--> -->
<integer name="config_shortPressOnPowerBehavior">1</integer> <integer name="config_shortPressOnPowerBehavior">1</integer>
<!-- Control the behavior when the user double presses the power button.
0 - Nothing
1 - Toggle theater mode setting
2 - Brightness boost
-->
<integer name="config_doublePressOnPowerBehavior">0</integer>
<!-- Control the behavior when the user triple presses the power button.
0 - Nothing
1 - Toggle theater mode setting
2 - Brightness boost
-->
<integer name="config_triplePressOnPowerBehavior">0</integer>
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] --> <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
<string name="widget_default_package_name" translatable="false"></string> <string name="widget_default_package_name" translatable="false"></string>

View File

@@ -340,6 +340,7 @@
<java-symbol type="integer" name="config_bluetooth_max_advertisers" /> <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" /> <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
<java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" /> <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
<java-symbol type="integer" name="config_extraFreeKbytesAbsolute" /> <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
<java-symbol type="integer" name="config_immersive_mode_confirmation_panic" /> <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
@@ -354,6 +355,7 @@
<java-symbol type="integer" name="config_ntpTimeout" /> <java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_shortPressOnPowerBehavior" /> <java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
<java-symbol type="integer" name="config_toastDefaultGravity" /> <java-symbol type="integer" name="config_toastDefaultGravity" />
<java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" /> <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" /> <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" /> <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />

View File

@@ -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 = 2;
static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; 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 // These need to match the documentation/constant in
// core/res/res/values/config.xml // core/res/res/values/config.xml
static final int LONG_PRESS_HOME_NOTHING = 0; static final int LONG_PRESS_HOME_NOTHING = 0;
@@ -301,12 +305,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}; };
GlobalActions mGlobalActions; GlobalActions mGlobalActions;
volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
boolean mPendingPowerKeyUpCanceled;
Handler mHandler; Handler mHandler;
WindowState mLastInputMethodWindow = null; WindowState mLastInputMethodWindow = null;
WindowState mLastInputMethodTargetWindow = 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; boolean mRecentsVisible;
int mRecentAppsHeldModifiers; int mRecentAppsHeldModifiers;
boolean mLanguageSwitchKeyPressed; boolean mLanguageSwitchKeyPressed;
@@ -346,8 +359,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mLidKeyboardAccessibility; int mLidKeyboardAccessibility;
int mLidNavigationAccessibility; int mLidNavigationAccessibility;
boolean mLidControlsSleep; boolean mLidControlsSleep;
int mShortPressOnPowerBehavior = -1; int mShortPressOnPowerBehavior;
int mLongPressOnPowerBehavior = -1; int mLongPressOnPowerBehavior;
int mDoublePressOnPowerBehavior;
int mTriplePressOnPowerBehavior;
boolean mAwake; boolean mAwake;
boolean mScreenOnEarly; boolean mScreenOnEarly;
boolean mScreenOnFully; boolean mScreenOnFully;
@@ -518,12 +533,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Increase the chord delay when taking a screenshot from the keyguard // Increase the chord delay when taking a screenshot from the keyguard
private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f; private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
private boolean mScreenshotChordEnabled; private boolean mScreenshotChordEnabled;
private boolean mVolumeDownKeyTriggered; private boolean mScreenshotChordVolumeDownKeyTriggered;
private long mVolumeDownKeyTime; private long mScreenshotChordVolumeDownKeyTime;
private boolean mVolumeDownKeyConsumedByScreenshotChord; private boolean mScreenshotChordVolumeDownKeyConsumed;
private boolean mVolumeUpKeyTriggered; private boolean mScreenshotChordVolumeUpKeyTriggered;
private boolean mPowerKeyTriggered; private boolean mScreenshotChordPowerKeyTriggered;
private long mPowerKeyTime; private long mScreenshotChordPowerKeyTime;
/* The number of steps between min and max brightness */ /* The number of steps between min and max brightness */
private static final int BRIGHTNESS_STEPS = 10; private static final int BRIGHTNESS_STEPS = 10;
@@ -531,6 +546,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
SettingsObserver mSettingsObserver; SettingsObserver mSettingsObserver;
ShortcutManager mShortcutManager; ShortcutManager mShortcutManager;
PowerManager.WakeLock mBroadcastWakeLock; PowerManager.WakeLock mBroadcastWakeLock;
PowerManager.WakeLock mPowerKeyWakeLock;
boolean mHavePendingMediaKeyRepeatWithWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock;
private int mCurrentUserId; 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_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
private static final int MSG_HIDE_BOOT_MESSAGE = 11; 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_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 { private class PolicyHandler extends Handler {
@Override @Override
@@ -597,6 +615,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK: case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock(msg.arg1 != 0); launchVoiceAssistWithWakeLock(msg.arg1 != 0);
break; 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,64 +815,137 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} }
} }
private void interceptPowerKeyDown(boolean handled) { private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
mPowerKeyHandled = handled; // Hold a wake lock until the power key is released.
if (!handled) { if (!mPowerKeyWakeLock.isHeld()) {
mHandler.postDelayed(mPowerLongPress, mPowerKeyWakeLock.acquire();
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); }
// 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();
} }
} }
private boolean interceptPowerKeyUp(boolean canceled) { // 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 (!mPowerKeyHandled) {
mHandler.removeCallbacks(mPowerLongPress); if (interactive) {
return !canceled; // 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) {
// 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 void finishPowerKeyPress() {
mPowerKeyPressCounter = 0;
if (mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.release();
} }
return false;
} }
private void cancelPendingPowerKeyAction() { private void cancelPendingPowerKeyAction() {
if (!mPowerKeyHandled) { if (!mPowerKeyHandled) {
mHandler.removeCallbacks(mPowerLongPress); mPowerKeyHandled = true;
} mHandler.removeMessages(MSG_POWER_LONG_PRESS);
if (mPowerKeyTriggered) {
mPendingPowerKeyUpCanceled = true;
} }
} }
private void interceptScreenshotChord() { private void powerPress(long eventTime, boolean interactive, int count) {
if (mScreenshotChordEnabled if (mScreenOnEarly && !mScreenOnFully) {
&& mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { Slog.i(TAG, "Suppressed redundant power key press while "
final long now = SystemClock.uptimeMillis(); + "already in the process of turning the screen on.");
if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS return;
&& now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mVolumeDownKeyConsumedByScreenshotChord = true;
cancelPendingPowerKeyAction();
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}
}
}
private long getScreenshotChordLongPressDelay() {
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
}
private void cancelPendingScreenshotChordAction() {
mHandler.removeCallbacks(mScreenshotRunnable);
}
private void powerShortPress(long eventTime) {
if (mShortPressOnPowerBehavior < 0) {
mShortPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnPowerBehavior);
} }
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (!interactive) {
wakeUpFromPowerKey(eventTime);
} else {
switch (mShortPressOnPowerBehavior) { switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING: case SHORT_PRESS_POWER_NOTHING:
break; break;
@@ -868,21 +966,49 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break; break;
} }
} }
private final Runnable mPowerLongPress = 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) { 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: case LONG_PRESS_POWER_NOTHING:
break; break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS: case LONG_PRESS_POWER_GLOBAL_ACTIONS:
@@ -897,10 +1023,60 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerKeyHandled = true; mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF); mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break; 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
&& mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
&& !mScreenshotChordVolumeUpKeyTriggered) {
final long now = SystemClock.uptimeMillis();
if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
&& now <= mScreenshotChordPowerKeyTime
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mScreenshotChordVolumeDownKeyConsumed = true;
cancelPendingPowerKeyAction();
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}
}
}
private long getScreenshotChordLongPressDelay() {
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
}
private void cancelPendingScreenshotChordAction() {
mHandler.removeCallbacks(mScreenshotRunnable);
}
private final Runnable mEndCallLongPress = new Runnable() {
@Override
public void run() {
mEndCallKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
showGlobalActionsInternal();
}
}; };
private final Runnable mScreenshotRunnable = new Runnable() { private final Runnable mScreenshotRunnable = new Runnable() {
@@ -940,6 +1116,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; 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() { private void handleLongPressOnHome() {
if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
mHomeConsumed = true; mHomeConsumed = true;
@@ -965,7 +1153,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void run() { public void run() {
if (mHomeDoubleTapPending) { if (mHomeDoubleTapPending) {
mHomeDoubleTapPending = false; mHomeDoubleTapPending = false;
launchHomeFromHotKey(); handleShortPressOnHome();
} }
} }
}; };
@@ -1008,6 +1196,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mBroadcastWakeLock"); "PhoneWindowManager.mBroadcastWakeLock");
mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mPowerKeyWakeLock");
mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
mSupportAutoRotation = mContext.getResources().getBoolean( mSupportAutoRotation = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_supportAutoRotation); com.android.internal.R.bool.config_supportAutoRotation);
@@ -1046,6 +1236,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean( mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture); 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(); readConfigurationDependentBehaviors();
mAccessibilityManager = (AccessibilityManager) context.getSystemService( 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 // but we're not sure, then tell the dispatcher to wait a little while and
// try again later before dispatching. // try again later before dispatching.
if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) { if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) { if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
final long now = SystemClock.uptimeMillis(); 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) { if (now < timeoutTime) {
return timeoutTime - now; return timeoutTime - now;
} }
} }
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
&& mVolumeDownKeyConsumedByScreenshotChord) { && mScreenshotChordVolumeDownKeyConsumed) {
if (!down) { if (!down) {
mVolumeDownKeyConsumedByScreenshotChord = false; mScreenshotChordVolumeDownKeyConsumed = false;
} }
return -1; return -1;
} }
@@ -2242,15 +2442,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1; return -1;
} }
// If there's a dream running then use home to escape the dream handleShortPressOnHome();
// but don't actually go home.
if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
mDreamManagerInternal.stopDream(false /*immediate*/);
return -1;
}
// Go home!
launchHomeFromHotKey();
return -1; return -1;
} }
@@ -2524,7 +2716,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1; return -1;
} }
if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
return -1; 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 // If the key would be handled globally, just return the result, don't worry about special
// key processing. // key processing.
if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
if (isWakeKey) { if (isWakeKey) {
wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
} }
return result; return result;
} }
@@ -4309,28 +4502,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_MUTE: { case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) { if (down) {
if (interactive && !mVolumeDownKeyTriggered if (interactive && !mScreenshotChordVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeDownKeyTriggered = true; mScreenshotChordVolumeDownKeyTriggered = true;
mVolumeDownKeyTime = event.getDownTime(); mScreenshotChordVolumeDownKeyTime = event.getDownTime();
mVolumeDownKeyConsumedByScreenshotChord = false; mScreenshotChordVolumeDownKeyConsumed = false;
cancelPendingPowerKeyAction(); cancelPendingPowerKeyAction();
interceptScreenshotChord(); interceptScreenshotChord();
} }
} else { } else {
mVolumeDownKeyTriggered = false; mScreenshotChordVolumeDownKeyTriggered = false;
cancelPendingScreenshotChordAction(); cancelPendingScreenshotChordAction();
} }
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (down) { if (down) {
if (interactive && !mVolumeUpKeyTriggered if (interactive && !mScreenshotChordVolumeUpKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeUpKeyTriggered = true; mScreenshotChordVolumeUpKeyTriggered = true;
cancelPendingPowerKeyAction(); cancelPendingPowerKeyAction();
cancelPendingScreenshotChordAction(); cancelPendingScreenshotChordAction();
} }
} else { } else {
mVolumeUpKeyTriggered = false; mScreenshotChordVolumeUpKeyTriggered = false;
cancelPendingScreenshotChordAction(); cancelPendingScreenshotChordAction();
} }
} }
@@ -4387,9 +4580,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (telecomManager != null) { if (telecomManager != null) {
hungUp = telecomManager.endCall(); hungUp = telecomManager.endCall();
} }
interceptPowerKeyDown(!interactive || hungUp); if (interactive && !hungUp) {
mEndCallKeyHandled = false;
mHandler.postDelayed(mEndCallLongPress,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
} else { } else {
if (interceptPowerKeyUp(canceled)) { mEndCallKeyHandled = true;
}
} else {
if (!mEndCallKeyHandled) {
mHandler.removeCallbacks(mEndCallLongPress);
if (!canceled) {
if ((mEndcallBehavior if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
if (goHome()) { if (goHome()) {
@@ -4404,54 +4605,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} }
} }
} }
}
break; break;
} }
case KeyEvent.KEYCODE_POWER: { case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER; result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) { if (down) {
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, interceptPowerKeyDown(event, 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);
} else { } else {
mPowerKeyTriggered = false; interceptPowerKeyUp(event, interactive, canceled);
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;
} }
break; break;
} }
@@ -4542,13 +4706,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} }
if (isWakeKey) { if (isWakeKey) {
wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
} }
return result; 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 * When the screen is off we ignore some keys that might otherwise typically
* be considered wake keys. We filter them out here. * 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) { private void wakeUp(long wakeTime, boolean wakeInTheaterMode) {
if (!wakeInTheaterMode && isTheaterModeEnabled()) { if (!wakeInTheaterMode && isTheaterModeEnabled()) {
return; return;
@@ -5986,6 +6169,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(prefix); pw.print(prefix);
pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior); pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior); 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("mHasSoftInput="); pw.println(mHasSoftInput);
pw.print(prefix); pw.print("mAwake="); pw.println(mAwake); pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);