Fix an event injection bug when the policy is bypassed.

Added the concept of a "trusted" event to distinguish between events from
attached input devices or trusted injectors vs. other applications.
This change enables us to move certain policy decisions out of the
dispatcher and into the policy itself where they can be handled more
systematically.

Change-Id: I4d56fdcdd31aaa675d452088af39a70c4e039970
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index ef7716e..1fd31a3 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -77,6 +77,7 @@
     public final static int FLAG_VIRTUAL = 0x00000100;
 
     public final static int FLAG_INJECTED = 0x01000000;
+    public final static int FLAG_TRUSTED = 0x02000000;
 
     public final static int FLAG_WOKE_HERE = 0x10000000;
     public final static int FLAG_BRIGHT_HERE = 0x20000000;
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 66061fd..8c6018b 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -95,6 +95,10 @@
     // Indicates that the input event was injected.
     POLICY_FLAG_INJECTED = 0x01000000,
 
+    // Indicates that the input event is from a trusted source such as a directly attached
+    // input device or an application with system-wide event injection permission.
+    POLICY_FLAG_TRUSTED = 0x02000000,
+
     /* These flags are set by the input reader policy as it intercepts each event. */
 
     // Indicates that the screen was off when the event was received and the event
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 0834e86..3599163 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -913,7 +913,6 @@
     void drainInboundQueueLocked();
     void releasePendingEventLocked();
     void releaseInboundEventLocked(EventEntry* entry);
-    bool isEventFromTrustedSourceLocked(EventEntry* entry);
 
     // Dispatch state.
     bool mDispatchEnabled;
@@ -960,10 +959,10 @@
             nsecs_t currentTime, ConfigurationChangedEntry* entry);
     bool dispatchKeyLocked(
             nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-            bool dropEvent, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime);
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
-            bool dropEvent, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime);
     void dispatchEventToCurrentInputTargetsLocked(
             nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
 
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 58c2cdf..41b6ff3 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -370,7 +370,7 @@
             }
         }
         done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
-                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
+                &dropReason, nextWakeupTime);
         break;
     }
 
@@ -380,7 +380,7 @@
             dropReason = DROP_REASON_APP_SWITCH;
         }
         done = dispatchMotionLocked(currentTime, typedEntry,
-                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
+                &dropReason, nextWakeupTime);
         break;
     }
 
@@ -431,6 +431,9 @@
     const char* reason;
     switch (dropReason) {
     case DROP_REASON_POLICY:
+#if DEBUG_INBOUND_EVENT_DETAILS
+        LOGD("Dropped event because policy requested that it not be delivered to the application.");
+#endif
         reason = "inbound event was dropped because the policy requested that it not be "
                 "delivered to the application";
         break;
@@ -473,7 +476,7 @@
 bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
     return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
             && isAppSwitchKeyCode(keyEntry->keyCode)
-            && isEventFromTrustedSourceLocked(keyEntry)
+            && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
             && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
 }
 
@@ -541,12 +544,6 @@
     mAllocator.releaseEventEntry(entry);
 }
 
-bool InputDispatcher::isEventFromTrustedSourceLocked(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
-    return ! injectionState
-            || hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid);
-}
-
 void InputDispatcher::resetKeyRepeatLocked() {
     if (mKeyRepeatState.lastKeyEntry) {
         mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry);
@@ -559,7 +556,8 @@
     KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
 
     // Reuse the repeated key entry if it is otherwise unreferenced.
-    uint32_t policyFlags = entry->policyFlags & (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER);
+    uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK)
+            | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED;
     if (entry->refCount == 1) {
         mAllocator.recycleKeyEntry(entry);
         entry->eventTime = currentTime;
@@ -608,19 +606,13 @@
 
 bool InputDispatcher::dispatchKeyLocked(
         nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-        bool dropEvent, nsecs_t* nextWakeupTime) {
+        DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Give the policy a chance to intercept the key.
     if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
-        bool trusted;
-        if (! dropEvent && mFocusedWindow) {
-            trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState);
-        } else {
-            trusted = isEventFromTrustedSourceLocked(entry);
-        }
-        if (trusted) {
+        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (! dropEvent && mFocusedWindow) {
+            if (mFocusedWindow) {
                 commandEntry->inputChannel = mFocusedWindow->inputChannel;
             }
             commandEntry->keyEntry = entry;
@@ -630,13 +622,16 @@
             entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
         }
     } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
+        if (*dropReason == DROP_REASON_NOT_DROPPED) {
+            *dropReason = DROP_REASON_POLICY;
+        }
         resetTargetsLocked();
         setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
         return true;
     }
 
     // Clean up if dropping the event.
-    if (dropEvent) {
+    if (*dropReason != DROP_REASON_NOT_DROPPED) {
         resetTargetsLocked();
         setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
         return true;
@@ -648,7 +643,8 @@
 
         if (entry->repeatCount == 0
                 && entry->action == AKEY_EVENT_ACTION_DOWN
-                && ! entry->isInjected()) {
+                && (entry->policyFlags & POLICY_FLAG_TRUSTED)
+                && !entry->isInjected()) {
             if (mKeyRepeatState.lastKeyEntry
                     && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
                 // We have seen two identical key downs in a row which indicates that the device
@@ -713,9 +709,9 @@
 }
 
 bool InputDispatcher::dispatchMotionLocked(
-        nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
+        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Clean up if dropping the event.
-    if (dropEvent) {
+    if (*dropReason != DROP_REASON_NOT_DROPPED) {
         resetTargetsLocked();
         setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
         return true;
@@ -2085,6 +2081,7 @@
         return;
     }
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
             keyCode, scanCode, /*byref*/ policyFlags);
 
@@ -2130,6 +2127,7 @@
         return;
     }
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
 
     bool needWake;
@@ -2263,6 +2261,7 @@
             switchCode, switchValue, policyFlags);
 #endif
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags);
 }
 
@@ -2275,7 +2274,11 @@
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
-    bool trusted = hasInjectionPermission(injectorPid, injectorUid);
+
+    uint32_t policyFlags = POLICY_FLAG_INJECTED;
+    if (hasInjectionPermission(injectorPid, injectorUid)) {
+        policyFlags |= POLICY_FLAG_TRUSTED;
+    }
 
     EventEntry* injectedEntry;
     switch (event->getType()) {
@@ -2291,11 +2294,8 @@
         int32_t flags = keyEvent->getFlags();
         int32_t keyCode = keyEvent->getKeyCode();
         int32_t scanCode = keyEvent->getScanCode();
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-        if (trusted) {
-            mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
-                    keyCode, scanCode, /*byref*/ policyFlags);
-        }
+        mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+                keyCode, scanCode, /*byref*/ policyFlags);
 
         mLock.lock();
         injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
@@ -2314,10 +2314,7 @@
         }
 
         nsecs_t eventTime = motionEvent->getEventTime();
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-        if (trusted) {
-            mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
-        }
+        mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
 
         mLock.lock();
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index f21d357..d9bceec 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1057,6 +1057,10 @@
     @Override
     public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
             int keyCode, int metaState, int repeatCount, int policyFlags) {
+        if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) {
+            return false;
+        }
+
         final boolean keyguardOn = keyguardOn();
         final boolean down = (action == KeyEvent.ACTION_DOWN);
         final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1083,7 +1087,7 @@
                 if (!down) {
                     mHomePressed = false;
                     
-                    if (! canceled) {
+                    if (!canceled) {
                         // If an incoming call is ringing, HOME is totally disabled.
                         // (The user is already on the InCallScreen at this point,
                         // and his ONLY options are to answer or reject the call.)
@@ -1735,7 +1739,14 @@
     public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
             int policyFlags, boolean isScreenOn) {
         int result = ACTION_PASS_TO_USER;
-        
+        if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) {
+            return result;
+        }
+
+        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
+
         final boolean isWakeKey = (policyFlags
                 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
         
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index ed1243a..df41264 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -359,11 +359,6 @@
         private static final String CALIBRATION_DIR_PATH = "usr/idc/";
         
         @SuppressWarnings("unused")
-        public void virtualKeyDownFeedback() {
-            mWindowManagerService.mInputMonitor.virtualKeyDownFeedback();
-        }
-        
-        @SuppressWarnings("unused")
         public void notifyConfigurationChanged(long whenNanos) {
             mWindowManagerService.sendNewConfiguration();
         }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 0de57ab..42fffb0 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5243,13 +5243,6 @@
             mTempInputWindows.clear();
         }
         
-        /* Provides feedback for a virtual key down. */
-        public void virtualKeyDownFeedback() {
-            synchronized (mWindowMap) {
-                mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-            }
-        }
-        
         /* Notifies that the lid switch changed state. */
         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
             mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 18037e4..a0b0aba 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -50,7 +50,6 @@
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
     jmethodID notifyANR;
-    jmethodID virtualKeyDownFeedback;
     jmethodID interceptKeyBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID checkInjectEventsPermission;
@@ -192,6 +191,8 @@
 
     /* --- InputDispatcherPolicyInterface implementation --- */
 
+    virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+            uint32_t policyFlags);
     virtual void notifyConfigurationChanged(nsecs_t when);
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
             const sp<InputChannel>& inputChannel);
@@ -205,8 +206,6 @@
     virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
     virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
             const KeyEvent* keyEvent, uint32_t policyFlags);
-    virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
-            uint32_t policyFlags);
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
     virtual bool checkInjectEventsPermissionNonReentrant(
             int32_t injectorPid, int32_t injectorUid);
@@ -255,7 +254,6 @@
 
     static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow);
 
-    static bool isPolicyKey(int32_t keyCode, bool isScreenOn);
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -291,37 +289,6 @@
     dump.append("\n");
 }
 
-bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
-    // Special keys that the WindowManagerPolicy might care about.
-    switch (keyCode) {
-    case AKEYCODE_VOLUME_UP:
-    case AKEYCODE_VOLUME_DOWN:
-    case AKEYCODE_ENDCALL:
-    case AKEYCODE_POWER:
-    case AKEYCODE_CALL:
-    case AKEYCODE_HOME:
-    case AKEYCODE_MENU:
-    case AKEYCODE_SEARCH:
-        // media keys
-    case AKEYCODE_HEADSETHOOK:
-    case AKEYCODE_MEDIA_PLAY_PAUSE:
-    case AKEYCODE_MEDIA_STOP:
-    case AKEYCODE_MEDIA_NEXT:
-    case AKEYCODE_MEDIA_PREVIOUS:
-    case AKEYCODE_MEDIA_REWIND:
-    case AKEYCODE_MEDIA_FAST_FORWARD:
-        // The policy always cares about these keys.
-        return true;
-    default:
-        // We need to pass all keys to the policy in the following cases:
-        // - screen is off
-        // - keyguard is visible
-        // - policy is performing key chording
-        //return ! isScreenOn || keyguardVisible || chording;
-        return true; // XXX stubbed out for now
-    }
-}
-
 bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     if (env->ExceptionCheck()) {
         LOGE("An exception was thrown by callback '%s'.", methodName);
@@ -454,115 +421,6 @@
     return result;
 }
 
-bool NativeInputManager::isScreenOn() {
-    return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
-    return android_server_PowerManagerService_isScreenBright();
-}
-
-void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
-        int32_t deviceId, int32_t action, int32_t &flags,
-        int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, "
-            "keyCode=%d, scanCode=%d, policyFlags=0x%x",
-            when, deviceId, action, flags, keyCode, scanCode, policyFlags);
-#endif
-
-    bool down = action == AKEY_EVENT_ACTION_DOWN;
-    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
-        policyFlags |= POLICY_FLAG_VIRTUAL;
-        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
-
-        if (down) {
-            JNIEnv* env = jniEnv();
-            env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
-            checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
-        }
-    }
-
-    const int32_t WM_ACTION_PASS_TO_USER = 1;
-    const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
-    const int32_t WM_ACTION_GO_TO_SLEEP = 4;
-
-    bool isScreenOn = this->isScreenOn();
-    bool isScreenBright = this->isScreenBright();
-
-    jint wmActions = 0;
-    if (isPolicyKey(keyCode, isScreenOn)) {
-        JNIEnv* env = jniEnv();
-
-        wmActions = env->CallIntMethod(mCallbacksObj,
-                gCallbacksClassInfo.interceptKeyBeforeQueueing,
-                when, keyCode, down, policyFlags, isScreenOn);
-        if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
-            wmActions = 0;
-        }
-    } else {
-        wmActions = WM_ACTION_PASS_TO_USER;
-    }
-
-    if (! isScreenOn) {
-        // Key presses and releases wake the device.
-        policyFlags |= POLICY_FLAG_WOKE_HERE;
-        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-    }
-
-    if (! isScreenBright) {
-        // Key presses and releases brighten the screen if dimmed.
-        policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-    }
-
-    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-        android_server_PowerManagerService_goToSleep(when);
-    }
-
-    if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
-        android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
-    }
-
-    if (wmActions & WM_ACTION_PASS_TO_USER) {
-        policyFlags |= POLICY_FLAG_PASS_TO_USER;
-    }
-}
-
-void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
-#endif
-
-    if (isScreenOn()) {
-        // Only dispatch events when the device is awake.
-        // Do not wake the device.
-        policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
-        if (! isScreenBright()) {
-            // Brighten the screen if dimmed.
-            policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-        }
-    }
-}
-
-void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
-        int32_t switchValue, uint32_t policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
-            when, switchCode, switchValue, policyFlags);
-#endif
-
-    JNIEnv* env = jniEnv();
-
-    switch (switchCode) {
-    case SW_LID:
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
-                when, switchValue == 0);
-        checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
-        break;
-    }
-}
-
 bool NativeInputManager::filterTouchEvents() {
     if (mFilterTouchEvents < 0) {
         JNIEnv* env = jniEnv();
@@ -692,6 +550,24 @@
     }
 }
 
+void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
+        int32_t switchValue, uint32_t policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    LOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
+            when, switchCode, switchValue, policyFlags);
+#endif
+
+    JNIEnv* env = jniEnv();
+
+    switch (switchCode) {
+    case SW_LID:
+        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
+                when, switchValue == 0);
+        checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
+        break;
+    }
+}
+
 void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     LOGD("notifyConfigurationChanged - when=%lld", when);
@@ -944,13 +820,88 @@
     mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
 }
 
-bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
-        const KeyEvent* keyEvent, uint32_t policyFlags) {
-    bool isScreenOn = this->isScreenOn();
-    if (! isPolicyKey(keyEvent->getKeyCode(), isScreenOn)) {
-        return false;
+bool NativeInputManager::isScreenOn() {
+    return android_server_PowerManagerService_isScreenOn();
+}
+
+bool NativeInputManager::isScreenBright() {
+    return android_server_PowerManagerService_isScreenBright();
+}
+
+void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
+        int32_t deviceId, int32_t action, int32_t &flags,
+        int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, "
+            "keyCode=%d, scanCode=%d, policyFlags=0x%x",
+            when, deviceId, action, flags, keyCode, scanCode, policyFlags);
+#endif
+
+    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
+        policyFlags |= POLICY_FLAG_VIRTUAL;
+        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
     }
 
+    const int32_t WM_ACTION_PASS_TO_USER = 1;
+    const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
+    const int32_t WM_ACTION_GO_TO_SLEEP = 4;
+
+    bool isScreenOn = this->isScreenOn();
+    bool isScreenBright = this->isScreenBright();
+
+    JNIEnv* env = jniEnv();
+    jint wmActions = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.interceptKeyBeforeQueueing,
+            when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
+    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+        wmActions = 0;
+    }
+
+    if (policyFlags & POLICY_FLAG_TRUSTED) {
+        if (! isScreenOn) {
+            // Key presses and releases wake the device.
+            policyFlags |= POLICY_FLAG_WOKE_HERE;
+            flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+        }
+
+        if (! isScreenBright) {
+            // Key presses and releases brighten the screen if dimmed.
+            policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+        }
+
+        if (wmActions & WM_ACTION_GO_TO_SLEEP) {
+            android_server_PowerManagerService_goToSleep(when);
+        }
+
+        if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
+            android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
+        }
+    }
+
+    if (wmActions & WM_ACTION_PASS_TO_USER) {
+        policyFlags |= POLICY_FLAG_PASS_TO_USER;
+    }
+}
+
+void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
+#endif
+
+    if (isScreenOn()) {
+        // Only dispatch events when the device is awake.
+        // Do not wake the device.
+        policyFlags |= POLICY_FLAG_PASS_TO_USER;
+
+        if ((policyFlags & POLICY_FLAG_TRUSTED) && !isScreenBright()) {
+            // Brighten the screen if dimmed.
+            policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+        }
+    }
+}
+
+bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
+        const KeyEvent* keyEvent, uint32_t policyFlags) {
     JNIEnv* env = jniEnv();
 
     // Note: inputChannel may be null.
@@ -1365,9 +1316,6 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
             "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
 
-    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
-            "virtualKeyDownFeedback", "()V");
-
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
             "interceptKeyBeforeQueueing", "(JIZIZ)I");