am eec69d29: Merge "Fix bug with phantom input windows." into gingerbread

Merge commit 'eec69d2923636b2aaa51df93bacc2b3bbb742736' into gingerbread-plus-aosp

* commit 'eec69d2923636b2aaa51df93bacc2b3bbb742736':
  Fix bug with phantom input windows.
diff --git a/api/current.xml b/api/current.xml
index d0a4ab0..1c91cfb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -173117,6 +173117,19 @@
  visibility="public"
 >
 </constructor>
+<method name="getDevice"
+ return="android.view.InputDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
 <method name="getKeyCharacterMap"
  return="android.view.KeyCharacterMap"
  abstract="false"
@@ -173128,6 +173141,19 @@
  visibility="public"
 >
 </method>
+<method name="getMotionRange"
+ return="android.view.InputDevice.MotionRange"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="range" type="int">
+</parameter>
+</method>
 <method name="getName"
  return="java.lang.String"
  abstract="false"
@@ -173150,6 +173176,118 @@
  visibility="public"
 >
 </method>
+<method name="hasKey"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+</method>
+<field name="MOTION_RANGE_ORIENTATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_PRESSURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_SIZE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_TOOL_MAJOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_TOOL_MINOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_TOUCH_MAJOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_TOUCH_MINOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_X"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MOTION_RANGE_Y"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SOURCE_CLASS_BUTTON"
  type="int"
  transient="false"
@@ -173327,6 +173465,78 @@
 >
 </field>
 </class>
+<class name="InputDevice.MotionRange"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="InputDevice.MotionRange"
+ type="android.view.InputDevice.MotionRange"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getFlat"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFuzz"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMax"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMin"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRange"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="InputEvent"
  extends="java.lang.Object"
  abstract="true"
@@ -173337,6 +173547,17 @@
 >
 <implements name="android.os.Parcelable">
 </implements>
+<method name="getDevice"
+ return="android.view.InputDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDeviceId"
  return="int"
  abstract="false"
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 568caa2..21c2976 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -50,7 +50,7 @@
      * 
      * A {@link KeyEvent} should be interpreted as a button or key press.
      * 
-     * Use {@link #hasKeyCode} to query whether the device supports a particular button or key.
+     * Use {@link #hasKey} to query whether the device supports a particular button or key.
      */
     public static final int SOURCE_CLASS_BUTTON = 0x00000001;
     
@@ -154,7 +154,7 @@
     
     /**
      * The input source is a touch pad or digitizer tablet that is not
-     * associated with a display (unlike {@link SOURCE_TOUCHSCREEN}).
+     * associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
      * 
      * @see #SOURCE_CLASS_POSITION
      */
@@ -174,20 +174,79 @@
      */
     public static final int SOURCE_JOYSTICK_RIGHT = 0x02000000 | SOURCE_CLASS_JOYSTICK;
 
-    /*
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#x}.
+     * 
+     * @see #getMotionRange
+     */
     public static final int MOTION_RANGE_X = 0;
-    public static final int MOTION_RANGE_Y = 1;
-    public static final int MOTION_RANGE_PRESSURE = 2;
-    public static final int MOTION_RANGE_SIZE = 3;
-    public static final int MOTION_RANGE_TOUCH_MAJOR = 4;
-    public static final int MOTION_RANGE_TOUCH_MINOR = 5;
-    public static final int MOTION_RANGE_TOOL_MAJOR = 6;
-    public static final int MOTION_RANGE_TOOL_MINOR = 7;
-    public static final int MOTION_RANGE_ORIENTATION = 8;
     
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#y}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_Y = 1;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#pressure}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_PRESSURE = 2;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#size}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_SIZE = 3;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#touchMajor}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_TOUCH_MAJOR = 4;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#touchMinor}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_TOUCH_MINOR = 5;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#toolMajor}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_TOOL_MAJOR = 6;
+    
+    /**
+     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#toolMinor}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_TOOL_MINOR = 7;
+    
+    /**
+     * Constant for retrieving the range of values for
+     * {@link MotionEvent.PointerCoords#orientation}.
+     * 
+     * @see #getMotionRange
+     */
+    public static final int MOTION_RANGE_ORIENTATION = 8;
+
+    /**
+     * Gets information about the input device with the specified id.
+     * @param id The device id.
+     * @return The input device or null if not found.
+     */
     public static InputDevice getDevice(int id) {
+        // TODO
+        return null;
     }
-    */
     
     /**
      * Gets the name of this input device.
@@ -213,19 +272,80 @@
         return KeyCharacterMap.load(mId);
     }
     
-    /*
-    
+    /**
+     * Gets information about the range of values for a particular {@link MotionEvent}
+     * coordinate.
+     * @param range The motion range constant.
+     * @return The range of values, or null if the requested coordinate is not
+     * supported by the device.
+     */
     public MotionRange getMotionRange(int range) {
+        // TODO
+        return null;
     }
     
-    public boolean hasKeyCode(int keyCode) {
+    /**
+     * Returns true if the device supports a particular button or key.
+     * @param keyCode The key code.
+     * @return True if the device supports the key.
+     */
+    public boolean hasKey(int keyCode) {
+        // TODO
+        return false;
     }
     
+    /**
+     * Provides information about the range of values for a particular {@link MotionEvent}
+     * coordinate.
+     */
     public static final class MotionRange {
-        public float min;
-        public float max;
-        public float range;
-        public float flat;
-        public float fuzz;
-    }*/
+        /**
+         * Gets the minimum value for the coordinate.
+         * @return The minimum value.
+         */
+        public float getMin() {
+            // TODO
+            return 0;
+        }
+        
+        /**
+         * Gets the maximum value for the coordinate.
+         * @return The minimum value.
+         */
+        public float getMax() {
+            // TODO
+            return 0;
+        }
+        
+        /**
+         * Gets the range of the coordinate (difference between maximum and minimum).
+         * @return The range of values.
+         */
+        public float getRange() {
+            // TODO
+            return 0;
+        }
+        
+        /**
+         * Gets the extent of the center flat position with respect to this coordinate.
+         * For example, a flat value of 8 means that the center position is between -8 and +8.
+         * This value is mainly useful for calibrating joysticks.
+         * @return The extent of the center flat position.
+         */
+        public float getFlat() {
+            // TODO
+            return 0;
+        }
+        
+        /**
+         * Gets the error tolerance for input device measurements with respect to this coordinate.
+         * For example, a value of 2 indicates that the measured value may be up to +/- 2 units
+         * away from the actual value due to noise and device sensitivity limitations.
+         * @return The error tolerance.
+         */
+        public float getFuzz() {
+            // TODO
+            return 0;
+        }
+    }
 }
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 445a980..78b73fe 100755
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -42,9 +42,18 @@
     }
     
     /**
+     * Gets the device that this event came from.
+     * 
+     * @return The device, or null if unknown.
+     */
+    public final InputDevice getDevice() {
+        return InputDevice.getDevice(mDeviceId);
+    }
+    
+    /**
      * Gets the source of the event.
      * 
-     * @return The event source or {@link InputDevice.SOURCE_UNKNOWN} if unknown.
+     * @return The event source or {@link InputDevice#SOURCE_UNKNOWN} if unknown.
      * @see InputDevice#getSourceInfo
      */
     public final int getSource() {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0015db0..13360d9 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1403,7 +1403,7 @@
      * current location, position and size is updated to the new values.
      * The current values in the event are added to a list of historical values.
      * 
-     * Only applies to {@link ACTION_MOVE} events.
+     * Only applies to {@link #ACTION_MOVE} events.
      *
      * @param eventTime The time stamp (in ms) for this data.
      * @param x The new X position.
@@ -1427,7 +1427,7 @@
      * current location, position and size is updated to the new values.
      * The current values in the event are added to a list of historical values.
      * 
-     * Only applies to {@link ACTION_MOVE} events.
+     * Only applies to {@link #ACTION_MOVE} events.
      *
      * @param eventTime The time stamp (in ms) for this data.
      * @param pointerCoords The new pointer coordinates.
diff --git a/include/utils/String8.h b/include/utils/String8.h
index c4b18a4..0b18fe3 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -171,6 +171,8 @@
             status_t            append(const char* other);
             status_t            append(const char* other, size_t numChars);
 
+            status_t            appendFormat(const char* fmt, ...);
+
             // Note that this function takes O(N) time to calculate the value.
             // No cache value is stored.
             size_t              getUtf32Length() const;
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index 82776f4..1c4f80c 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -372,6 +372,27 @@
     return real_append(other, otherLen);
 }
 
+status_t String8::appendFormat(const char* fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+
+    int result = NO_ERROR;
+    int n = vsnprintf(NULL, 0, fmt, ap);
+    if (n != 0) {
+        size_t oldLength = length();
+        char* buf = lockBuffer(oldLength + n);
+        if (buf) {
+            vsnprintf(buf + oldLength, n + 1, fmt, ap);
+        } else {
+            result = NO_MEMORY;
+        }
+    }
+
+    va_end(ap);
+    return result;
+}
+
 status_t String8::real_append(const char* other, size_t otherLen)
 {
     const size_t myLen = bytes();
@@ -411,15 +432,16 @@
     if (size != this->size()) {
         SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
             ->editResize(size+1);
-        if (buf) {
-            char* str = (char*)buf->data();
-            str[size] = 0;
-            mString = str;
-            return NO_ERROR;
+        if (! buf) {
+            return NO_MEMORY;
         }
+
+        char* str = (char*)buf->data();
+        str[size] = 0;
+        mString = str;
     }
-    
-    return NO_MEMORY;
+
+    return NO_ERROR;
 }
 
 ssize_t String8::find(const char* other, size_t start) const
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 3c60a98..b4f46ab 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -56,8 +56,6 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    private final PowerManager mPowerManager;
-    private final PowerManagerService mPowerManagerService;
     
     private int mTouchScreenConfig;
     private int mKeyboardConfig;
@@ -85,6 +83,7 @@
     private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
     private static native void nativeSetFocusedApplication(InputApplication application);
     private static native void nativePreemptInputDispatch();
+    private static native String nativeDump();
     
     // Device class as defined by EventHub.
     private static final int CLASS_KEYBOARD = 0x00000001;
@@ -100,14 +99,9 @@
     static final int INPUT_EVENT_INJECTION_FAILED = 2;
     static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
     
-    public InputManager(Context context,
-            WindowManagerService windowManagerService,
-            PowerManager powerManager,
-            PowerManagerService powerManagerService) {
+    public InputManager(Context context, WindowManagerService windowManagerService) {
         this.mContext = context;
         this.mWindowManagerService = windowManagerService;
-        this.mPowerManager = powerManager;
-        this.mPowerManagerService = powerManagerService;
         
         this.mCallbacks = new Callbacks();
         
@@ -297,7 +291,10 @@
     }
     
     public void dump(PrintWriter pw) {
-        // TODO
+        String dumpStr = nativeDump();
+        if (dumpStr != null) {
+            pw.println(dumpStr);
+        }
     }
     
     private static final class VirtualKeyDefinition {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 37a2a58..2e28afb 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -332,7 +332,7 @@
     /**
      * Z-ordered (bottom-most first) list of all Window objects.
      */
-    final ArrayList mWindows = new ArrayList();
+    final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
 
     /**
      * Windows that are being resized.  Used so we can tell the client about
@@ -630,7 +630,7 @@
                 "KEEP_SCREEN_ON_FLAG");
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        mInputManager = new InputManager(context, this, pmc, mPowerManager);
+        mInputManager = new InputManager(context, this);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -665,7 +665,7 @@
         }
     }
 
-    private void placeWindowAfter(Object pos, WindowState window) {
+    private void placeWindowAfter(WindowState pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
         if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
             TAG, "Adding window " + window + " at "
@@ -674,7 +674,7 @@
         mWindowsChanged = true;
     }
 
-    private void placeWindowBefore(Object pos, WindowState window) {
+    private void placeWindowBefore(WindowState pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
         if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
             TAG, "Adding window " + window + " at "
@@ -687,13 +687,13 @@
     //win. used for z ordering the windows in mWindows
     private int findIdxBasedOnAppTokens(WindowState win) {
         //use a local variable to cache mWindows
-        ArrayList localmWindows = mWindows;
+        ArrayList<WindowState> localmWindows = mWindows;
         int jmax = localmWindows.size();
         if(jmax == 0) {
             return -1;
         }
         for(int j = (jmax-1); j >= 0; j--) {
-            WindowState wentry = (WindowState)localmWindows.get(j);
+            WindowState wentry = localmWindows.get(j);
             if(wentry.mAppToken == win.mAppToken) {
                 return j;
             }
@@ -704,7 +704,7 @@
     private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
-        final ArrayList localmWindows = mWindows;
+        final ArrayList<WindowState> localmWindows = mWindows;
 
         final int N = localmWindows.size();
         final WindowState attached = win.mAttachedWindow;
@@ -749,7 +749,7 @@
                     // Figure out where the window should go, based on the
                     // order of applications.
                     final int NA = mAppTokens.size();
-                    Object pos = null;
+                    WindowState pos = null;
                     for (i=NA-1; i>=0; i--) {
                         AppWindowToken t = mAppTokens.get(i);
                         if (t == token) {
@@ -769,8 +769,7 @@
                     // we need to look some more.
                     if (pos != null) {
                         // Move behind any windows attached to this one.
-                        WindowToken atoken =
-                            mTokenMap.get(((WindowState)pos).mClient.asBinder());
+                        WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
                         if (atoken != null) {
                             final int NC = atoken.windows.size();
                             if (NC > 0) {
@@ -796,8 +795,7 @@
                         if (pos != null) {
                             // Move in front of any windows attached to this
                             // one.
-                            WindowToken atoken =
-                                mTokenMap.get(((WindowState)pos).mClient.asBinder());
+                            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
                             if (atoken != null) {
                                 final int NC = atoken.windows.size();
                                 if (NC > 0) {
@@ -812,7 +810,7 @@
                             // Just search for the start of this layer.
                             final int myLayer = win.mBaseLayer;
                             for (i=0; i<N; i++) {
-                                WindowState w = (WindowState)localmWindows.get(i);
+                                WindowState w = localmWindows.get(i);
                                 if (w.mBaseLayer > myLayer) {
                                     break;
                                 }
@@ -829,7 +827,7 @@
                 // Figure out where window should go, based on layer.
                 final int myLayer = win.mBaseLayer;
                 for (i=N-1; i>=0; i--) {
-                    if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
+                    if (localmWindows.get(i).mBaseLayer <= myLayer) {
                         i++;
                         break;
                     }
@@ -912,13 +910,13 @@
     }
 
     int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
-        final ArrayList localmWindows = mWindows;
+        final ArrayList<WindowState> localmWindows = mWindows;
         final int N = localmWindows.size();
         WindowState w = null;
         int i = N;
         while (i > 0) {
             i--;
-            w = (WindowState)localmWindows.get(i);
+            w = localmWindows.get(i);
 
             //Slog.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
             //        + Integer.toHexString(w.mAttrs.flags));
@@ -933,7 +931,7 @@
                 if (!willMove
                         && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                         && i > 0) {
-                    WindowState wb = (WindowState)localmWindows.get(i-1);
+                    WindowState wb = localmWindows.get(i-1);
                     if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
                         i--;
                         w = wb;
@@ -963,7 +961,7 @@
                     int pos = 0;
                     pos = localmWindows.indexOf(curTarget);
                     while (pos >= 0) {
-                        WindowState win = (WindowState)localmWindows.get(pos);
+                        WindowState win = localmWindows.get(pos);
                         if (win.mAppToken != token) {
                             break;
                         }
@@ -1068,7 +1066,7 @@
             int wi = imw.mChildWindows.size();
             while (wi > 0) {
                 wi--;
-                WindowState cw = (WindowState)imw.mChildWindows.get(wi);
+                WindowState cw = imw.mChildWindows.get(wi);
                 cw.mAnimLayer = cw.mLayer + adj;
                 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + cw
                         + " anim layer: " + cw.mAnimLayer);
@@ -1094,7 +1092,7 @@
             int NC = win.mChildWindows.size();
             while (NC > 0) {
                 NC--;
-                WindowState cw = (WindowState)win.mChildWindows.get(NC);
+                WindowState cw = win.mChildWindows.get(NC);
                 int cpos = mWindows.indexOf(cw);
                 if (cpos >= 0) {
                     if (cpos < interestingPos) interestingPos--;
@@ -1146,7 +1144,7 @@
         if (pos >= 0) {
             final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
             if (pos < mWindows.size()) {
-                WindowState wp = (WindowState)mWindows.get(pos);
+                WindowState wp = mWindows.get(pos);
                 if (wp == mInputMethodWindow) {
                     pos++;
                 }
@@ -1190,14 +1188,14 @@
             // located here, and contiguous.
             final int N = mWindows.size();
             WindowState firstImWin = imPos < N
-                    ? (WindowState)mWindows.get(imPos) : null;
+                    ? mWindows.get(imPos) : null;
 
             // Figure out the actual input method window that should be
             // at the bottom of their stack.
             WindowState baseImWin = imWin != null
                     ? imWin : mInputMethodDialogs.get(0);
             if (baseImWin.mChildWindows.size() > 0) {
-                WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
+                WindowState cw = baseImWin.mChildWindows.get(0);
                 if (cw.mSubLayer < 0) baseImWin = cw;
             }
 
@@ -1206,7 +1204,7 @@
                 // First find the top IM window.
                 int pos = imPos+1;
                 while (pos < N) {
-                    if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
+                    if (!(mWindows.get(pos)).mIsImWindow) {
                         break;
                     }
                     pos++;
@@ -1214,7 +1212,7 @@
                 pos++;
                 // Now there should be no more input method windows above.
                 while (pos < N) {
-                    if (((WindowState)mWindows.get(pos)).mIsImWindow) {
+                    if ((mWindows.get(pos)).mIsImWindow) {
                         break;
                     }
                     pos++;
@@ -1302,7 +1300,7 @@
 
         // First find top-most window that has asked to be on top of the
         // wallpaper; all wallpapers go behind it.
-        final ArrayList localmWindows = mWindows;
+        final ArrayList<WindowState> localmWindows = mWindows;
         int N = localmWindows.size();
         WindowState w = null;
         WindowState foundW = null;
@@ -1312,7 +1310,7 @@
         int i = N;
         while (i > 0) {
             i--;
-            w = (WindowState)localmWindows.get(i);
+            w = localmWindows.get(i);
             if ((w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER)) {
                 if (topCurW == null) {
                     topCurW = w;
@@ -1483,7 +1481,7 @@
             // AND any starting window associated with it, AND below the
             // maximum layer the policy allows for wallpapers.
             while (foundI > 0) {
-                WindowState wb = (WindowState)localmWindows.get(foundI-1);
+                WindowState wb = localmWindows.get(foundI-1);
                 if (wb.mBaseLayer < maxLayer &&
                         wb.mAttachedWindow != foundW &&
                         (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
@@ -1507,7 +1505,7 @@
         } else {
             // Okay i is the position immediately above the wallpaper.  Look at
             // what is below it for later.
-            foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
+            foundW = foundI > 0 ? localmWindows.get(foundI-1) : null;
         }
 
         if (visible) {
@@ -1566,7 +1564,7 @@
                 if (wallpaper == foundW) {
                     foundI--;
                     foundW = foundI > 0
-                            ? (WindowState)localmWindows.get(foundI-1) : null;
+                            ? localmWindows.get(foundI-1) : null;
                     continue;
                 }
 
@@ -2403,6 +2401,8 @@
                         outSurface.release();
                     }
                 } catch (Exception e) {
+                    mInputMonitor.updateInputWindowsLw();
+                    
                     Slog.w(TAG, "Exception thrown when creating surface for client "
                              + client + " (" + win.mAttrs.getTitle() + ")",
                              e);
@@ -2449,7 +2449,6 @@
                               applyAnimationLocked(win, transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
-                            mInputMonitor.windowIsBecomingInvisibleLw(win);
                         } else if (win.isAnimating()) {
                             // Currently in a hide animation... turn this into
                             // an exit.
@@ -2544,6 +2543,8 @@
                 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
 
             inTouchMode = mInTouchMode;
+            
+            mInputMonitor.updateInputWindowsLw();
         }
 
         if (configChanged) {
@@ -2999,7 +3000,7 @@
     public int getOrientationFromWindowsLocked() {
         int pos = mWindows.size() - 1;
         while (pos >= 0) {
-            WindowState wtoken = (WindowState) mWindows.get(pos);
+            WindowState wtoken = mWindows.get(pos);
             pos--;
             if (wtoken.mAppToken != null) {
                 // We hit an application window. so the orientation will be determined by the
@@ -3553,7 +3554,6 @@
                         applyAnimationLocked(win,
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
                     }
-                    mInputMonitor.windowIsBecomingInvisibleLw(win);
                     changed = true;
                 }
             }
@@ -3581,6 +3581,8 @@
                 if (performLayout) {
                     updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
                     performLayoutAndPlaceSurfacesLocked();
+                } else {
+                    mInputMonitor.updateInputWindowsLw();
                 }
             }
         }
@@ -3868,7 +3870,7 @@
             int j = win.mChildWindows.size();
             while (j > 0) {
                 j--;
-                WindowState cwin = (WindowState)win.mChildWindows.get(j);
+                WindowState cwin = win.mChildWindows.get(j);
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                         "Tmp removing child window " + cwin);
                 mWindows.remove(cwin);
@@ -3896,7 +3898,7 @@
             int i = NW;
             while (i > 0) {
                 i--;
-                WindowState win = (WindowState)mWindows.get(i);
+                WindowState win = mWindows.get(i);
                 if (win.getAppToken() != null) {
                     return i+1;
                 }
@@ -3922,7 +3924,7 @@
                 int j = win.mChildWindows.size();
                 while (j > 0) {
                     j--;
-                    WindowState cwin = (WindowState)win.mChildWindows.get(j);
+                    WindowState cwin = win.mChildWindows.get(j);
                     if (cwin.mSubLayer >= 0) {
                         for (int pos=NW-1; pos>=0; pos--) {
                             if (mWindows.get(pos) == cwin) {
@@ -3950,7 +3952,7 @@
         final int NCW = win.mChildWindows.size();
         boolean added = false;
         for (int j=0; j<NCW; j++) {
-            WindowState cwin = (WindowState)win.mChildWindows.get(j);
+            WindowState cwin = win.mChildWindows.get(j);
             if (!added && cwin.mSubLayer >= 0) {
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
                         + index + ": " + cwin);
@@ -4234,7 +4236,7 @@
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
             for (int i=mWindows.size()-1; i>=0; i--) {
-                WindowState w = (WindowState)mWindows.get(i);
+                WindowState w = mWindows.get(i);
                 if (w.mSurface != null) {
                     try {
                         w.mClient.closeSystemDialogs(reason);
@@ -4418,7 +4420,7 @@
             // have been drawn.
             final int N = mWindows.size();
             for (int i=0; i<N; i++) {
-                WindowState w = (WindowState)mWindows.get(i);
+                WindowState w = mWindows.get(i);
                 if (w.isVisibleLw() && !w.mObscured
                         && (w.mOrientationChanging || !w.isDrawnLw())) {
                     return;
@@ -4531,7 +4533,7 @@
                 Surface.setOrientation(0, rotation, animFlags);
             }
             for (int i=mWindows.size()-1; i>=0; i--) {
-                WindowState w = (WindowState)mWindows.get(i);
+                WindowState w = mWindows.get(i);
                 if (w.mSurface != null) {
                     w.mOrientationChanging = true;
                 }
@@ -4687,11 +4689,10 @@
 
         boolean result = true;
 
-        Object[] windows;
+        WindowState[] windows;
         synchronized (mWindowMap) {
-            windows = new Object[mWindows.size()];
             //noinspection unchecked
-            windows = mWindows.toArray(windows);
+            windows = mWindows.toArray(new WindowState[mWindows.size()]);
         }
 
         BufferedWriter out = null;
@@ -4703,7 +4704,7 @@
 
             final int count = windows.length;
             for (int i = 0; i < count; i++) {
-                final WindowState w = (WindowState) windows[i];
+                final WindowState w = windows[i];
                 out.write(Integer.toHexString(System.identityHashCode(w)));
                 out.write(' ');
                 out.append(w.mAttrs.getTitle());
@@ -4856,11 +4857,11 @@
         }
 
         synchronized (mWindowMap) {
-            final ArrayList windows = mWindows;
+            final ArrayList<WindowState> windows = mWindows;
             final int count = windows.size();
 
             for (int i = 0; i < count; i++) {
-                WindowState w = (WindowState) windows.get(i);
+                WindowState w = windows.get(i);
                 if (System.identityHashCode(w) == hashCode) {
                     return w;
                 }
@@ -5094,7 +5095,7 @@
         private WindowState getWindowStateForInputChannelLocked(InputChannel inputChannel) {
             int windowCount = mWindows.size();
             for (int i = 0; i < windowCount; i++) {
-                WindowState windowState = (WindowState) mWindows.get(i);
+                WindowState windowState = mWindows.get(i);
                 if (windowState.mInputChannel == inputChannel) {
                     return windowState;
                 }
@@ -5110,10 +5111,10 @@
             // As an optimization, we could try to prune the list of windows but this turns
             // out to be difficult because only the native code knows for sure which window
             // currently has touch focus.
-            final ArrayList windows = mWindows;
+            final ArrayList<WindowState> windows = mWindows;
             final int N = windows.size();
             for (int i = N - 1; i >= 0; i--) {
-                final WindowState child = (WindowState) windows.get(i);
+                final WindowState child = windows.get(i);
                 if (child.mInputChannel == null || child.mRemoved) {
                     // Skip this window because it cannot possibly receive input.
                     continue;
@@ -5258,17 +5259,6 @@
             }
         }
         
-        public void windowIsBecomingInvisibleLw(WindowState window) {
-            // The window is becoming invisible.  Preempt input dispatch in progress
-            // so that the next window below can receive focus.
-            if (window == mInputFocus) {
-                mInputFocus = null;
-                preemptInputDispatchLw();
-            }
-            
-            updateInputWindowsLw();
-        }
-        
         /* Tells the dispatcher to stop waiting for its current synchronous event targets.
          * Essentially, just makes those dispatches asynchronous so a new dispatch cycle
          * can begin.
@@ -5779,7 +5769,7 @@
         final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
         final DeathRecipient mDeathRecipient;
         final WindowState mAttachedWindow;
-        final ArrayList mChildWindows = new ArrayList();
+        final ArrayList<WindowState> mChildWindows = new ArrayList<WindowState>();
         final int mBaseLayer;
         final int mSubLayer;
         final boolean mLayoutAttached;
@@ -6335,10 +6325,8 @@
                 int i = mChildWindows.size();
                 while (i > 0) {
                     i--;
-                    WindowState c = (WindowState)mChildWindows.get(i);
+                    WindowState c = mChildWindows.get(i);
                     c.mAttachedHidden = true;
-                    
-                    mInputMonitor.windowIsBecomingInvisibleLw(c);
                 }
 
                 if (mReportDestroySurface) {
@@ -6448,7 +6436,7 @@
                 int i = mChildWindows.size();
                 while (i > 0) {
                     i--;
-                    WindowState c = (WindowState)mChildWindows.get(i);
+                    WindowState c = mChildWindows.get(i);
                     if (c.mAttachedHidden) {
                         c.mAttachedHidden = false;
                         if (c.mSurface != null) {
@@ -6621,7 +6609,7 @@
 
             final int N = mChildWindows.size();
             for (int i=0; i<N; i++) {
-                ((WindowState)mChildWindows.get(i)).finishExit();
+                mChildWindows.get(i).finishExit();
             }
 
             if (!mExiting) {
@@ -6646,10 +6634,6 @@
                     Slog.w(TAG, "Error hiding surface in " + this, e);
                 }
                 mLastHidden = true;
-                
-                for (int i=0; i<N; i++) {
-                    mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
-                }
             }
             mExiting = false;
             if (mRemoveOnExit) {
@@ -7554,7 +7538,7 @@
 
             final int N = windows.size();
             for (int i=0; i<N; i++) {
-                ((WindowState)windows.get(i)).finishExit();
+                windows.get(i).finishExit();
             }
             updateReportedVisibilityLocked();
 
@@ -7980,7 +7964,7 @@
                         int i = mWindows.size();
                         while (i > 0) {
                             i--;
-                            WindowState w = (WindowState)mWindows.get(i);
+                            WindowState w = mWindows.get(i);
                             if (w.mOrientationChanging) {
                                 w.mOrientationChanging = false;
                                 Slog.w(TAG, "Force clearing orientation change: " + w);
@@ -8119,7 +8103,7 @@
             int idx = findDesiredInputMethodWindowIndexLocked(false);
             WindowState imFocus;
             if (idx > 0) {
-                imFocus = (WindowState)mWindows.get(idx-1);
+                imFocus = mWindows.get(idx-1);
                 if (imFocus != null) {
                     if (imFocus.mSession.mClient != null &&
                             imFocus.mSession.mClient.asBinder() == client.asBinder()) {
@@ -8177,9 +8161,9 @@
         // First remove all existing app windows.
         i=0;
         while (i < NW) {
-            WindowState w = (WindowState)mWindows.get(i);
+            WindowState w = mWindows.get(i);
             if (w.mAppToken != null) {
-                WindowState win = (WindowState)mWindows.remove(i);
+                WindowState win = mWindows.remove(i);
                 mWindowsChanged = true;
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                         "Rebuild removing window: " + win);
@@ -8227,7 +8211,7 @@
         int i;
 
         for (i=0; i<N; i++) {
-            WindowState w = (WindowState)mWindows.get(i);
+            WindowState w = mWindows.get(i);
             if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
                     || (i > 0 && w.mIsWallpaper)) {
                 curLayer += WINDOW_LAYER_MULTIPLIER;
@@ -8352,7 +8336,7 @@
         // to another window).
         int topAttached = -1;
         for (i = N-1; i >= 0; i--) {
-            WindowState win = (WindowState) mWindows.get(i);
+            WindowState win = mWindows.get(i);
 
             // Don't do layout of a window if it is not visible, or
             // soon won't be visible, to avoid wasting time and funky
@@ -8401,7 +8385,7 @@
         // XXX does not deal with windows that are attached to windows
         // that are themselves attached.
         for (i = topAttached; i >= 0; i--) {
-            WindowState win = (WindowState) mWindows.get(i);
+            WindowState win = mWindows.get(i);
 
             // If this view is GONE, then skip it -- keep the current
             // frame, and let the caller know so they can ignore it
@@ -8548,7 +8532,7 @@
                 final int N = mWindows.size();
 
                 for (i=N-1; i>=0; i--) {
-                    WindowState w = (WindowState)mWindows.get(i);
+                    WindowState w = mWindows.get(i);
 
                     final WindowManager.LayoutParams attrs = w.mAttrs;
 
@@ -8981,7 +8965,7 @@
                         // Clear them out.
                         forceHiding = false;
                         for (i=N-1; i>=0; i--) {
-                            WindowState w = (WindowState)mWindows.get(i);
+                            WindowState w = mWindows.get(i);
                             if (w.mSurface != null) {
                                 final WindowManager.LayoutParams attrs = w.mAttrs;
                                 if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
@@ -9031,6 +9015,7 @@
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
                         + Integer.toHexString(changes));
                 
+                mInputMonitor.updateInputWindowsLw();
             } while (changes != 0);
 
             // THIRD LOOP: Update the surfaces of all windows.
@@ -9047,7 +9032,7 @@
             final int N = mWindows.size();
 
             for (i=N-1; i>=0; i--) {
-                WindowState w = (WindowState)mWindows.get(i);
+                WindowState w = mWindows.get(i);
 
                 boolean displayed = false;
                 final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -9227,7 +9212,6 @@
                                     Slog.w(TAG, "Exception hiding surface in " + w);
                                 }
                             }
-                            mInputMonitor.windowIsBecomingInvisibleLw(w);
                         }
                         // If we are waiting for this window to handle an
                         // orientation change, well, it is hidden, so
@@ -9487,6 +9471,8 @@
             Slog.e(TAG, "Unhandled exception in Window Manager", e);
         }
 
+        mInputMonitor.updateInputWindowsLw();
+        
         Surface.closeTransaction();
 
         if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
@@ -9612,6 +9598,8 @@
             requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
         }
         
+        mInputMonitor.updateInputWindowsLw();
+        
         if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
                 + " holdScreen=" + holdScreen);
         if (!mDisplayFrozen) {
@@ -9718,7 +9706,7 @@
             boolean leakedSurface = false;
             Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
             for (int i=0; i<N; i++) {
-                WindowState ws = (WindowState)mWindows.get(i);
+                WindowState ws = mWindows.get(i);
                 if (ws.mSurface != null) {
                     if (!mSessions.contains(ws.mSession)) {
                         Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
@@ -9750,7 +9738,7 @@
                 Slog.w(TAG, "No leaked surfaces; killing applicatons!");
                 SparseIntArray pidCandidates = new SparseIntArray();
                 for (int i=0; i<N; i++) {
-                    WindowState ws = (WindowState)mWindows.get(i);
+                    WindowState ws = mWindows.get(i);
                     if (ws.mSurface != null) {
                         pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
                     }
@@ -9842,7 +9830,7 @@
             ? mAppTokens.get(nextAppIndex) : null;
 
         while (i >= 0) {
-            win = (WindowState)mWindows.get(i);
+            win = mWindows.get(i);
 
             if (localLOGV || DEBUG_FOCUS) Slog.v(
                 TAG, "Looking for focus: " + i
@@ -9990,14 +9978,13 @@
             return;
         }
 
-        pw.println("Input Dispatcher State:");
         mInputManager.dump(pw);
         pw.println(" ");
         
         synchronized(mWindowMap) {
             pw.println("Current Window Manager state:");
             for (int i=mWindows.size()-1; i>=0; i--) {
-                WindowState w = (WindowState)mWindows.get(i);
+                WindowState w = mWindows.get(i);
                 pw.print("  Window #"); pw.print(i); pw.print(' ');
                         pw.print(w); pw.println(":");
                 w.dump(pw, "    ");
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index bc052a0..f19f1ec 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -199,6 +199,8 @@
 
     inline sp<InputManager> getInputManager() const { return mInputManager; }
 
+    String8 dump();
+
     void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
     void setDisplayOrientation(int32_t displayId, int32_t orientation);
 
@@ -341,7 +343,8 @@
     InputApplication* mFocusedApplication;
     InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
 
-    void dumpDispatchStateLd();
+    void dumpDispatchStateLd(String8& dump);
+    void logDispatchStateLd();
 
     bool notifyANR(jobject tokenObj, nsecs_t& outNewTimeout);
     void releaseFocusedApplicationLd(JNIEnv* env);
@@ -404,6 +407,13 @@
     releaseFocusedApplicationLd(env);
 }
 
+String8 NativeInputManager::dump() {
+    String8 dump;
+    dump.append("Native Input Dispatcher State:\n");
+    dumpDispatchStateLd(dump);
+    return dump;
+}
+
 bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
     return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
 }
@@ -921,6 +931,8 @@
             mTouchedWallpaperWindows.clear();
         }
 
+        bool hadFocusedWindow = mFocusedWindow != NULL;
+
         mWindows.clear();
         mFocusedWindow = NULL;
         mWallpaperWindows.clear();
@@ -972,10 +984,15 @@
 
         mTempTouchedWallpaperChannels.clear();
 
+        if (hadFocusedWindow && ! mFocusedWindow
+                || mFocusedWindow && ! mFocusedWindow->visible) {
+            preemptInputDispatch();
+        }
+
         mDispatchStateChanged.broadcast();
 
 #if DEBUG_FOCUS
-        dumpDispatchStateLd();
+        logDispatchStateLd();
 #endif
     } // release lock
 }
@@ -1092,7 +1109,7 @@
         mDispatchStateChanged.broadcast();
 
 #if DEBUG_FOCUS
-        dumpDispatchStateLd();
+        logDispatchStateLd();
 #endif
     } // release lock
 }
@@ -1120,7 +1137,7 @@
         }
 
 #if DEBUG_FOCUS
-        dumpDispatchStateLd();
+        logDispatchStateLd();
 #endif
     } // release lock
 }
@@ -1217,7 +1234,7 @@
 #if DEBUG_FOCUS
     LOGD("waitForFocusedWindow finished: injectionResult=%d",
             injectionResult);
-    dumpDispatchStateLd();
+    logDispatchStateLd();
 #endif
     return injectionResult;
 }
@@ -1490,7 +1507,7 @@
 #if DEBUG_FOCUS
     LOGD("waitForTouchedWindow finished: injectionResult=%d",
             injectionResult);
-    dumpDispatchStateLd();
+    logDispatchStateLd();
 #endif
     return injectionResult;
 }
@@ -1697,31 +1714,38 @@
     android_server_PowerManagerService_userActivity(eventTime, eventType);
 }
 
-void NativeInputManager::dumpDispatchStateLd() {
-#if DEBUG_FOCUS
-    LOGD("  dispatcherState: dispatchEnabled=%d, dispatchFrozen=%d, windowsReady=%d",
-            mDispatchEnabled, mDispatchFrozen, mWindowsReady);
+void NativeInputManager::logDispatchStateLd() {
+    String8 dump;
+    dumpDispatchStateLd(dump);
+    LOGD("%s", dump.string());
+}
+
+void NativeInputManager::dumpDispatchStateLd(String8& dump) {
+    dump.appendFormat("  dispatchEnabled: %d\n", mDispatchEnabled);
+    dump.appendFormat("  dispatchFrozen: %d\n", mDispatchFrozen);
+    dump.appendFormat("  windowsReady: %d\n", mWindowsReady);
+
     if (mFocusedApplication) {
-        LOGD("  focusedApplication: name='%s', dispatchingTimeout=%0.3fms",
+        dump.appendFormat("  focusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
                 mFocusedApplication->name.string(),
                 mFocusedApplication->dispatchingTimeout / 1000000.0);
     } else {
-        LOGD("  focusedApplication: <null>");
+        dump.append("  focusedApplication: <null>\n");
     }
-    LOGD("  focusedWindow: '%s'",
+    dump.appendFormat("  focusedWindow: '%s'\n",
             mFocusedWindow != NULL ? mFocusedWindow->inputChannel->getName().string() : "<null>");
-    LOGD("  touchedWindow: '%s', touchDown=%d",
+    dump.appendFormat("  touchedWindow: '%s', touchDown=%d\n",
             mTouchedWindow != NULL ? mTouchedWindow->inputChannel->getName().string() : "<null>",
             mTouchDown);
     for (size_t i = 0; i < mTouchedWallpaperWindows.size(); i++) {
-        LOGD("  touchedWallpaperWindows[%d]: '%s'",
+        dump.appendFormat("  touchedWallpaperWindows[%d]: '%s'\n",
                 i, mTouchedWallpaperWindows[i]->inputChannel->getName().string());
     }
     for (size_t i = 0; i < mWindows.size(); i++) {
-        LOGD("  windows[%d]: '%s', paused=%d, hasFocus=%d, hasWallpaper=%d, visible=%d, "
-                "flags=0x%08x, type=0x%08x, "
+        dump.appendFormat("  windows[%d]: '%s', paused=%d, hasFocus=%d, hasWallpaper=%d, "
+                "visible=%d, flags=0x%08x, type=0x%08x, "
                 "frame=[%d,%d], touchableArea=[%d,%d][%d,%d], "
-                "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms",
+                "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                 i, mWindows[i].inputChannel->getName().string(),
                 mWindows[i].paused, mWindows[i].hasFocus, mWindows[i].hasWallpaper,
                 mWindows[i].visible, mWindows[i].layoutParamsFlags, mWindows[i].layoutParamsType,
@@ -1731,7 +1755,6 @@
                 mWindows[i].ownerPid, mWindows[i].ownerUid,
                 mWindows[i].dispatchingTimeout / 1000000.0);
     }
-#endif
 }
 
 // ----------------------------------------------------------------------------
@@ -2048,6 +2071,15 @@
     gNativeInputManager->preemptInputDispatch();
 }
 
+static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) {
+    if (checkInputManagerUnitialized(env)) {
+        return NULL;
+    }
+
+    String8 dump(gNativeInputManager->dump());
+    return env->NewStringUTF(dump.string());
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gInputManagerMethods[] = {
@@ -2083,7 +2115,9 @@
     { "nativeSetInputDispatchMode", "(ZZ)V",
             (void*) android_server_InputManager_nativeSetInputDispatchMode },
     { "nativePreemptInputDispatch", "()V",
-            (void*) android_server_InputManager_nativePreemptInputDispatch }
+            (void*) android_server_InputManager_nativePreemptInputDispatch },
+    { "nativeDump", "()Ljava/lang/String;",
+            (void*) android_server_InputManager_nativeDump },
 };
 
 #define FIND_CLASS(var, className) \