Merge "Refactor input dispatcher use of window/app handles."
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index cc80062..8902f7a 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -26,26 +26,32 @@
 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
+ * Describes the properties of an application that can receive input.
+ *
+ * Used by the native input dispatcher as a handle for the window manager objects
  * that describe an application.
  */
 class InputApplicationHandle : public RefBase {
+public:
+    String8 name;
+    nsecs_t dispatchingTimeout;
+
+    /**
+     * Requests that the state of this object be updated to reflect
+     * the most current available information about the application.
+     *
+     * This method should only be called from within the input dispatcher's
+     * critical section.
+     *
+     * Returns true on success, or false if the handle is no longer valid.
+     */
+    virtual bool update() = 0;
+
 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 10b9083..1cac5025 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -211,11 +211,8 @@
     mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
     mNextUnblockedEvent(NULL),
     mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
-    mFocusedWindow(NULL),
-    mFocusedApplication(NULL),
     mCurrentInputTargetsValid(false),
-    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE),
-    mLastHoverWindow(NULL) {
+    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
     mLooper = new Looper(false);
 
     mInboundQueue.headSentinel.refCount = -1;
@@ -501,16 +498,15 @@
         if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                 && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                 && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
-                && mInputTargetWaitApplication != NULL) {
+                && mInputTargetWaitApplicationHandle != NULL) {
             int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_X));
             int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_Y));
-            const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y);
-            if (touchedWindow
-                    && touchedWindow->inputWindowHandle != NULL
-                    && touchedWindow->inputWindowHandle->getInputApplicationHandle()
-                            != mInputTargetWaitApplication) {
+            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
+            if (touchedWindowHandle != NULL
+                    && touchedWindowHandle->inputApplicationHandle
+                            != mInputTargetWaitApplicationHandle) {
                 // User touched a different application than the one we are waiting on.
                 // Flag the event, and start pruning the input queue.
                 mNextUnblockedEvent = motionEntry;
@@ -524,25 +520,25 @@
     return needWake;
 }
 
-const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
+sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
     // Traverse windows from front to back to find touched window.
-    size_t numWindows = mWindows.size();
+    size_t numWindows = mWindowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        const InputWindow* window = & mWindows.editItemAt(i);
-        int32_t flags = window->layoutParamsFlags;
+        sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+        int32_t flags = windowHandle->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->touchableRegionContainsPoint(x, y)) {
+        if (windowHandle->visible) {
+            if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+                bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+                        | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+                if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
                     // Found window.
-                    return window;
+                    return windowHandle;
                 }
             }
         }
 
-        if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
+        if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
             // Error window is on top but not visible, so touch is dropped.
             return NULL;
         }
@@ -781,8 +777,8 @@
         if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (mFocusedWindow) {
-                commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle;
+            if (mFocusedWindowHandle != NULL) {
+                commandEntry->inputWindowHandle = mFocusedWindowHandle;
             }
             commandEntry->keyEntry = entry;
             entry->refCount += 1;
@@ -1011,7 +1007,7 @@
     mCurrentInputTargetsValid = false;
     mCurrentInputTargets.clear();
     mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
-    mInputTargetWaitApplication.clear();
+    mInputTargetWaitApplicationHandle.clear();
 }
 
 void InputDispatcher::commitTargetsLocked() {
@@ -1019,9 +1015,11 @@
 }
 
 int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
-        const EventEntry* entry, const InputApplication* application, const InputWindow* window,
+        const EventEntry* entry,
+        const sp<InputApplicationHandle>& applicationHandle,
+        const sp<InputWindowHandle>& windowHandle,
         nsecs_t* nextWakeupTime) {
-    if (application == NULL && window == NULL) {
+    if (applicationHandle == NULL && windowHandle == NULL) {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
 #if DEBUG_FOCUS
             LOGD("Waiting for system to become ready for input.");
@@ -1030,29 +1028,29 @@
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
             mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplication.clear();
+            mInputTargetWaitApplicationHandle.clear();
         }
     } else {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
 #if DEBUG_FOCUS
             LOGD("Waiting for application to become ready for input: %s",
-                    getApplicationWindowLabelLocked(application, window).string());
+                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
 #endif
-            nsecs_t timeout = window ? window->dispatchingTimeout :
-                application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+            nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout :
+                applicationHandle != NULL ?
+                        applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
 
             mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = currentTime + timeout;
             mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplication.clear();
+            mInputTargetWaitApplicationHandle.clear();
 
-            if (window && window->inputWindowHandle != NULL) {
-                mInputTargetWaitApplication =
-                        window->inputWindowHandle->getInputApplicationHandle();
+            if (windowHandle != NULL) {
+                mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
             }
-            if (mInputTargetWaitApplication == NULL && application) {
-                mInputTargetWaitApplication = application->inputApplicationHandle;
+            if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
+                mInputTargetWaitApplicationHandle = applicationHandle;
             }
         }
     }
@@ -1062,7 +1060,8 @@
     }
 
     if (currentTime >= mInputTargetWaitTimeoutTime) {
-        onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime);
+        onANRLocked(currentTime, applicationHandle, windowHandle,
+                entry->eventTime, mInputTargetWaitStartTime);
 
         // Force poll loop to wake up immediately on next iteration once we get the
         // ANR response back from the policy.
@@ -1129,15 +1128,15 @@
 
     // If there is no currently focused window and no focused application
     // then drop the event.
-    if (! mFocusedWindow) {
-        if (mFocusedApplication) {
+    if (mFocusedWindowHandle == NULL) {
+        if (mFocusedApplicationHandle != NULL) {
 #if DEBUG_FOCUS
             LOGD("Waiting because there is no focused window but there is a "
                     "focused application that may eventually add a window: %s.",
-                    getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+                    getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
 #endif
             injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                    mFocusedApplication, NULL, nextWakeupTime);
+                    mFocusedApplicationHandle, NULL, nextWakeupTime);
             goto Unresponsive;
         }
 
@@ -1147,34 +1146,34 @@
     }
 
     // Check permissions.
-    if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
+    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
         goto Failed;
     }
 
     // If the currently focused window is paused then keep waiting.
-    if (mFocusedWindow->paused) {
+    if (mFocusedWindowHandle->paused) {
 #if DEBUG_FOCUS
         LOGD("Waiting because focused window is paused.");
 #endif
         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplication, mFocusedWindow, nextWakeupTime);
+                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
         goto Unresponsive;
     }
 
     // If the currently focused window is still working on previous events then keep waiting.
-    if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
+    if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
 #if DEBUG_FOCUS
         LOGD("Waiting because focused window still processing previous input.");
 #endif
         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplication, mFocusedWindow, nextWakeupTime);
+                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
         goto Unresponsive;
     }
 
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-    addWindowTargetLocked(mFocusedWindow,
+    addWindowTargetLocked(mFocusedWindowHandle,
             InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
 
     // Done.
@@ -1236,7 +1235,7 @@
     // Update the touch state as needed based on the properties of the touch event.
     int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
     InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
-    const InputWindow* newHoverWindow = NULL;
+    sp<InputWindowHandle> newHoverWindowHandle;
 
     bool isSplit = mTouchState.split;
     bool switchedDevice = mTouchState.deviceId >= 0
@@ -1279,42 +1278,44 @@
                 getAxisValue(AMOTION_EVENT_AXIS_X));
         int32_t y = int32_t(sample->pointerCoords[pointerIndex].
                 getAxisValue(AMOTION_EVENT_AXIS_Y));
-        const InputWindow* newTouchedWindow = NULL;
-        const InputWindow* topErrorWindow = NULL;
+        sp<InputWindowHandle> newTouchedWindowHandle;
+        sp<InputWindowHandle> topErrorWindowHandle;
         bool isTouchModal = false;
 
         // Traverse windows from front to back to find touched window and outside targets.
-        size_t numWindows = mWindows.size();
+        size_t numWindows = mWindowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
-            const InputWindow* window = & mWindows.editItemAt(i);
-            int32_t flags = window->layoutParamsFlags;
+            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+            int32_t flags = windowHandle->layoutParamsFlags;
 
-            if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
-                if (! topErrorWindow) {
-                    topErrorWindow = window;
+            if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+                if (topErrorWindowHandle == NULL) {
+                    topErrorWindowHandle = windowHandle;
                 }
             }
 
-            if (window->visible) {
-                if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
-                    isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
-                            | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
-                    if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
-                        if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
-                            newTouchedWindow = window;
+            if (windowHandle->visible) {
+                if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+                    isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+                            | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+                    if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+                        if (! screenWasOff
+                                || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) {
+                            newTouchedWindowHandle = windowHandle;
                         }
                         break; // found touched window, exit window loop
                     }
                 }
 
                 if (maskedAction == AMOTION_EVENT_ACTION_DOWN
-                        && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
+                        && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) {
                     int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
-                    if (isWindowObscuredAtPointLocked(window, x, y)) {
+                    if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
                         outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
                     }
 
-                    mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
+                    mTempTouchState.addOrUpdateWindow(
+                            windowHandle, outsideTargetFlags, BitSet32(0));
                 }
             }
         }
@@ -1322,7 +1323,7 @@
         // If there is an error window but it is not taking focus (typically because
         // it is invisible) then wait for it.  Any other focused window may in
         // fact be in ANR state.
-        if (topErrorWindow && newTouchedWindow != topErrorWindow) {
+        if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) {
 #if DEBUG_FOCUS
             LOGD("Waiting because system error window is pending.");
 #endif
@@ -1333,26 +1334,26 @@
         }
 
         // Figure out whether splitting will be allowed for this window.
-        if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) {
+        if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) {
             // New window supports splitting.
             isSplit = true;
         } else if (isSplit) {
             // New window does not support splitting but we have already split events.
             // Assign the pointer to the first foreground window we find.
             // (May be NULL which is why we put this code block before the next check.)
-            newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
+            newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
         }
 
         // If we did not find a touched window then fail.
-        if (! newTouchedWindow) {
-            if (mFocusedApplication) {
+        if (newTouchedWindowHandle == NULL) {
+            if (mFocusedApplicationHandle != NULL) {
 #if DEBUG_FOCUS
                 LOGD("Waiting because there is no touched window but there is a "
                         "focused application that may eventually add a new window: %s.",
-                        getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+                        getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
 #endif
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        mFocusedApplication, NULL, nextWakeupTime);
+                        mFocusedApplicationHandle, NULL, nextWakeupTime);
                 goto Unresponsive;
             }
 
@@ -1366,20 +1367,20 @@
         if (isSplit) {
             targetFlags |= InputTarget::FLAG_SPLIT;
         }
-        if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+        if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
             targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
         }
 
         // Update hover state.
         if (isHoverAction) {
-            newHoverWindow = newTouchedWindow;
+            newHoverWindowHandle = newTouchedWindowHandle;
 
             // Ensure all subsequent motion samples are also within the touched window.
             // Set *outSplitBatchAfterSample to the sample before the first one that is not
             // within the touched window.
             if (!isTouchModal) {
                 while (sample->next) {
-                    if (!newHoverWindow->touchableRegionContainsPoint(
+                    if (!newHoverWindowHandle->touchableRegionContainsPoint(
                             sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
                             sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
                         *outSplitBatchAfterSample = sample;
@@ -1389,7 +1390,7 @@
                 }
             }
         } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
-            newHoverWindow = mLastHoverWindow;
+            newHoverWindowHandle = mLastHoverWindowHandle;
         }
 
         // Update the temporary touch state.
@@ -1398,7 +1399,7 @@
             uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
             pointerIds.markBit(pointerId);
         }
-        mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+        mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
     } else {
         /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
 
@@ -1420,19 +1421,22 @@
             int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
             int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
 
-            const InputWindow* oldTouchedWindow = mTempTouchState.getFirstForegroundWindow();
-            const InputWindow* newTouchedWindow = findTouchedWindowAtLocked(x, y);
-            if (oldTouchedWindow != newTouchedWindow && newTouchedWindow) {
+            sp<InputWindowHandle> oldTouchedWindowHandle =
+                    mTempTouchState.getFirstForegroundWindowHandle();
+            sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(x, y);
+            if (oldTouchedWindowHandle != newTouchedWindowHandle
+                    && newTouchedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 LOGD("Touch is slipping out of window %s into window %s.",
-                        oldTouchedWindow->name.string(), newTouchedWindow->name.string());
+                        oldTouchedWindowHandle->name.string(),
+                        newTouchedWindowHandle->name.string());
 #endif
                 // Make a slippery exit from the old window.
-                mTempTouchState.addOrUpdateWindow(oldTouchedWindow,
+                mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
                         InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
 
                 // Make a slippery entrance into the new window.
-                if (newTouchedWindow->supportsSplitTouch()) {
+                if (newTouchedWindowHandle->supportsSplitTouch()) {
                     isSplit = true;
                 }
 
@@ -1441,7 +1445,7 @@
                 if (isSplit) {
                     targetFlags |= InputTarget::FLAG_SPLIT;
                 }
-                if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+                if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
                     targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
                 }
 
@@ -1449,7 +1453,7 @@
                 if (isSplit) {
                     pointerIds.markBit(entry->pointerProperties[0].id);
                 }
-                mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+                mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
 
                 // Split the batch here so we send exactly one sample.
                 *outSplitBatchAfterSample = &entry->firstSample;
@@ -1457,25 +1461,25 @@
         }
     }
 
-    if (newHoverWindow != mLastHoverWindow) {
+    if (newHoverWindowHandle != mLastHoverWindowHandle) {
         // Split the batch here so we send exactly one sample as part of ENTER or EXIT.
         *outSplitBatchAfterSample = &entry->firstSample;
 
         // Let the previous window know that the hover sequence is over.
-        if (mLastHoverWindow) {
+        if (mLastHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
-            LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string());
+            LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string());
 #endif
-            mTempTouchState.addOrUpdateWindow(mLastHoverWindow,
+            mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
         }
 
         // Let the new window know that the hover sequence is starting.
-        if (newHoverWindow) {
+        if (newHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
-            LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string());
+            LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string());
 #endif
-            mTempTouchState.addOrUpdateWindow(newHoverWindow,
+            mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
         }
     }
@@ -1488,7 +1492,8 @@
             const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
             if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
                 haveForegroundWindow = true;
-                if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {
+                if (! checkInjectionPermission(touchedWindow.windowHandle,
+                        entry->injectionState)) {
                     injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
                     injectionPermission = INJECTION_PERMISSION_DENIED;
                     goto Failed;
@@ -1510,14 +1515,15 @@
     // Check whether windows listening for outside touches are owned by the same UID. If it is
     // set the policy flag that we will not reveal coordinate information to this window.
     if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
-        const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
-        const int32_t foregroundWindowUid = foregroundWindow->ownerUid;
+        sp<InputWindowHandle> foregroundWindowHandle =
+                mTempTouchState.getFirstForegroundWindowHandle();
+        const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid;
         for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
             const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
             if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
-                const InputWindow* inputWindow = touchedWindow.window;
-                if (inputWindow->ownerUid != foregroundWindowUid) {
-                    mTempTouchState.addOrUpdateWindow(inputWindow,
+                sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
+                if (inputWindowHandle->ownerUid != foregroundWindowUid) {
+                    mTempTouchState.addOrUpdateWindow(inputWindowHandle,
                             InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
                 }
             }
@@ -1529,22 +1535,22 @@
         const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
         if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
             // If the touched window is paused then keep waiting.
-            if (touchedWindow.window->paused) {
+            if (touchedWindow.windowHandle->paused) {
 #if DEBUG_FOCUS
                 LOGD("Waiting because touched window is paused.");
 #endif
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.window, nextWakeupTime);
+                        NULL, touchedWindow.windowHandle, nextWakeupTime);
                 goto Unresponsive;
             }
 
             // If the touched window is still working on previous events then keep waiting.
-            if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {
+            if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
                 LOGD("Waiting because touched window still processing previous input.");
 #endif
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.window, nextWakeupTime);
+                        NULL, touchedWindow.windowHandle, nextWakeupTime);
                 goto Unresponsive;
             }
         }
@@ -1557,12 +1563,13 @@
     // engine only supports touch events.  We would need to add a mechanism similar
     // to View.onGenericMotionEvent to enable wallpapers to handle these events.
     if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
-        const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
-        if (foregroundWindow->hasWallpaper) {
-            for (size_t i = 0; i < mWindows.size(); i++) {
-                const InputWindow* window = & mWindows[i];
-                if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
-                    mTempTouchState.addOrUpdateWindow(window,
+        sp<InputWindowHandle> foregroundWindowHandle =
+                mTempTouchState.getFirstForegroundWindowHandle();
+        if (foregroundWindowHandle->hasWallpaper) {
+            for (size_t i = 0; i < mWindowHandles.size(); i++) {
+                sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+                if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) {
+                    mTempTouchState.addOrUpdateWindow(windowHandle,
                             InputTarget::FLAG_WINDOW_IS_OBSCURED
                                     | InputTarget::FLAG_DISPATCH_AS_IS,
                             BitSet32(0));
@@ -1576,7 +1583,7 @@
 
     for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
         const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
-        addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,
+        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                 touchedWindow.pointerIds);
     }
 
@@ -1658,7 +1665,7 @@
             }
 
             // Update hover state.
-            mLastHoverWindow = newHoverWindow;
+            mLastHoverWindowHandle = newHoverWindowHandle;
         }
     } else {
 #if DEBUG_FOCUS
@@ -1681,16 +1688,16 @@
     return injectionResult;
 }
 
-void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
-        BitSet32 pointerIds) {
+void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+        int32_t targetFlags, BitSet32 pointerIds) {
     mCurrentInputTargets.push();
 
     InputTarget& target = mCurrentInputTargets.editTop();
-    target.inputChannel = window->inputChannel;
+    target.inputChannel = windowHandle->inputChannel;
     target.flags = targetFlags;
-    target.xOffset = - window->frameLeft;
-    target.yOffset = - window->frameTop;
-    target.scaleFactor = window->scaleFactor;
+    target.xOffset = - windowHandle->frameLeft;
+    target.yOffset = - windowHandle->frameTop;
+    target.scaleFactor = windowHandle->scaleFactor;
     target.pointerIds = pointerIds;
 }
 
@@ -1708,17 +1715,17 @@
     }
 }
 
-bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
+bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
         const InjectionState* injectionState) {
     if (injectionState
-            && (window == NULL || window->ownerUid != injectionState->injectorUid)
+            && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid)
             && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
-        if (window) {
-            LOGW("Permission denied: injecting event from pid %d uid %d to window "
-                    "with input channel %s owned by uid %d",
+        if (windowHandle != NULL) {
+            LOGW("Permission denied: injecting event from pid %d uid %d to window %s "
+                    "owned by uid %d",
                     injectionState->injectorPid, injectionState->injectorUid,
-                    window->inputChannel->getName().string(),
-                    window->ownerUid);
+                    windowHandle->name.string(),
+                    windowHandle->ownerUid);
         } else {
             LOGW("Permission denied: injecting event from pid %d uid %d",
                     injectionState->injectorPid, injectionState->injectorUid);
@@ -1729,22 +1736,24 @@
 }
 
 bool InputDispatcher::isWindowObscuredAtPointLocked(
-        const InputWindow* window, int32_t x, int32_t y) const {
-    size_t numWindows = mWindows.size();
+        const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
+    size_t numWindows = mWindowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        const InputWindow* other = & mWindows.itemAt(i);
-        if (other == window) {
+        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        if (otherHandle == windowHandle) {
             break;
         }
-        if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) {
+        if (otherHandle->visible && ! otherHandle->isTrustedOverlay()
+                && otherHandle->frameContainsPoint(x, y)) {
             return true;
         }
     }
     return false;
 }
 
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) {
-    ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel);
+bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
+        const sp<InputWindowHandle>& windowHandle) {
+    ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel);
     if (connectionIndex >= 0) {
         sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
         return connection->outboundQueue.isEmpty();
@@ -1753,19 +1762,20 @@
     }
 }
 
-String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application,
-        const InputWindow* window) {
-    if (application) {
-        if (window) {
-            String8 label(application->name);
+String8 InputDispatcher::getApplicationWindowLabelLocked(
+        const sp<InputApplicationHandle>& applicationHandle,
+        const sp<InputWindowHandle>& windowHandle) {
+    if (applicationHandle != NULL) {
+        if (windowHandle != NULL) {
+            String8 label(applicationHandle->name);
             label.append(" - ");
-            label.append(window->name);
+            label.append(windowHandle->name);
             return label;
         } else {
-            return application->name;
+            return applicationHandle->name;
         }
-    } else if (window) {
-        return window->name;
+    } else if (windowHandle != NULL) {
+        return windowHandle->name;
     } else {
         return String8("<unknown application or window>");
     }
@@ -2422,11 +2432,11 @@
             }
 
             InputTarget target;
-            const InputWindow* window = getWindowLocked(connection->inputChannel);
-            if (window) {
-                target.xOffset = -window->frameLeft;
-                target.yOffset = -window->frameTop;
-                target.scaleFactor = window->scaleFactor;
+            sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
+            if (windowHandle != NULL) {
+                target.xOffset = -windowHandle->frameLeft;
+                target.yOffset = -windowHandle->frameTop;
+                target.scaleFactor = windowHandle->scaleFactor;
             } else {
                 target.xOffset = 0;
                 target.yOffset = 0;
@@ -2809,7 +2819,7 @@
                     }
 
                     if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-                        if (!mLastHoverWindow) {
+                        if (mLastHoverWindowHandle == NULL) {
 #if DEBUG_BATCHING
                             LOGD("Not streaming hover move because there is no "
                                     "last hovered window.");
@@ -2817,15 +2827,16 @@
                             goto NoBatchingOrStreaming;
                         }
 
-                        const InputWindow* hoverWindow = findTouchedWindowAtLocked(
+                        sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
                                 pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
                                 pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-                        if (mLastHoverWindow != hoverWindow) {
+                        if (mLastHoverWindowHandle != hoverWindowHandle) {
 #if DEBUG_BATCHING
                             LOGD("Not streaming hover move because the last hovered window "
                                     "is '%s' but the currently hovered window is '%s'.",
-                                    mLastHoverWindow->name.string(),
-                                    hoverWindow ? hoverWindow->name.string() : "<null>");
+                                    mLastHoverWindowHandle->name.string(),
+                                    hoverWindowHandle != NULL
+                                            ? hoverWindowHandle->name.string() : "<null>");
 #endif
                             goto NoBatchingOrStreaming;
                         }
@@ -3125,113 +3136,109 @@
     }
 }
 
-const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
-    for (size_t i = 0; i < mWindows.size(); i++) {
-        const InputWindow* window = & mWindows[i];
-        if (window->inputChannel == inputChannel) {
-            return window;
+sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
+        const sp<InputChannel>& inputChannel) const {
+    size_t numWindows = mWindowHandles.size();
+    for (size_t i = 0; i < numWindows; i++) {
+        const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+        if (windowHandle->inputChannel == inputChannel) {
+            return windowHandle;
         }
     }
     return NULL;
 }
 
-void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
+bool InputDispatcher::hasWindowHandleLocked(
+        const sp<InputWindowHandle>& windowHandle) const {
+    size_t numWindows = mWindowHandles.size();
+    for (size_t i = 0; i < numWindows; i++) {
+        if (mWindowHandles.itemAt(i) == windowHandle) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
 #if DEBUG_FOCUS
     LOGD("setInputWindows");
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
 
-        // Clear old window pointers.
-        sp<InputChannel> oldFocusedWindowChannel;
-        if (mFocusedWindow) {
-            oldFocusedWindowChannel = mFocusedWindow->inputChannel;
-            mFocusedWindow = NULL;
-        }
-        sp<InputChannel> oldLastHoverWindowChannel;
-        if (mLastHoverWindow) {
-            oldLastHoverWindowChannel = mLastHoverWindow->inputChannel;
-            mLastHoverWindow = NULL;
-        }
+        mWindowHandles = inputWindowHandles;
 
-        mWindows.clear();
-
-        // Loop over new windows and rebuild the necessary window pointers for
-        // tracking focus and touch.
-        mWindows.appendVector(inputWindows);
-
-        size_t numWindows = mWindows.size();
-        for (size_t i = 0; i < numWindows; i++) {
-            const InputWindow* window = & mWindows.itemAt(i);
-            if (window->hasFocus) {
-                mFocusedWindow = window;
-                break;
+        sp<InputWindowHandle> newFocusedWindowHandle;
+        bool foundHoveredWindow = false;
+        for (size_t i = 0; i < mWindowHandles.size(); i++) {
+            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+            if (!windowHandle->update() || windowHandle->inputChannel == NULL) {
+                mWindowHandles.removeAt(i--);
+                continue;
+            }
+            if (windowHandle->hasFocus) {
+                newFocusedWindowHandle = windowHandle;
+            }
+            if (windowHandle == mLastHoverWindowHandle) {
+                foundHoveredWindow = true;
             }
         }
 
-        if (oldFocusedWindowChannel != NULL) {
-            if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+        if (!foundHoveredWindow) {
+            mLastHoverWindowHandle = NULL;
+        }
+
+        if (mFocusedWindowHandle != newFocusedWindowHandle) {
+            if (mFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 LOGD("Focus left window: %s",
-                        oldFocusedWindowChannel->getName().string());
+                        mFocusedWindowHandle->name.string());
 #endif
                 CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                         "focus left window");
-                synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
-                oldFocusedWindowChannel.clear();
+                synthesizeCancelationEventsForInputChannelLocked(
+                        mFocusedWindowHandle->inputChannel, options);
             }
-        }
-        if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+            if (newFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
-            LOGD("Focus entered window: %s",
-                    mFocusedWindow->inputChannel->getName().string());
+                LOGD("Focus entered window: %s",
+                        newFocusedWindowHandle->name.string());
 #endif
+            }
+            mFocusedWindowHandle = newFocusedWindowHandle;
         }
 
-        for (size_t i = 0; i < mTouchState.windows.size(); ) {
+        for (size_t i = 0; i < mTouchState.windows.size(); i++) {
             TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
-            const InputWindow* window = getWindowLocked(touchedWindow.channel);
-            if (window) {
-                touchedWindow.window = window;
-                i += 1;
-            } else {
+            if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
-                LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+                LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string());
 #endif
                 CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                         "touched window was removed");
-                synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
-                mTouchState.windows.removeAt(i);
+                synthesizeCancelationEventsForInputChannelLocked(
+                        touchedWindow.windowHandle->inputChannel, options);
+                mTouchState.windows.removeAt(i--);
             }
         }
-
-        // Recover the last hovered window.
-        if (oldLastHoverWindowChannel != NULL) {
-            mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel);
-            oldLastHoverWindowChannel.clear();
-        }
-
-#if DEBUG_FOCUS
-        //logDispatchStateLocked();
-#endif
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
     mLooper->wake();
 }
 
-void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
+void InputDispatcher::setFocusedApplication(
+        const sp<InputApplicationHandle>& inputApplicationHandle) {
 #if DEBUG_FOCUS
     LOGD("setFocusedApplication");
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
 
-        releaseFocusedApplicationLocked();
-
-        if (inputApplication) {
-            mFocusedApplicationStorage = *inputApplication;
-            mFocusedApplication = & mFocusedApplicationStorage;
+        if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
+            mFocusedApplicationHandle = inputApplicationHandle;
+        } else {
+            mFocusedApplicationHandle.clear();
         }
 
 #if DEBUG_FOCUS
@@ -3243,13 +3250,6 @@
     mLooper->wake();
 }
 
-void InputDispatcher::releaseFocusedApplicationLocked() {
-    if (mFocusedApplication) {
-        mFocusedApplication = NULL;
-        mFocusedApplicationStorage.inputApplicationHandle.clear();
-    }
-}
-
 void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
 #if DEBUG_FOCUS
     LOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3315,15 +3315,15 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        const InputWindow* fromWindow = getWindowLocked(fromChannel);
-        const InputWindow* toWindow = getWindowLocked(toChannel);
-        if (! fromWindow || ! toWindow) {
+        sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
+        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
+        if (fromWindowHandle == NULL || toWindowHandle == NULL) {
 #if DEBUG_FOCUS
             LOGD("Cannot transfer focus because from or to window not found.");
 #endif
             return false;
         }
-        if (fromWindow == toWindow) {
+        if (fromWindowHandle == toWindowHandle) {
 #if DEBUG_FOCUS
             LOGD("Trivial transfer to same window.");
 #endif
@@ -3333,7 +3333,7 @@
         bool found = false;
         for (size_t i = 0; i < mTouchState.windows.size(); i++) {
             const TouchedWindow& touchedWindow = mTouchState.windows[i];
-            if (touchedWindow.window == fromWindow) {
+            if (touchedWindow.windowHandle == fromWindowHandle) {
                 int32_t oldTargetFlags = touchedWindow.targetFlags;
                 BitSet32 pointerIds = touchedWindow.pointerIds;
 
@@ -3342,7 +3342,7 @@
                 int32_t newTargetFlags = oldTargetFlags
                         & (InputTarget::FLAG_FOREGROUND
                                 | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
-                mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+                mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
 
                 found = true;
                 break;
@@ -3392,7 +3392,7 @@
     resetTargetsLocked();
 
     mTouchState.reset();
-    mLastHoverWindow = NULL;
+    mLastHoverWindowHandle.clear();
 }
 
 void InputDispatcher::logDispatchStateLocked() {
@@ -3415,15 +3415,15 @@
     dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
     dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
 
-    if (mFocusedApplication) {
+    if (mFocusedApplicationHandle != NULL) {
         dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
-                mFocusedApplication->name.string(),
-                mFocusedApplication->dispatchingTimeout / 1000000.0);
+                mFocusedApplicationHandle->name.string(),
+                mFocusedApplicationHandle->dispatchingTimeout / 1000000.0);
     } else {
         dump.append(INDENT "FocusedApplication: <null>\n");
     }
     dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
-            mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>");
+            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>");
 
     dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
     dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
@@ -3434,37 +3434,37 @@
         for (size_t i = 0; i < mTouchState.windows.size(); i++) {
             const TouchedWindow& touchedWindow = mTouchState.windows[i];
             dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
-                    i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value,
+                    i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value,
                     touchedWindow.targetFlags);
         }
     } else {
         dump.append(INDENT "TouchedWindows: <none>\n");
     }
 
-    if (!mWindows.isEmpty()) {
+    if (!mWindowHandles.isEmpty()) {
         dump.append(INDENT "Windows:\n");
-        for (size_t i = 0; i < mWindows.size(); i++) {
-            const InputWindow& window = mWindows[i];
+        for (size_t i = 0; i < mWindowHandles.size(); i++) {
+            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
             dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                     "frame=[%d,%d][%d,%d], scale=%f, "
                     "touchableRegion=",
-                    i, window.name.string(),
-                    toString(window.paused),
-                    toString(window.hasFocus),
-                    toString(window.hasWallpaper),
-                    toString(window.visible),
-                    toString(window.canReceiveKeys),
-                    window.layoutParamsFlags, window.layoutParamsType,
-                    window.layer,
-                    window.frameLeft, window.frameTop,
-                    window.frameRight, window.frameBottom,
-                    window.scaleFactor);
-            dumpRegion(dump, window.touchableRegion);
-            dump.appendFormat(", inputFeatures=0x%08x", window.inputFeatures);
+                    i, windowHandle->name.string(),
+                    toString(windowHandle->paused),
+                    toString(windowHandle->hasFocus),
+                    toString(windowHandle->hasWallpaper),
+                    toString(windowHandle->visible),
+                    toString(windowHandle->canReceiveKeys),
+                    windowHandle->layoutParamsFlags, windowHandle->layoutParamsType,
+                    windowHandle->layer,
+                    windowHandle->frameLeft, windowHandle->frameTop,
+                    windowHandle->frameRight, windowHandle->frameBottom,
+                    windowHandle->scaleFactor);
+            dumpRegion(dump, windowHandle->touchableRegion);
+            dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures);
             dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
-                    window.ownerPid, window.ownerUid,
-                    window.dispatchingTimeout / 1000000.0);
+                    windowHandle->ownerPid, windowHandle->ownerUid,
+                    windowHandle->dispatchingTimeout / 1000000.0);
         }
     } else {
         dump.append(INDENT "Windows: <none>\n");
@@ -3636,23 +3636,19 @@
 }
 
 void InputDispatcher::onANRLocked(
-        nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+        nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+        const sp<InputWindowHandle>& windowHandle,
         nsecs_t eventTime, nsecs_t waitStartTime) {
     LOGI("Application is not responding: %s.  "
             "%01.1fms since event, %01.1fms since wait started",
-            getApplicationWindowLabelLocked(application, window).string(),
+            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
             (currentTime - eventTime) / 1000000.0,
             (currentTime - waitStartTime) / 1000000.0);
 
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyANRLockedInterruptible);
-    if (application) {
-        commandEntry->inputApplicationHandle = application->inputApplicationHandle;
-    }
-    if (window) {
-        commandEntry->inputWindowHandle = window->inputWindowHandle;
-        commandEntry->inputChannel = window->inputChannel;
-    }
+    commandEntry->inputApplicationHandle = applicationHandle;
+    commandEntry->inputWindowHandle = windowHandle;
 }
 
 void InputDispatcher::doNotifyConfigurationChangedInterruptible(
@@ -3686,7 +3682,9 @@
 
     mLock.lock();
 
-    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel);
+    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
+            commandEntry->inputWindowHandle != NULL
+                    ? commandEntry->inputWindowHandle->inputChannel : NULL);
 }
 
 void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4560,11 +4558,10 @@
     split = other.split;
     deviceId = other.deviceId;
     source = other.source;
-    windows.clear();
-    windows.appendVector(other.windows);
+    windows = other.windows;
 }
 
-void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
+void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
         int32_t targetFlags, BitSet32 pointerIds) {
     if (targetFlags & InputTarget::FLAG_SPLIT) {
         split = true;
@@ -4572,7 +4569,7 @@
 
     for (size_t i = 0; i < windows.size(); i++) {
         TouchedWindow& touchedWindow = windows.editItemAt(i);
-        if (touchedWindow.window == window) {
+        if (touchedWindow.windowHandle == windowHandle) {
             touchedWindow.targetFlags |= targetFlags;
             if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
                 touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
@@ -4585,10 +4582,9 @@
     windows.push();
 
     TouchedWindow& touchedWindow = windows.editTop();
-    touchedWindow.window = window;
+    touchedWindow.windowHandle = windowHandle;
     touchedWindow.targetFlags = targetFlags;
     touchedWindow.pointerIds = pointerIds;
-    touchedWindow.channel = window->inputChannel;
 }
 
 void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
@@ -4605,11 +4601,11 @@
     }
 }
 
-const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() const {
+sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
     for (size_t i = 0; i < windows.size(); i++) {
         const TouchedWindow& window = windows.itemAt(i);
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
-            return window.window;
+            return window.windowHandle;
         }
     }
     return NULL;
@@ -4621,8 +4617,8 @@
     for (size_t i = 0; i < windows.size(); i++) {
         const TouchedWindow& window = windows.itemAt(i);
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
-            if (haveSlipperyForegroundWindow
-                    || !(window.window->layoutParamsFlags & InputWindow::FLAG_SLIPPERY)) {
+            if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags
+                    & InputWindowHandle::FLAG_SLIPPERY)) {
                 return false;
             }
             haveSlipperyForegroundWindow = true;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index bdd1922..15fd274 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -321,13 +321,14 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0;
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
 
     /* Sets the focused application.
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void setFocusedApplication(const InputApplication* inputApplication) = 0;
+    virtual void setFocusedApplication(
+            const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
 
     /* Sets the input dispatching mode.
      *
@@ -406,8 +407,8 @@
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
-    virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
-    virtual void setFocusedApplication(const InputApplication* inputApplication);
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled);
 
@@ -578,7 +579,6 @@
         sp<Connection> connection;
         nsecs_t eventTime;
         KeyEntry* keyEntry;
-        sp<InputChannel> inputChannel;
         sp<InputApplicationHandle> inputApplicationHandle;
         sp<InputWindowHandle> inputWindowHandle;
         int32_t userActivityEventType;
@@ -894,7 +894,7 @@
     // to transfer focus to a new application.
     EventEntry* mNextUnblockedEvent;
 
-    const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y);
+    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
 
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
@@ -953,19 +953,19 @@
     bool mDispatchFrozen;
     bool mInputFilterEnabled;
 
-    Vector<InputWindow> mWindows;
+    Vector<sp<InputWindowHandle> > mWindowHandles;
 
-    const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel);
+    sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
     // Focus tracking for keys, trackball, etc.
-    const InputWindow* mFocusedWindow;
+    sp<InputWindowHandle> mFocusedWindowHandle;
 
     // Focus tracking for touch.
     struct TouchedWindow {
-        const InputWindow* window;
+        sp<InputWindowHandle> windowHandle;
         int32_t targetFlags;
         BitSet32 pointerIds;        // zero unless target flag FLAG_SPLIT is set
-        sp<InputChannel> channel;
     };
     struct TouchState {
         bool down;
@@ -978,9 +978,10 @@
         ~TouchState();
         void reset();
         void copyFrom(const TouchState& other);
-        void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds);
+        void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
+                int32_t targetFlags, BitSet32 pointerIds);
         void filterNonAsIsTouchWindows();
-        const InputWindow* getFirstForegroundWindow() const;
+        sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
         bool isSlippery() const;
     };
 
@@ -988,9 +989,7 @@
     TouchState mTempTouchState;
 
     // Focused application.
-    InputApplication* mFocusedApplication;
-    InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
-    void releaseFocusedApplicationLocked();
+    sp<InputApplicationHandle> mFocusedApplicationHandle;
 
     // Dispatch inbound events.
     bool dispatchConfigurationChangedLocked(
@@ -1021,16 +1020,17 @@
     nsecs_t mInputTargetWaitStartTime;
     nsecs_t mInputTargetWaitTimeoutTime;
     bool mInputTargetWaitTimeoutExpired;
-    sp<InputApplicationHandle> mInputTargetWaitApplication;
+    sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
 
     // Contains the last window which received a hover event.
-    const InputWindow* mLastHoverWindow;
+    sp<InputWindowHandle> mLastHoverWindowHandle;
 
     // Finding targets for input events.
     void resetTargetsLocked();
     void commitTargetsLocked();
     int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
-            const InputApplication* application, const InputWindow* window,
+            const sp<InputApplicationHandle>& applicationHandle,
+            const sp<InputWindowHandle>& windowHandle,
             nsecs_t* nextWakeupTime);
     void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
             const sp<InputChannel>& inputChannel);
@@ -1043,15 +1043,17 @@
             nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
             const MotionSample** outSplitBatchAfterSample);
 
-    void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
-            BitSet32 pointerIds);
+    void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+            int32_t targetFlags, BitSet32 pointerIds);
     void addMonitoringTargetsLocked();
     void pokeUserActivityLocked(const EventEntry* eventEntry);
-    bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
-    bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
-    bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
-    String8 getApplicationWindowLabelLocked(const InputApplication* application,
-            const InputWindow* window);
+    bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
+            const InjectionState* injectionState);
+    bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
+            int32_t x, int32_t y) const;
+    bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+    String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+            const sp<InputWindowHandle>& windowHandle);
 
     // Manage the dispatch cycle for a single connection.
     // These methods are deliberately not Interruptible because doing all of the work
@@ -1100,7 +1102,8 @@
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
     void onANRLocked(
-            nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+            nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+            const sp<InputWindowHandle>& windowHandle,
             nsecs_t eventTime, nsecs_t waitStartTime);
 
     // Outbound policy interactions.
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index b552f6d..0ce8867 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -22,25 +22,25 @@
 
 namespace android {
 
-// --- InputWindow ---
+// --- InputWindowHandle ---
 
-bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
     return touchableRegion.contains(x, y);
 }
 
-bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
     return x >= frameLeft && x <= frameRight
             && y >= frameTop && y <= frameBottom;
 }
 
-bool InputWindow::isTrustedOverlay() const {
+bool InputWindowHandle::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;
+bool InputWindowHandle::supportsSplitTouch() const {
+    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
 }
 
 } // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index d166ad4..272081c 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -31,29 +31,14 @@
 
 /*
  * 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;
-    }
+    const sp<InputApplicationHandle> inputApplicationHandle;
 
-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,
@@ -164,6 +149,22 @@
     bool isTrustedOverlay() const;
 
     bool supportsSplitTouch() const;
+
+    /**
+     * Requests that the state of this object be updated to reflect
+     * the most current available information about the application.
+     *
+     * This method should only be called from within the input dispatcher's
+     * critical section.
+     *
+     * Returns true on success, or false if the handle is no longer valid.
+     */
+    virtual bool update() = 0;
+
+protected:
+    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+            inputApplicationHandle(inputApplicationHandle) { }
+    virtual ~InputWindowHandle() { }
 };
 
 } // namespace android
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 67067de..131894a 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -369,11 +369,12 @@
         return INPUT_EVENT_INJECTION_FAILED;
     }
 
-    virtual void setInputWindows(const Vector<InputWindow>& inputWindows) {
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
         ADD_FAILURE() << "Should never be called by input reader.";
     }
 
-    virtual void setFocusedApplication(const InputApplication* inputApplication) {
+    virtual void setFocusedApplication(
+            const sp<InputApplicationHandle>& inputApplicationHandle) {
         ADD_FAILURE() << "Should never be called by input reader.";
     }
 
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index d3d9df4..bfa2b39 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -101,7 +101,7 @@
     boolean firstWindowDrawn;
 
     // Input application handle used by the input dispatcher.
-    InputApplicationHandle mInputApplicationHandle;
+    final InputApplicationHandle mInputApplicationHandle;
 
     AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
         super(_service, _token.asBinder(),
diff --git a/services/java/com/android/server/wm/InputApplication.java b/services/java/com/android/server/wm/InputApplication.java
deleted file mode 100644
index e04fd31..0000000
--- a/services/java/com/android/server/wm/InputApplication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2010 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.wm;
-
-
-/**
- * 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;
-
-    public void recycle() {
-        inputApplicationHandle = null;
-    }
-}
diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java
index 64c8e7e..d78b1d9 100644
--- a/services/java/com/android/server/wm/InputApplicationHandle.java
+++ b/services/java/com/android/server/wm/InputApplicationHandle.java
@@ -32,6 +32,12 @@
     // The window manager's application window token.
     public final AppWindowToken appWindowToken;
 
+    // Application name.
+    public String name;
+
+    // Dispatching timeout.
+    public long dispatchingTimeoutNanos;
+
     private native void nativeDispose();
 
     public InputApplicationHandle(AppWindowToken appWindowToken) {
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 65007f9..3133a19 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -25,7 +25,6 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.os.Environment;
-import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.SystemProperties;
@@ -83,10 +82,10 @@
     private static native int nativeInjectInputEvent(InputEvent event,
             int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
             int policyFlags);
-    private static native void nativeSetInputWindows(InputWindow[] windows);
+    private static native void nativeSetInputWindows(InputWindowHandle[] windowHandles);
     private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
     private static native void nativeSetSystemUiVisibility(int visibility);
-    private static native void nativeSetFocusedApplication(InputApplication application);
+    private static native void nativeSetFocusedApplication(InputApplicationHandle application);
     private static native InputDevice nativeGetInputDevice(int deviceId);
     private static native void nativeGetInputConfiguration(Configuration configuration);
     private static native int[] nativeGetInputDeviceIds();
@@ -372,11 +371,11 @@
         return nativeGetInputDeviceIds();
     }
     
-    public void setInputWindows(InputWindow[] windows) {
-        nativeSetInputWindows(windows);
+    public void setInputWindows(InputWindowHandle[] windowHandles) {
+        nativeSetInputWindows(windowHandles);
     }
     
-    public void setFocusedApplication(InputApplication application) {
+    public void setFocusedApplication(InputApplicationHandle application) {
         nativeSetFocusedApplication(application);
     }
     
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 6806634..08a3560 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import android.graphics.Rect;
-import android.os.Binder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -26,6 +25,7 @@
 import android.view.WindowManager;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 final class InputMonitor {
     private final WindowManagerService mService;
@@ -42,12 +42,14 @@
     // When true, need to call updateInputWindowsLw().
     private boolean mUpdateInputWindowsNeeded = true;
 
-    // Temporary list of windows information to provide to the input dispatcher.
-    private InputWindowList mTempInputWindows = new InputWindowList();
-    
-    // Temporary input application object to provide to the input dispatcher.
-    private InputApplication mTempInputApplication = new InputApplication();
-    
+    // Fake handles for the drag surface, lazily initialized.
+    private InputApplicationHandle mDragApplicationHandle;
+    private InputWindowHandle mDragWindowHandle;
+
+    // Array of window handles to provide to the input dispatcher.
+    private InputWindowHandle[] mInputWindowHandles;
+    private int mInputWindowHandleCount;
+
     // Set to true when the first input device configuration change notification
     // is received to indicate that the input devices are ready.
     private final Object mInputDevicesReadyMonitor = new Object();
@@ -68,8 +70,10 @@
 
         synchronized (mService.mWindowMap) {
             WindowState windowState = (WindowState) inputWindowHandle.windowState;
-            Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
-            mService.removeWindowLocked(windowState.mSession, windowState);
+            if (windowState != null) {
+                Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
+                mService.removeWindowLocked(windowState.mSession, windowState);
+            }
         }
     }
     
@@ -94,8 +98,11 @@
         
         if (appWindowToken == null && inputApplicationHandle != null) {
             appWindowToken = inputApplicationHandle.appWindowToken;
-            Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application "
-                    + appWindowToken.stringName);
+            if (appWindowToken != null) {
+                Slog.i(WindowManagerService.TAG,
+                        "Input event dispatching timed out sending to application "
+                                + appWindowToken.stringName);
+            }
         }
 
         if (appWindowToken != null && appWindowToken.appToken != null) {
@@ -114,32 +121,59 @@
         return 0; // abort dispatching
     }
 
-    private void addDragInputWindowLw(InputWindowList windowList) {
-        final InputWindow inputWindow = windowList.add();
-        inputWindow.inputChannel = mService.mDragState.mServerChannel;
-        inputWindow.name = "drag";
-        inputWindow.layoutParamsFlags = 0;
-        inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
-        inputWindow.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
-        inputWindow.visible = true;
-        inputWindow.canReceiveKeys = false;
-        inputWindow.hasFocus = true;
-        inputWindow.hasWallpaper = false;
-        inputWindow.paused = false;
-        inputWindow.layer = mService.mDragState.getDragLayerLw();
-        inputWindow.ownerPid = Process.myPid();
-        inputWindow.ownerUid = Process.myUid();
-        inputWindow.inputFeatures = 0;
-        inputWindow.scaleFactor = 1.0f;
+    private void addDragInputWindowLw() {
+        if (mDragWindowHandle == null) {
+            mDragApplicationHandle = new InputApplicationHandle(null);
+            mDragApplicationHandle.name = "drag";
+            mDragApplicationHandle.dispatchingTimeoutNanos =
+                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+            mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null);
+            mDragWindowHandle.name = "drag";
+            mDragWindowHandle.layoutParamsFlags = 0;
+            mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+            mDragWindowHandle.dispatchingTimeoutNanos =
+                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+            mDragWindowHandle.visible = true;
+            mDragWindowHandle.canReceiveKeys = false;
+            mDragWindowHandle.hasFocus = true;
+            mDragWindowHandle.hasWallpaper = false;
+            mDragWindowHandle.paused = false;
+            mDragWindowHandle.ownerPid = Process.myPid();
+            mDragWindowHandle.ownerUid = Process.myUid();
+            mDragWindowHandle.inputFeatures = 0;
+            mDragWindowHandle.scaleFactor = 1.0f;
+
+            // The drag window cannot receive new touches.
+            mDragWindowHandle.touchableRegion.setEmpty();
+        }
+
+        mDragWindowHandle.layer = mService.mDragState.getDragLayerLw();
 
         // The drag window covers the entire display
-        inputWindow.frameLeft = 0;
-        inputWindow.frameTop = 0;
-        inputWindow.frameRight = mService.mDisplay.getRealWidth();
-        inputWindow.frameBottom = mService.mDisplay.getRealHeight();
+        mDragWindowHandle.frameLeft = 0;
+        mDragWindowHandle.frameTop = 0;
+        mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
+        mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
 
-        // The drag window cannot receive new touches.
-        inputWindow.touchableRegion.setEmpty();
+        addInputWindowHandleLw(mDragWindowHandle);
+    }
+
+    private void addInputWindowHandleLw(InputWindowHandle windowHandle) {
+        if (mInputWindowHandles == null) {
+            mInputWindowHandles = new InputWindowHandle[16];
+        }
+        if (mInputWindowHandleCount >= mInputWindowHandles.length) {
+            mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
+                    mInputWindowHandleCount * 2);
+        }
+        mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
+    }
+
+    private void clearInputWindowHandlesLw() {
+        while (mInputWindowHandleCount != 0) {
+            mInputWindowHandles[--mInputWindowHandleCount] = null;
+        }
     }
 
     public void setUpdateInputWindowsNeededLw() {
@@ -154,7 +188,7 @@
         mUpdateInputWindowsNeeded = false;
 
         if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");
-        
+
         // Populate the input window list with information about all of the windows that
         // could potentially receive input.
         // As an optimization, we could try to prune the list of windows but this turns
@@ -168,7 +202,7 @@
             if (WindowManagerService.DEBUG_DRAG) {
                 Log.d(WindowManagerService.TAG, "Inserting drag window");
             }
-            addDragInputWindowLw(mTempInputWindows);
+            addDragInputWindowLw();
         }
 
         final int N = windows.size();
@@ -194,48 +228,48 @@
             }
 
             // 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;
-            inputWindow.layoutParamsType = type;
-            inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
-            inputWindow.visible = isVisible;
-            inputWindow.canReceiveKeys = child.canReceiveKeys();
-            inputWindow.hasFocus = hasFocus;
-            inputWindow.hasWallpaper = hasWallpaper;
-            inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
-            inputWindow.layer = child.mLayer;
-            inputWindow.ownerPid = child.mSession.mPid;
-            inputWindow.ownerUid = child.mSession.mUid;
-            inputWindow.inputFeatures = child.mAttrs.inputFeatures;
+            final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+            inputWindowHandle.inputChannel = child.mInputChannel;
+            inputWindowHandle.name = child.toString();
+            inputWindowHandle.layoutParamsFlags = flags;
+            inputWindowHandle.layoutParamsType = type;
+            inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+            inputWindowHandle.visible = isVisible;
+            inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
+            inputWindowHandle.hasFocus = hasFocus;
+            inputWindowHandle.hasWallpaper = hasWallpaper;
+            inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
+            inputWindowHandle.layer = child.mLayer;
+            inputWindowHandle.ownerPid = child.mSession.mPid;
+            inputWindowHandle.ownerUid = child.mSession.mUid;
+            inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
 
             final Rect frame = child.mFrame;
-            inputWindow.frameLeft = frame.left;
-            inputWindow.frameTop = frame.top;
-            inputWindow.frameRight = frame.right;
-            inputWindow.frameBottom = frame.bottom;
+            inputWindowHandle.frameLeft = frame.left;
+            inputWindowHandle.frameTop = frame.top;
+            inputWindowHandle.frameRight = frame.right;
+            inputWindowHandle.frameBottom = frame.bottom;
 
             if (child.mGlobalScale != 1) {
                 // If we are scaling the window, input coordinates need
                 // to be inversely scaled to map from what is on screen
                 // to what is actually being touched in the UI.
-                inputWindow.scaleFactor = 1.0f/child.mGlobalScale;
+                inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
             } else {
-                inputWindow.scaleFactor = 1;
+                inputWindowHandle.scaleFactor = 1;
             }
 
-            child.getTouchableRegion(inputWindow.touchableRegion);
+            child.getTouchableRegion(inputWindowHandle.touchableRegion);
+
+            addInputWindowHandleLw(inputWindowHandle);
         }
 
         // Send windows to native code.
-        mService.mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
-        
+        mService.mInputManager.setInputWindows(mInputWindowHandles);
+
         // Clear the list in preparation for the next round.
-        // Also avoids keeping InputChannel objects referenced unnecessarily.
-        mTempInputWindows.clear();
-        
+        clearInputWindowHandlesLw();
+
         if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
     }
 
@@ -329,14 +363,11 @@
         if (newApp == null) {
             mService.mInputManager.setFocusedApplication(null);
         } else {
-            mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle;
-            mTempInputApplication.name = newApp.toString();
-            mTempInputApplication.dispatchingTimeoutNanos =
-                    newApp.inputDispatchingTimeoutNanos;
+            final InputApplicationHandle handle = newApp.mInputApplicationHandle;
+            handle.name = newApp.toString();
+            handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos;
 
-            mService.mInputManager.setFocusedApplication(mTempInputApplication);
-
-            mTempInputApplication.recycle();
+            mService.mInputManager.setFocusedApplication(handle);
         }
     }
     
diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java
deleted file mode 100644
index 655d734..0000000
--- a/services/java/com/android/server/wm/InputWindow.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2010 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.wm;
-
-import android.graphics.Region;
-import android.view.InputChannel;
-
-/**
- * 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.
-    public int frameLeft;
-    public int frameTop;
-    public int frameRight;
-    public int frameBottom;
-
-    // Global scaling factor applied to touch events when they are dispatched
-    // to the window
-    public float scaleFactor;
-
-    // Window touchable region.
-    public final Region touchableRegion = new Region();
-
-    // 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;
-
-    // Window input features.
-    public int inputFeatures;
-
-    public void recycle() {
-        inputWindowHandle = null;
-        inputChannel = null;
-    }
-}
diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/wm/InputWindowHandle.java
index cc508c6..abf68d9 100644
--- a/services/java/com/android/server/wm/InputWindowHandle.java
+++ b/services/java/com/android/server/wm/InputWindowHandle.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import android.graphics.Region;
+import android.view.InputChannel;
 import android.view.WindowManagerPolicy;
 
 /**
@@ -35,6 +37,57 @@
     // The window manager's window state.
     public final WindowManagerPolicy.WindowState windowState;
 
+    // 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.
+    public int frameLeft;
+    public int frameTop;
+    public int frameRight;
+    public int frameBottom;
+
+    // Global scaling factor applied to touch events when they are dispatched
+    // to the window
+    public float scaleFactor;
+
+    // Window touchable region.
+    public final Region touchableRegion = new Region();
+
+    // 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;
+
+    // Window input features.
+    public int inputFeatures;
+
     private native void nativeDispose();
 
     public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
diff --git a/services/java/com/android/server/wm/InputWindowList.java b/services/java/com/android/server/wm/InputWindowList.java
deleted file mode 100644
index 6077337..0000000
--- a/services/java/com/android/server/wm/InputWindowList.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 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.wm;
-
-
-/**
- * A specialized list of window information objects backed by an array.
- * 
- * This class is part of an InputManager optimization to avoid allocating objects and arrays
- * unnecessarily.  Internally, it keeps an array full of demand-allocated objects that it
- * recycles each time the list is cleared.  The used portion of the array is padded with a null.
- * 
- * The contents of the list are intended to be Z-ordered from top to bottom.
- * 
- * @hide
- */
-public final class InputWindowList {
-    private InputWindow[] mArray;
-    private int mCount;
-    
-    /**
-     * Creates an empty list.
-     */
-    public InputWindowList() {
-        mArray = new InputWindow[8];
-    }
-    
-    /**
-     * Clears the list.
-     */
-    public void clear() {
-        if (mCount == 0) {
-            return;
-        }
-        
-        int count = mCount;
-        mCount = 0;
-        mArray[count] = mArray[0];
-        while (count > 0) {
-            count -= 1;
-            mArray[count].recycle();
-        }
-        mArray[0] = null;
-    }
-    
-    /**
-     * Adds an uninitialized input window object to the list and returns it.
-     */
-    public InputWindow add() {
-        if (mCount + 1 == mArray.length) {
-            InputWindow[] oldArray = mArray;
-            mArray = new InputWindow[oldArray.length * 2];
-            System.arraycopy(oldArray, 0, mArray, 0, mCount);
-        }
-        
-        // Grab object from tail (after used section) if available.
-        InputWindow item = mArray[mCount + 1];
-        if (item == null) {
-            item = new InputWindow();
-        }
-        
-        mArray[mCount] = item;
-        mCount += 1;
-        mArray[mCount] = null;
-        return item;
-    }
-    
-    /**
-     * Gets the input window objects as a null-terminated array.
-     * @return The input window array.
-     */
-    public InputWindow[] toNullTerminatedArray() {
-        return mArray;
-    }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index b370ec9..d298ff7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -272,7 +272,7 @@
     float mSurfaceAlpha;
     
     // Input channel and input window handle used by the input dispatcher.
-    InputWindowHandle mInputWindowHandle;
+    final InputWindowHandle mInputWindowHandle;
     InputChannel mInputChannel;
     
     // Used to improve performance of toString()
@@ -306,6 +306,7 @@
             mIsFloatingLayer = false;
             mBaseLayer = 0;
             mSubLayer = 0;
+            mInputWindowHandle = null;
             return;
         }
         mDeathRecipient = deathRecipient;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index e1c7305..6fa5dfa 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,10 +4,8 @@
 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 \
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
deleted file mode 100644
index 1f80242..0000000
--- a/services/jni/com_android_server_InputApplication.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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 {
-    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);
-
-#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) {
-    jclass clazz;
-    FIND_CLASS(clazz, "com/android/server/wm/InputApplication");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
-            clazz,
-            "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.name, clazz,
-            "name", "Ljava/lang/String;");
-
-    GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
-            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
deleted file mode 100644
index 85fb891..0000000
--- a/services/jni/com_android_server_InputApplication.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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
index 9516964..7de67d9 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -27,6 +27,8 @@
 
 static struct {
     jfieldID ptr;
+    jfieldID name;
+    jfieldID dispatchingTimeoutNanos;
 } gInputApplicationHandleClassInfo;
 
 static Mutex gHandleMutex;
@@ -47,6 +49,31 @@
     return env->NewLocalRef(mObjWeak);
 }
 
+bool NativeInputApplicationHandle::update() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject obj = env->NewLocalRef(mObjWeak);
+    if (!obj) {
+        return false;
+    }
+
+    jstring nameObj = jstring(env->GetObjectField(obj,
+            gInputApplicationHandleClassInfo.name));
+    if (nameObj) {
+        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+        name.setTo(nameStr);
+        env->ReleaseStringUTFChars(nameObj, nameStr);
+        env->DeleteLocalRef(nameObj);
+    } else {
+        name.setTo("<null>");
+    }
+
+    dispatchingTimeout = env->GetLongField(obj,
+            gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+
+    env->DeleteLocalRef(obj);
+    return true;
+}
+
 
 // --- Global functions ---
 
@@ -113,6 +140,13 @@
     GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
             "ptr", "I");
 
+    GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
+            "name", "Ljava/lang/String;");
+
+    GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
+            clazz,
+            "dispatchingTimeoutNanos", "J");
+
     return 0;
 }
 
diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h
index 9d18721..04cd9d6 100644
--- a/services/jni/com_android_server_InputApplicationHandle.h
+++ b/services/jni/com_android_server_InputApplicationHandle.h
@@ -31,6 +31,8 @@
 
     jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
 
+    virtual bool update();
+
 private:
     jweak mObjWeak;
 };
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 14a4109..de9c9d0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -46,9 +46,7 @@
 #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 {
@@ -175,8 +173,8 @@
             const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
     status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
 
-    void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
-    void setFocusedApplication(JNIEnv* env, jobject applicationObj);
+    void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
+    void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
     void setInputDispatchMode(bool enabled, bool frozen);
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
@@ -582,31 +580,38 @@
     return isScreenOn();
 }
 
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) {
-    Vector<InputWindow> windows;
+void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
+    Vector<sp<InputWindowHandle> > windowHandles;
 
-    bool newPointerGesturesEnabled = true;
-    jsize length = env->GetArrayLength(windowObjArray);
-    for (jsize i = 0; i < length; i++) {
-        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();
-        android_server_InputWindow_toNative(env, windowObj, &window);
-        if (window.inputChannel == NULL) {
-            windows.pop();
-        } else if (window.hasFocus) {
-            if (window.inputFeatures & InputWindow::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES) {
-                newPointerGesturesEnabled = false;
+    if (windowHandleObjArray) {
+        jsize length = env->GetArrayLength(windowHandleObjArray);
+        for (jsize i = 0; i < length; i++) {
+            jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
+            if (! windowHandleObj) {
+                break; // found null element indicating end of used portion of the array
             }
+
+            sp<InputWindowHandle> windowHandle =
+                    android_server_InputWindowHandle_getHandle(env, windowHandleObj);
+            if (windowHandle != NULL) {
+                windowHandles.push(windowHandle);
+            }
+            env->DeleteLocalRef(windowHandleObj);
         }
-        env->DeleteLocalRef(windowObj);
     }
 
-    mInputManager->getDispatcher()->setInputWindows(windows);
+    mInputManager->getDispatcher()->setInputWindows(windowHandles);
+
+    // Do this after the dispatcher has updated the window handle state.
+    bool newPointerGesturesEnabled = true;
+    size_t numWindows = windowHandles.size();
+    for (size_t i = 0; i < numWindows; i++) {
+        const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+        if (windowHandle->hasFocus && (windowHandle->inputFeatures
+                & InputWindowHandle::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
+            newPointerGesturesEnabled = false;
+        }
+    }
 
     uint32_t changes = 0;
     { // acquire lock
@@ -623,16 +628,10 @@
     }
 }
 
-void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) {
-    if (applicationObj) {
-        InputApplication application;
-        android_server_InputApplication_toNative(env, applicationObj, &application);
-        if (application.inputApplicationHandle != NULL) {
-            mInputManager->getDispatcher()->setFocusedApplication(&application);
-            return;
-        }
-    }
-    mInputManager->getDispatcher()->setFocusedApplication(NULL);
+void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) {
+    sp<InputApplicationHandle> applicationHandle =
+            android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
+    mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
 }
 
 void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
@@ -1137,21 +1136,21 @@
 }
 
 static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz,
-        jobjectArray windowObjArray) {
+        jobjectArray windowHandleObjArray) {
     if (checkInputManagerUnitialized(env)) {
         return;
     }
 
-    gNativeInputManager->setInputWindows(env, windowObjArray);
+    gNativeInputManager->setInputWindows(env, windowHandleObjArray);
 }
 
 static void android_server_InputManager_nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
-        jobject applicationObj) {
+        jobject applicationHandleObj) {
     if (checkInputManagerUnitialized(env)) {
         return;
     }
 
-    gNativeInputManager->setFocusedApplication(env, applicationObj);
+    gNativeInputManager->setFocusedApplication(env, applicationHandleObj);
 }
 
 static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env,
@@ -1313,9 +1312,9 @@
             (void*) android_server_InputManager_nativeSetInputFilterEnabled },
     { "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIIII)I",
             (void*) android_server_InputManager_nativeInjectInputEvent },
-    { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindow;)V",
+    { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindowHandle;)V",
             (void*) android_server_InputManager_nativeSetInputWindows },
-    { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplication;)V",
+    { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplicationHandle;)V",
             (void*) android_server_InputManager_nativeSetFocusedApplication },
     { "nativeSetInputDispatchMode", "(ZZ)V",
             (void*) android_server_InputManager_nativeSetInputDispatchMode },
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
deleted file mode 100644
index 0426f63..0000000
--- a/services/jni/com_android_server_InputWindow.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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 <android/graphics/Region.h>
-#include "com_android_server_InputWindow.h"
-#include "com_android_server_InputWindowHandle.h"
-
-namespace android {
-
-static struct {
-    jfieldID inputWindowHandle;
-    jfieldID inputChannel;
-    jfieldID name;
-    jfieldID layoutParamsFlags;
-    jfieldID layoutParamsType;
-    jfieldID dispatchingTimeoutNanos;
-    jfieldID frameLeft;
-    jfieldID frameTop;
-    jfieldID frameRight;
-    jfieldID frameBottom;
-    jfieldID scaleFactor;
-    jfieldID touchableRegion;
-    jfieldID visible;
-    jfieldID canReceiveKeys;
-    jfieldID hasFocus;
-    jfieldID hasWallpaper;
-    jfieldID paused;
-    jfieldID layer;
-    jfieldID ownerPid;
-    jfieldID ownerUid;
-    jfieldID inputFeatures;
-} 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->scaleFactor = env->GetFloatField(inputWindowObj,
-            gInputWindowClassInfo.scaleFactor);
-
-    jobject regionObj = env->GetObjectField(inputWindowObj,
-            gInputWindowClassInfo.touchableRegion);
-    if (regionObj) {
-        SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
-        outInputWindow->touchableRegion.set(*region);
-        env->DeleteLocalRef(regionObj);
-    } else {
-        outInputWindow->touchableRegion.setEmpty();
-    }
-
-    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);
-    outInputWindow->inputFeatures = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.inputFeatures);
-}
-
-
-// --- JNI ---
-
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#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) {
-    jclass clazz;
-    FIND_CLASS(clazz, "com/android/server/wm/InputWindow");
-
-    GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz,
-            "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz,
-            "inputChannel", "Landroid/view/InputChannel;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.name, clazz,
-            "name", "Ljava/lang/String;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz,
-            "layoutParamsFlags", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz,
-            "layoutParamsType", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz,
-            "dispatchingTimeoutNanos", "J");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz,
-            "frameLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz,
-            "frameTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz,
-            "frameRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
-            "frameBottom", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, clazz,
-            "scaleFactor", "F");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
-            "touchableRegion", "Landroid/graphics/Region;");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visible, clazz,
-            "visible", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz,
-            "canReceiveKeys", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz,
-            "hasFocus", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz,
-            "hasWallpaper", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.paused, clazz,
-            "paused", "Z");
-
-    GET_FIELD_ID(gInputWindowClassInfo.layer, clazz,
-            "layer", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz,
-            "ownerPid", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz,
-            "ownerUid", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.inputFeatures, clazz,
-            "inputFeatures", "I");
-    return 0;
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h
deleted file mode 100644
index eaf7bde..0000000
--- a/services/jni/com_android_server_InputWindow.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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
index aaf679c..09be881 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -21,6 +21,9 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/threads.h>
 
+#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
+
 #include "com_android_server_InputWindowHandle.h"
 #include "com_android_server_InputApplicationHandle.h"
 
@@ -29,6 +32,26 @@
 static struct {
     jfieldID ptr;
     jfieldID inputApplicationHandle;
+    jfieldID inputChannel;
+    jfieldID name;
+    jfieldID layoutParamsFlags;
+    jfieldID layoutParamsType;
+    jfieldID dispatchingTimeoutNanos;
+    jfieldID frameLeft;
+    jfieldID frameTop;
+    jfieldID frameRight;
+    jfieldID frameBottom;
+    jfieldID scaleFactor;
+    jfieldID touchableRegion;
+    jfieldID visible;
+    jfieldID canReceiveKeys;
+    jfieldID hasFocus;
+    jfieldID hasWallpaper;
+    jfieldID paused;
+    jfieldID layer;
+    jfieldID ownerPid;
+    jfieldID ownerUid;
+    jfieldID inputFeatures;
 } gInputWindowHandleClassInfo;
 
 static Mutex gHandleMutex;
@@ -51,6 +74,83 @@
     return env->NewLocalRef(mObjWeak);
 }
 
+bool NativeInputWindowHandle::update() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject obj = env->NewLocalRef(mObjWeak);
+    if (!obj) {
+        return false;
+    }
+
+    jobject inputChannelObj = env->GetObjectField(obj,
+            gInputWindowHandleClassInfo.inputChannel);
+    if (inputChannelObj) {
+        inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
+        env->DeleteLocalRef(inputChannelObj);
+    } else {
+        inputChannel = NULL;
+    }
+
+    jstring nameObj = jstring(env->GetObjectField(obj,
+            gInputWindowHandleClassInfo.name));
+    if (nameObj) {
+        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+        name.setTo(nameStr);
+        env->ReleaseStringUTFChars(nameObj, nameStr);
+        env->DeleteLocalRef(nameObj);
+    } else {
+        name.setTo("<null>");
+    }
+
+    layoutParamsFlags = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.layoutParamsFlags);
+    layoutParamsType = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.layoutParamsType);
+    dispatchingTimeout = env->GetLongField(obj,
+            gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
+    frameLeft = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.frameLeft);
+    frameTop = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.frameTop);
+    frameRight = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.frameRight);
+    frameBottom = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.frameBottom);
+    scaleFactor = env->GetFloatField(obj,
+            gInputWindowHandleClassInfo.scaleFactor);
+
+    jobject regionObj = env->GetObjectField(obj,
+            gInputWindowHandleClassInfo.touchableRegion);
+    if (regionObj) {
+        SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+        touchableRegion.set(*region);
+        env->DeleteLocalRef(regionObj);
+    } else {
+        touchableRegion.setEmpty();
+    }
+
+    visible = env->GetBooleanField(obj,
+            gInputWindowHandleClassInfo.visible);
+    canReceiveKeys = env->GetBooleanField(obj,
+            gInputWindowHandleClassInfo.canReceiveKeys);
+    hasFocus = env->GetBooleanField(obj,
+            gInputWindowHandleClassInfo.hasFocus);
+    hasWallpaper = env->GetBooleanField(obj,
+            gInputWindowHandleClassInfo.hasWallpaper);
+    paused = env->GetBooleanField(obj,
+            gInputWindowHandleClassInfo.paused);
+    layer = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.layer);
+    ownerPid = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.ownerPid);
+    ownerUid = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.ownerUid);
+    inputFeatures = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.inputFeatures);
+
+    env->DeleteLocalRef(obj);
+    return true;
+}
+
 
 // --- Global functions ---
 
@@ -127,6 +227,65 @@
             clazz,
             "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
 
+    GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz,
+            "inputChannel", "Landroid/view/InputChannel;");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
+            "name", "Ljava/lang/String;");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
+            "layoutParamsFlags", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
+            "layoutParamsType", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
+            "dispatchingTimeoutNanos", "J");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
+            "frameLeft", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
+            "frameTop", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
+            "frameRight", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
+            "frameBottom", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
+            "scaleFactor", "F");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
+            "touchableRegion", "Landroid/graphics/Region;");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
+            "visible", "Z");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
+            "canReceiveKeys", "Z");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
+            "hasFocus", "Z");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
+            "hasWallpaper", "Z");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
+            "paused", "Z");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz,
+            "layer", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
+            "ownerPid", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
+            "ownerUid", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
+            "inputFeatures", "I");
     return 0;
 }
 
diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h
index 43f2a6b..913c3b1 100644
--- a/services/jni/com_android_server_InputWindowHandle.h
+++ b/services/jni/com_android_server_InputWindowHandle.h
@@ -32,6 +32,8 @@
 
     jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
 
+    virtual bool update();
+
 private:
     jweak mObjWeak;
 };
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 9dff48b..4178039 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -22,9 +22,7 @@
 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);
@@ -51,9 +49,7 @@
     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);