Add panic detection to back button
Adds "panic" detection to the back button. Implemented solution uses 4x button presses in a short duration to detect for "panic". The value used to determine the duration between key up and key down that still count as a multi-button press is configurable via the Settings Provider. BUG: 28027764 Change-Id: Ibf1370ff3cb539a9a54002a8704922744a3ca5d7
This commit is contained in:
@@ -5344,6 +5344,13 @@ public final class Settings {
|
||||
*/
|
||||
public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
|
||||
|
||||
/**
|
||||
* The duration in milliseconds between the first tap's up event and the second tap's
|
||||
* down event for an interaction to be considered part of the same multi-press.
|
||||
* @hide
|
||||
*/
|
||||
public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
|
||||
|
||||
/**
|
||||
* List of the enabled print services.
|
||||
*
|
||||
|
||||
@@ -63,6 +63,12 @@ public class ViewConfiguration {
|
||||
*/
|
||||
private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;
|
||||
|
||||
/**
|
||||
* Defines the default duration in milliseconds between the first tap's up event and the second
|
||||
* tap's down event for an interaction to be considered part of the same multi-press.
|
||||
*/
|
||||
private static final int DEFAULT_MULTI_PRESS_TIMEOUT = 300;
|
||||
|
||||
/**
|
||||
* Defines the time between successive key repeats in milliseconds.
|
||||
*/
|
||||
@@ -440,6 +446,16 @@ public class ViewConfiguration {
|
||||
DEFAULT_LONG_PRESS_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration in milliseconds between the first tap's up event and the second tap's
|
||||
* down event for an interaction to be considered part of the same multi-press.
|
||||
* @hide
|
||||
*/
|
||||
public static int getMultiPressTimeout() {
|
||||
return AppGlobals.getIntCoreSetting(Settings.Secure.MULTI_PRESS_TIMEOUT,
|
||||
DEFAULT_MULTI_PRESS_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time before the first key repeat in milliseconds.
|
||||
*/
|
||||
|
||||
@@ -796,6 +796,12 @@
|
||||
-->
|
||||
<integer name="config_longPressOnBackBehavior">0</integer>
|
||||
|
||||
<!-- Control the behavior when the user panic presses the back button.
|
||||
0 - Nothing
|
||||
1 - Go to home
|
||||
-->
|
||||
<integer name="config_backPanicBehavior">0</integer>
|
||||
|
||||
<!-- Control the behavior when the user short presses the power button.
|
||||
0 - Nothing
|
||||
1 - Go to sleep (doze)
|
||||
|
||||
@@ -375,6 +375,7 @@
|
||||
<java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
|
||||
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />
|
||||
<java-symbol type="integer" name="config_longPressOnBackBehavior" />
|
||||
<java-symbol type="integer" name="config_backPanicBehavior" />
|
||||
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
|
||||
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
|
||||
<java-symbol type="integer" name="config_max_pan_devices" />
|
||||
|
||||
@@ -155,6 +155,9 @@
|
||||
<!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS -->
|
||||
<integer name="def_long_press_timeout_millis">400</integer>
|
||||
|
||||
<!-- Default for Settings.Secure.MULTI_PRESS_TIMEOUT -->
|
||||
<integer name="def_multi_press_timeout_millis">300</integer>
|
||||
|
||||
<!-- Default for Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD -->
|
||||
<bool name="def_show_ime_with_hard_keyboard">false</bool>
|
||||
|
||||
|
||||
@@ -2090,7 +2090,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
private final class UpgradeController {
|
||||
private static final int SETTINGS_VERSION = 130;
|
||||
private static final int SETTINGS_VERSION = 131;
|
||||
|
||||
private final int mUserId;
|
||||
|
||||
@@ -2398,6 +2398,22 @@ public class SettingsProvider extends ContentProvider {
|
||||
currentVersion = 130;
|
||||
}
|
||||
|
||||
if (currentVersion == 130) {
|
||||
// Initialize new multi-press timeout to default value
|
||||
final SettingsState systemSecureSettings = getSecureSettingsLocked(userId);
|
||||
final String oldValue = systemSecureSettings.getSettingLocked(
|
||||
Settings.Secure.MULTI_PRESS_TIMEOUT).getValue();
|
||||
if (TextUtils.equals(null, oldValue)) {
|
||||
systemSecureSettings.insertSettingLocked(
|
||||
Settings.Secure.MULTI_PRESS_TIMEOUT,
|
||||
String.valueOf(getContext().getResources().getInteger(
|
||||
R.integer.def_multi_press_timeout_millis)),
|
||||
SettingsState.SYSTEM_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
currentVersion = 131;
|
||||
}
|
||||
|
||||
if (currentVersion != newVersion) {
|
||||
Slog.w("SettingsProvider", "warning: upgrading settings database to version "
|
||||
+ newVersion + " left it at "
|
||||
|
||||
@@ -42,6 +42,7 @@ final class CoreSettingsObserver extends ContentObserver {
|
||||
String, Class<?>>();
|
||||
static {
|
||||
sSecureSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class);
|
||||
sSecureSettingToTypeMap.put(Settings.Secure.MULTI_PRESS_TIMEOUT, int.class);
|
||||
// add other secure settings here...
|
||||
|
||||
sSystemSettingToTypeMap.put(Settings.System.TIME_12_24, String.class);
|
||||
|
||||
@@ -200,6 +200,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
|
||||
static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
|
||||
|
||||
// Number of presses needed before we induce panic press behavior on the back button
|
||||
static final int PANIC_PRESS_BACK_COUNT = 4;
|
||||
static final int PANIC_PRESS_BACK_NOTHING = 0;
|
||||
static final int PANIC_PRESS_BACK_HOME = 1;
|
||||
|
||||
// These need to match the documentation/constant in
|
||||
// core/res/res/values/config.xml
|
||||
static final int LONG_PRESS_HOME_NOTHING = 0;
|
||||
@@ -406,6 +411,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
volatile boolean mBackKeyHandled;
|
||||
volatile boolean mBeganFromNonInteractive;
|
||||
volatile int mPowerKeyPressCounter;
|
||||
volatile int mBackKeyPressCounter;
|
||||
volatile boolean mEndCallKeyHandled;
|
||||
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
|
||||
volatile boolean mGoingToSleep;
|
||||
@@ -464,6 +470,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
int mDoublePressOnPowerBehavior;
|
||||
int mTriplePressOnPowerBehavior;
|
||||
int mLongPressOnBackBehavior;
|
||||
int mPanicPressOnBackBehavior;
|
||||
int mShortPressOnSleepBehavior;
|
||||
int mShortPressWindowBehavior;
|
||||
boolean mAwake;
|
||||
@@ -726,6 +733,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
private static final int MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU = 17;
|
||||
private static final int MSG_BACK_LONG_PRESS = 18;
|
||||
private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
|
||||
private static final int MSG_BACK_DELAYED_PRESS = 20;
|
||||
|
||||
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
|
||||
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
|
||||
@@ -792,10 +800,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
break;
|
||||
case MSG_BACK_LONG_PRESS:
|
||||
backLongPress();
|
||||
finishBackKeyPress();
|
||||
break;
|
||||
case MSG_DISPOSE_INPUT_CONSUMER:
|
||||
disposeInputConsumer((InputConsumer) msg.obj);
|
||||
break;
|
||||
case MSG_BACK_DELAYED_PRESS:
|
||||
backMultiPressAction((Long) msg.obj, msg.arg1);
|
||||
finishBackKeyPress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1010,6 +1023,52 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
private void interceptBackKeyDown() {
|
||||
// Reset back key state for long press
|
||||
mBackKeyHandled = false;
|
||||
|
||||
// Cancel multi-press detection timeout.
|
||||
if (hasPanicPressOnBackBehavior()) {
|
||||
if (mBackKeyPressCounter != 0
|
||||
&& mBackKeyPressCounter < PANIC_PRESS_BACK_COUNT) {
|
||||
mHandler.removeMessages(MSG_BACK_DELAYED_PRESS);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// Cache handled state
|
||||
boolean handled = mBackKeyHandled;
|
||||
|
||||
if (hasPanicPressOnBackBehavior()) {
|
||||
// Check for back key panic press
|
||||
++mBackKeyPressCounter;
|
||||
|
||||
final long eventTime = event.getDownTime();
|
||||
|
||||
if (mBackKeyPressCounter <= PANIC_PRESS_BACK_COUNT) {
|
||||
// This could be a multi-press. Wait a little bit longer to confirm.
|
||||
Message msg = mHandler.obtainMessage(MSG_BACK_DELAYED_PRESS,
|
||||
mBackKeyPressCounter, 0, eventTime);
|
||||
msg.setAsynchronous(true);
|
||||
mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
// Reset back long press state
|
||||
cancelPendingBackKeyAction();
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
|
||||
// Hold a wake lock until the power key is released.
|
||||
if (!mPowerKeyWakeLock.isHeld()) {
|
||||
@@ -1140,6 +1199,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
private void finishBackKeyPress() {
|
||||
mBackKeyPressCounter = 0;
|
||||
}
|
||||
|
||||
private void cancelPendingPowerKeyAction() {
|
||||
if (!mPowerKeyHandled) {
|
||||
mPowerKeyHandled = true;
|
||||
@@ -1154,6 +1217,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
private void backMultiPressAction(long eventTime, int count) {
|
||||
if (count >= PANIC_PRESS_BACK_COUNT) {
|
||||
switch (mPanicPressOnBackBehavior) {
|
||||
case PANIC_PRESS_BACK_NOTHING:
|
||||
break;
|
||||
case PANIC_PRESS_BACK_HOME:
|
||||
launchHomeFromHotKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void powerPress(long eventTime, boolean interactive, int count) {
|
||||
if (mScreenOnEarly && !mScreenOnFully) {
|
||||
Slog.i(TAG, "Suppressed redundant power key press while "
|
||||
@@ -1312,6 +1387,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
return mLongPressOnBackBehavior != LONG_PRESS_BACK_NOTHING;
|
||||
}
|
||||
|
||||
private boolean hasPanicPressOnBackBehavior() {
|
||||
return mPanicPressOnBackBehavior != PANIC_PRESS_BACK_NOTHING;
|
||||
}
|
||||
|
||||
private void interceptScreenshotChord() {
|
||||
if (mScreenshotChordEnabled
|
||||
&& mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
|
||||
@@ -1639,6 +1718,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
|
||||
mLongPressOnBackBehavior = mContext.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_longPressOnBackBehavior);
|
||||
mPanicPressOnBackBehavior = mContext.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_backPanicBehavior);
|
||||
|
||||
mShortPressOnPowerBehavior = mContext.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_shortPressOnPowerBehavior);
|
||||
@@ -5607,20 +5688,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK: {
|
||||
if (down) {
|
||||
mBackKeyHandled = false;
|
||||
if (hasLongPressOnBackBehavior()) {
|
||||
Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
|
||||
msg.setAsynchronous(true);
|
||||
mHandler.sendMessageDelayed(msg,
|
||||
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
|
||||
}
|
||||
interceptBackKeyDown();
|
||||
} else {
|
||||
boolean handled = mBackKeyHandled;
|
||||
boolean handled = interceptBackKeyUp(event);
|
||||
|
||||
// Reset back key state
|
||||
cancelPendingBackKeyAction();
|
||||
|
||||
// Don't pass back press to app if we've already handled it
|
||||
// Don't pass back press to app if we've already handled it via long press
|
||||
if (handled) {
|
||||
result &= ~ACTION_PASS_TO_USER;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user