From 4b13ab892ef095af6b76708876270139443df58e Mon Sep 17 00:00:00 2001 From: Anthony Hugh Date: Tue, 17 May 2016 13:03:00 -0700 Subject: [PATCH] Prevent back button from being handled by app after waking device The current implementation marks KEYCODE_BACK as a wake key in KeyEvent. In theory, this prevents the back key from being dispatched to the app. In practice though, on watches the key both wakes the device and dispatches the back button. This behavior is because of the logic in interceptKeyBeforeQueueing(). Watches spend the majority of their time in ambient, so when the code runs the shouldDispatchInputWhenNonInteractive() logic, it always assumes wake key events should be passed through. With this change, I am adjusting the behavior for watches. shouldDispatchInputWhenNonInteractive() has been modified to handle the back button specially on watches so that the Down event is treated as a wake up only. The above change had an unintended side effect of sending an Up event to the app without a corresponding Down event. I've also added a cached value so that we don't send the Up event if a Down event was responsible for waking the device. BUG: 28716144 Change-Id: If8906bffd9b3e0b6070de3b4e7bce4d8178ac65d --- .../server/policy/PhoneWindowManager.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b2cf89b17cfc6..3a3d8db09f914 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -216,6 +216,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0; static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1; + static final int PENDING_KEY_NULL = -1; + // Controls navigation bar opacity depending on which workspace stacks are currently // visible. // Nav bar is always opaque when either the freeform stack or docked stack is visible. @@ -407,6 +409,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile boolean mRecentsVisible; volatile boolean mTvPictureInPictureVisible; + // Used to hold the last user key used to wake the device. This helps us prevent up events + // from being passed to the foregrounded app without a corresponding down event + volatile int mPendingWakeKey = PENDING_KEY_NULL; + int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; @@ -5429,12 +5435,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { // key to the application. result = ACTION_PASS_TO_USER; isWakeKey = false; - } else if (!interactive && shouldDispatchInputWhenNonInteractive()) { + + if (interactive) { + // If the screen is awake, but the button pressed was the one that woke the device + // then don't pass it to the application + if (keyCode == mPendingWakeKey && !down) { + result = 0; + } + // Reset the pending key + mPendingWakeKey = PENDING_KEY_NULL; + } + } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) { // If we're currently dozing with the screen on and the keyguard showing, pass the key // to the application but preserve its wake key status to make sure we still move // from dozing to fully interactive if we would normally go from off to fully // interactive. result = ACTION_PASS_TO_USER; + // Since we're dispatching the input, reset the pending key + mPendingWakeKey = PENDING_KEY_NULL; } else { // When the screen is off and the key is not injected, determine whether // to wake the device but don't pass the key to the application. @@ -5442,6 +5460,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) { isWakeKey = false; } + // Cache the wake key on down event so we can also avoid sending the up event to the app + if (isWakeKey && down) { + mPendingWakeKey = keyCode; + } } // If the key would be handled globally, just return the result, don't worry about special @@ -5789,7 +5811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - if (shouldDispatchInputWhenNonInteractive()) { + if (shouldDispatchInputWhenNonInteractive(null)) { return ACTION_PASS_TO_USER; } @@ -5804,7 +5826,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - private boolean shouldDispatchInputWhenNonInteractive() { + private boolean shouldDispatchInputWhenNonInteractive(KeyEvent event) { final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF); if (displayOff && !mHasFeatureWatch) { @@ -5816,6 +5838,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } + // Watches handle BACK specially + if (mHasFeatureWatch + && event != null + && (event.getKeyCode() == KeyEvent.KEYCODE_BACK + || event.getKeyCode() == KeyEvent.KEYCODE_STEM_PRIMARY)) { + return false; + } + // Send events to a dozing dream even if the screen is off since the dream // is in control of the state of the screen. IDreamManager dreamManager = getDreamManager();