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:
Anthony Hugh
2016-07-12 15:17:24 -07:00
parent f3c613335a
commit 96e9cc5700
8 changed files with 135 additions and 13 deletions

View File

@@ -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.
*

View File

@@ -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.
*/

View File

@@ -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)

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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 "

View File

@@ -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);

View File

@@ -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;
}