More native input event dispatching.

Added ANRs handling.
Added event injection.
Fixed a NPE ActivityManagerServer writing ANRs to the drop box.
Fixed HOME key interception.
Fixed trackball reporting.
Fixed pointer rotation in landscape mode.

Change-Id: I50340f559f22899ab924e220a78119ffc79469b7
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 72c4166..8d9bb29 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -81,6 +81,10 @@
     private static native boolean nativeHasKeys(int[] keyCodes, boolean[] keyExists);
     private static native void nativeRegisterInputChannel(InputChannel inputChannel);
     private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
+    private static native int nativeInjectKeyEvent(KeyEvent event, int nature,
+            int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
+    private static native int nativeInjectMotionEvent(MotionEvent event, int nature,
+            int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
     
     // Device class as defined by EventHub.
     private static final int CLASS_KEYBOARD = 0x00000001;
@@ -90,6 +94,12 @@
     private static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
     private static final int CLASS_DPAD = 0x00000020;
     
+    // Input event injection constants defined in InputDispatcher.h.
+    static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
+    static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
+    static final int INPUT_EVENT_INJECTION_FAILED = 2;
+    static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
+    
     public InputManager(Context context,
             WindowManagerService windowManagerService,
             WindowManagerPolicy windowManagerPolicy,
@@ -215,37 +225,63 @@
         nativeUnregisterInputChannel(inputChannel);
     }
     
-    // TBD where this really belongs, duplicate copy in WindowManagerService
-    static final int INJECT_FAILED = 0;
-    static final int INJECT_SUCCEEDED = 1;
-    static final int INJECT_NO_PERMISSION = -1;
-    
     /**
      * Injects a key event into the event system on behalf of an application.
+     * This method may block even if sync is false because it must wait for previous events
+     * to be dispatched before it can determine whether input event injection will be
+     * permitted based on the current input focus.
      * @param event The event to inject.
      * @param nature The nature of the event.
+     * @param injectorPid The pid of the injecting application.
+     * @param injectorUid The uid of the injecting application.
      * @param sync If true, waits for the event to be completed before returning.
-     * @param pid The pid of the injecting application.
-     * @param uid The uid of the injecting application.
-     * @return INJECT_SUCCEEDED, INJECT_FAILED or INJECT_NO_PERMISSION
+     * @param timeoutMillis The injection timeout in milliseconds.
+     * @return One of the INPUT_EVENT_INJECTION_XXX constants.
      */
-    public int injectKeyEvent(KeyEvent event, int nature, boolean sync, int pid, int uid) {
-        // TODO
-        return INJECT_FAILED;
+    public int injectKeyEvent(KeyEvent event, int nature, int injectorPid, int injectorUid,
+            boolean sync, int timeoutMillis) {
+        if (event == null) {
+            throw new IllegalArgumentException("event must not be null");
+        }
+        if (injectorPid < 0 || injectorUid < 0) {
+            throw new IllegalArgumentException("injectorPid and injectorUid must not be negative.");
+        }
+        if (timeoutMillis <= 0) {
+            throw new IllegalArgumentException("timeoutMillis must be positive");
+        }
+        
+        return nativeInjectKeyEvent(event, nature, injectorPid, injectorUid,
+                sync, timeoutMillis);
     }
     
     /**
      * Injects a motion event into the event system on behalf of an application.
+     * This method may block even if sync is false because it must wait for previous events
+     * to be dispatched before it can determine whether input event injection will be
+     * permitted based on the current input focus.
      * @param event The event to inject.
      * @param nature The nature of the event.
      * @param sync If true, waits for the event to be completed before returning.
-     * @param pid The pid of the injecting application.
-     * @param uid The uid of the injecting application.
-     * @return INJECT_SUCCEEDED, INJECT_FAILED or INJECT_NO_PERMISSION
+     * @param injectorPid The pid of the injecting application.
+     * @param injectorUid The uid of the injecting application.
+     * @param sync If true, waits for the event to be completed before returning.
+     * @param timeoutMillis The injection timeout in milliseconds.
+     * @return One of the INPUT_EVENT_INJECTION_XXX constants.
      */
-    public int injectMotionEvent(MotionEvent event, int nature, boolean sync, int pid, int uid) {
-        // TODO
-        return INJECT_FAILED;
+    public int injectMotionEvent(MotionEvent event, int nature, int injectorPid, int injectorUid,
+            boolean sync, int timeoutMillis) {
+        if (event == null) {
+            throw new IllegalArgumentException("event must not be null");
+        }
+        if (injectorPid < 0 || injectorUid < 0) {
+            throw new IllegalArgumentException("injectorPid and injectorUid must not be negative.");
+        }
+        if (timeoutMillis <= 0) {
+            throw new IllegalArgumentException("timeoutMillis must be positive");
+        }
+        
+        return nativeInjectMotionEvent(event, nature, injectorPid, injectorUid,
+                sync, timeoutMillis);
     }
     
     public void dump(PrintWriter pw) {
@@ -271,8 +307,6 @@
         private static final boolean DEBUG_VIRTUAL_KEYS = false;
         private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
         
-        private final InputTargetList mReusableInputTargetList = new InputTargetList();
-        
         @SuppressWarnings("unused")
         public boolean isScreenOn() {
             return mPowerManagerService.isScreenOn();
@@ -309,6 +343,21 @@
         }
         
         @SuppressWarnings("unused")
+        public void notifyInputChannelBroken(InputChannel inputChannel) {
+            mWindowManagerService.notifyInputChannelBroken(inputChannel);
+        }
+
+        @SuppressWarnings("unused")
+        public long notifyInputChannelANR(InputChannel inputChannel) {
+            return mWindowManagerService.notifyInputChannelANR(inputChannel);
+        }
+
+        @SuppressWarnings("unused")
+        public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
+            mWindowManagerService.notifyInputChannelRecoveredFromANR(inputChannel);
+        }
+        
+        @SuppressWarnings("unused")
         public int hackInterceptKey(int deviceId, int type, int scanCode,
                 int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
             RawInputEvent event = new RawInputEvent();
@@ -437,24 +486,23 @@
             return names.toArray(new String[names.size()]);
         }
         
+        // TODO All code related to target identification should be moved down into native.
         @SuppressWarnings("unused")
-        public InputTarget[] getKeyEventTargets(KeyEvent event, int nature, int policyFlags) {
-            mReusableInputTargetList.clear();
-            
-            mWindowManagerService.getKeyEventTargets(mReusableInputTargetList,
-                    event, nature, policyFlags);
-            
-            return mReusableInputTargetList.toNullTerminatedArray();
+        public int getKeyEventTargets(InputTargetList inputTargets,
+                KeyEvent event, int nature, int policyFlags,
+                int injectorPid, int injectorUid) {
+            inputTargets.clear();
+            return mWindowManagerService.getKeyEventTargetsTd(
+                    inputTargets, event, nature, policyFlags, injectorPid, injectorUid);
         }
         
         @SuppressWarnings("unused")
-        public InputTarget[] getMotionEventTargets(MotionEvent event, int nature, int policyFlags) {
-            mReusableInputTargetList.clear();
-            
-            mWindowManagerService.getMotionEventTargets(mReusableInputTargetList,
-                    event, nature, policyFlags);
-            
-            return mReusableInputTargetList.toNullTerminatedArray();
+        public int getMotionEventTargets(InputTargetList inputTargets,
+                MotionEvent event, int nature, int policyFlags,
+                int injectorPid, int injectorUid) {
+            inputTargets.clear();
+            return mWindowManagerService.getMotionEventTargetsTd(
+                    inputTargets, event, nature, policyFlags, injectorPid, injectorUid);
         }
     }
 }