Merge "Added more robust tracking and cancelation of events." into gingerbread
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 912180b..0e5ece1 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -46,10 +46,12 @@
  * with the special action {@link #ACTION_MULTIPLE} that either specifies
  * that single repeated key code or a sequence of characters to insert.
  * </p><p>
- * In general, the framework makes no guarantees that the key events delivered
- * to a view constitute a complete key press.  In particular, there is no
- * guarantee that a view will always receive a key event with {@link #ACTION_UP}
- * for each {@link #ACTION_DOWN} that was delivered.
+ * In general, the framework cannot guarantee that the key events it delivers
+ * to a view always constitute complete key sequences since some events may be dropped
+ * or modified by containing views before they are delivered.  The view implementation
+ * should be prepared to handle {@link #FLAG_CANCELED} and should tolerate anomalous
+ * situations such as receiving a new {@link #ACTION_DOWN} without first having
+ * received an {@link #ACTION_UP} for the prior key press.
  * </p><p>
  * Refer to {@link InputDevice} for more information about how different kinds of
  * input devices and sources represent keys and buttons.
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 6705596..c2fec96 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -81,10 +81,12 @@
  *     }
  * }
  * </code></pre></p><p>
- * In general, the framework makes no guarantees that the motion events delivered
- * to a view constitute a complete gesture.  In particular, there is no
- * guarantee that a view will always receive a motion event with {@link #ACTION_UP}
- * for each {@link #ACTION_DOWN} that was delivered.
+ * In general, the framework cannot guarantee that the motion events it delivers
+ * to a view always constitute a complete motion sequences since some events may be dropped
+ * or modified by containing views before they are delivered.  The view implementation
+ * should be prepared to handle {@link #ACTION_CANCEL} and should tolerate anomalous
+ * situations such as receiving a new {@link #ACTION_DOWN} without first having
+ * received an {@link #ACTION_UP} for the prior gesture.
  * </p><p>
  * Refer to {@link InputDevice} for more information about how different kinds of
  * input devices and sources represent pointer coordinates.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 954b3e7..ef7716e 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -65,6 +65,7 @@
  * @hide
  */
 public interface WindowManagerPolicy {
+    // Policy flags.  These flags are also defined in frameworks/base/include/ui/Input.h.
     public final static int FLAG_WAKE = 0x00000001;
     public final static int FLAG_WAKE_DROPPED = 0x00000002;
     public final static int FLAG_SHIFT = 0x00000004;
@@ -79,6 +80,7 @@
 
     public final static int FLAG_WOKE_HERE = 0x10000000;
     public final static int FLAG_BRIGHT_HERE = 0x20000000;
+    public final static int FLAG_PASS_TO_USER = 0x40000000;
 
     public final static boolean WATCH_POINTER = false;
 
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ee40b85..66061fd 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -71,6 +71,8 @@
 /*
  * Flags that flow alongside events in the input dispatch system to help with certain
  * policy decisions such as waking from device sleep.
+ *
+ * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
  */
 enum {
     /* These flags originate in RawEvents and are generally set in the key map.
@@ -102,6 +104,11 @@
     // Indicates that the screen was dim when the event was received and the event
     // should brighten the device.
     POLICY_FLAG_BRIGHT_HERE = 0x20000000,
+
+    // Indicates that the event should be dispatched to applications.
+    // The input event should still be sent to the InputDispatcher so that it can see all
+    // input events received include those that it will not deliver.
+    POLICY_FLAG_PASS_TO_USER = 0x40000000,
 };
 
 /*
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 47c5326..0834e86 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -282,10 +282,35 @@
      */
     virtual int32_t getMaxEventsPerSecond() = 0;
 
+    /* Intercepts a key event immediately before queueing it.
+     * The policy can use this method as an opportunity to perform power management functions
+     * and early event preprocessing such as updating policy flags.
+     *
+     * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+     * should be dispatched to applications.
+     */
+    virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
+            int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
+            uint32_t& policyFlags) = 0;
+
+    /* Intercepts a generic touch, trackball or other event before queueing it.
+     * The policy can use this method as an opportunity to perform power management functions
+     * and early event preprocessing such as updating policy flags.
+     *
+     * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+     * should be dispatched to applications.
+     */
+    virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
+
     /* Allows the policy a chance to intercept a key before dispatching. */
     virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
             const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
 
+    /* Notifies the policy about switch events.
+     */
+    virtual void notifySwitch(nsecs_t when,
+            int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
+
     /* Poke user activity for an event dispatched to a window. */
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
 
@@ -333,6 +358,8 @@
             int32_t metaState, int32_t edgeFlags,
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime) = 0;
+    virtual void notifySwitch(nsecs_t when,
+            int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
 
     /* Injects an input event and optionally waits for sync.
      * The synchronization mode determines whether the method blocks while waiting for
@@ -408,6 +435,8 @@
             int32_t metaState, int32_t edgeFlags,
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
+    virtual void notifySwitch(nsecs_t when,
+            int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ;
 
     virtual int32_t injectInputEvent(const InputEvent* event,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
@@ -447,6 +476,7 @@
         mutable int32_t refCount;
         int32_t type;
         nsecs_t eventTime;
+        uint32_t policyFlags;
         InjectionState* injectionState;
 
         bool dispatchInProgress; // initially false, set to true while dispatching
@@ -460,7 +490,6 @@
     struct KeyEntry : EventEntry {
         int32_t deviceId;
         int32_t source;
-        uint32_t policyFlags;
         int32_t action;
         int32_t flags;
         int32_t keyCode;
@@ -489,7 +518,6 @@
     struct MotionEntry : EventEntry {
         int32_t deviceId;
         int32_t source;
-        uint32_t policyFlags;
         int32_t action;
         int32_t flags;
         int32_t metaState;
@@ -664,7 +692,8 @@
         Pool<DispatchEntry> mDispatchEntryPool;
         Pool<CommandEntry> mCommandEntryPool;
 
-        void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
+        void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime,
+                uint32_t policyFlags);
         void releaseEventEntryInjectionState(EventEntry* entry);
     };
 
@@ -685,21 +714,19 @@
             BROKEN
         };
 
+        // Specifies the sources to cancel.
+        enum CancelationOptions {
+            CANCEL_ALL_EVENTS = 0,
+            CANCEL_POINTER_EVENTS = 1,
+            CANCEL_NON_POINTER_EVENTS = 2,
+        };
+
         InputState();
         ~InputState();
 
         // Returns true if there is no state to be canceled.
         bool isNeutral() const;
 
-        // Returns true if the input state believes it is out of sync.
-        bool isOutOfSync() const;
-
-        // Sets the input state to be out of sync if it is not neutral.
-        void setOutOfSync();
-
-        // Resets the input state out of sync flag.
-        void resetOutOfSync();
-
         // Records tracking information for an event that has just been published.
         // Returns whether the event is consistent with the current input state.
         Consistency trackEvent(const EventEntry* entry);
@@ -712,16 +739,14 @@
         // Returns whether the event is consistent with the current input state.
         Consistency trackMotion(const MotionEntry* entry);
 
-        // Synthesizes cancelation events for the current state.
-        void synthesizeCancelationEvents(Allocator* allocator,
-                Vector<EventEntry*>& outEvents) const;
+        // Synthesizes cancelation events for the current state and resets the tracked state.
+        void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
+                Vector<EventEntry*>& outEvents, CancelationOptions options);
 
         // Clears the current state.
         void clear();
 
     private:
-        bool mIsOutOfSync;
-
         struct KeyMemento {
             int32_t deviceId;
             int32_t source;
@@ -745,6 +770,8 @@
 
         Vector<KeyMemento> mKeyMementos;
         Vector<MotionMemento> mMotionMementos;
+
+        static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options);
     };
 
     /* Manages the dispatch state associated with a single input channel. */
@@ -794,6 +821,13 @@
         status_t initialize();
     };
 
+    enum DropReason {
+        DROP_REASON_NOT_DROPPED = 0,
+        DROP_REASON_POLICY = 1,
+        DROP_REASON_APP_SWITCH = 2,
+        DROP_REASON_DISABLED = 3,
+    };
+
     sp<InputDispatcherPolicyInterface> mPolicy;
 
     Mutex mLock;
@@ -813,12 +847,16 @@
     // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
     bool enqueueInboundEventLocked(EventEntry* entry);
 
+    // Cleans up input state when dropping an inbound event.
+    void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
+
     // App switch latency optimization.
+    bool mAppSwitchSawKeyDown;
     nsecs_t mAppSwitchDueTime;
 
-    static bool isAppSwitchKey(int32_t keyCode);
+    static bool isAppSwitchKeyCode(int32_t keyCode);
+    bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
     bool isAppSwitchPendingLocked();
-    bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry);
     void resetPendingAppSwitchLocked(bool handled);
 
     // All registered connections mapped by receive pipe file descriptor.
@@ -840,7 +878,7 @@
 
     // Event injection and synchronization.
     Condition mInjectionResultAvailableCondition;
-    EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event);
+    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
     void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
 
     Condition mInjectionSyncFinishedCondition;
@@ -875,7 +913,7 @@
     void drainInboundQueueLocked();
     void releasePendingEventLocked();
     void releaseInboundEventLocked(EventEntry* entry);
-    bool isEventFromReliableSourceLocked(EventEntry* entry);
+    bool isEventFromTrustedSourceLocked(EventEntry* entry);
 
     // Dispatch state.
     bool mDispatchEnabled;
@@ -984,11 +1022,17 @@
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
-    void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            bool broken);
+    void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void drainOutboundQueueLocked(Connection* connection);
     static int handleReceiveCallback(int receiveFd, int events, void* data);
 
+    void synthesizeCancelationEventsForAllConnectionsLocked(
+            InputState::CancelationOptions options, const char* reason);
+    void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
+            InputState::CancelationOptions options, const char* reason);
+    void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
+            InputState::CancelationOptions options, const char* reason);
+
     // Splitting motion events across windows.
     MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
 
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 3619189..c15e382 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -87,49 +87,12 @@
         ROTATION_270 = 3
     };
 
-    /* Actions returned by interceptXXX methods. */
-    enum {
-        // The input dispatcher should do nothing and discard the input unless other
-        // flags are set.
-        ACTION_NONE = 0,
-
-        // The input dispatcher should dispatch the input to the application.
-        ACTION_DISPATCH = 0x00000001,
-    };
-
     /* Gets information about the display with the specified id.
      * Returns true if the display info is available, false otherwise.
      */
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Intercepts a key event.
-     * The policy can use this method as an opportunity to perform power management functions
-     * and early event preprocessing such as updating policy flags.
-     *
-     * Returns a policy action constant such as ACTION_DISPATCH.
-     */
-    virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
-            bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0;
-
-    /* Intercepts a switch event.
-     * The policy can use this method as an opportunity to perform power management functions
-     * and early event preprocessing such as updating policy flags.
-     *
-     * Switches are not dispatched to applications so this method should
-     * usually return ACTION_NONE.
-     */
-    virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
-            uint32_t& policyFlags) = 0;
-
-    /* Intercepts a generic touch, trackball or other event.
-     * The policy can use this method as an opportunity to perform power management functions
-     * and early event preprocessing such as updating policy flags.
-     *
-     * Returns a policy action constant such as ACTION_DISPATCH.
-     */
-    virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0;
-
     /* Determines whether to turn on some hacks we have to improve the touch interaction with a
      * certain device whose screen currently is not all that good.
      */
@@ -403,8 +366,6 @@
 protected:
     InputDevice* mDevice;
     InputReaderContext* mContext;
-
-    bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions);
 };
 
 
@@ -466,8 +427,6 @@
 
     void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
             uint32_t policyFlags);
-    void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags,
-            bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
 
     ssize_t findKeyDownLocked(int32_t scanCode);
 };
@@ -525,8 +484,6 @@
     void initializeLocked();
 
     void sync(nsecs_t when);
-    void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
-            PointerCoords* pointerCoords, nsecs_t downTime);
 };
 
 
@@ -829,10 +786,6 @@
             BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
             int32_t motionEventAction);
 
-    void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
-            int32_t keyEventAction, int32_t keyEventFlags,
-            int32_t keyCode, int32_t scanCode, nsecs_t downTime);
-
     bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
 
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) {
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 29ca9a4..ed1243a 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -49,6 +49,8 @@
 public class InputManager {
     static final String TAG = "InputManager";
     
+    private static final boolean DEBUG = false;
+
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
@@ -129,7 +131,9 @@
             throw new IllegalArgumentException("Invalid display id or dimensions.");
         }
         
-        Slog.i(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+        if (DEBUG) {
+            Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+        }
         nativeSetDisplaySize(displayId, width, height);
     }
     
@@ -138,7 +142,9 @@
             throw new IllegalArgumentException("Invalid rotation.");
         }
         
-        Slog.i(TAG, "Setting display #" + displayId + " orientation to " + rotation);
+        if (DEBUG) {
+            Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation);
+        }
         nativeSetDisplayOrientation(displayId, rotation);
     }
     
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 8e7be44..18037e4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -182,11 +182,6 @@
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
-            bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags);
-    virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
-            uint32_t& policyFlags);
-    virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags);
     virtual bool filterTouchEvents();
     virtual bool filterJumpyTouchEvents();
     virtual void getVirtualKeyDefinitions(const String8& deviceName,
@@ -204,8 +199,14 @@
     virtual nsecs_t getKeyRepeatTimeout();
     virtual nsecs_t getKeyRepeatDelay();
     virtual int32_t getMaxEventsPerSecond();
+    virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
+            int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
+            uint32_t& policyFlags);
+    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);
@@ -461,18 +462,25 @@
     return android_server_PowerManagerService_isScreenBright();
 }
 
-int32_t NativeInputManager::interceptKey(nsecs_t when,
-        int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
-    LOGD("interceptKey - when=%lld, deviceId=%d, down=%d, keyCode=%d, scanCode=%d, "
-            "policyFlags=0x%x",
-            when, deviceId, down, keyCode, scanCode, policyFlags);
+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 (down && (policyFlags & POLICY_FLAG_VIRTUAL)) {
-        JNIEnv* env = jniEnv();
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
-        checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
+    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;
@@ -496,10 +504,10 @@
         wmActions = WM_ACTION_PASS_TO_USER;
     }
 
-    int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
     if (! isScreenOn) {
         // Key presses and releases wake the device.
         policyFlags |= POLICY_FLAG_WOKE_HERE;
+        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
     }
 
     if (! isScreenBright) {
@@ -516,36 +524,31 @@
     }
 
     if (wmActions & WM_ACTION_PASS_TO_USER) {
-        actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
+        policyFlags |= POLICY_FLAG_PASS_TO_USER;
     }
-
-    return actions;
 }
 
-int32_t NativeInputManager::interceptGeneric(nsecs_t when, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
-    LOGD("interceptGeneric - when=%lld, policyFlags=0x%x", when, policyFlags);
+void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
 #endif
 
-    int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
     if (isScreenOn()) {
         // Only dispatch events when the device is awake.
         // Do not wake the device.
-        actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
+        policyFlags |= POLICY_FLAG_PASS_TO_USER;
 
         if (! isScreenBright()) {
             // Brighten the screen if dimmed.
             policyFlags |= POLICY_FLAG_BRIGHT_HERE;
         }
     }
-
-    return actions;
 }
 
-int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode,
-        int32_t switchValue, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
-    LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
+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
 
@@ -558,8 +561,6 @@
         checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
         break;
     }
-
-    return InputReaderPolicyInterface::ACTION_NONE;
 }
 
 bool NativeInputManager::filterTouchEvents() {