Prevent events from getting backlogged.

This change implements two heuristics.

1. When events are older than 10 seconds, they are dropped.

2. If the application is currently busy processing an event and
   the user touches a window belonging to a different application
   then we drop the currently queued events so the other application
   can start processing the gesture immediately.

Note that the system takes care of synthesizing cancelation events
automatically for any events that it drops.

Added some new handle types to allow the native dispatcher to
indirectly refer to the WindowManager's window state and app window
token.  This was done to enable the dispatcher to identify the
application to which each window belongs but it also eliminates
some lookup tables and linear searches through the window list
on each key press.

Bug: 3224911
Change-Id: I9dae8dfe23d195d76865f97011fe2f1d351e2940
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 37804ff..d7b61fc 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -21,6 +21,7 @@
     InputDispatcher.cpp \
     InputManager.cpp \
     InputReader.cpp \
+    InputWindow.cpp \
     PointerController.cpp
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
new file mode 100644
index 0000000..cc80062
--- /dev/null
+++ b/services/input/InputApplication.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_APPLICATION_H
+#define _UI_INPUT_APPLICATION_H
+
+#include <ui/Input.h>
+
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/String8.h>
+
+namespace android {
+
+/*
+ * A handle to an application that can receive input.
+ * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * that describe an application.
+ */
+class InputApplicationHandle : public RefBase {
+protected:
+    InputApplicationHandle() { }
+    virtual ~InputApplicationHandle() { }
+};
+
+
+/*
+ * An input application describes properties of an application that can receive input.
+ */
+struct InputApplication {
+    sp<InputApplicationHandle> inputApplicationHandle;
+    String8 name;
+    nsecs_t dispatchingTimeout;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_APPLICATION_H
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 89a7751..b5a4bd2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -72,6 +72,10 @@
 // when an application takes too long to respond and the user has pressed an app switch key.
 const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
+// Amount of time to allow for an event to be dispatched (measured since its eventTime)
+// before considering it stale and dropping it.
+const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
+
 
 static inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -151,34 +155,12 @@
 }
 
 
-// --- InputWindow ---
-
-bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
-    return x >= touchableAreaLeft && x <= touchableAreaRight
-            && y >= touchableAreaTop && y <= touchableAreaBottom;
-}
-
-bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
-    return x >= frameLeft && x <= frameRight
-            && y >= frameTop && y <= frameBottom;
-}
-
-bool InputWindow::isTrustedOverlay() const {
-    return layoutParamsType == TYPE_INPUT_METHOD
-            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
-            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
-}
-
-bool InputWindow::supportsSplitTouch() const {
-    return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
-}
-
-
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy),
-    mPendingEvent(NULL), mAppSwitchDueTime(LONG_LONG_MAX),
+    mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
+    mNextUnblockedEvent(NULL),
     mDispatchEnabled(true), mDispatchFrozen(false),
     mFocusedWindow(NULL),
     mFocusedApplication(NULL),
@@ -368,6 +350,7 @@
     }
 
     // Now we have an event to dispatch.
+    // All events are eventually dequeued and processed this way, even if we intend to drop them.
     assert(mPendingEvent != NULL);
     bool done = false;
     DropReason dropReason = DROP_REASON_NOT_DROPPED;
@@ -376,6 +359,11 @@
     } else if (!mDispatchEnabled) {
         dropReason = DROP_REASON_DISABLED;
     }
+
+    if (mNextUnblockedEvent == mPendingEvent) {
+        mNextUnblockedEvent = NULL;
+    }
+
     switch (mPendingEvent->type) {
     case EventEntry::TYPE_CONFIGURATION_CHANGED: {
         ConfigurationChangedEntry* typedEntry =
@@ -395,6 +383,13 @@
                 dropReason = DROP_REASON_APP_SWITCH;
             }
         }
+        if (dropReason == DROP_REASON_NOT_DROPPED
+                && isStaleEventLocked(currentTime, typedEntry)) {
+            dropReason = DROP_REASON_STALE;
+        }
+        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
+            dropReason = DROP_REASON_BLOCKED;
+        }
         done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
                 &dropReason, nextWakeupTime);
         break;
@@ -405,6 +400,13 @@
         if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
             dropReason = DROP_REASON_APP_SWITCH;
         }
+        if (dropReason == DROP_REASON_NOT_DROPPED
+                && isStaleEventLocked(currentTime, typedEntry)) {
+            dropReason = DROP_REASON_STALE;
+        }
+        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
+            dropReason = DROP_REASON_BLOCKED;
+        }
         done = dispatchMotionLocked(currentTime, typedEntry,
                 &dropReason, nextWakeupTime);
         break;
@@ -431,6 +433,9 @@
 
     switch (entry->type) {
     case EventEntry::TYPE_KEY: {
+        // Optimize app switch latency.
+        // If the application takes too long to catch up then we drop all events preceding
+        // the app switch key.
         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
         if (isAppSwitchKeyEventLocked(keyEntry)) {
             if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
@@ -448,11 +453,63 @@
         }
         break;
     }
+
+    case EventEntry::TYPE_MOTION: {
+        // Optimize case where the current application is unresponsive and the user
+        // decides to touch a window in a different application.
+        // If the application takes too long to catch up then we drop all events preceding
+        // the touch into the other window.
+        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
+        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
+                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
+                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
+                && mInputTargetWaitApplication != NULL) {
+            int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].x);
+            int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].y);
+            const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y);
+            if (touchedWindow
+                    && touchedWindow->inputWindowHandle != NULL
+                    && touchedWindow->inputWindowHandle->getInputApplicationHandle()
+                            != mInputTargetWaitApplication) {
+                // User touched a different application than the one we are waiting on.
+                // Flag the event, and start pruning the input queue.
+                mNextUnblockedEvent = motionEntry;
+                needWake = true;
+            }
+        }
+        break;
+    }
     }
 
     return needWake;
 }
 
+const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
+    // Traverse windows from front to back to find touched window.
+    size_t numWindows = mWindows.size();
+    for (size_t i = 0; i < numWindows; i++) {
+        const InputWindow* window = & mWindows.editItemAt(i);
+        int32_t flags = window->layoutParamsFlags;
+
+        if (window->visible) {
+            if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
+                bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
+                        | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
+                if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+                    // Found window.
+                    return window;
+                }
+            }
+        }
+
+        if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
+            // Error window is on top but not visible, so touch is dropped.
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
 void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
     const char* reason;
     switch (dropReason) {
@@ -470,6 +527,16 @@
         LOGI("Dropped event because of pending overdue app switch.");
         reason = "inbound event was dropped because of pending overdue app switch";
         break;
+    case DROP_REASON_BLOCKED:
+        LOGI("Dropped event because the current application is not responding and the user "
+                "has started interating with a different application.");
+        reason = "inbound event was dropped because the current application is not responding "
+                "and the user has started interating with a different application";
+        break;
+    case DROP_REASON_STALE:
+        LOGI("Dropped event because it is stale.");
+        reason = "inbound event was dropped because it is stale";
+        break;
     default:
         assert(false);
         return;
@@ -521,6 +588,10 @@
 #endif
 }
 
+bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) {
+    return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
+}
+
 bool InputDispatcher::runCommandsLockedInterruptible() {
     if (mCommandQueue.isEmpty()) {
         return false;
@@ -670,7 +741,7 @@
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
             if (mFocusedWindow) {
-                commandEntry->inputChannel = mFocusedWindow->inputChannel;
+                commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle;
             }
             commandEntry->keyEntry = entry;
             entry->refCount += 1;
@@ -848,6 +919,7 @@
     mCurrentInputTargetsValid = false;
     mCurrentInputTargets.clear();
     mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
+    mInputTargetWaitApplication.clear();
 }
 
 void InputDispatcher::commitTargetsLocked() {
@@ -866,6 +938,7 @@
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
             mInputTargetWaitTimeoutExpired = false;
+            mInputTargetWaitApplication.clear();
         }
     } else {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
@@ -880,6 +953,15 @@
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = currentTime + timeout;
             mInputTargetWaitTimeoutExpired = false;
+            mInputTargetWaitApplication.clear();
+
+            if (window && window->inputWindowHandle != NULL) {
+                mInputTargetWaitApplication =
+                        window->inputWindowHandle->getInputApplicationHandle();
+            }
+            if (mInputTargetWaitApplication == NULL && application) {
+                mInputTargetWaitApplication = application->inputApplicationHandle;
+            }
         }
     }
 
@@ -2624,7 +2706,7 @@
 void InputDispatcher::releaseFocusedApplicationLocked() {
     if (mFocusedApplication) {
         mFocusedApplication = NULL;
-        mFocusedApplicationStorage.handle.clear();
+        mFocusedApplicationStorage.inputApplicationHandle.clear();
     }
 }
 
@@ -2860,7 +2942,8 @@
     }
 }
 
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) {
+status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
+        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
 #if DEBUG_REGISTRATION
     LOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
             toString(monitor));
@@ -2875,7 +2958,7 @@
             return BAD_VALUE;
         }
 
-        sp<Connection> connection = new Connection(inputChannel);
+        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle);
         status_t status = connection->initialize();
         if (status) {
             LOGE("Failed to initialize input publisher for input channel '%s', status=%d",
@@ -3002,9 +3085,10 @@
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyANRLockedInterruptible);
     if (application) {
-        commandEntry->inputApplicationHandle = application->handle;
+        commandEntry->inputApplicationHandle = application->inputApplicationHandle;
     }
     if (window) {
+        commandEntry->inputWindowHandle = window->inputWindowHandle;
         commandEntry->inputChannel = window->inputChannel;
     }
 }
@@ -3025,7 +3109,7 @@
     if (connection->status != Connection::STATUS_ZOMBIE) {
         mLock.unlock();
 
-        mPolicy->notifyInputChannelBroken(connection->inputChannel);
+        mPolicy->notifyInputChannelBroken(connection->inputWindowHandle);
 
         mLock.lock();
     }
@@ -3036,7 +3120,7 @@
     mLock.unlock();
 
     nsecs_t newTimeout = mPolicy->notifyANR(
-            commandEntry->inputApplicationHandle, commandEntry->inputChannel);
+            commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle);
 
     mLock.lock();
 
@@ -3052,7 +3136,7 @@
 
     mLock.unlock();
 
-    bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel,
+    bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
             &event, entry->policyFlags);
 
     mLock.lock();
@@ -3095,7 +3179,7 @@
 
                     mLock.unlock();
 
-                    bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel,
+                    bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
                             &event, keyEntry->policyFlags, &event);
 
                     mLock.lock();
@@ -3604,8 +3688,10 @@
 
 // --- InputDispatcher::Connection ---
 
-InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) :
-        status(STATUS_NORMAL), inputChannel(inputChannel), inputPublisher(inputChannel),
+InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
+        const sp<InputWindowHandle>& inputWindowHandle) :
+        status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
+        inputPublisher(inputChannel),
         lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
 }
 
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index c8beab2..11e5117 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -33,6 +33,9 @@
 #include <unistd.h>
 #include <limits.h>
 
+#include "InputWindow.h"
+#include "InputApplication.h"
+
 
 namespace android {
 
@@ -116,137 +119,6 @@
 
 
 /*
- * An input window describes the bounds of a window that can receive input.
- */
-struct InputWindow {
-    // Window flags from WindowManager.LayoutParams
-    enum {
-        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001,
-        FLAG_DIM_BEHIND        = 0x00000002,
-        FLAG_BLUR_BEHIND        = 0x00000004,
-        FLAG_NOT_FOCUSABLE      = 0x00000008,
-        FLAG_NOT_TOUCHABLE      = 0x00000010,
-        FLAG_NOT_TOUCH_MODAL    = 0x00000020,
-        FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
-        FLAG_KEEP_SCREEN_ON     = 0x00000080,
-        FLAG_LAYOUT_IN_SCREEN   = 0x00000100,
-        FLAG_LAYOUT_NO_LIMITS   = 0x00000200,
-        FLAG_FULLSCREEN      = 0x00000400,
-        FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800,
-        FLAG_DITHER             = 0x00001000,
-        FLAG_SECURE             = 0x00002000,
-        FLAG_SCALED             = 0x00004000,
-        FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000,
-        FLAG_LAYOUT_INSET_DECOR = 0x00010000,
-        FLAG_ALT_FOCUSABLE_IM = 0x00020000,
-        FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
-        FLAG_SHOW_WHEN_LOCKED = 0x00080000,
-        FLAG_SHOW_WALLPAPER = 0x00100000,
-        FLAG_TURN_SCREEN_ON = 0x00200000,
-        FLAG_DISMISS_KEYGUARD = 0x00400000,
-        FLAG_SPLIT_TOUCH = 0x00800000,
-        FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
-        FLAG_COMPATIBLE_WINDOW = 0x20000000,
-        FLAG_SYSTEM_ERROR = 0x40000000,
-    };
-
-    // Window types from WindowManager.LayoutParams
-    enum {
-        FIRST_APPLICATION_WINDOW = 1,
-        TYPE_BASE_APPLICATION   = 1,
-        TYPE_APPLICATION        = 2,
-        TYPE_APPLICATION_STARTING = 3,
-        LAST_APPLICATION_WINDOW = 99,
-        FIRST_SUB_WINDOW        = 1000,
-        TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW,
-        TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1,
-        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
-        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
-        TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4,
-        LAST_SUB_WINDOW         = 1999,
-        FIRST_SYSTEM_WINDOW     = 2000,
-        TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW,
-        TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1,
-        TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2,
-        TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3,
-        TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4,
-        TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5,
-        TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6,
-        TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7,
-        TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8,
-        TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9,
-        TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10,
-        TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11,
-        TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
-        TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13,
-        TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+14,
-        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
-        TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
-        TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+17,
-        LAST_SYSTEM_WINDOW      = 2999,
-    };
-
-    sp<InputChannel> inputChannel;
-    String8 name;
-    int32_t layoutParamsFlags;
-    int32_t layoutParamsType;
-    nsecs_t dispatchingTimeout;
-    int32_t frameLeft;
-    int32_t frameTop;
-    int32_t frameRight;
-    int32_t frameBottom;
-    int32_t visibleFrameLeft;
-    int32_t visibleFrameTop;
-    int32_t visibleFrameRight;
-    int32_t visibleFrameBottom;
-    int32_t touchableAreaLeft;
-    int32_t touchableAreaTop;
-    int32_t touchableAreaRight;
-    int32_t touchableAreaBottom;
-    bool visible;
-    bool canReceiveKeys;
-    bool hasFocus;
-    bool hasWallpaper;
-    bool paused;
-    int32_t layer;
-    int32_t ownerPid;
-    int32_t ownerUid;
-
-    bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
-    bool frameContainsPoint(int32_t x, int32_t y) const;
-
-    /* Returns true if the window is of a trusted type that is allowed to silently
-     * overlay other windows for the purpose of implementing the secure views feature.
-     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
-     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
-     */
-    bool isTrustedOverlay() const;
-
-    bool supportsSplitTouch() const;
-};
-
-
-/*
- * A private handle type used by the input manager to track the window.
- */
-class InputApplicationHandle : public RefBase {
-protected:
-    InputApplicationHandle() { }
-    virtual ~InputApplicationHandle() { }
-};
-
-
-/*
- * An input application describes properties of an application that can receive input.
- */
-struct InputApplication {
-    String8 name;
-    nsecs_t dispatchingTimeout;
-    sp<InputApplicationHandle> handle;
-};
-
-
-/*
  * Input dispatcher policy interface.
  *
  * The input reader policy is used by the input reader to interact with the Window Manager
@@ -267,10 +139,10 @@
     /* Notifies the system that an application is not responding.
      * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputChannel>& inputChannel) = 0;
+            const sp<InputWindowHandle>& inputWindowHandle) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
-    virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
+    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
 
     /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */
     virtual nsecs_t getKeyRepeatTimeout() = 0;
@@ -303,12 +175,12 @@
     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,
+    virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
 
     /* Allows the policy a chance to perform default processing for an unhandled key.
      * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
-    virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
 
     /* Notifies the policy about switch events.
@@ -407,7 +279,8 @@
      *
      * These methods may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) = 0;
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
+            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0;
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
 };
 
@@ -461,7 +334,8 @@
     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
             const sp<InputChannel>& toChannel);
 
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
+            const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
 
 private:
@@ -615,6 +489,7 @@
         KeyEntry* keyEntry;
         sp<InputChannel> inputChannel;
         sp<InputApplicationHandle> inputApplicationHandle;
+        sp<InputWindowHandle> inputWindowHandle;
         int32_t userActivityEventType;
         bool handled;
     };
@@ -815,7 +690,8 @@
         };
 
         Status status;
-        sp<InputChannel> inputChannel;
+        sp<InputChannel> inputChannel; // never null
+        sp<InputWindowHandle> inputWindowHandle; // may be null
         InputPublisher inputPublisher;
         InputState inputState;
         Queue<DispatchEntry> outboundQueue;
@@ -823,7 +699,8 @@
         nsecs_t lastEventTime; // the time when the event was originally captured
         nsecs_t lastDispatchTime; // the time when the last event was dispatched
 
-        explicit Connection(const sp<InputChannel>& inputChannel);
+        explicit Connection(const sp<InputChannel>& inputChannel,
+                const sp<InputWindowHandle>& inputWindowHandle);
 
         inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
 
@@ -851,6 +728,8 @@
         DROP_REASON_POLICY = 1,
         DROP_REASON_APP_SWITCH = 2,
         DROP_REASON_DISABLED = 3,
+        DROP_REASON_BLOCKED = 4,
+        DROP_REASON_STALE = 5,
     };
 
     sp<InputDispatcherPolicyInterface> mPolicy;
@@ -884,6 +763,15 @@
     bool isAppSwitchPendingLocked();
     void resetPendingAppSwitchLocked(bool handled);
 
+    // Stale event latency optimization.
+    static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry);
+
+    // Blocked event latency optimization.  Drops old events when the user intends
+    // to transfer focus to a new application.
+    EventEntry* mNextUnblockedEvent;
+
+    const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y);
+
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
@@ -1006,6 +894,7 @@
     nsecs_t mInputTargetWaitStartTime;
     nsecs_t mInputTargetWaitTimeoutTime;
     bool mInputTargetWaitTimeoutExpired;
+    sp<InputApplicationHandle> mInputTargetWaitApplication;
 
     // Finding targets for input events.
     void resetTargetsLocked();
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
new file mode 100644
index 0000000..9ce45f5
--- /dev/null
+++ b/services/input/InputWindow.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputWindow"
+
+#include "InputWindow.h"
+
+#include <cutils/log.h>
+
+namespace android {
+
+// --- InputWindow ---
+
+bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
+    return x >= touchableAreaLeft && x <= touchableAreaRight
+            && y >= touchableAreaTop && y <= touchableAreaBottom;
+}
+
+bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+    return x >= frameLeft && x <= frameRight
+            && y >= frameTop && y <= frameBottom;
+}
+
+bool InputWindow::isTrustedOverlay() const {
+    return layoutParamsType == TYPE_INPUT_METHOD
+            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
+            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
+}
+
+bool InputWindow::supportsSplitTouch() const {
+    return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
+}
+
+} // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
new file mode 100644
index 0000000..b3d5a65
--- /dev/null
+++ b/services/input/InputWindow.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_WINDOW_H
+#define _UI_INPUT_WINDOW_H
+
+#include <ui/Input.h>
+#include <ui/InputTransport.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/String8.h>
+
+#include "InputApplication.h"
+
+namespace android {
+
+/*
+ * A handle to a window that can receive input.
+ * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * that describe a window.
+ */
+class InputWindowHandle : public RefBase {
+protected:
+    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+            mInputApplicationHandle(inputApplicationHandle) { }
+    virtual ~InputWindowHandle() { }
+
+public:
+    inline sp<InputApplicationHandle> getInputApplicationHandle() {
+        return mInputApplicationHandle;
+    }
+
+private:
+    sp<InputApplicationHandle> mInputApplicationHandle;
+};
+
+
+/*
+ * An input window describes the bounds of a window that can receive input.
+ */
+struct InputWindow {
+    // Window flags from WindowManager.LayoutParams
+    enum {
+        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001,
+        FLAG_DIM_BEHIND        = 0x00000002,
+        FLAG_BLUR_BEHIND        = 0x00000004,
+        FLAG_NOT_FOCUSABLE      = 0x00000008,
+        FLAG_NOT_TOUCHABLE      = 0x00000010,
+        FLAG_NOT_TOUCH_MODAL    = 0x00000020,
+        FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
+        FLAG_KEEP_SCREEN_ON     = 0x00000080,
+        FLAG_LAYOUT_IN_SCREEN   = 0x00000100,
+        FLAG_LAYOUT_NO_LIMITS   = 0x00000200,
+        FLAG_FULLSCREEN      = 0x00000400,
+        FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800,
+        FLAG_DITHER             = 0x00001000,
+        FLAG_SECURE             = 0x00002000,
+        FLAG_SCALED             = 0x00004000,
+        FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000,
+        FLAG_LAYOUT_INSET_DECOR = 0x00010000,
+        FLAG_ALT_FOCUSABLE_IM = 0x00020000,
+        FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
+        FLAG_SHOW_WHEN_LOCKED = 0x00080000,
+        FLAG_SHOW_WALLPAPER = 0x00100000,
+        FLAG_TURN_SCREEN_ON = 0x00200000,
+        FLAG_DISMISS_KEYGUARD = 0x00400000,
+        FLAG_SPLIT_TOUCH = 0x00800000,
+        FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
+        FLAG_COMPATIBLE_WINDOW = 0x20000000,
+        FLAG_SYSTEM_ERROR = 0x40000000,
+    };
+
+    // Window types from WindowManager.LayoutParams
+    enum {
+        FIRST_APPLICATION_WINDOW = 1,
+        TYPE_BASE_APPLICATION   = 1,
+        TYPE_APPLICATION        = 2,
+        TYPE_APPLICATION_STARTING = 3,
+        LAST_APPLICATION_WINDOW = 99,
+        FIRST_SUB_WINDOW        = 1000,
+        TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW,
+        TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1,
+        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
+        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
+        TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4,
+        LAST_SUB_WINDOW         = 1999,
+        FIRST_SYSTEM_WINDOW     = 2000,
+        TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW,
+        TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1,
+        TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2,
+        TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3,
+        TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4,
+        TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5,
+        TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6,
+        TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7,
+        TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8,
+        TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9,
+        TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10,
+        TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11,
+        TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
+        TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13,
+        TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+14,
+        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
+        TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
+        TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+17,
+        LAST_SYSTEM_WINDOW      = 2999,
+    };
+
+    sp<InputWindowHandle> inputWindowHandle;
+    sp<InputChannel> inputChannel;
+    String8 name;
+    int32_t layoutParamsFlags;
+    int32_t layoutParamsType;
+    nsecs_t dispatchingTimeout;
+    int32_t frameLeft;
+    int32_t frameTop;
+    int32_t frameRight;
+    int32_t frameBottom;
+    int32_t visibleFrameLeft;
+    int32_t visibleFrameTop;
+    int32_t visibleFrameRight;
+    int32_t visibleFrameBottom;
+    int32_t touchableAreaLeft;
+    int32_t touchableAreaTop;
+    int32_t touchableAreaRight;
+    int32_t touchableAreaBottom;
+    bool visible;
+    bool canReceiveKeys;
+    bool hasFocus;
+    bool hasWallpaper;
+    bool paused;
+    int32_t layer;
+    int32_t ownerPid;
+    int32_t ownerUid;
+
+    bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+    bool frameContainsPoint(int32_t x, int32_t y) const;
+
+    /* Returns true if the window is of a trusted type that is allowed to silently
+     * overlay other windows for the purpose of implementing the secure views feature.
+     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
+     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+     */
+    bool isTrustedOverlay() const;
+
+    bool supportsSplitTouch() const;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_WINDOW_H
diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index b79633a..5ba1867 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -36,11 +36,11 @@
     }
 
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputChannel>& inputChannel) {
+            const sp<InputWindowHandle>& inputWindowHandle) {
         return 0;
     }
 
-    virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) {
+    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
     }
 
     virtual nsecs_t getKeyRepeatTimeout() {
@@ -61,12 +61,12 @@
     virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
     }
 
-    virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
+    virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags) {
         return false;
     }
 
-    virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
         return false;
     }
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 9d2c52f..8ec6f53 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -368,7 +368,8 @@
         return 0;
     }
 
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) {
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
+            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
         ADD_FAILURE() << "Should never be called by input reader.";
         return 0;
     }
diff --git a/services/java/com/android/server/InputApplication.java b/services/java/com/android/server/InputApplication.java
index 38420d4..ae09484 100644
--- a/services/java/com/android/server/InputApplication.java
+++ b/services/java/com/android/server/InputApplication.java
@@ -18,16 +18,19 @@
 
 /**
  * Describes input-related application properties for use by the input dispatcher.
- * 
  * @hide
  */
 public final class InputApplication {
+    // Application handle.
+    public InputApplicationHandle inputApplicationHandle;
+
     // Application name.
     public String name;
-    
+
     // Dispatching timeout.
     public long dispatchingTimeoutNanos;
-    
-    // The application window token.
-    public Object token;
+
+    public void recycle() {
+        inputApplicationHandle = null;
+    }
 }
diff --git a/services/java/com/android/server/InputApplicationHandle.java b/services/java/com/android/server/InputApplicationHandle.java
new file mode 100644
index 0000000..d396d11
--- /dev/null
+++ b/services/java/com/android/server/InputApplicationHandle.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+/**
+ * Functions as a handle for an application that can receive input.
+ * Enables the native input dispatcher to refer indirectly to the window manager's
+ * application window token.
+ * @hide
+ */
+public final class InputApplicationHandle {
+    // Pointer to the native input application handle.
+    // This field is lazily initialized via JNI.
+    @SuppressWarnings("unused")
+    private int ptr;
+
+    // The window manager's application window token.
+    public final WindowManagerService.AppWindowToken appWindowToken;
+
+    private native void nativeDispose();
+
+    public InputApplicationHandle(WindowManagerService.AppWindowToken appWindowToken) {
+        this.appWindowToken = appWindowToken;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        nativeDispose();
+        super.finalize();
+    }
+}
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 410b8c2..5c2048b 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -77,7 +77,7 @@
     private static native boolean nativeHasKeys(int deviceId, int sourceMask,
             int[] keyCodes, boolean[] keyExists);
     private static native void nativeRegisterInputChannel(InputChannel inputChannel,
-            boolean monitor);
+            InputWindowHandle inputWindowHandle, boolean monitor);
     private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
     private static native int nativeInjectInputEvent(InputEvent event,
             int injectorPid, int injectorUid, int syncMode, int timeoutMillis);
@@ -240,7 +240,7 @@
         }
         
         InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
-        nativeRegisterInputChannel(inputChannels[0], true);
+        nativeRegisterInputChannel(inputChannels[0], null, true);
         inputChannels[0].dispose(); // don't need to retain the Java object reference
         return inputChannels[1];
     }
@@ -248,13 +248,16 @@
     /**
      * Registers an input channel so that it can be used as an input event target.
      * @param inputChannel The input channel to register.
+     * @param inputWindowHandle The handle of the input window associated with the
+     * input channel, or null if none.
      */
-    public void registerInputChannel(InputChannel inputChannel) {
+    public void registerInputChannel(InputChannel inputChannel,
+            InputWindowHandle inputWindowHandle) {
         if (inputChannel == null) {
             throw new IllegalArgumentException("inputChannel must not be null.");
         }
         
-        nativeRegisterInputChannel(inputChannel, false);
+        nativeRegisterInputChannel(inputChannel, inputWindowHandle, false);
     }
     
     /**
@@ -429,13 +432,15 @@
         }
         
         @SuppressWarnings("unused")
-        public void notifyInputChannelBroken(InputChannel inputChannel) {
-            mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel);
+        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
+            mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputWindowHandle);
         }
         
         @SuppressWarnings("unused")
-        public long notifyANR(Object token, InputChannel inputChannel) {
-            return mWindowManagerService.mInputMonitor.notifyANR(token, inputChannel);
+        public long notifyANR(InputApplicationHandle inputApplicationHandle,
+                InputWindowHandle inputWindowHandle) {
+            return mWindowManagerService.mInputMonitor.notifyANR(
+                    inputApplicationHandle, inputWindowHandle);
         }
         
         @SuppressWarnings("unused")
@@ -445,14 +450,14 @@
         }
         
         @SuppressWarnings("unused")
-        public boolean interceptKeyBeforeDispatching(InputChannel focus,
+        public boolean interceptKeyBeforeDispatching(InputWindowHandle focus,
                 KeyEvent event, int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(
                     focus, event, policyFlags);
         }
         
         @SuppressWarnings("unused")
-        public KeyEvent dispatchUnhandledKey(InputChannel focus,
+        public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
                 KeyEvent event, int policyFlags) {
             return mWindowManagerService.mInputMonitor.dispatchUnhandledKey(
                     focus, event, policyFlags);
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index befc770..1515290 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -20,64 +20,67 @@
 
 /**
  * Describes input-related window properties for use by the input dispatcher.
- * 
  * @hide
  */
 public final class InputWindow {
+    // The window handle.
+    public InputWindowHandle inputWindowHandle;
+
     // The input channel associated with the window.
     public InputChannel inputChannel;
-    
+
     // The window name.
     public String name;
-    
+
     // Window layout params attributes.  (WindowManager.LayoutParams)
     public int layoutParamsFlags;
     public int layoutParamsType;
-    
+
     // Dispatching timeout.
     public long dispatchingTimeoutNanos;
-    
+
     // Window frame area.
     public int frameLeft;
     public int frameTop;
     public int frameRight;
     public int frameBottom;
-    
+
     // Window visible frame area.
     public int visibleFrameLeft;
     public int visibleFrameTop;
     public int visibleFrameRight;
     public int visibleFrameBottom;
-    
+
     // Window touchable area.
     public int touchableAreaLeft;
     public int touchableAreaTop;
     public int touchableAreaRight;
     public int touchableAreaBottom;
-    
+
     // Window is visible.
     public boolean visible;
-    
+
     // Window can receive keys.
     public boolean canReceiveKeys;
-    
+
     // Window has focus.
     public boolean hasFocus;
-    
+
     // Window has wallpaper.  (window is the current wallpaper target)
     public boolean hasWallpaper;
-    
+
     // Input event dispatching is paused.
     public boolean paused;
-    
+
     // Window layer.
     public int layer;
-    
+
     // Id of process and user that owns the window.
     public int ownerPid;
     public int ownerUid;
-    
+
     public void recycle() {
+        inputWindowHandle = null;
         inputChannel = null;
     }
 }
diff --git a/services/java/com/android/server/InputWindowHandle.java b/services/java/com/android/server/InputWindowHandle.java
new file mode 100644
index 0000000..4b92939
--- /dev/null
+++ b/services/java/com/android/server/InputWindowHandle.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.view.WindowManagerPolicy;
+
+/**
+ * Functions as a handle for a window that can receive input.
+ * Enables the native input dispatcher to refer indirectly to the window manager's window state.
+ * @hide
+ */
+public final class InputWindowHandle {
+    // Pointer to the native input window handle.
+    // This field is lazily initialized via JNI.
+    @SuppressWarnings("unused")
+    private int ptr;
+
+    // The input application handle.
+    public final InputApplicationHandle inputApplicationHandle;
+
+    // The window manager's window state.
+    public final WindowManagerPolicy.WindowState windowState;
+
+    private native void nativeDispose();
+
+    public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
+            WindowManagerPolicy.WindowState windowState) {
+        this.inputApplicationHandle = inputApplicationHandle;
+        this.windowState = windowState;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        nativeDispose();
+        super.finalize();
+    }
+}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c33d19d..5c823ba 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -536,7 +536,7 @@
                 InputChannel[] channels = InputChannel.openInputChannelPair("drag");
                 mServerChannel = channels[0];
                 mClientChannel = channels[1];
-                mInputManager.registerInputChannel(mServerChannel);
+                mInputManager.registerInputChannel(mServerChannel, null);
                 InputQueue.registerInputChannel(mClientChannel, mDragInputHandler,
                         mH.getLooper().getQueue());
             }
@@ -2311,7 +2311,7 @@
                 win.mInputChannel = inputChannels[0];
                 inputChannels[1].transferToBinderOutParameter(outInputChannel);
                 
-                mInputManager.registerInputChannel(win.mInputChannel);
+                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
             }
 
             // From now on, no exceptions or errors allowed!
@@ -5711,13 +5711,13 @@
          * 
          * Called by the InputManager.
          */
-        public void notifyInputChannelBroken(InputChannel inputChannel) {
+        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
+            if (inputWindowHandle == null) {
+                return;
+            }
+
             synchronized (mWindowMap) {
-                WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
-                if (windowState == null) {
-                    return; // irrelevant
-                }
-                
+                WindowState windowState = (WindowState) inputWindowHandle.windowState;
                 Slog.i(TAG, "WINDOW DIED " + windowState);
                 removeWindowLocked(windowState.mSession, windowState);
             }
@@ -5728,11 +5728,12 @@
          * 
          * Called by the InputManager.
          */
-        public long notifyANR(Object token, InputChannel inputChannel) {
+        public long notifyANR(InputApplicationHandle inputApplicationHandle,
+                InputWindowHandle inputWindowHandle) {
             AppWindowToken appWindowToken = null;
-            if (inputChannel != null) {
+            if (inputWindowHandle != null) {
                 synchronized (mWindowMap) {
-                    WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
+                    WindowState windowState = (WindowState) inputWindowHandle.windowState;
                     if (windowState != null) {
                         Slog.i(TAG, "Input event dispatching timed out sending to "
                                 + windowState.mAttrs.getTitle());
@@ -5741,8 +5742,8 @@
                 }
             }
             
-            if (appWindowToken == null && token != null) {
-                appWindowToken = (AppWindowToken) token;
+            if (appWindowToken == null && inputApplicationHandle != null) {
+                appWindowToken = inputApplicationHandle.appWindowToken;
                 Slog.i(TAG, "Input event dispatching timed out sending to application "
                         + appWindowToken.stringName);
             }
@@ -5762,24 +5763,6 @@
             }
             return 0; // abort dispatching
         }
-        
-        private WindowState getWindowStateForInputChannel(InputChannel inputChannel) {
-            synchronized (mWindowMap) {
-                return getWindowStateForInputChannelLocked(inputChannel);
-            }
-        }
-        
-        private WindowState getWindowStateForInputChannelLocked(InputChannel inputChannel) {
-            int windowCount = mWindows.size();
-            for (int i = 0; i < windowCount; i++) {
-                WindowState windowState = mWindows.get(i);
-                if (windowState.mInputChannel == inputChannel) {
-                    return windowState;
-                }
-            }
-            
-            return null;
-        }
 
         private void addDragInputWindowLw(InputWindowList windowList) {
             final InputWindow inputWindow = windowList.add();
@@ -5856,6 +5839,7 @@
 
                 // Add a window to our list of input windows.
                 final InputWindow inputWindow = mTempInputWindows.add();
+                inputWindow.inputWindowHandle = child.mInputWindowHandle;
                 inputWindow.inputChannel = child.mInputChannel;
                 inputWindow.name = child.toString();
                 inputWindow.layoutParamsFlags = flags;
@@ -5934,16 +5918,16 @@
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
         public boolean interceptKeyBeforeDispatching(
-                InputChannel focus, KeyEvent event, int policyFlags) {
-            WindowState windowState = getWindowStateForInputChannel(focus);
+                InputWindowHandle focus, KeyEvent event, int policyFlags) {
+            WindowState windowState = (WindowState) focus.windowState;
             return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
         }
         
         /* Provides an opportunity for the window manager policy to process a key that
          * the application did not handle. */
         public KeyEvent dispatchUnhandledKey(
-                InputChannel focus, KeyEvent event, int policyFlags) {
-            WindowState windowState = getWindowStateForInputChannel(focus);
+                InputWindowHandle focus, KeyEvent event, int policyFlags) {
+            WindowState windowState = (WindowState) focus.windowState;
             return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
         }
         
@@ -5973,12 +5957,14 @@
             if (newApp == null) {
                 mInputManager.setFocusedApplication(null);
             } else {
+                mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle;
                 mTempInputApplication.name = newApp.toString();
                 mTempInputApplication.dispatchingTimeoutNanos =
                         newApp.inputDispatchingTimeoutNanos;
-                mTempInputApplication.token = newApp;
-                
+
                 mInputManager.setFocusedApplication(mTempInputApplication);
+
+                mTempInputApplication.recycle();
             }
         }
         
@@ -6823,7 +6809,8 @@
         int mSurfaceLayer;
         float mSurfaceAlpha;
         
-        // Input channel
+        // Input channel and input window handle used by the input dispatcher.
+        InputWindowHandle mInputWindowHandle;
         InputChannel mInputChannel;
         
         // Used to improve performance of toString()
@@ -6915,6 +6902,8 @@
             mLayer = 0;
             mAnimLayer = 0;
             mLastLayer = 0;
+            mInputWindowHandle = new InputWindowHandle(
+                    mAppToken != null ? mAppToken.mInputApplicationHandle : null, this);
         }
 
         void attach() {
@@ -8304,11 +8293,15 @@
         boolean startingMoved;
         boolean firstWindowDrawn;
 
+        // Input application handle used by the input dispatcher.
+        InputApplicationHandle mInputApplicationHandle;
+
         AppWindowToken(IApplicationToken _token) {
             super(_token.asBinder(),
                     WindowManager.LayoutParams.TYPE_APPLICATION, true);
             appWindowToken = this;
             appToken = _token;
+            mInputApplicationHandle = new InputApplicationHandle(this);
         }
 
         public void setAnimation(Animation anim) {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index ec85e54..f5a5b4d 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,7 +4,11 @@
 LOCAL_SRC_FILES:= \
     com_android_server_AlarmManagerService.cpp \
     com_android_server_BatteryService.cpp \
+    com_android_server_InputApplication.cpp \
+    com_android_server_InputApplicationHandle.cpp \
     com_android_server_InputManager.cpp \
+    com_android_server_InputWindow.cpp \
+    com_android_server_InputWindowHandle.cpp \
     com_android_server_LightsService.cpp \
     com_android_server_PowerManagerService.cpp \
     com_android_server_SystemServer.cpp \
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
new file mode 100644
index 0000000..a46a162
--- /dev/null
+++ b/services/jni/com_android_server_InputApplication.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputApplication"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "com_android_server_InputApplication.h"
+#include "com_android_server_InputApplicationHandle.h"
+
+namespace android {
+
+static struct {
+    jclass clazz;
+
+    jfieldID inputApplicationHandle;
+    jfieldID name;
+    jfieldID dispatchingTimeoutNanos;
+} gInputApplicationClassInfo;
+
+
+// --- Global functions ---
+
+void android_server_InputApplication_toNative(
+        JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) {
+    jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj,
+            gInputApplicationClassInfo.inputApplicationHandle);
+    if (inputApplicationHandleObj) {
+        outInputApplication->inputApplicationHandle =
+                android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+        env->DeleteLocalRef(inputApplicationHandleObj);
+    } else {
+        outInputApplication->inputApplicationHandle = NULL;
+    }
+
+    jstring nameObj = jstring(env->GetObjectField(inputApplicationObj,
+            gInputApplicationClassInfo.name));
+    if (nameObj) {
+        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+        outInputApplication->name.setTo(nameStr);
+        env->ReleaseStringUTFChars(nameObj, nameStr);
+        env->DeleteLocalRef(nameObj);
+    } else {
+        LOGE("InputApplication.name should not be null.");
+        outInputApplication->name.setTo("unknown");
+    }
+
+    outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj,
+            gInputApplicationClassInfo.dispatchingTimeoutNanos);
+}
+
+
+// --- JNI ---
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputApplication(JNIEnv* env) {
+    FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication");
+
+    GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
+            gInputApplicationClassInfo.clazz,
+            "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;");
+
+    GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz,
+            "name", "Ljava/lang/String;");
+
+    GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
+            gInputApplicationClassInfo.clazz,
+            "dispatchingTimeoutNanos", "J");
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h
new file mode 100644
index 0000000..85fb891
--- /dev/null
+++ b/services/jni/com_android_server_InputApplication.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H
+#define _ANDROID_SERVER_INPUT_APPLICATION_H
+
+#include <input/InputApplication.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+extern void android_server_InputApplication_toNative(
+        JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_APPLICATION_H
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
new file mode 100644
index 0000000..ab82635
--- /dev/null
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputApplicationHandle"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
+
+#include "com_android_server_InputApplicationHandle.h"
+
+namespace android {
+
+static struct {
+    jclass clazz;
+
+    jfieldID ptr;
+} gInputApplicationHandleClassInfo;
+
+static Mutex gHandleMutex;
+
+
+// --- NativeInputApplicationHandle ---
+
+NativeInputApplicationHandle::NativeInputApplicationHandle(jweak objWeak) :
+        mObjWeak(objWeak) {
+}
+
+NativeInputApplicationHandle::~NativeInputApplicationHandle() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteWeakGlobalRef(mObjWeak);
+}
+
+jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEnv* env) {
+    return env->NewLocalRef(mObjWeak);
+}
+
+
+// --- Global functions ---
+
+sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+        JNIEnv* env, jobject inputApplicationHandleObj) {
+    if (!inputApplicationHandleObj) {
+        return NULL;
+    }
+
+    AutoMutex _l(gHandleMutex);
+
+    int ptr = env->GetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr);
+    NativeInputApplicationHandle* handle;
+    if (ptr) {
+        handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+    } else {
+        jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
+        handle = new NativeInputApplicationHandle(objWeak);
+        handle->incStrong(inputApplicationHandleObj);
+        env->SetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
+                reinterpret_cast<int>(handle));
+    }
+    return handle;
+}
+
+
+// --- JNI ---
+
+static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
+    AutoMutex _l(gHandleMutex);
+
+    int ptr = env->GetIntField(obj, gInputApplicationHandleClassInfo.ptr);
+    if (ptr) {
+        env->SetIntField(obj, gInputApplicationHandleClassInfo.ptr, 0);
+
+        NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+        handle->decStrong(obj);
+    }
+}
+
+
+static JNINativeMethod gInputApplicationHandleMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeDispose", "()V",
+            (void*) android_server_InputApplicationHandle_nativeDispose },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputApplicationHandle(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/InputApplicationHandle",
+            gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/InputApplicationHandle");
+
+    GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz,
+            "ptr", "I");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h
new file mode 100644
index 0000000..9d18721
--- /dev/null
+++ b/services/jni/com_android_server_InputApplicationHandle.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
+#define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
+
+#include <input/InputApplication.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+class NativeInputApplicationHandle : public InputApplicationHandle {
+public:
+    NativeInputApplicationHandle(jweak objWeak);
+    virtual ~NativeInputApplicationHandle();
+
+    jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
+
+private:
+    jweak mObjWeak;
+};
+
+
+extern sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+        JNIEnv* env, jobject inputApplicationHandleObj);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 5ed63f0..e04e4c3 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -42,11 +42,13 @@
 #include <android/graphics/GraphicsJNI.h>
 
 #include "com_android_server_PowerManagerService.h"
+#include "com_android_server_InputApplication.h"
+#include "com_android_server_InputApplicationHandle.h"
+#include "com_android_server_InputWindow.h"
+#include "com_android_server_InputWindowHandle.h"
 
 namespace android {
 
-// ----------------------------------------------------------------------------
-
 static struct {
     jclass clazz;
 
@@ -68,44 +70,6 @@
 
 static struct {
     jclass clazz;
-
-    jfieldID inputChannel;
-    jfieldID name;
-    jfieldID layoutParamsFlags;
-    jfieldID layoutParamsType;
-    jfieldID dispatchingTimeoutNanos;
-    jfieldID frameLeft;
-    jfieldID frameTop;
-    jfieldID frameRight;
-    jfieldID frameBottom;
-    jfieldID visibleFrameLeft;
-    jfieldID visibleFrameTop;
-    jfieldID visibleFrameRight;
-    jfieldID visibleFrameBottom;
-    jfieldID touchableAreaLeft;
-    jfieldID touchableAreaTop;
-    jfieldID touchableAreaRight;
-    jfieldID touchableAreaBottom;
-    jfieldID visible;
-    jfieldID canReceiveKeys;
-    jfieldID hasFocus;
-    jfieldID hasWallpaper;
-    jfieldID paused;
-    jfieldID layer;
-    jfieldID ownerPid;
-    jfieldID ownerUid;
-} gInputWindowClassInfo;
-
-static struct {
-    jclass clazz;
-
-    jfieldID name;
-    jfieldID dispatchingTimeoutNanos;
-    jfieldID token;
-} gInputApplicationClassInfo;
-
-static struct {
-    jclass clazz;
 } gKeyEventClassInfo;
 
 static struct {
@@ -141,7 +105,29 @@
     jfieldID hotSpotY;
 } gPointerIconClassInfo;
 
-// ----------------------------------------------------------------------------
+
+// --- Global functions ---
+
+static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
+        const sp<InputApplicationHandle>& inputApplicationHandle) {
+    if (inputApplicationHandle == NULL) {
+        return NULL;
+    }
+    return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())->
+            getInputApplicationHandleObjLocalRef(env);
+}
+
+static jobject getInputWindowHandleObjLocalRef(JNIEnv* env,
+        const sp<InputWindowHandle>& inputWindowHandle) {
+    if (inputWindowHandle == NULL) {
+        return NULL;
+    }
+    return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())->
+            getInputWindowHandleObjLocalRef(env);
+}
+
+
+// --- NativeInputManager ---
 
 class NativeInputManager : public virtual RefBase,
     public virtual InputReaderPolicyInterface,
@@ -160,7 +146,7 @@
     void setDisplayOrientation(int32_t displayId, int32_t orientation);
 
     status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
-            jweak inputChannelObjWeak, bool monitor);
+            const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
     status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
 
     void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
@@ -182,37 +168,22 @@
             uint32_t policyFlags);
     virtual void notifyConfigurationChanged(nsecs_t when);
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputChannel>& inputChannel);
-    virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel);
+            const sp<InputWindowHandle>& inputWindowHandle);
+    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
     virtual nsecs_t getKeyRepeatTimeout();
     virtual nsecs_t getKeyRepeatDelay();
     virtual int32_t getMaxEventsPerSecond();
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
     virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
-    virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
+    virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags);
-    virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
             const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent);
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
     virtual bool checkInjectEventsPermissionNonReentrant(
             int32_t injectorPid, int32_t injectorUid);
 
 private:
-    class ApplicationToken : public InputApplicationHandle {
-        jweak mTokenObjWeak;
-
-    public:
-        ApplicationToken(jweak tokenObjWeak) :
-            mTokenObjWeak(tokenObjWeak) { }
-
-        virtual ~ApplicationToken() {
-            JNIEnv* env = NativeInputManager::jniEnv();
-            env->DeleteWeakGlobalRef(mTokenObjWeak);
-        }
-
-        inline jweak getTokenObj() { return mTokenObjWeak; }
-    };
-
     sp<InputManager> mInputManager;
 
     jobject mCallbacksObj;
@@ -232,19 +203,12 @@
 
         // Pointer controller singleton, created and destroyed as needed.
         wp<PointerController> pointerController;
-
-        // Weak references to all currently registered input channels by connection pointer.
-        KeyedVector<InputChannel*, jweak> inputChannelObjWeakTable;
     } mLocked;
 
     // Power manager interactions.
     bool isScreenOn();
     bool isScreenBright();
 
-    jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel);
-
-    static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow);
-
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -252,7 +216,7 @@
     }
 };
 
-// ----------------------------------------------------------------------------
+
 
 NativeInputManager::NativeInputManager(jobject callbacksObj) :
     mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1),
@@ -328,88 +292,17 @@
 }
 
 status_t NativeInputManager::registerInputChannel(JNIEnv* env,
-        const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) {
-    jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj);
-    if (! inputChannelObjWeak) {
-        LOGE("Could not create weak reference for input channel.");
-        LOGE_EX(env);
-        return NO_MEMORY;
-    }
-
-    status_t status;
-    {
-        AutoMutex _l(mLock);
-
-        ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get());
-        if (index >= 0) {
-            LOGE("Input channel object '%s' has already been registered",
-                    inputChannel->getName().string());
-            status = INVALID_OPERATION;
-            goto DeleteWeakRef;
-        }
-
-        mLocked.inputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak);
-    }
-
-    status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor);
-    if (! status) {
-        // Success.
-        return OK;
-    }
-
-    // Failed!
-    {
-        AutoMutex _l(mLock);
-        mLocked.inputChannelObjWeakTable.removeItem(inputChannel.get());
-    }
-
-DeleteWeakRef:
-    env->DeleteWeakGlobalRef(inputChannelObjWeak);
-    return status;
+        const sp<InputChannel>& inputChannel,
+        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+    return mInputManager->getDispatcher()->registerInputChannel(
+            inputChannel, inputWindowHandle, monitor);
 }
 
 status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
         const sp<InputChannel>& inputChannel) {
-    jweak inputChannelObjWeak;
-    {
-        AutoMutex _l(mLock);
-
-        ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get());
-        if (index < 0) {
-            LOGE("Input channel object '%s' is not currently registered",
-                    inputChannel->getName().string());
-            return INVALID_OPERATION;
-        }
-
-        inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index);
-        mLocked.inputChannelObjWeakTable.removeItemsAt(index);
-    }
-
-    env->DeleteWeakGlobalRef(inputChannelObjWeak);
-
     return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
 }
 
-jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env,
-        const sp<InputChannel>& inputChannel) {
-    InputChannel* inputChannelPtr = inputChannel.get();
-    if (! inputChannelPtr) {
-        return NULL;
-    }
-
-    {
-        AutoMutex _l(mLock);
-
-        ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannelPtr);
-        if (index < 0) {
-            return NULL;
-        }
-
-        jweak inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index);
-        return env->NewLocalRef(inputChannelObjWeak);
-    }
-}
-
 bool NativeInputManager::getDisplayInfo(int32_t displayId,
         int32_t* width, int32_t* height, int32_t* orientation) {
     bool result = false;
@@ -549,50 +442,46 @@
 }
 
 nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-        const sp<InputChannel>& inputChannel) {
+        const sp<InputWindowHandle>& inputWindowHandle) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     LOGD("notifyANR");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    jobject tokenObjLocal;
-    if (inputApplicationHandle.get()) {
-        ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get());
-        jweak tokenObjWeak = token->getTokenObj();
-        tokenObjLocal = env->NewLocalRef(tokenObjWeak);
-    } else {
-        tokenObjLocal = NULL;
-    }
+    jobject inputApplicationHandleObj =
+            getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
+    jobject inputWindowHandleObj =
+            getInputWindowHandleObjLocalRef(env, inputWindowHandle);
 
-    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
     jlong newTimeout = env->CallLongMethod(mCallbacksObj,
-                gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal);
+                gCallbacksClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
     if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
         newTimeout = 0; // abort dispatch
     } else {
         assert(newTimeout >= 0);
     }
 
-    env->DeleteLocalRef(tokenObjLocal);
-    env->DeleteLocalRef(inputChannelObjLocal);
+    env->DeleteLocalRef(inputWindowHandleObj);
+    env->DeleteLocalRef(inputApplicationHandleObj);
     return newTimeout;
 }
 
-void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) {
+void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string());
+    LOGD("notifyInputChannelBroken");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
-    if (inputChannelObjLocal) {
+    jobject inputWindowHandleObj =
+            getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+    if (inputWindowHandleObj) {
         env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelBroken,
-                inputChannelObjLocal);
+                inputWindowHandleObj);
         checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken");
 
-        env->DeleteLocalRef(inputChannelObjLocal);
+        env->DeleteLocalRef(inputWindowHandleObj);
     }
 }
 
@@ -630,160 +519,32 @@
 
     jsize length = env->GetArrayLength(windowObjArray);
     for (jsize i = 0; i < length; i++) {
-        jobject inputTargetObj = env->GetObjectArrayElement(windowObjArray, i);
-        if (! inputTargetObj) {
+        jobject windowObj = env->GetObjectArrayElement(windowObjArray, i);
+        if (! windowObj) {
             break; // found null element indicating end of used portion of the array
         }
 
         windows.push();
         InputWindow& window = windows.editTop();
-        bool valid = populateWindow(env, inputTargetObj, window);
-        if (! valid) {
+        android_server_InputWindow_toNative(env, windowObj, &window);
+        if (window.inputChannel == NULL) {
             windows.pop();
         }
-
-        env->DeleteLocalRef(inputTargetObj);
+        env->DeleteLocalRef(windowObj);
     }
 
     mInputManager->getDispatcher()->setInputWindows(windows);
 }
 
-bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
-        InputWindow& outWindow) {
-    bool valid = false;
-
-    jobject inputChannelObj = env->GetObjectField(windowObj,
-            gInputWindowClassInfo.inputChannel);
-    if (inputChannelObj) {
-        sp<InputChannel> inputChannel =
-                android_view_InputChannel_getInputChannel(env, inputChannelObj);
-        if (inputChannel != NULL) {
-            jstring name = jstring(env->GetObjectField(windowObj,
-                    gInputWindowClassInfo.name));
-            jint layoutParamsFlags = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.layoutParamsFlags);
-            jint layoutParamsType = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.layoutParamsType);
-            jlong dispatchingTimeoutNanos = env->GetLongField(windowObj,
-                    gInputWindowClassInfo.dispatchingTimeoutNanos);
-            jint frameLeft = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.frameLeft);
-            jint frameTop = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.frameTop);
-            jint frameRight = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.frameRight);
-            jint frameBottom = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.frameBottom);
-            jint visibleFrameLeft = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.visibleFrameLeft);
-            jint visibleFrameTop = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.visibleFrameTop);
-            jint visibleFrameRight = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.visibleFrameRight);
-            jint visibleFrameBottom = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.visibleFrameBottom);
-            jint touchableAreaLeft = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.touchableAreaLeft);
-            jint touchableAreaTop = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.touchableAreaTop);
-            jint touchableAreaRight = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.touchableAreaRight);
-            jint touchableAreaBottom = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.touchableAreaBottom);
-            jboolean visible = env->GetBooleanField(windowObj,
-                    gInputWindowClassInfo.visible);
-            jboolean canReceiveKeys = env->GetBooleanField(windowObj,
-                    gInputWindowClassInfo.canReceiveKeys);
-            jboolean hasFocus = env->GetBooleanField(windowObj,
-                    gInputWindowClassInfo.hasFocus);
-            jboolean hasWallpaper = env->GetBooleanField(windowObj,
-                    gInputWindowClassInfo.hasWallpaper);
-            jboolean paused = env->GetBooleanField(windowObj,
-                    gInputWindowClassInfo.paused);
-            jint layer = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.layer);
-            jint ownerPid = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.ownerPid);
-            jint ownerUid = env->GetIntField(windowObj,
-                    gInputWindowClassInfo.ownerUid);
-
-            const char* nameStr = env->GetStringUTFChars(name, NULL);
-
-            outWindow.inputChannel = inputChannel;
-            outWindow.name.setTo(nameStr);
-            outWindow.layoutParamsFlags = layoutParamsFlags;
-            outWindow.layoutParamsType = layoutParamsType;
-            outWindow.dispatchingTimeout = dispatchingTimeoutNanos;
-            outWindow.frameLeft = frameLeft;
-            outWindow.frameTop = frameTop;
-            outWindow.frameRight = frameRight;
-            outWindow.frameBottom = frameBottom;
-            outWindow.visibleFrameLeft = visibleFrameLeft;
-            outWindow.visibleFrameTop = visibleFrameTop;
-            outWindow.visibleFrameRight = visibleFrameRight;
-            outWindow.visibleFrameBottom = visibleFrameBottom;
-            outWindow.touchableAreaLeft = touchableAreaLeft;
-            outWindow.touchableAreaTop = touchableAreaTop;
-            outWindow.touchableAreaRight = touchableAreaRight;
-            outWindow.touchableAreaBottom = touchableAreaBottom;
-            outWindow.visible = visible;
-            outWindow.canReceiveKeys = canReceiveKeys;
-            outWindow.hasFocus = hasFocus;
-            outWindow.hasWallpaper = hasWallpaper;
-            outWindow.paused = paused;
-            outWindow.layer = layer;
-            outWindow.ownerPid = ownerPid;
-            outWindow.ownerUid = ownerUid;
-
-            env->ReleaseStringUTFChars(name, nameStr);
-            env->DeleteLocalRef(name);
-            valid = true;
-        } else {
-            LOGW("Dropping input target because its input channel is not initialized.");
-        }
-
-        env->DeleteLocalRef(inputChannelObj);
-    } else {
-        LOGW("Dropping input target because the input channel object was null.");
-    }
-    return valid;
-}
-
 void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) {
     if (applicationObj) {
-        jstring nameObj = jstring(env->GetObjectField(applicationObj,
-                gInputApplicationClassInfo.name));
-        jlong dispatchingTimeoutNanos = env->GetLongField(applicationObj,
-                gInputApplicationClassInfo.dispatchingTimeoutNanos);
-        jobject tokenObj = env->GetObjectField(applicationObj,
-                gInputApplicationClassInfo.token);
-        jweak tokenObjWeak = env->NewWeakGlobalRef(tokenObj);
-        if (! tokenObjWeak) {
-            LOGE("Could not create weak reference for application token.");
-            LOGE_EX(env);
-            env->ExceptionClear();
-        }
-        env->DeleteLocalRef(tokenObj);
-
-        String8 name;
-        if (nameObj) {
-            const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
-            name.setTo(nameStr);
-            env->ReleaseStringUTFChars(nameObj, nameStr);
-            env->DeleteLocalRef(nameObj);
-        } else {
-            LOGE("InputApplication.name should not be null.");
-            name.setTo("unknown");
-        }
-
         InputApplication application;
-        application.name = name;
-        application.dispatchingTimeout = dispatchingTimeoutNanos;
-        application.handle = new ApplicationToken(tokenObjWeak);
-        mInputManager->getDispatcher()->setFocusedApplication(& application);
-    } else {
-        mInputManager->getDispatcher()->setFocusedApplication(NULL);
+        android_server_InputApplication_toNative(env, applicationObj, &application);
+        if (application.inputApplicationHandle != NULL) {
+            mInputManager->getDispatcher()->setFocusedApplication(&application);
+        }
     }
+    mInputManager->getDispatcher()->setFocusedApplication(NULL);
 }
 
 void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
@@ -875,7 +636,8 @@
     }
 }
 
-bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
+bool NativeInputManager::interceptKeyBeforeDispatching(
+        const sp<InputWindowHandle>& inputWindowHandle,
         const KeyEvent* keyEvent, uint32_t policyFlags) {
     // Policy:
     // - Ignore untrusted events and pass them along.
@@ -885,13 +647,13 @@
     if (policyFlags & POLICY_FLAG_TRUSTED) {
         JNIEnv* env = jniEnv();
 
-        // Note: inputChannel may be null.
-        jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
+        // Note: inputWindowHandle may be null.
+        jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
         if (keyEventObj) {
             jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                     gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                    inputChannelObj, keyEventObj, policyFlags);
+                    inputWindowHandleObj, keyEventObj, policyFlags);
             bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
             android_view_KeyEvent_recycle(env, keyEventObj);
             env->DeleteLocalRef(keyEventObj);
@@ -899,12 +661,12 @@
         } else {
             LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
         }
-        env->DeleteLocalRef(inputChannelObj);
+        env->DeleteLocalRef(inputWindowHandleObj);
     }
     return result;
 }
 
-bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
         const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
     // Policy:
     // - Ignore untrusted events and do not perform default handling.
@@ -912,13 +674,13 @@
     if (policyFlags & POLICY_FLAG_TRUSTED) {
         JNIEnv* env = jniEnv();
 
-        // Note: inputChannel may be null.
-        jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
+        // Note: inputWindowHandle may be null.
+        jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
         if (keyEventObj) {
             jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj,
                     gCallbacksClassInfo.dispatchUnhandledKey,
-                    inputChannelObj, keyEventObj, policyFlags);
+                    inputWindowHandleObj, keyEventObj, policyFlags);
             checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
             android_view_KeyEvent_recycle(env, keyEventObj);
             env->DeleteLocalRef(keyEventObj);
@@ -935,7 +697,7 @@
         } else {
             LOGE("Failed to obtain key event object for dispatchUnhandledKey.");
         }
-        env->DeleteLocalRef(inputChannelObj);
+        env->DeleteLocalRef(inputWindowHandleObj);
     }
     return result;
 }
@@ -1079,7 +841,7 @@
 }
 
 static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
-        jobject inputChannelObj, jboolean monitor) {
+        jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
     if (checkInputManagerUnitialized(env)) {
         return;
     }
@@ -1091,9 +853,11 @@
         return;
     }
 
+    sp<InputWindowHandle> inputWindowHandle =
+            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
 
     status_t status = gNativeInputManager->registerInputChannel(
-            env, inputChannel, inputChannelObj, monitor);
+            env, inputChannel, inputWindowHandle, monitor);
     if (status) {
         jniThrowRuntimeException(env, "Failed to register input channel.  "
                 "Check logs for details.");
@@ -1311,7 +1075,8 @@
             (void*) android_server_InputManager_nativeGetSwitchState },
     { "nativeHasKeys", "(II[I[Z)Z",
             (void*) android_server_InputManager_nativeHasKeys },
-    { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V",
+    { "nativeRegisterInputChannel",
+            "(Landroid/view/InputChannel;Lcom/android/server/InputWindowHandle;Z)V",
             (void*) android_server_InputManager_nativeRegisterInputChannel },
     { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
             (void*) android_server_InputManager_nativeUnregisterInputChannel },
@@ -1364,21 +1129,22 @@
             "notifyLidSwitchChanged", "(JZ)V");
 
     GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
-            "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V");
+            "notifyInputChannelBroken", "(Lcom/android/server/InputWindowHandle;)V");
 
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
-            "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
+            "notifyANR",
+            "(Lcom/android/server/InputApplicationHandle;Lcom/android/server/InputWindowHandle;)J");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
             "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
             "interceptKeyBeforeDispatching",
-            "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z");
+            "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz,
             "dispatchUnhandledKey",
-            "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
+            "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
@@ -1401,99 +1167,6 @@
     GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz,
             "getPointerIcon", "()Lcom/android/server/InputManager$PointerIcon;");
 
-    // InputWindow
-
-    FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
-
-    GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
-            "inputChannel", "Landroid/view/InputChannel;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
-            "name", "Ljava/lang/String;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
-            "layoutParamsFlags", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz,
-            "layoutParamsType", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz,
-            "dispatchingTimeoutNanos", "J");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz,
-            "frameLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz,
-            "frameTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz,
-            "frameRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
-            "frameBottom", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
-            "visibleFrameLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
-            "visibleFrameTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
-            "visibleFrameRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
-            "visibleFrameBottom", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
-            "touchableAreaLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz,
-            "touchableAreaTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz,
-            "touchableAreaRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz,
-            "touchableAreaBottom", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
-            "visible", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
-            "canReceiveKeys", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
-            "hasFocus", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz,
-            "hasWallpaper", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
-            "paused", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
-            "layer", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
-            "ownerPid", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz,
-            "ownerUid", "I");
-
-    // InputApplication
-
-    FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz,
-            "name", "Ljava/lang/String;");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
-            gInputApplicationClassInfo.clazz,
-            "dispatchingTimeoutNanos", "J");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.token, gInputApplicationClassInfo.clazz,
-            "token", "Ljava/lang/Object;");
-
     // KeyEvent
 
     FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
new file mode 100644
index 0000000..a4609a0
--- /dev/null
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputWindow"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <android_view_InputChannel.h>
+#include "com_android_server_InputWindow.h"
+#include "com_android_server_InputWindowHandle.h"
+
+namespace android {
+
+static struct {
+    jclass clazz;
+
+    jfieldID inputWindowHandle;
+    jfieldID inputChannel;
+    jfieldID name;
+    jfieldID layoutParamsFlags;
+    jfieldID layoutParamsType;
+    jfieldID dispatchingTimeoutNanos;
+    jfieldID frameLeft;
+    jfieldID frameTop;
+    jfieldID frameRight;
+    jfieldID frameBottom;
+    jfieldID visibleFrameLeft;
+    jfieldID visibleFrameTop;
+    jfieldID visibleFrameRight;
+    jfieldID visibleFrameBottom;
+    jfieldID touchableAreaLeft;
+    jfieldID touchableAreaTop;
+    jfieldID touchableAreaRight;
+    jfieldID touchableAreaBottom;
+    jfieldID visible;
+    jfieldID canReceiveKeys;
+    jfieldID hasFocus;
+    jfieldID hasWallpaper;
+    jfieldID paused;
+    jfieldID layer;
+    jfieldID ownerPid;
+    jfieldID ownerUid;
+} gInputWindowClassInfo;
+
+
+// --- Global functions ---
+
+void android_server_InputWindow_toNative(
+        JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) {
+    jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj,
+            gInputWindowClassInfo.inputWindowHandle);
+    if (inputWindowHandleObj) {
+        outInputWindow->inputWindowHandle =
+                android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
+        env->DeleteLocalRef(inputWindowHandleObj);
+    } else {
+        outInputWindow->inputWindowHandle = NULL;
+    }
+
+    jobject inputChannelObj = env->GetObjectField(inputWindowObj,
+            gInputWindowClassInfo.inputChannel);
+    if (inputChannelObj) {
+        outInputWindow->inputChannel =
+                android_view_InputChannel_getInputChannel(env, inputChannelObj);
+        env->DeleteLocalRef(inputChannelObj);
+    } else {
+        outInputWindow->inputChannel = NULL;
+    }
+
+    jstring nameObj = jstring(env->GetObjectField(inputWindowObj,
+            gInputWindowClassInfo.name));
+    if (nameObj) {
+        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+        outInputWindow->name.setTo(nameStr);
+        env->ReleaseStringUTFChars(nameObj, nameStr);
+        env->DeleteLocalRef(nameObj);
+    } else {
+        LOGE("InputWindow.name should not be null.");
+        outInputWindow->name.setTo("unknown");
+    }
+
+    outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.layoutParamsFlags);
+    outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.layoutParamsType);
+    outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj,
+            gInputWindowClassInfo.dispatchingTimeoutNanos);
+    outInputWindow->frameLeft = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.frameLeft);
+    outInputWindow->frameTop = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.frameTop);
+    outInputWindow->frameRight = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.frameRight);
+    outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.frameBottom);
+    outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.visibleFrameLeft);
+    outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.visibleFrameTop);
+    outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.visibleFrameRight);
+    outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.visibleFrameBottom);
+    outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.touchableAreaLeft);
+    outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.touchableAreaTop);
+    outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.touchableAreaRight);
+    outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.touchableAreaBottom);
+    outInputWindow->visible = env->GetBooleanField(inputWindowObj,
+            gInputWindowClassInfo.visible);
+    outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
+            gInputWindowClassInfo.canReceiveKeys);
+    outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj,
+            gInputWindowClassInfo.hasFocus);
+    outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj,
+            gInputWindowClassInfo.hasWallpaper);
+    outInputWindow->paused = env->GetBooleanField(inputWindowObj,
+            gInputWindowClassInfo.paused);
+    outInputWindow->layer = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.layer);
+    outInputWindow->ownerPid = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.ownerPid);
+    outInputWindow->ownerUid = env->GetIntField(inputWindowObj,
+            gInputWindowClassInfo.ownerUid);
+}
+
+
+// --- JNI ---
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputWindow(JNIEnv* env) {
+    FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
+
+    GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz,
+            "inputWindowHandle", "Lcom/android/server/InputWindowHandle;");
+
+    GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
+            "inputChannel", "Landroid/view/InputChannel;");
+
+    GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
+            "name", "Ljava/lang/String;");
+
+    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
+            "layoutParamsFlags", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz,
+            "layoutParamsType", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz,
+            "dispatchingTimeoutNanos", "J");
+
+    GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz,
+            "frameLeft", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz,
+            "frameTop", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz,
+            "frameRight", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
+            "frameBottom", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
+            "visibleFrameLeft", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
+            "visibleFrameTop", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
+            "visibleFrameRight", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
+            "visibleFrameBottom", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
+            "touchableAreaLeft", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz,
+            "touchableAreaTop", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz,
+            "touchableAreaRight", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz,
+            "touchableAreaBottom", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
+            "visible", "Z");
+
+    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
+            "canReceiveKeys", "Z");
+
+    GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
+            "hasFocus", "Z");
+
+    GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz,
+            "hasWallpaper", "Z");
+
+    GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
+            "paused", "Z");
+
+    GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
+            "layer", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
+            "ownerPid", "I");
+
+    GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz,
+            "ownerUid", "I");
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h
new file mode 100644
index 0000000..eaf7bde
--- /dev/null
+++ b/services/jni/com_android_server_InputWindow.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_INPUT_WINDOW_H
+#define _ANDROID_SERVER_INPUT_WINDOW_H
+
+#include <input/InputWindow.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+extern void android_server_InputWindow_toNative(
+        JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_WINDOW_H
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
new file mode 100644
index 0000000..4d66212
--- /dev/null
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputWindowHandle"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
+
+#include "com_android_server_InputWindowHandle.h"
+#include "com_android_server_InputApplicationHandle.h"
+
+namespace android {
+
+static struct {
+    jclass clazz;
+
+    jfieldID ptr;
+    jfieldID inputApplicationHandle;
+} gInputWindowHandleClassInfo;
+
+static Mutex gHandleMutex;
+
+
+// --- NativeInputWindowHandle ---
+
+NativeInputWindowHandle::NativeInputWindowHandle(
+        const sp<InputApplicationHandle>& inputApplicationHandle, jweak objWeak) :
+        InputWindowHandle(inputApplicationHandle),
+        mObjWeak(objWeak) {
+}
+
+NativeInputWindowHandle::~NativeInputWindowHandle() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteWeakGlobalRef(mObjWeak);
+}
+
+jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) {
+    return env->NewLocalRef(mObjWeak);
+}
+
+
+// --- Global functions ---
+
+sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+        JNIEnv* env, jobject inputWindowHandleObj) {
+    if (!inputWindowHandleObj) {
+        return NULL;
+    }
+
+    AutoMutex _l(gHandleMutex);
+
+    int ptr = env->GetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
+    NativeInputWindowHandle* handle;
+    if (ptr) {
+        handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
+    } else {
+        jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj,
+                gInputWindowHandleClassInfo.inputApplicationHandle);
+        sp<InputApplicationHandle> inputApplicationHandle =
+                android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+        env->DeleteLocalRef(inputApplicationHandleObj);
+
+        jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
+        handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak);
+        handle->incStrong(inputWindowHandleObj);
+        env->SetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
+                reinterpret_cast<int>(handle));
+    }
+    return handle;
+}
+
+
+// --- JNI ---
+
+static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
+    AutoMutex _l(gHandleMutex);
+
+    int ptr = env->GetIntField(obj, gInputWindowHandleClassInfo.ptr);
+    if (ptr) {
+        env->SetIntField(obj, gInputWindowHandleClassInfo.ptr, 0);
+
+        NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
+        handle->decStrong(obj);
+    }
+}
+
+
+static JNINativeMethod gInputWindowHandleMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeDispose", "()V",
+            (void*) android_server_InputWindowHandle_nativeDispose },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputWindowHandle(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/InputWindowHandle",
+            gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/InputWindowHandle");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz,
+            "ptr", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle,
+            gInputWindowHandleClassInfo.clazz,
+            "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h
new file mode 100644
index 0000000..43f2a6b
--- /dev/null
+++ b/services/jni/com_android_server_InputWindowHandle.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
+#define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
+
+#include <input/InputWindow.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+class NativeInputWindowHandle : public InputWindowHandle {
+public:
+    NativeInputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+            jweak objWeak);
+    virtual ~NativeInputWindowHandle();
+
+    jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
+
+private:
+    jweak mObjWeak;
+};
+
+
+extern sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+        JNIEnv* env, jobject inputWindowHandleObj);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index cd4f0a4..bdd6d80 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -6,6 +6,10 @@
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_BatteryService(JNIEnv* env);
+int register_android_server_InputApplication(JNIEnv* env);
+int register_android_server_InputApplicationHandle(JNIEnv* env);
+int register_android_server_InputWindow(JNIEnv* env);
+int register_android_server_InputWindowHandle(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
@@ -28,6 +32,10 @@
     LOG_ASSERT(env, "Could not retrieve the env!");
 
     register_android_server_PowerManagerService(env);
+    register_android_server_InputApplication(env);
+    register_android_server_InputApplicationHandle(env);
+    register_android_server_InputWindow(env);
+    register_android_server_InputWindowHandle(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);