Added more robust tracking and cancelation of events.

This change fixes several issues where events would be dropped in the
input dispatch pipeline in such a way that the dispatcher could not
accurately track the state of the input device.

Given more robust tracking, we can now also provide robust cancelation
of input events in cases where an application might otherwise become
out of sync with the event stream due to ANR, app switch, policy decisions,
or forced focus transitions.

Pruned some of the input dispatcher log output.

Moved the responsibility for calling intercept*BeforeQueueing into
the input dispatcher instead of the input reader and added support for
early interception of injected events for events coming from trusted
sources.  This enables behaviors like injection of media keys while
the screen is off, haptic feedback of injected virtual keys, so injected
events become more "first class" in a way.

Change-Id: Iec6ff1dd21e5f3c7feb80ea4feb5382bd090dbd9
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index fe8555d..58c2cdf 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,16 +95,19 @@
     return true;
 }
 
-static bool isValidMotionAction(int32_t action) {
+static bool isValidMotionAction(int32_t action, size_t pointerCount) {
     switch (action & AMOTION_EVENT_ACTION_MASK) {
     case AMOTION_EVENT_ACTION_DOWN:
     case AMOTION_EVENT_ACTION_UP:
     case AMOTION_EVENT_ACTION_CANCEL:
     case AMOTION_EVENT_ACTION_MOVE:
-    case AMOTION_EVENT_ACTION_POINTER_DOWN:
-    case AMOTION_EVENT_ACTION_POINTER_UP:
     case AMOTION_EVENT_ACTION_OUTSIDE:
         return true;
+    case AMOTION_EVENT_ACTION_POINTER_DOWN:
+    case AMOTION_EVENT_ACTION_POINTER_UP: {
+        int32_t index = getMotionEventActionPointerIndex(action);
+        return index >= 0 && size_t(index) < pointerCount;
+    }
     default:
         return false;
     }
@@ -112,7 +115,7 @@
 
 static bool validateMotionEvent(int32_t action, size_t pointerCount,
         const int32_t* pointerIds) {
-    if (! isValidMotionAction(action)) {
+    if (! isValidMotionAction(action, pointerCount)) {
         LOGE("Motion event has invalid action code 0x%x", action);
         return false;
     }
@@ -235,16 +238,6 @@
         resetKeyRepeatLocked();
     }
 
-    // If dispatching is disabled, drop all events in the queue.
-    if (! mDispatchEnabled) {
-        if (mPendingEvent || ! mInboundQueue.isEmpty()) {
-            LOGI("Dropping pending events because input dispatch is disabled.");
-            releasePendingEventLocked();
-            drainInboundQueueLocked();
-        }
-        return;
-    }
-
     // If dispatching is frozen, do not process timeouts or try to deliver any new events.
     if (mDispatchFrozen) {
 #if DEBUG_FOCUS
@@ -294,7 +287,11 @@
             // samples may be appended to this event by the time the throttling timeout
             // expires.
             // TODO Make this smarter and consider throttling per device independently.
-            if (entry->type == EventEntry::TYPE_MOTION) {
+            if (entry->type == EventEntry::TYPE_MOTION
+                    && !isAppSwitchDue
+                    && mDispatchEnabled
+                    && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
+                    && !entry->isInjected()) {
                 MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
                 int32_t deviceId = motionEntry->deviceId;
                 uint32_t source = motionEntry->source;
@@ -347,39 +344,43 @@
     // Now we have an event to dispatch.
     assert(mPendingEvent != NULL);
     bool done = false;
+    DropReason dropReason = DROP_REASON_NOT_DROPPED;
+    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
+        dropReason = DROP_REASON_POLICY;
+    } else if (!mDispatchEnabled) {
+        dropReason = DROP_REASON_DISABLED;
+    }
     switch (mPendingEvent->type) {
     case EventEntry::TYPE_CONFIGURATION_CHANGED: {
         ConfigurationChangedEntry* typedEntry =
                 static_cast<ConfigurationChangedEntry*>(mPendingEvent);
         done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
+        dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
         break;
     }
 
     case EventEntry::TYPE_KEY: {
         KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
-        bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode);
-        bool dropEvent = isAppSwitchDue && ! appSwitchKey;
-        done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent,
-                nextWakeupTime);
-        if (done) {
-            if (dropEvent) {
-                LOGI("Dropped key because of pending overdue app switch.");
-            } else if (appSwitchKey) {
+        if (isAppSwitchDue) {
+            if (isAppSwitchKeyEventLocked(typedEntry)) {
                 resetPendingAppSwitchLocked(true);
+                isAppSwitchDue = false;
+            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
+                dropReason = DROP_REASON_APP_SWITCH;
             }
         }
+        done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
+                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
         break;
     }
 
     case EventEntry::TYPE_MOTION: {
         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
-        bool dropEvent = isAppSwitchDue;
-        done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime);
-        if (done) {
-            if (dropEvent) {
-                LOGI("Dropped motion because of pending overdue app switch.");
-            }
+        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
+            dropReason = DROP_REASON_APP_SWITCH;
         }
+        done = dispatchMotionLocked(currentTime, typedEntry,
+                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
         break;
     }
 
@@ -389,6 +390,10 @@
     }
 
     if (done) {
+        if (dropReason != DROP_REASON_NOT_DROPPED) {
+            dropInboundEventLocked(mPendingEvent, dropReason);
+        }
+
         releasePendingEventLocked();
         *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
     }
@@ -399,36 +404,83 @@
     mInboundQueue.enqueueAtTail(entry);
 
     switch (entry->type) {
-    case EventEntry::TYPE_KEY:
-        needWake |= detectPendingAppSwitchLocked(static_cast<KeyEntry*>(entry));
+    case EventEntry::TYPE_KEY: {
+        KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
+        if (isAppSwitchKeyEventLocked(keyEntry)) {
+            if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
+                mAppSwitchSawKeyDown = true;
+            } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+                if (mAppSwitchSawKeyDown) {
+#if DEBUG_APP_SWITCH
+                    LOGD("App switch is pending!");
+#endif
+                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
+                    mAppSwitchSawKeyDown = false;
+                    needWake = true;
+                }
+            }
+        }
         break;
     }
+    }
 
     return needWake;
 }
 
-bool InputDispatcher::isAppSwitchKey(int32_t keyCode) {
+void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
+    const char* reason;
+    switch (dropReason) {
+    case DROP_REASON_POLICY:
+        reason = "inbound event was dropped because the policy requested that it not be "
+                "delivered to the application";
+        break;
+    case DROP_REASON_DISABLED:
+        LOGI("Dropped event because input dispatch is disabled.");
+        reason = "inbound event was dropped because input dispatch is disabled";
+        break;
+    case DROP_REASON_APP_SWITCH:
+        LOGI("Dropped event because of pending overdue app switch.");
+        reason = "inbound event was dropped because of pending overdue app switch";
+        break;
+    default:
+        assert(false);
+        return;
+    }
+
+    switch (entry->type) {
+    case EventEntry::TYPE_KEY:
+        synthesizeCancelationEventsForAllConnectionsLocked(
+                InputState::CANCEL_NON_POINTER_EVENTS, reason);
+        break;
+    case EventEntry::TYPE_MOTION: {
+        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
+        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+            synthesizeCancelationEventsForAllConnectionsLocked(
+                    InputState::CANCEL_POINTER_EVENTS, reason);
+        } else {
+            synthesizeCancelationEventsForAllConnectionsLocked(
+                    InputState::CANCEL_NON_POINTER_EVENTS, reason);
+        }
+        break;
+    }
+    }
+}
+
+bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
     return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
 }
 
+bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
+    return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
+            && isAppSwitchKeyCode(keyEntry->keyCode)
+            && isEventFromTrustedSourceLocked(keyEntry)
+            && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
+}
+
 bool InputDispatcher::isAppSwitchPendingLocked() {
     return mAppSwitchDueTime != LONG_LONG_MAX;
 }
 
-bool InputDispatcher::detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry) {
-    if (inboundKeyEntry->action == AKEY_EVENT_ACTION_UP
-            && ! (inboundKeyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
-            && isAppSwitchKey(inboundKeyEntry->keyCode)
-            && isEventFromReliableSourceLocked(inboundKeyEntry)) {
-#if DEBUG_APP_SWITCH
-        LOGD("App switch is pending!");
-#endif
-        mAppSwitchDueTime = inboundKeyEntry->eventTime + APP_SWITCH_TIMEOUT;
-        return true; // need wake
-    }
-    return false;
-}
-
 void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
     mAppSwitchDueTime = LONG_LONG_MAX;
 
@@ -489,12 +541,10 @@
     mAllocator.releaseEventEntry(entry);
 }
 
-bool InputDispatcher::isEventFromReliableSourceLocked(EventEntry* entry) {
+bool InputDispatcher::isEventFromTrustedSourceLocked(EventEntry* entry) {
     InjectionState* injectionState = entry->injectionState;
     return ! injectionState
-            || injectionState->injectorUid == 0
-            || mPolicy->checkInjectEventsPermissionNonReentrant(
-                    injectionState->injectorPid, injectionState->injectorUid);
+            || hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid);
 }
 
 void InputDispatcher::resetKeyRepeatLocked() {
@@ -509,7 +559,7 @@
     KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
 
     // Reuse the repeated key entry if it is otherwise unreferenced.
-    uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
+    uint32_t policyFlags = entry->policyFlags & (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER);
     if (entry->refCount == 1) {
         mAllocator.recycleKeyEntry(entry);
         entry->eventTime = currentTime;
@@ -565,7 +615,7 @@
         if (! dropEvent && mFocusedWindow) {
             trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState);
         } else {
-            trusted = isEventFromReliableSourceLocked(entry);
+            trusted = isEventFromTrustedSourceLocked(entry);
         }
         if (trusted) {
             CommandEntry* commandEntry = postCommandLocked(
@@ -793,9 +843,11 @@
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
                     resumeWithAppendedMotionSample);
         } else {
-            LOGW("Framework requested delivery of an input event to channel '%s' but it "
-                    "is not registered with the input dispatcher.",
+#if DEBUG_FOCUS
+            LOGD("Dropping event delivery to target with channel '%s' because it "
+                    "is no longer registered with the input dispatcher.",
                     inputTarget.inputChannel->getName().string());
+#endif
         }
     }
 }
@@ -876,7 +928,9 @@
             ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
             if (connectionIndex >= 0) {
                 sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-                connection->inputState.setOutOfSync();
+                synthesizeCancelationEventsForConnectionLocked(
+                        connection, InputState::CANCEL_ALL_EVENTS,
+                        "application not responding");
             }
         }
     }
@@ -1236,7 +1290,9 @@
         } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
             // First pointer went down.
             if (mTouchState.down) {
-                LOGW("Pointer down received while already down.");
+#if DEBUG_FOCUS
+                LOGD("Pointer down received while already down.");
+#endif
             }
         } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
             // One pointer went up.
@@ -1307,23 +1363,19 @@
 bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
         const InjectionState* injectionState) {
     if (injectionState
-            && injectionState->injectorUid > 0
-            && (window == NULL || window->ownerUid != injectionState->injectorUid)) {
-        bool result = mPolicy->checkInjectEventsPermissionNonReentrant(
-                injectionState->injectorPid, injectionState->injectorUid);
-        if (! result) {
-            if (window) {
-                LOGW("Permission denied: injecting event from pid %d uid %d to window "
-                        "with input channel %s owned by uid %d",
-                        injectionState->injectorPid, injectionState->injectorUid,
-                        window->inputChannel->getName().string(),
-                        window->ownerUid);
-            } else {
-                LOGW("Permission denied: injecting event from pid %d uid %d",
-                        injectionState->injectorPid, injectionState->injectorUid);
-            }
-            return false;
+            && (window == NULL || window->ownerUid != injectionState->injectorUid)
+            && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
+        if (window) {
+            LOGW("Permission denied: injecting event from pid %d uid %d to window "
+                    "with input channel %s owned by uid %d",
+                    injectionState->injectorPid, injectionState->injectorUid,
+                    window->inputChannel->getName().string(),
+                    window->ownerUid);
+        } else {
+            LOGW("Permission denied: injecting event from pid %d uid %d",
+                    injectionState->injectorPid, injectionState->injectorUid);
         }
+        return false;
     }
     return true;
 }
@@ -1408,8 +1460,10 @@
     // Skip this event if the connection status is not normal.
     // We don't want to enqueue additional outbound events if the connection is broken.
     if (connection->status != Connection::STATUS_NORMAL) {
-        LOGW("channel '%s' ~ Dropping event because the channel status is %s",
+#if DEBUG_DISPATCH_CYCLE
+        LOGD("channel '%s' ~ Dropping event because the channel status is %s",
                 connection->getInputChannelName(), connection->getStatusLabel());
+#endif
         return;
     }
 
@@ -1508,40 +1562,6 @@
         }
     }
 
-    // Bring the input state back in line with reality in case it drifted off during an ANR.
-    if (connection->inputState.isOutOfSync()) {
-        mTempCancelationEvents.clear();
-        connection->inputState.synthesizeCancelationEvents(& mAllocator, mTempCancelationEvents);
-        connection->inputState.resetOutOfSync();
-
-        if (! mTempCancelationEvents.isEmpty()) {
-            LOGI("channel '%s' ~ Generated %d cancelation events to bring channel back in sync "
-                    "with reality.",
-                    connection->getInputChannelName(), mTempCancelationEvents.size());
-
-            for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
-                EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
-                switch (cancelationEventEntry->type) {
-                case EventEntry::TYPE_KEY:
-                    logOutboundKeyDetailsLocked("  ",
-                            static_cast<KeyEntry*>(cancelationEventEntry));
-                    break;
-                case EventEntry::TYPE_MOTION:
-                    logOutboundMotionDetailsLocked("  ",
-                            static_cast<MotionEntry*>(cancelationEventEntry));
-                    break;
-                }
-
-                DispatchEntry* cancelationDispatchEntry =
-                        mAllocator.obtainDispatchEntry(cancelationEventEntry,
-                        0, inputTarget->xOffset, inputTarget->yOffset); // increments ref
-                connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
-
-                mAllocator.releaseEventEntry(cancelationEventEntry);
-            }
-        }
-    }
-
     // This is a new event.
     // Enqueue a new dispatch entry onto the outbound queue for this connection.
     DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
@@ -1635,7 +1655,7 @@
         if (status) {
             LOGE("channel '%s' ~ Could not publish key event, "
                     "status=%d", connection->getInputChannelName(), status);
-            abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+            abortBrokenDispatchCycleLocked(currentTime, connection);
             return;
         }
         break;
@@ -1685,7 +1705,7 @@
         if (status) {
             LOGE("channel '%s' ~ Could not publish motion event, "
                     "status=%d", connection->getInputChannelName(), status);
-            abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+            abortBrokenDispatchCycleLocked(currentTime, connection);
             return;
         }
 
@@ -1706,7 +1726,7 @@
                 LOGE("channel '%s' ~ Could not append motion sample "
                         "for a reason other than out of memory, status=%d",
                         connection->getInputChannelName(), status);
-                abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+                abortBrokenDispatchCycleLocked(currentTime, connection);
                 return;
             }
         }
@@ -1727,7 +1747,7 @@
     if (status) {
         LOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
                 connection->getInputChannelName(), status);
-        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+        abortBrokenDispatchCycleLocked(currentTime, connection);
         return;
     }
 
@@ -1764,7 +1784,7 @@
     if (status) {
         LOGE("channel '%s' ~ Could not reset publisher, status=%d",
                 connection->getInputChannelName(), status);
-        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+        abortBrokenDispatchCycleLocked(currentTime, connection);
         return;
     }
 
@@ -1806,28 +1826,23 @@
     deactivateConnectionLocked(connection.get());
 }
 
-void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, bool broken) {
+void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
-    LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
+    LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s",
             connection->getInputChannelName(), toString(broken));
 #endif
 
-    // Input state will no longer be realistic.
-    connection->inputState.setOutOfSync();
-
     // Clear the outbound queue.
     drainOutboundQueueLocked(connection.get());
 
-    // Handle the case where the connection appears to be unrecoverably broken.
+    // The connection appears to be unrecoverably broken.
     // Ignore already broken or zombie connections.
-    if (broken) {
-        if (connection->status == Connection::STATUS_NORMAL) {
-            connection->status = Connection::STATUS_BROKEN;
+    if (connection->status == Connection::STATUS_NORMAL) {
+        connection->status = Connection::STATUS_BROKEN;
 
-            // Notify other system components.
-            onDispatchCycleBrokenLocked(currentTime, connection);
-        }
+        // Notify other system components.
+        onDispatchCycleBrokenLocked(currentTime, connection);
     }
 }
 
@@ -1862,7 +1877,7 @@
         if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
             LOGE("channel '%s' ~ Consumer closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+            d->abortBrokenDispatchCycleLocked(currentTime, connection);
             d->runCommandsLockedInterruptible();
             return 0; // remove the callback
         }
@@ -1877,7 +1892,7 @@
         if (status) {
             LOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
                     connection->getInputChannelName(), status);
-            d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+            d->abortBrokenDispatchCycleLocked(currentTime, connection);
             d->runCommandsLockedInterruptible();
             return 0; // remove the callback
         }
@@ -1888,6 +1903,77 @@
     } // release lock
 }
 
+void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
+        InputState::CancelationOptions options, const char* reason) {
+    for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+        synthesizeCancelationEventsForConnectionLocked(
+                mConnectionsByReceiveFd.valueAt(i), options, reason);
+    }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
+        const sp<InputChannel>& channel, InputState::CancelationOptions options,
+        const char* reason) {
+    ssize_t index = getConnectionIndexLocked(channel);
+    if (index >= 0) {
+        synthesizeCancelationEventsForConnectionLocked(
+                mConnectionsByReceiveFd.valueAt(index), options, reason);
+    }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
+        const sp<Connection>& connection, InputState::CancelationOptions options,
+        const char* reason) {
+    nsecs_t currentTime = now();
+
+    mTempCancelationEvents.clear();
+    connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator,
+            mTempCancelationEvents, options);
+
+    if (! mTempCancelationEvents.isEmpty()
+            && connection->status != Connection::STATUS_BROKEN) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+        LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+                "with reality: %s, options=%d.",
+                connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
+#endif
+        for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
+            EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+            switch (cancelationEventEntry->type) {
+            case EventEntry::TYPE_KEY:
+                logOutboundKeyDetailsLocked("cancel - ",
+                        static_cast<KeyEntry*>(cancelationEventEntry));
+                break;
+            case EventEntry::TYPE_MOTION:
+                logOutboundMotionDetailsLocked("cancel - ",
+                        static_cast<MotionEntry*>(cancelationEventEntry));
+                break;
+            }
+
+            int32_t xOffset, yOffset;
+            const InputWindow* window = getWindowLocked(connection->inputChannel);
+            if (window) {
+                xOffset = -window->frameLeft;
+                yOffset = -window->frameTop;
+            } else {
+                xOffset = 0;
+                yOffset = 0;
+            }
+
+            DispatchEntry* cancelationDispatchEntry =
+                    mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
+                    0, xOffset, yOffset);
+            connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
+
+            mAllocator.releaseEventEntry(cancelationEventEntry);
+        }
+
+        if (!connection->outboundQueue.headSentinel.next->inProgress) {
+            startDispatchCycleLocked(currentTime, connection);
+        }
+    }
+}
+
 InputDispatcher::MotionEntry*
 InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) {
     assert(pointerIds.value != 0);
@@ -1999,6 +2085,9 @@
         return;
     }
 
+    mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+            keyCode, scanCode, /*byref*/ policyFlags);
+
     bool needWake;
     { // acquire lock
         AutoMutex _l(mLock);
@@ -2041,6 +2130,8 @@
         return;
     }
 
+    mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
+
     bool needWake;
     { // acquire lock
         AutoMutex _l(mLock);
@@ -2165,6 +2256,16 @@
     }
 }
 
+void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+        uint32_t policyFlags) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x",
+            switchCode, switchValue, policyFlags);
+#endif
+
+    mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags);
+}
+
 int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
         int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
 #if DEBUG_INBOUND_EVENT_DETAILS
@@ -2174,27 +2275,84 @@
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
+    bool trusted = hasInjectionPermission(injectorPid, injectorUid);
 
-    InjectionState* injectionState;
-    bool needWake;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        EventEntry* injectedEntry = createEntryFromInjectedInputEventLocked(event);
-        if (! injectedEntry) {
+    EventEntry* injectedEntry;
+    switch (event->getType()) {
+    case AINPUT_EVENT_TYPE_KEY: {
+        const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
+        int32_t action = keyEvent->getAction();
+        if (! validateKeyEvent(action)) {
             return INPUT_EVENT_INJECTION_FAILED;
         }
 
-        injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
-        if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
-            injectionState->injectionIsAsync = true;
+        nsecs_t eventTime = keyEvent->getEventTime();
+        int32_t deviceId = keyEvent->getDeviceId();
+        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);
         }
 
-        injectionState->refCount += 1;
-        injectedEntry->injectionState = injectionState;
+        mLock.lock();
+        injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
+                policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+                keyEvent->getRepeatCount(), keyEvent->getDownTime());
+        break;
+    }
 
-        needWake = enqueueInboundEventLocked(injectedEntry);
-    } // release lock
+    case AINPUT_EVENT_TYPE_MOTION: {
+        const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
+        int32_t action = motionEvent->getAction();
+        size_t pointerCount = motionEvent->getPointerCount();
+        const int32_t* pointerIds = motionEvent->getPointerIds();
+        if (! validateMotionEvent(action, pointerCount, pointerIds)) {
+            return INPUT_EVENT_INJECTION_FAILED;
+        }
+
+        nsecs_t eventTime = motionEvent->getEventTime();
+        uint32_t policyFlags = POLICY_FLAG_INJECTED;
+        if (trusted) {
+            mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
+        }
+
+        mLock.lock();
+        const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
+        const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
+        MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
+                motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+                action, motionEvent->getFlags(),
+                motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
+                motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+                motionEvent->getDownTime(), uint32_t(pointerCount),
+                pointerIds, samplePointerCoords);
+        for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
+            sampleEventTimes += 1;
+            samplePointerCoords += pointerCount;
+            mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
+        }
+        injectedEntry = motionEntry;
+        break;
+    }
+
+    default:
+        LOGW("Cannot inject event of type %d", event->getType());
+        return INPUT_EVENT_INJECTION_FAILED;
+    }
+
+    InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
+    if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+        injectionState->injectionIsAsync = true;
+    }
+
+    injectionState->refCount += 1;
+    injectedEntry->injectionState = injectionState;
+
+    bool needWake = enqueueInboundEventLocked(injectedEntry);
+    mLock.unlock();
 
     if (needWake) {
         mLooper->wake();
@@ -2260,6 +2418,11 @@
     return injectionResult;
 }
 
+bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
+    return injectorUid == 0
+            || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
+}
+
 void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
     InjectionState* injectionState = entry->injectionState;
     if (injectionState) {
@@ -2310,59 +2473,6 @@
     }
 }
 
-InputDispatcher::EventEntry* InputDispatcher::createEntryFromInjectedInputEventLocked(
-        const InputEvent* event) {
-    switch (event->getType()) {
-    case AINPUT_EVENT_TYPE_KEY: {
-        const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
-        if (! validateKeyEvent(keyEvent->getAction())) {
-            return NULL;
-        }
-
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
-        KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
-                keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags,
-                keyEvent->getAction(), keyEvent->getFlags(),
-                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
-                keyEvent->getRepeatCount(), keyEvent->getDownTime());
-        return keyEntry;
-    }
-
-    case AINPUT_EVENT_TYPE_MOTION: {
-        const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
-        if (! validateMotionEvent(motionEvent->getAction(),
-                motionEvent->getPointerCount(), motionEvent->getPointerIds())) {
-            return NULL;
-        }
-
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
-        const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
-        const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-        size_t pointerCount = motionEvent->getPointerCount();
-
-        MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
-                motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
-                motionEvent->getAction(), motionEvent->getFlags(),
-                motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
-                motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                motionEvent->getDownTime(), uint32_t(pointerCount),
-                motionEvent->getPointerIds(), samplePointerCoords);
-        for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
-            sampleEventTimes += 1;
-            samplePointerCoords += pointerCount;
-            mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
-        }
-        return motionEntry;
-    }
-
-    default:
-        assert(false);
-        return NULL;
-    }
-}
-
 const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
     for (size_t i = 0; i < mWindows.size(); i++) {
         const InputWindow* window = & mWindows[i];
@@ -2381,7 +2491,12 @@
         AutoMutex _l(mLock);
 
         // Clear old window pointers.
-        mFocusedWindow = NULL;
+        sp<InputChannel> oldFocusedWindowChannel;
+        if (mFocusedWindow) {
+            oldFocusedWindowChannel = mFocusedWindow->inputChannel;
+            mFocusedWindow = NULL;
+        }
+
         mWindows.clear();
 
         // Loop over new windows and rebuild the necessary window pointers for
@@ -2397,6 +2512,24 @@
             }
         }
 
+        if (oldFocusedWindowChannel != NULL) {
+            if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+#if DEBUG_FOCUS
+                LOGD("Focus left window: %s",
+                        oldFocusedWindowChannel->getName().string());
+#endif
+                synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
+                        InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
+                oldFocusedWindowChannel.clear();
+            }
+        }
+        if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+#if DEBUG_FOCUS
+            LOGD("Focus entered window: %s",
+                    mFocusedWindow->inputChannel->getName().string());
+#endif
+        }
+
         for (size_t i = 0; i < mTouchState.windows.size(); ) {
             TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
             const InputWindow* window = getWindowLocked(touchedWindow.channel);
@@ -2404,12 +2537,17 @@
                 touchedWindow.window = window;
                 i += 1;
             } else {
+#if DEBUG_FOCUS
+                LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+#endif
                 mTouchState.windows.removeAt(i);
+                synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
+                        InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
             }
         }
 
 #if DEBUG_FOCUS
-        logDispatchStateLocked();
+        //logDispatchStateLocked();
 #endif
     } // release lock
 
@@ -2432,7 +2570,7 @@
         }
 
 #if DEBUG_FOCUS
-        logDispatchStateLocked();
+        //logDispatchStateLocked();
 #endif
     } // release lock
 
@@ -2469,7 +2607,7 @@
         }
 
 #if DEBUG_FOCUS
-        logDispatchStateLocked();
+        //logDispatchStateLocked();
 #endif
     } // release lock
 
@@ -2571,11 +2709,10 @@
         for (size_t i = 0; i < mActiveConnections.size(); i++) {
             const Connection* connection = mActiveConnections[i];
             dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u"
-                    "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n",
+                    "inputState.isNeutral=%s\n",
                     i, connection->getInputChannelName(), connection->getStatusLabel(),
                     connection->outboundQueue.count(),
-                    toString(connection->inputState.isNeutral()),
-                    toString(connection->inputState.isOutOfSync()));
+                    toString(connection->inputState.isNeutral()));
         }
     } else {
         dump.append(INDENT "ActiveConnections: <none>\n");
@@ -2656,7 +2793,7 @@
         mLooper->removeFd(inputChannel->getReceivePipeFd());
 
         nsecs_t currentTime = now();
-        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+        abortBrokenDispatchCycleLocked(currentTime, connection);
 
         runCommandsLockedInterruptible();
     } // release lock
@@ -2837,11 +2974,12 @@
 }
 
 void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type,
-        nsecs_t eventTime) {
+        nsecs_t eventTime, uint32_t policyFlags) {
     entry->type = type;
     entry->refCount = 1;
     entry->dispatchInProgress = false;
     entry->eventTime = eventTime;
+    entry->policyFlags = policyFlags;
     entry->injectionState = NULL;
 }
 
@@ -2855,7 +2993,7 @@
 InputDispatcher::ConfigurationChangedEntry*
 InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) {
     ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
-    initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime);
+    initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0);
     return entry;
 }
 
@@ -2864,11 +3002,10 @@
         int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
         int32_t repeatCount, nsecs_t downTime) {
     KeyEntry* entry = mKeyEntryPool.alloc();
-    initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime);
+    initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags);
 
     entry->deviceId = deviceId;
     entry->source = source;
-    entry->policyFlags = policyFlags;
     entry->action = action;
     entry->flags = flags;
     entry->keyCode = keyCode;
@@ -2887,12 +3024,11 @@
         nsecs_t downTime, uint32_t pointerCount,
         const int32_t* pointerIds, const PointerCoords* pointerCoords) {
     MotionEntry* entry = mMotionEntryPool.alloc();
-    initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime);
+    initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags);
 
     entry->eventTime = eventTime;
     entry->deviceId = deviceId;
     entry->source = source;
-    entry->policyFlags = policyFlags;
     entry->action = action;
     entry->flags = flags;
     entry->metaState = metaState;
@@ -3039,8 +3175,7 @@
 
 // --- InputDispatcher::InputState ---
 
-InputDispatcher::InputState::InputState() :
-        mIsOutOfSync(false) {
+InputDispatcher::InputState::InputState() {
 }
 
 InputDispatcher::InputState::~InputState() {
@@ -3050,20 +3185,6 @@
     return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
 }
 
-bool InputDispatcher::InputState::isOutOfSync() const {
-    return mIsOutOfSync;
-}
-
-void InputDispatcher::InputState::setOutOfSync() {
-    if (! isNeutral()) {
-        mIsOutOfSync = true;
-    }
-}
-
-void InputDispatcher::InputState::resetOutOfSync() {
-    mIsOutOfSync = false;
-}
-
 InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent(
         const EventEntry* entry) {
     switch (entry->type) {
@@ -3090,9 +3211,6 @@
             switch (action) {
             case AKEY_EVENT_ACTION_UP:
                 mKeyMementos.removeAt(i);
-                if (isNeutral()) {
-                    mIsOutOfSync = false;
-                }
                 return CONSISTENT;
 
             case AKEY_EVENT_ACTION_DOWN:
@@ -3132,9 +3250,6 @@
             case AMOTION_EVENT_ACTION_UP:
             case AMOTION_EVENT_ACTION_CANCEL:
                 mMotionMementos.removeAt(i);
-                if (isNeutral()) {
-                    mIsOutOfSync = false;
-                }
                 return CONSISTENT;
 
             case AMOTION_EVENT_ACTION_DOWN:
@@ -3192,30 +3307,52 @@
     }
 }
 
-void InputDispatcher::InputState::synthesizeCancelationEvents(
-        Allocator* allocator, Vector<EventEntry*>& outEvents) const {
-    for (size_t i = 0; i < mKeyMementos.size(); i++) {
+void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
+        Allocator* allocator, Vector<EventEntry*>& outEvents,
+        CancelationOptions options) {
+    for (size_t i = 0; i < mKeyMementos.size(); ) {
         const KeyMemento& memento = mKeyMementos.itemAt(i);
-        outEvents.push(allocator->obtainKeyEntry(now(),
-                memento.deviceId, memento.source, 0,
-                AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
-                memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+        if (shouldCancelEvent(memento.source, options)) {
+            outEvents.push(allocator->obtainKeyEntry(currentTime,
+                    memento.deviceId, memento.source, 0,
+                    AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
+                    memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+            mKeyMementos.removeAt(i);
+        } else {
+            i += 1;
+        }
     }
 
     for (size_t i = 0; i < mMotionMementos.size(); i++) {
         const MotionMemento& memento = mMotionMementos.itemAt(i);
-        outEvents.push(allocator->obtainMotionEntry(now(),
-                memento.deviceId, memento.source, 0,
-                AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
-                memento.xPrecision, memento.yPrecision, memento.downTime,
-                memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+        if (shouldCancelEvent(memento.source, options)) {
+            outEvents.push(allocator->obtainMotionEntry(currentTime,
+                    memento.deviceId, memento.source, 0,
+                    AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
+                    memento.xPrecision, memento.yPrecision, memento.downTime,
+                    memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+            mMotionMementos.removeAt(i);
+        } else {
+            i += 1;
+        }
     }
 }
 
 void InputDispatcher::InputState::clear() {
     mKeyMementos.clear();
     mMotionMementos.clear();
-    mIsOutOfSync = false;
+}
+
+bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
+        CancelationOptions options) {
+    switch (options) {
+    case CANCEL_POINTER_EVENTS:
+        return eventSource & AINPUT_SOURCE_CLASS_POINTER;
+    case CANCEL_NON_POINTER_EVENTS:
+        return !(eventSource & AINPUT_SOURCE_CLASS_POINTER);
+    default:
+        return true;
+    }
 }
 
 
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 7adc764..0560bb8 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -796,10 +796,6 @@
     return 0;
 }
 
-bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
-    return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
-}
-
 
 // --- SwitchInputMapper ---
 
@@ -823,11 +819,7 @@
 }
 
 void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) {
-    uint32_t policyFlags = 0;
-    int32_t policyActions = getPolicy()->interceptSwitch(
-            when, switchCode, switchValue, policyFlags);
-
-    applyStandardPolicyActions(when, policyActions);
+    getDispatcher()->notifySwitch(when, switchCode, switchValue, 0);
 }
 
 int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
@@ -983,29 +975,9 @@
         getContext()->updateGlobalMetaState();
     }
 
-    applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime);
-}
-
-void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down,
-        int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
-    int32_t policyActions = getPolicy()->interceptKey(when,
-            getDeviceId(), down, keyCode, scanCode, policyFlags);
-
-    if (! applyStandardPolicyActions(when, policyActions)) {
-        return; // event dropped
-    }
-
-    int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
-    int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
-    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-        keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
-    }
-    if (policyFlags & POLICY_FLAG_VIRTUAL) {
-        keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
-    }
-
     getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
 }
 
 ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) {
@@ -1215,26 +1187,13 @@
         }
     } // release lock
 
-    applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
-
-    mAccumulator.clear();
-}
-
-void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
-        PointerCoords* pointerCoords, nsecs_t downTime) {
-    uint32_t policyFlags = 0;
-    int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
-    if (! applyStandardPolicyActions(when, policyActions)) {
-        return; // event dropped
-    }
-
     int32_t metaState = mContext->getGlobalMetaState();
     int32_t pointerId = 0;
-
-    getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
+    getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0,
             motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
+            1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
+
+    mAccumulator.clear();
 }
 
 int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
@@ -2012,15 +1971,7 @@
 }
 
 void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
-    // Apply generic policy actions.
-
     uint32_t policyFlags = 0;
-    int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
-    if (! applyStandardPolicyActions(when, policyActions)) {
-        mLastTouch.clear();
-        return; // event dropped
-    }
 
     // Preprocess pointer data.
 
@@ -2160,24 +2111,11 @@
     } // release lock
 
     // Dispatch virtual key.
-    applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags,
-            keyCode, scanCode, downTime);
-    return touchResult;
-}
-
-void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
-        int32_t keyEventAction, int32_t keyEventFlags,
-        int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
     int32_t metaState = mContext->getGlobalMetaState();
-
     policyFlags |= POLICY_FLAG_VIRTUAL;
-    int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
-            keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
-
-    if (applyStandardPolicyActions(when, policyActions)) {
-        getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-                keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
-    }
+    getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
+            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+    return touchResult;
 }
 
 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {