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
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b2cf89b..3a3d8db 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 @@
     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 @@
     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 @@
             // 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 @@
             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 @@
             }
         }
 
-        if (shouldDispatchInputWhenNonInteractive()) {
+        if (shouldDispatchInputWhenNonInteractive(null)) {
             return ACTION_PASS_TO_USER;
         }
 
@@ -5804,7 +5826,7 @@
         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 @@
             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();