Merge "AmrInputStream refresh: eliminate the dependency upon OpenCore's code" into gingerbread
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index 6dee816..ff5aced 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -14,6 +14,7 @@
     struct binder_io msg, reply;
 
     bio_init(&msg, iodata, sizeof(iodata), 4);
+    bio_put_uint32(&msg, 0);  // strict mode header
     bio_put_string16_x(&msg, SVC_MGR_NAME);
     bio_put_string16_x(&msg, name);
 
@@ -37,7 +38,7 @@
     struct binder_io msg, reply;
 
     bio_init(&msg, iodata, sizeof(iodata), 4);
-
+    bio_put_uint32(&msg, 0);  // strict mode header
     bio_put_string16_x(&msg, SVC_MGR_NAME);
     bio_put_string16_x(&msg, name);
     bio_put_obj(&msg, ptr);
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index a2006c1..01cddc6 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -193,6 +193,7 @@
     uint16_t *s;
     unsigned len;
     void *ptr;
+    uint32_t strict_policy;
 
 //    LOGI("target=%p code=%d pid=%d uid=%d\n",
 //         txn->target, txn->code, txn->sender_pid, txn->sender_euid);
@@ -200,8 +201,12 @@
     if (txn->target != svcmgr_handle)
         return -1;
 
+    // Equivalent to Parcel::enforceInterface(), reading the RPC
+    // header with the strict mode policy mask and the interface name.
+    // Note that we ignore the strict_policy and don't propagate it
+    // further (since we do no outbound RPCs anyway).
+    strict_policy = bio_get_uint32(msg);
     s = bio_get_string16(msg, &len);
-
     if ((len != (sizeof(svcmgr_id) / 2)) ||
         memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
         fprintf(stderr,"invalid id %s\n", str8(s));
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 317e547..e2f5ada 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -17,65 +17,61 @@
 
 package android.hardware;
 
-/** 
- * Class representing a sensor. Use {@link SensorManager#getSensorList}
- * to get the list of available Sensors.
+/**
+ * Class representing a sensor. Use {@link SensorManager#getSensorList} to get
+ * the list of available Sensors.
  */
 public class Sensor {
 
-    /** 
-     * A constant describing an accelerometer sensor type.
-     * See {@link android.hardware.SensorEvent SensorEvent}
-     * for more details.
+    /**
+     * A constant describing an accelerometer sensor type. See
+     * {@link android.hardware.SensorEvent SensorEvent} for more details.
      */
-    public static final int TYPE_ACCELEROMETER  = 1;
+    public static final int TYPE_ACCELEROMETER = 1;
 
-    /** 
-     * A constant describing a magnetic field sensor type.
-     * See {@link android.hardware.SensorEvent SensorEvent}
-     * for more details.
+    /**
+     * A constant describing a magnetic field sensor type. See
+     * {@link android.hardware.SensorEvent SensorEvent} for more details.
      */
     public static final int TYPE_MAGNETIC_FIELD = 2;
-    
-    /** 
-     * A constant describing an orientation sensor type.
-     * See {@link android.hardware.SensorEvent SensorEvent}
-     * for more details.
+
+    /**
+     * A constant describing an orientation sensor type. See
+     * {@link android.hardware.SensorEvent SensorEvent} for more details.
+     *
      * @deprecated use {@link android.hardware.SensorManager#getOrientation
-     *  SensorManager.getOrientation()} instead.
+     *             SensorManager.getOrientation()} instead.
      */
     @Deprecated
-    public static final int TYPE_ORIENTATION    = 3;
+    public static final int TYPE_ORIENTATION = 3;
 
     /** A constant describing a gyroscope sensor type */
-    public static final int TYPE_GYROSCOPE      = 4;
+    public static final int TYPE_GYROSCOPE = 4;
+
     /**
-     * A constant describing an light sensor type.
-     * See {@link android.hardware.SensorEvent SensorEvent}
-     * for more details.
+     * A constant describing an light sensor type. See
+     * {@link android.hardware.SensorEvent SensorEvent} for more details.
      */
-    public static final int TYPE_LIGHT          = 5;
+    public static final int TYPE_LIGHT = 5;
 
     /** A constant describing a pressure sensor type */
-    public static final int TYPE_PRESSURE       = 6;
+    public static final int TYPE_PRESSURE = 6;
 
     /** A constant describing a temperature sensor type */
-    public static final int TYPE_TEMPERATURE    = 7;
+    public static final int TYPE_TEMPERATURE = 7;
 
     /**
-     * A constant describing an proximity sensor type.
-     * See {@link android.hardware.SensorEvent SensorEvent}
-     * for more details.
+     * A constant describing an proximity sensor type. See
+     * {@link android.hardware.SensorEvent SensorEvent} for more details.
      */
-    public static final int TYPE_PROXIMITY      = 8;
+    public static final int TYPE_PROXIMITY = 8;
 
-    
-    /** 
+    /**
      * A constant describing all sensor types.
      */
-    public static final int TYPE_ALL             = -1;
+    public static final int TYPE_ALL = -1;
 
-    /* Some of these fields are set only by the native bindings in 
+    /* Some of these fields are set only by the native bindings in
      * SensorManager.
      */
     private String  mName;
@@ -87,8 +83,8 @@
     private float   mResolution;
     private float   mPower;
     private int     mLegacyType;
-    
-    
+
+
     Sensor() {
     }
 
@@ -105,51 +101,51 @@
     public String getVendor() {
         return mVendor;
     }
-    
+
     /**
      * @return generic type of this sensor.
      */
     public int getType() {
         return mType;
     }
-    
+
     /**
      * @return version of the sensor's module.
      */
     public int getVersion() {
         return mVersion;
     }
-    
+
     /**
      * @return maximum range of the sensor in the sensor's unit.
      */
     public float getMaximumRange() {
         return mMaxRange;
     }
-    
+
     /**
      * @return resolution of the sensor in the sensor's unit.
      */
     public float getResolution() {
         return mResolution;
     }
-    
+
     /**
      * @return the power in mA used by this sensor while in use
      */
     public float getPower() {
         return mPower;
     }
-    
+
     int getHandle() {
         return mHandle;
     }
-    
+
     void setRange(float max, float res) {
         mMaxRange = max;
         mResolution = res;
     }
-    
+
     void setLegacyType(int legacyType) {
         mLegacyType = legacyType;
     }
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 9a9f0bf..dfefe7e 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -17,26 +17,36 @@
 package android.hardware;
 
 /**
- * This class represents a sensor event and holds informations such as the
- * sensor type (eg: accelerometer, orientation, etc...), the time-stamp, 
- * accuracy and of course the sensor's {@link SensorEvent#values data}.
+ * <p>
+ * This class represents a {@link android.hardware.Sensor Sensor} event and
+ * holds informations such as the sensor's type, the time-stamp, accuracy and of
+ * course the sensor's {@link SensorEvent#values data}.
+ * </p>
  *
- * <p><u>Definition of the coordinate system used by the SensorEvent API.</u><p>
- * 
- * <pre>
- * The coordinate space is defined relative to the screen of the phone 
- * in its default orientation. The axes are not swapped when the device's
- * screen orientation changes.
- * 
- * The OpenGL ES coordinate system is used. The origin is in the
- * lower-left corner  with respect to the screen, with the X axis horizontal
- * and pointing  right, the Y axis vertical and pointing up and the Z axis
- * pointing outside the front face of the screen. In this system, coordinates
- * behind the screen have negative Z values.
- * 
+ * <p>
+ * <u>Definition of the coordinate system used by the SensorEvent API.</u>
+ * </p>
+ *
+ * <p>
+ * The coordinate space is defined relative to the screen of the phone in its
+ * default orientation. The axes are not swapped when the device's screen
+ * orientation changes.
+ * </p>
+ *
+ * <p>
+ * The OpenGL ES coordinate system is used. The origin is in the lower-left
+ * corner with respect to the screen, with the X axis horizontal and pointing
+ * right, the Y axis vertical and pointing up and the Z axis pointing outside
+ * the front face of the screen. In this system, coordinates behind the screen
+ * have negative Z values.
+ * </p>
+ *
+ * <p>
  * <b>Note:</b> This coordinate system is different from the one used in the
- * Android 2D APIs where the origin is in the top-left corner. 
+ * Android 2D APIs where the origin is in the top-left corner.
+ * </p>
  *
+ * <pre>
  *   x<0         x>0
  *                ^
  *                |
@@ -60,100 +70,125 @@
 
 public class SensorEvent {
     /**
+     * <p>
      * The length and contents of the values array vary depending on which
-     * sensor type is being monitored (see also {@link SensorEvent} for a 
-     * definition of the coordinate system used):
-     * 
-     * <p>{@link android.hardware.Sensor#TYPE_ORIENTATION Sensor.TYPE_ORIENTATION}:<p>
-     *  All values are angles in degrees.
-     * 
-     * <p>values[0]: Azimuth, angle between the magnetic north direction and
-     * the Y axis, around the Z axis (0 to 359).
-     * 0=North, 90=East, 180=South, 270=West
+     * {@link android.hardware.Sensor sensor} type is being monitored (see also
+     * {@link SensorEvent} for a definition of the coordinate system used):
+     * </p>
      *
-     * <p>values[1]: Pitch, rotation around X axis (-180 to 180), 
-     * with positive values when the z-axis moves <b>toward</b> the y-axis.
+     * <h3>{@link android.hardware.Sensor#TYPE_ORIENTATION
+     * Sensor.TYPE_ORIENTATION}:</h3> All values are angles in degrees.
      *
-     * <p>values[2]: Roll, rotation around Y axis (-90 to 90), with 
-     * positive values  when the x-axis moves <b>toward</b> the z-axis.
-     * 
-     * <p><b>Important note:</b> For historical reasons the roll angle is
-     * positive in the clockwise direction (mathematically speaking, it
-     * should be positive in the counter-clockwise direction).
+     * <ul>
+     * <p>
+     * values[0]: Azimuth, angle between the magnetic north direction and the Y
+     * axis, around the Z axis (0 to 359). 0=North, 90=East, 180=South, 270=West
      *
-     * <p><b>Note:</b> This definition is different from <b>yaw, pitch and 
-     * roll</b> used in aviation where the X axis is along the long side of
-     * the plane (tail to nose).
+     * <p>
+     * values[1]: Pitch, rotation around X axis (-180 to 180), with positive
+     * values when the z-axis moves <b>toward</b> the y-axis.
      *
-     * <p><b>Note:</b> This sensor type exists for legacy reasons, please use
-     * {@link android.hardware.SensorManager#getRotationMatrix 
-     *      getRotationMatrix()} in conjunction with
-     * {@link android.hardware.SensorManager#remapCoordinateSystem 
-     *      remapCoordinateSystem()} and
-     * {@link android.hardware.SensorManager#getOrientation getOrientation()}
-     * to compute these values instead.
+     * <p>
+     * values[2]: Roll, rotation around Y axis (-90 to 90), with positive values
+     * when the x-axis moves <b>toward</b> the z-axis.
+     * </ul>
      *
-     * <p>{@link android.hardware.Sensor#TYPE_ACCELEROMETER Sensor.TYPE_ACCELEROMETER}:<p>
-     *  All values are in SI units (m/s^2) and measure the acceleration applied
-     *  to the phone minus the force of gravity.
-     *  
-     *  <p>values[0]: Acceleration minus Gx on the x-axis 
-     *  <p>values[1]: Acceleration minus Gy on the y-axis 
-     *  <p>values[2]: Acceleration minus Gz on the z-axis
-     *  
-     *  <p><u>Examples</u>:
-     *    <li>When the device lies flat on a table and is pushed on its left 
-     *    side toward the right, the x acceleration value is positive.</li>
-     *    
-     *    <li>When the device lies flat on a table, the acceleration value is 
-     *    +9.81, which correspond to the acceleration of the device (0 m/s^2) 
-     *    minus the force of gravity (-9.81 m/s^2).</li>
-     *    
-     *    <li>When the device lies flat on a table and is pushed toward the sky
-     *    with an acceleration of A m/s^2, the acceleration value is equal to 
-     *    A+9.81 which correspond to the acceleration of the 
-     *    device (+A m/s^2) minus the force of gravity (-9.81 m/s^2).</li>
-     * 
-     * 
-     * <p>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD Sensor.TYPE_MAGNETIC_FIELD}:<p>
-     *  All values are in micro-Tesla (uT) and measure the ambient magnetic
-     *  field in the X, Y and Z axis.
+     * <p>
+     * <b>Important note:</b> For historical reasons the roll angle is positive
+     * in the clockwise direction (mathematically speaking, it should be
+     * positive in the counter-clockwise direction).
      *
-     * <p>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:<p>
+     * <p>
+     * <b>Note:</b> This definition is different from <b>yaw, pitch and roll</b>
+     * used in aviation where the X axis is along the long side of the plane
+     * (tail to nose).
      *
-     *  <p>values[0]: Ambient light level in SI lux units
+     * <p>
+     * <b>Note:</b> This sensor type exists for legacy reasons, please use
+     * {@link android.hardware.SensorManager#getRotationMatrix
+     * getRotationMatrix()} in conjunction with
+     * {@link android.hardware.SensorManager#remapCoordinateSystem
+     * remapCoordinateSystem()} and
+     * {@link android.hardware.SensorManager#getOrientation getOrientation()} to
+     * compute these values instead.
      *
-     * <p>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:<p>
+     * <h3>{@link android.hardware.Sensor#TYPE_ACCELEROMETER
+     * Sensor.TYPE_ACCELEROMETER}:</h3>
+     * All values are in SI units (m/s^2) and measure the acceleration applied
+     * to the phone minus the force of gravity.
      *
-     *  <p>values[0]: Proximity sensor distance measured in centimeters
+     * <ul>
+     * <p>
+     * values[0]: Acceleration minus Gx on the x-axis
+     * <p>
+     * values[1]: Acceleration minus Gy on the y-axis
+     * <p>
+     * values[2]: Acceleration minus Gz on the z-axis
+     * </ul>
      *
-     *  <p> Note that some proximity sensors only support a binary "close" or "far" measurement.
-     *   In this case, the sensor should report its maxRange value in the "far" state and a value
-     *   less than maxRange in the "near" state.
+     * <p>
+     * <u>Examples</u>:
+     * <ul>
+     * <li>When the device lies flat on a table and is pushed on its left side
+     * toward the right, the x acceleration value is positive.</li>
+     *
+     * <li>When the device lies flat on a table, the acceleration value is
+     * +9.81, which correspond to the acceleration of the device (0 m/s^2) minus
+     * the force of gravity (-9.81 m/s^2).</li>
+     *
+     * <li>When the device lies flat on a table and is pushed toward the sky
+     * with an acceleration of A m/s^2, the acceleration value is equal to
+     * A+9.81 which correspond to the acceleration of the device (+A m/s^2)
+     * minus the force of gravity (-9.81 m/s^2).</li>
+     * </ul>
+     *
+     *
+     * <h3>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD
+     * Sensor.TYPE_MAGNETIC_FIELD}:</h3>
+     * All values are in micro-Tesla (uT) and measure the ambient magnetic field
+     * in the X, Y and Z axis.
+     *
+     * <h3>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h3>
+     *
+     * <ul>
+     * <p>
+     * values[0]: Ambient light level in SI lux units
+     * </ul>
+     *
+     * <h3>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
+     * </h3>
+     *
+     * <ul>
+     * <p>
+     * values[0]: Proximity sensor distance measured in centimeters
+     * </ul>
+     *
+     * <p>
+     * Note that some proximity sensors only support a binary "close" or "far"
+     * measurement. In this case, the sensor should report its maxRange value in
+     * the "far" state and a value less than maxRange in the "near" state.
      */
     public final float[] values;
 
     /**
-     * The sensor that generated this event.
-     * See {@link android.hardware.SensorManager SensorManager}
-     * for details.
+     * The sensor that generated this event. See
+     * {@link android.hardware.SensorManager SensorManager} for details.
      */
-    public Sensor sensor;
-    
+   public Sensor sensor;
+
     /**
-     * The accuracy of this event.
-     * See {@link android.hardware.SensorManager SensorManager}
-     * for details.
+     * The accuracy of this event. See {@link android.hardware.SensorManager
+     * SensorManager} for details.
      */
     public int accuracy;
-    
-    
+
+
     /**
      * The time in nanosecond at which the event happened
      */
     public long timestamp;
 
-    
+
     SensorEvent(int size) {
         values = new float[size];
     }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 98172e6..f60e2d7 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -41,9 +41,11 @@
 import java.util.List;
 
 /**
- * Class that lets you access the device's sensors. Get an instance of this
- * class by calling {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with an argument of {@link android.content.Context#SENSOR_SERVICE}.
+ * SensorManager lets you access the device's {@link android.hardware.Sensor
+ * sensors}. Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String)
+ * Context.getSystemService()} with the argument
+ * {@link android.content.Context#SENSOR_SERVICE}.
  */
 public class SensorManager
 {
@@ -53,172 +55,220 @@
     /* NOTE: sensor IDs must be a power of 2 */
 
     /**
-     * A constant describing an orientation sensor.
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing an orientation sensor. See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_ORIENTATION = 1 << 0;
 
     /**
-     * A constant describing an accelerometer.
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing an accelerometer. See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_ACCELEROMETER = 1 << 1;
 
     /**
-     * A constant describing a temperature sensor
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing a temperature sensor See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_TEMPERATURE = 1 << 2;
 
     /**
-     * A constant describing a magnetic sensor
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing a magnetic sensor See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_MAGNETIC_FIELD = 1 << 3;
 
     /**
-     * A constant describing an ambient light sensor
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing an ambient light sensor See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_LIGHT = 1 << 4;
 
     /**
-     * A constant describing a proximity sensor
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing a proximity sensor See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_PROXIMITY = 1 << 5;
 
     /**
-     * A constant describing a Tricorder
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing a Tricorder See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_TRICORDER = 1 << 6;
 
     /**
-     * A constant describing an orientation sensor.
-     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * A constant describing an orientation sensor. See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
 
-    /** A constant that includes all sensors
+    /**
+     * A constant that includes all sensors
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_ALL = 0x7F;
 
-    /** Smallest sensor ID 
+    /**
+     * Smallest sensor ID
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_MIN = SENSOR_ORIENTATION;
 
-    /** Largest sensor ID
+    /**
+     * Largest sensor ID
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
 
 
-    /** Index of the X value in the array returned by
+    /**
+     * Index of the X value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int DATA_X = 0;
-    /** Index of the Y value in the array returned by
+
+    /**
+     * Index of the Y value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int DATA_Y = 1;
-    /** Index of the Z value in the array returned by
+
+    /**
+     * Index of the Z value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int DATA_Z = 2;
 
-    /** Offset to the untransformed values in the array returned by
+    /**
+     * Offset to the untransformed values in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int RAW_DATA_INDEX = 3;
 
-    /** Index of the untransformed X value in the array returned by
+    /**
+     * Index of the untransformed X value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int RAW_DATA_X = 3;
-    /** Index of the untransformed Y value in the array returned by
+
+    /**
+     * Index of the untransformed Y value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int RAW_DATA_Y = 4;
-    /** Index of the untransformed Z value in the array returned by
+
+    /**
+     * Index of the untransformed Z value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
+     * 
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
     public static final int RAW_DATA_Z = 5;
 
-
     /** Standard gravity (g) on Earth. This value is equivalent to 1G */
     public static final float STANDARD_GRAVITY = 9.80665f;
 
-    /** values returned by the accelerometer in various locations in the universe.
-     * all values are in SI units (m/s^2) */
+    /** Sun's gravity in SI units (m/s^2) */
     public static final float GRAVITY_SUN             = 275.0f;
+    /** Mercury's gravity in SI units (m/s^2) */
     public static final float GRAVITY_MERCURY         = 3.70f;
+    /** Venus' gravity in SI units (m/s^2) */
     public static final float GRAVITY_VENUS           = 8.87f;
+    /** Earth's gravity in SI units (m/s^2) */
     public static final float GRAVITY_EARTH           = 9.80665f;
+    /** The Moon's gravity in SI units (m/s^2) */
     public static final float GRAVITY_MOON            = 1.6f;
+    /** Mars' gravity in SI units (m/s^2) */
     public static final float GRAVITY_MARS            = 3.71f;
+    /** Jupiter's gravity in SI units (m/s^2) */
     public static final float GRAVITY_JUPITER         = 23.12f;
+    /** Saturn's gravity in SI units (m/s^2) */
     public static final float GRAVITY_SATURN          = 8.96f;
+    /** Uranus' gravity in SI units (m/s^2) */
     public static final float GRAVITY_URANUS          = 8.69f;
+    /** Neptune's gravity in SI units (m/s^2) */
     public static final float GRAVITY_NEPTUNE         = 11.0f;
+    /** Pluto's gravity in SI units (m/s^2) */
     public static final float GRAVITY_PLUTO           = 0.6f;
+    /** Gravity (estimate) on the first Death Star in Empire units (m/s^2) */
     public static final float GRAVITY_DEATH_STAR_I    = 0.000000353036145f;
+    /** Gravity on the island */
     public static final float GRAVITY_THE_ISLAND      = 4.815162342f;
 
 
     /** Maximum magnetic field on Earth's surface */
     public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f;
-
     /** Minimum magnetic field on Earth's surface */
     public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
 
-
-    /** Various luminance values during the day (lux) */
+    
+    /** Maximum luminance of sunlight in lux */
     public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
+    /** luminance of sunlight in lux */
     public static final float LIGHT_SUNLIGHT     = 110000.0f;
+    /** luminance in shade in lux */
     public static final float LIGHT_SHADE        = 20000.0f;
+    /** luminance under an overcast sky in lux */
     public static final float LIGHT_OVERCAST     = 10000.0f;
+    /** luminance at sunrise in lux */
     public static final float LIGHT_SUNRISE      = 400.0f;
+    /** luminance under a cloudy sky in lux */
     public static final float LIGHT_CLOUDY       = 100.0f;
-    /** Various luminance values during the night (lux) */
+    /** luminance at night with full moon in lux */
     public static final float LIGHT_FULLMOON     = 0.25f;
+    /** luminance at night with no moon in lux*/
     public static final float LIGHT_NO_MOON      = 0.001f;
 
+    
     /** get sensor data as fast as possible */
     public static final int SENSOR_DELAY_FASTEST = 0;
     /** rate suitable for games */
@@ -229,16 +279,22 @@
     public static final int SENSOR_DELAY_NORMAL = 3;
 
 
-    /** The values returned by this sensor cannot be trusted, calibration
-     * is needed or the environment doesn't allow readings */
+    /**
+     * The values returned by this sensor cannot be trusted, calibration is
+     * needed or the environment doesn't allow readings
+     */
     public static final int SENSOR_STATUS_UNRELIABLE = 0;
 
-    /** This sensor is reporting data with low accuracy, calibration with the
-     * environment is needed */
+    /**
+     * This sensor is reporting data with low accuracy, calibration with the
+     * environment is needed
+     */
     public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
 
-    /** This sensor is reporting data with an average level of accuracy,
-     * calibration with the environment may improve the readings */
+    /**
+     * This sensor is reporting data with an average level of accuracy,
+     * calibration with the environment may improve the readings
+     */
     public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
 
     /** This sensor is reporting data with maximum accuracy */
@@ -586,9 +642,10 @@
         return 0;
     }
 
-    /** @return available sensors.
+    /**
+     * @return available sensors.
      * @deprecated This method is deprecated, use
-     * {@link SensorManager#getSensorList(int)} instead
+     *             {@link SensorManager#getSensorList(int)} instead
      */
     @Deprecated
     public int getSensors() {
@@ -612,12 +669,14 @@
     }
 
     /**
-     * Use this method to get the list of available sensors of a certain
-     * type. Make multiple calls to get sensors of different types or use
-     * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all
-     * the sensors.
-     *
-     * @param type of sensors requested
+     * Use this method to get the list of available sensors of a certain type.
+     * Make multiple calls to get sensors of different types or use
+     * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all the
+     * sensors.
+     * 
+     * @param type
+     *        of sensors requested
+     * 
      * @return a list of sensors matching the asked type.
      */
     public List<Sensor> getSensorList(int type) {
@@ -644,13 +703,14 @@
     }
 
     /**
-     * Use this method to get the default sensor for a given type. Note that
-     * the returned sensor could be a composite sensor, and its data could be
+     * Use this method to get the default sensor for a given type. Note that the
+     * returned sensor could be a composite sensor, and its data could be
      * averaged or filtered. If you need to access the raw sensors use
      * {@link SensorManager#getSensorList(int) getSensorList}.
-     *
-     *
-     * @param type of sensors requested
+     * 
+     * @param type
+     *        of sensors requested
+     * 
      * @return the default sensors matching the asked type.
      */
     public Sensor getDefaultSensor(int type) {
@@ -659,17 +719,21 @@
         return l.isEmpty() ? null : l.get(0);
     }
 
-
     /**
      * Registers a listener for given sensors.
+     * 
      * @deprecated This method is deprecated, use
-     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
-     * instead.
-     *
-     * @param listener sensor listener object
-     * @param sensors a bit masks of the sensors to register to
-     *
-     * @return true if the sensor is supported and successfully enabled
+     *             {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
+     *             instead.
+     * 
+     * @param listener
+     *        sensor listener object
+     * 
+     * @param sensors
+     *        a bit masks of the sensors to register to
+     * 
+     * @return <code>true</code> if the sensor is supported and successfully
+     *         enabled
      */
     @Deprecated
     public boolean registerListener(SensorListener listener, int sensors) {
@@ -678,18 +742,26 @@
 
     /**
      * Registers a SensorListener for given sensors.
+     * 
      * @deprecated This method is deprecated, use
-     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
-     * instead.
-     *
-     * @param listener sensor listener object
-     * @param sensors a bit masks of the sensors to register to
-     * @param rate rate of events. This is only a hint to the system. events
-     * may be received faster or slower than the specified rate. Usually events
-     * are received faster. The value must be one of {@link #SENSOR_DELAY_NORMAL},
-     * {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
-     *
-     * @return true if the sensor is supported and successfully enabled
+     *             {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
+     *             instead.
+     * 
+     * @param listener
+     *        sensor listener object
+     * 
+     * @param sensors
+     *        a bit masks of the sensors to register to
+     * 
+     * @param rate
+     *        rate of events. This is only a hint to the system. events may be
+     *        received faster or slower than the specified rate. Usually events
+     *        are received faster. The value must be one of
+     *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
+     * 
+     * @return <code>true</code> if the sensor is supported and successfully
+     *         enabled
      */
     @Deprecated
     public boolean registerListener(SensorListener listener, int sensors, int rate) {
@@ -747,12 +819,16 @@
 
     /**
      * Unregisters a listener for the sensors with which it is registered.
+     * 
      * @deprecated This method is deprecated, use
-     * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
-     * instead.
-     *
-     * @param listener a SensorListener object
-     * @param sensors a bit masks of the sensors to unregister from
+     *             {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
+     *             instead.
+     * 
+     * @param listener
+     *        a SensorListener object
+     * 
+     * @param sensors
+     *        a bit masks of the sensors to unregister from
      */
     @Deprecated
     public void unregisterListener(SensorListener listener, int sensors) {
@@ -815,11 +891,13 @@
 
     /**
      * Unregisters a listener for all sensors.
+     * 
      * @deprecated This method is deprecated, use
-     * {@link SensorManager#unregisterListener(SensorEventListener)}
-     * instead.
-     *
-     * @param listener a SensorListener object
+     *             {@link SensorManager#unregisterListener(SensorEventListener)}
+     *             instead.
+     * 
+     * @param listener
+     *        a SensorListener object
      */
     @Deprecated
     public void unregisterListener(SensorListener listener) {
@@ -828,10 +906,12 @@
 
     /**
      * Unregisters a listener for the sensors with which it is registered.
-     *
-     * @param listener a SensorEventListener object
-     * @param sensor the sensor to unregister from
-     *
+     * 
+     * @param listener
+     *        a SensorEventListener object
+     * @param sensor
+     *        the sensor to unregister from
+     * 
      */
     public void unregisterListener(SensorEventListener listener, Sensor sensor) {
         unregisterListener((Object)listener, sensor);
@@ -839,50 +919,68 @@
 
     /**
      * Unregisters a listener for all sensors.
-     *
-     * @param listener a SensorListener object
-     *
+     * 
+     * @param listener
+     *        a SensorListener object
+     * 
      */
     public void unregisterListener(SensorEventListener listener) {
         unregisterListener((Object)listener);
     }
 
-
     /**
-     * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
-     * for the given sensor.
-     *
-     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
-     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
-     * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
-     * This is only a hint to the system. Events may be received faster or
-     * slower than the specified rate. Usually events are received faster. The value must be
-     * one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME},
-     * or {@link #SENSOR_DELAY_FASTEST}.
-     *
-     * @return true if the sensor is supported and successfully enabled.
-     *
+     * Registers a {@link android.hardware.SensorEventListener
+     * SensorEventListener} for the given sensor.
+     * 
+     * @param listener
+     *        A {@link android.hardware.SensorEventListener SensorEventListener}
+     *        object.
+     * 
+     * @param sensor
+     *        The {@link android.hardware.Sensor Sensor} to register to.
+     * 
+     * @param rate
+     *        The rate {@link android.hardware.SensorEvent sensor events} are
+     *        delivered at. This is only a hint to the system. Events may be
+     *        received faster or slower than the specified rate. Usually events
+     *        are received faster. The value must be one of
+     *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
+     * 
+     * @return <code>true</code> if the sensor is supported and successfully
+     *         enabled.
+     * 
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
         return registerListener(listener, sensor, rate, null);
     }
 
     /**
-     * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
-     * for the given sensor.
-     *
-     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
-     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
-     * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
-     * This is only a hint to the system. Events may be received faster or
-     * slower than the specified rate. Usually events are received faster. The value must be one
-     * of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or
-     * {@link #SENSOR_DELAY_FASTEST}.
-     * @param handler The {@link android.os.Handler Handler} the
-     * {@link android.hardware.SensorEvent sensor events} will be delivered to.
-     *
+     * Registers a {@link android.hardware.SensorEventListener
+     * SensorEventListener} for the given sensor.
+     * 
+     * @param listener
+     *        A {@link android.hardware.SensorEventListener SensorEventListener}
+     *        object.
+     * 
+     * @param sensor
+     *        The {@link android.hardware.Sensor Sensor} to register to.
+     * 
+     * @param rate
+     *        The rate {@link android.hardware.SensorEvent sensor events} are
+     *        delivered at. This is only a hint to the system. Events may be
+     *        received faster or slower than the specified rate. Usually events
+     *        are received faster. The value must be one of
+     *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
+     * 
+     * @param handler
+     *        The {@link android.os.Handler Handler} the
+     *        {@link android.hardware.SensorEvent sensor events} will be
+     *        delivered to.
+     * 
      * @return true if the sensor is supported and successfully enabled.
-     *
+     * 
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
             Handler handler) {
@@ -1003,95 +1101,126 @@
     }
 
     /**
-     * Computes the inclination matrix <b>I</b> as well as the rotation
-     * matrix <b>R</b> transforming a vector from the
-     * device coordinate system to the world's coordinate system which is
-     * defined as a direct orthonormal basis, where:
+     * <p>
+     * Computes the inclination matrix <b>I</b> as well as the rotation matrix
+     * <b>R</b> transforming a vector from the device coordinate system to the
+     * world's coordinate system which is defined as a direct orthonormal basis,
+     * where:
+     * </p>
      * 
+     * <ul>
      * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
      * the ground at the device's current location and roughly points East).</li>
      * <li>Y is tangential to the ground at the device's current location and
      * points towards the magnetic North Pole.</li>
      * <li>Z points towards the sky and is perpendicular to the ground.</li>
+     * </ul>
      * <p>
      * <hr>
-     * <p>By definition:
-     * <p>[0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity)
-     * <p>[0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b>
-     * (m = magnitude of geomagnetic field)
-     * <p><b>R</b> is the identity matrix when the device is aligned with the
+     * <p>
+     * By definition:
+     * <p>
+     * [0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity)
+     * <p>
+     * [0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b> (m = magnitude of
+     * geomagnetic field)
+     * <p>
+     * <b>R</b> is the identity matrix when the device is aligned with the
      * world's coordinate system, that is, when the device's X axis points
      * toward East, the Y axis points to the North Pole and the device is facing
      * the sky.
-     *
-     * <p><b>I</b> is a rotation matrix transforming the geomagnetic
-     * vector into the same coordinate space as gravity (the world's coordinate
-     * space). <b>I</b> is a simple rotation around the X axis.
-     * The inclination angle in radians can be computed with
-     * {@link #getInclination}.
+     * 
+     * <p>
+     * <b>I</b> is a rotation matrix transforming the geomagnetic vector into
+     * the same coordinate space as gravity (the world's coordinate space).
+     * <b>I</b> is a simple rotation around the X axis. The inclination angle in
+     * radians can be computed with {@link #getInclination}.
      * <hr>
      * 
-     * <p> Each matrix is returned either as a 3x3 or 4x4 row-major matrix
-     * depending on the length of the passed array:
-     * <p><u>If the array length is 16:</u>
+     * <p>
+     * Each matrix is returned either as a 3x3 or 4x4 row-major matrix depending
+     * on the length of the passed array:
+     * <p>
+     * <u>If the array length is 16:</u>
+     * 
      * <pre>
      *   /  M[ 0]   M[ 1]   M[ 2]   M[ 3]  \
      *   |  M[ 4]   M[ 5]   M[ 6]   M[ 7]  |
      *   |  M[ 8]   M[ 9]   M[10]   M[11]  |
      *   \  M[12]   M[13]   M[14]   M[15]  /
      *</pre>
-     * This matrix is ready to be used by OpenGL ES's 
-     * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int) 
-     * glLoadMatrixf(float[], int)}. 
-     * <p>Note that because OpenGL matrices are column-major matrices you must
-     * transpose the matrix before using it. However, since the matrix is a 
+     * 
+     * This matrix is ready to be used by OpenGL ES's
+     * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int)
+     * glLoadMatrixf(float[], int)}.
+     * <p>
+     * Note that because OpenGL matrices are column-major matrices you must
+     * transpose the matrix before using it. However, since the matrix is a
      * rotation matrix, its transpose is also its inverse, conveniently, it is
      * often the inverse of the rotation that is needed for rendering; it can
      * therefore be used with OpenGL ES directly.
      * <p>
      * Also note that the returned matrices always have this form:
+     * 
      * <pre>
      *   /  M[ 0]   M[ 1]   M[ 2]   0  \
      *   |  M[ 4]   M[ 5]   M[ 6]   0  |
      *   |  M[ 8]   M[ 9]   M[10]   0  |
      *   \      0       0       0   1  /
      *</pre>
-     * <p><u>If the array length is 9:</u>
+     * 
+     * <p>
+     * <u>If the array length is 9:</u>
+     * 
      * <pre>
      *   /  M[ 0]   M[ 1]   M[ 2]  \
      *   |  M[ 3]   M[ 4]   M[ 5]  |
      *   \  M[ 6]   M[ 7]   M[ 8]  /
      *</pre>
-     *
+     * 
      * <hr>
-     * <p>The inverse of each matrix can be computed easily by taking its
+     * <p>
+     * The inverse of each matrix can be computed easily by taking its
      * transpose.
-     *
-     * <p>The matrices returned by this function are meaningful only when the
-     * device is not free-falling and it is not close to the magnetic north.
-     * If the device is accelerating, or placed into a strong magnetic field,
-     * the returned matrices may be inaccurate.
-     *
-     * @param R is an array of 9 floats holding the rotation matrix <b>R</b>
-     * when this function returns. R can be null.<p>
-     * @param I is an array of 9 floats holding the rotation matrix <b>I</b>
-     * when this function returns. I can be null.<p>
-     * @param gravity is an array of 3 floats containing the gravity vector
-     * expressed in the device's coordinate. You can simply use the
-     * {@link android.hardware.SensorEvent#values values}
-     * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
-     * {@link android.hardware.Sensor Sensor} of type
-     * {@link android.hardware.Sensor#TYPE_ACCELEROMETER TYPE_ACCELEROMETER}.<p>
-     * @param geomagnetic is an array of 3 floats containing the geomagnetic
-     * vector expressed in the device's coordinate. You can simply use the
-     * {@link android.hardware.SensorEvent#values values}
-     * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
-     * {@link android.hardware.Sensor Sensor} of type
-     * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD}.
-     * @return
-     *   true on success<p>
-     *   false on failure (for instance, if the device is in free fall).
-     *   On failure the output matrices are not modified.
+     * 
+     * <p>
+     * The matrices returned by this function are meaningful only when the
+     * device is not free-falling and it is not close to the magnetic north. If
+     * the device is accelerating, or placed into a strong magnetic field, the
+     * returned matrices may be inaccurate.
+     * 
+     * @param R
+     *        is an array of 9 floats holding the rotation matrix <b>R</b> when
+     *        this function returns. R can be null.
+     *        <p>
+     * 
+     * @param I
+     *        is an array of 9 floats holding the rotation matrix <b>I</b> when
+     *        this function returns. I can be null.
+     *        <p>
+     * 
+     * @param gravity
+     *        is an array of 3 floats containing the gravity vector expressed in
+     *        the device's coordinate. You can simply use the
+     *        {@link android.hardware.SensorEvent#values values} returned by a
+     *        {@link android.hardware.SensorEvent SensorEvent} of a
+     *        {@link android.hardware.Sensor Sensor} of type
+     *        {@link android.hardware.Sensor#TYPE_ACCELEROMETER
+     *        TYPE_ACCELEROMETER}.
+     *        <p>
+     * 
+     * @param geomagnetic
+     *        is an array of 3 floats containing the geomagnetic vector
+     *        expressed in the device's coordinate. You can simply use the
+     *        {@link android.hardware.SensorEvent#values values} returned by a
+     *        {@link android.hardware.SensorEvent SensorEvent} of a
+     *        {@link android.hardware.Sensor Sensor} of type
+     *        {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD
+     *        TYPE_MAGNETIC_FIELD}.
+     * 
+     * @return <code>true</code> on success, <code>false</code> on failure (for
+     *         instance, if the device is in free fall). On failure the output
+     *         matrices are not modified.
      */
 
     public static boolean getRotationMatrix(float[] R, float[] I,
@@ -1160,7 +1289,9 @@
     /**
      * Computes the geomagnetic inclination angle in radians from the
      * inclination matrix <b>I</b> returned by {@link #getRotationMatrix}.
-     * @param I inclination matrix see {@link #getRotationMatrix}.
+     * 
+     * @param I
+     *        inclination matrix see {@link #getRotationMatrix}.
      * @return The geomagnetic inclination angle in radians.
      */
     public static float getInclination(float[] I) {
@@ -1172,52 +1303,76 @@
     }
 
     /**
-     * Rotates the supplied rotation matrix so it is expressed in a
-     * different coordinate system. This is typically used when an application
-     * needs to compute the three orientation angles of the device (see
+     * <p>
+     * Rotates the supplied rotation matrix so it is expressed in a different
+     * coordinate system. This is typically used when an application needs to
+     * compute the three orientation angles of the device (see
      * {@link #getOrientation}) in a different coordinate system.
+     * </p>
      * 
-     * <p>When the rotation matrix is used for drawing (for instance with 
-     * OpenGL ES), it usually <b>doesn't need</b> to be transformed by this 
-     * function, unless the screen is physically rotated, in which case you
-     * can use {@link android.view.Display#getRotation() Display.getRotation()}
-     * to retrieve the current rotation of the screen.  Note that because the
-     * user is generally free to rotate their screen, you often should
-     * consider the rotation in deciding the parameters to use here.
-     *
-     * <p><u>Examples:</u><p>
-     *
-     * <li>Using the camera (Y axis along the camera's axis) for an augmented 
-     * reality application where the rotation angles are needed: </li><p>
-     *
-     * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code><p>
-     *
+     * <p>
+     * When the rotation matrix is used for drawing (for instance with OpenGL
+     * ES), it usually <b>doesn't need</b> to be transformed by this function,
+     * unless the screen is physically rotated, in which case you can use
+     * {@link android.view.Display#getRotation() Display.getRotation()} to
+     * retrieve the current rotation of the screen. Note that because the user
+     * is generally free to rotate their screen, you often should consider the
+     * rotation in deciding the parameters to use here.
+     * </p>
+     * 
+     * <p>
+     * <u>Examples:</u>
+     * <p>
+     * 
+     * <ul>
+     * <li>Using the camera (Y axis along the camera's axis) for an augmented
+     * reality application where the rotation angles are needed:</li>
+     * 
+     * <p>
+     * <ul>
+     * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code>
+     * </ul>
+     * </p>
+     * 
      * <li>Using the device as a mechanical compass when rotation is
-     * {@link android.view.Surface#ROTATION_90 Surface.ROTATION_90}:</li><p>
-     *
-     * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code><p>
-     *
-     * Beware of the above example. This call is needed only to account for
-     * a rotation from its natural orientation when calculating the
-     * rotation angles (see {@link #getOrientation}).
-     * If the rotation matrix is also used for rendering, it may not need to 
-     * be transformed, for instance if your {@link android.app.Activity
-     * Activity} is running in landscape mode.
-     *
-     * <p>Since the resulting coordinate system is orthonormal, only two axes
-     * need to be specified.
-     *
-     * @param inR the rotation matrix to be transformed. Usually it is the
-     * matrix returned by {@link #getRotationMatrix}.
-     * @param X defines on which world axis and direction the X axis of the
-     *        device is mapped.
-     * @param Y defines on which world axis and direction the Y axis of the
-     *        device is mapped.
-     * @param outR the transformed rotation matrix. inR and outR can be the same
+     * {@link android.view.Surface#ROTATION_90 Surface.ROTATION_90}:</li>
+     * 
+     * <p>
+     * <ul>
+     * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code>
+     * </ul>
+     * </p>
+     * 
+     * Beware of the above example. This call is needed only to account for a
+     * rotation from its natural orientation when calculating the rotation
+     * angles (see {@link #getOrientation}). If the rotation matrix is also used
+     * for rendering, it may not need to be transformed, for instance if your
+     * {@link android.app.Activity Activity} is running in landscape mode.
+     * </ul>
+     * 
+     * <p>
+     * Since the resulting coordinate system is orthonormal, only two axes need
+     * to be specified.
+     * 
+     * @param inR
+     *        the rotation matrix to be transformed. Usually it is the matrix
+     *        returned by {@link #getRotationMatrix}.
+     * 
+     * @param X
+     *        defines on which world axis and direction the X axis of the device
+     *        is mapped.
+     * 
+     * @param Y
+     *        defines on which world axis and direction the Y axis of the device
+     *        is mapped.
+     * 
+     * @param outR
+     *        the transformed rotation matrix. inR and outR can be the same
      *        array, but it is not recommended for performance reason.
-     * @return true on success. false if the input parameters are incorrect, for
-     * instance if X and Y define the same axis. Or if inR and outR don't have 
-     * the same length.
+     * 
+     * @return <code>true</code> on success. <code>false</code> if the input
+     *         parameters are incorrect, for instance if X and Y define the same
+     *         axis. Or if inR and outR don't have the same length.
      */
 
     public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
@@ -1301,19 +1456,24 @@
 
     /**
      * Computes the device's orientation based on the rotation matrix.
-     * <p> When it returns, the array values is filled with the result:
+     * <p>
+     * When it returns, the array values is filled with the result:
+     * <ul>
      * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li>
      * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li>
      * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li>
+     * </ul>
      * <p>
      * All three angles above are in <b>radians</b> and <b>positive</b> in the
      * <b>counter-clockwise</b> direction.
-     *
-     * @param R rotation matrix see {@link #getRotationMatrix}.
-     * @param values an array of 3 floats to hold the result.
+     * 
+     * @param R
+     *        rotation matrix see {@link #getRotationMatrix}.
+     * @param values
+     *        an array of 3 floats to hold the result.
      * @return The array values passed as argument.
      */
-    public static float[] getOrientation(float[] R, float values[]) {
+   public static float[] getOrientation(float[] R, float values[]) {
         /*
          * 4x4 (length=16) case:
          *   /  R[ 0]   R[ 1]   R[ 2]   0  \
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index df30c76..adb11c8 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -341,11 +341,4 @@
         }
     }
     */
-
-    void poke()
-    {
-        synchronized (this) {
-            nativeWake();
-        }
-    }
 }
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index 66a83b8..e5ebc69 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -26,7 +26,7 @@
  * to the ViewRoot through a Binder transaction as part of registering the Window.
  * @hide
  */
-public class InputChannel implements Parcelable {
+public final class InputChannel implements Parcelable {
     private static final String TAG = "InputChannel";
     
     public static final Parcelable.Creator<InputChannel> CREATOR
diff --git a/core/java/android/view/InputTarget.java b/core/java/android/view/InputTarget.java
index e56e03c..6ff7305 100644
--- a/core/java/android/view/InputTarget.java
+++ b/core/java/android/view/InputTarget.java
@@ -25,7 +25,7 @@
  * These parameters are used by the native input dispatching code.
  * @hide
  */
-public class InputTarget {
+public final class InputTarget {
     public InputChannel mInputChannel;
     public int mFlags;
     public long mTimeoutNanos;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2534de7..e3ed91e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -580,19 +580,20 @@
          * If the keyguard is currently active and is secure (requires an
          * unlock pattern) than the user will still need to confirm it before
          * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
-         * also been set. */
+         * also been set.
+         */
         public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
 
         /** Window flag: This window corresponds to an immersive activity
          * that wishes not to be interrupted with notifications.  In general,
-         * applications may simply hide the status bar with {@link
-         * FLAG_FULLSCREEN} to suppress most notifications, but will still be
-         * interrupted by those with
-         * {@link android.app.Notification.fullScreenIntent} set (example: an
-         * incoming call).  Setting {@link FLAG_IMMERSIVE} will suppress the
-         * full-screen intent and show the status bar briefly for those
-         * important notifications instead.  See also
-         * {@link android.app.Notification.FLAG_HIGH_PRIORITY}.
+         * applications may simply hide the status bar with
+         * {@link #FLAG_FULLSCREEN} to suppress most notifications, but will
+         * still be interrupted by those with
+         * {@link android.app.Notification#fullScreenIntent fullScreenIntent}
+         * set (example: an incoming call). Setting {@link #FLAG_IMMERSIVE}
+         * will suppress the full-screen intent and show the status bar
+         * briefly for those important notifications instead.
+         * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
          */
         public static final int FLAG_IMMERSIVE = 0x00800000;
 
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 218054d..11095c0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -132,7 +132,7 @@
     <string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
     <string name="screen_lock" msgid="799094655496098153">"Display-Sperre"</string>
     <string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
-    <string name="shutdown_progress" msgid="2281079257329981203">"Fährt herunter..."</string>
+    <string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
     <string name="shutdown_confirm" msgid="649792175242821353">"Ihr Telefon wird heruntergefahren."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Zuletzt verwendet"</string>
     <string name="no_recent_tasks" msgid="279702952298056674">"Keine zuletzt verwendeten Anwendungen"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 33cb9fb..d0b3b8a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -734,7 +734,7 @@
     <string name="chooseActivity" msgid="1009246475582238425">"Seleziona un\'azione"</string>
     <string name="noApplications" msgid="1691104391758345586">"Nessuna applicazione è in grado di svolgere questa azione."</string>
     <string name="aerr_title" msgid="653922989522758100">"Spiacenti."</string>
-    <string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo<xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
+    <string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
     <string name="aerr_process" msgid="1551785535966089511">"Interruzione imprevista del processo <xliff:g id="PROCESS">%1$s</xliff:g>. Riprova."</string>
     <string name="anr_title" msgid="3100070910664756057">"Spiacenti."</string>
     <string name="anr_activity_application" msgid="3538242413112507636">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nell\'applicazione <xliff:g id="APPLICATION">%2$s</xliff:g>) non risponde."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index afe7b67..8aaf761 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -148,7 +148,7 @@
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
-    <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"응용프로그램이 요금이 부과될 수 있는 작업을 할 수 있도록 합니다."</string>
+    <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"애플리케이션이 요금이 부과될 수 있는 작업을 할 수 있도록 합니다."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
     <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS, 이메일 및 기타 메시지를 읽고 씁니다."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"개인정보"</string>
@@ -156,7 +156,7 @@
     <string name="permgrouplab_location" msgid="635149742436692049">"위치"</string>
     <string name="permgroupdesc_location" msgid="2430258821648348660">"실제 위치 모니터링"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"네트워크 통신"</string>
-    <string name="permgroupdesc_network" msgid="5035763698958415998">"응용프로그램이 다양한 네트워크 기능에 액세스할 수 있도록 합니다."</string>
+    <string name="permgroupdesc_network" msgid="5035763698958415998">"애플리케이션이 다양한 네트워크 기능에 액세스할 수 있도록 합니다."</string>
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"계정"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"사용 가능한 계정에 액세스합니다."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"하드웨어 제어"</string>
@@ -166,261 +166,261 @@
     <string name="permgrouplab_systemTools" msgid="4652191644082714048">"시스템 도구"</string>
     <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"시스템을 하위 수준에서 액세스하고 제어합니다."</string>
     <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"개발 도구"</string>
-    <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"응용프로그램 개발자에게만 필요한 기능입니다."</string>
+    <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"애플리케이션 개발자에게만 필요한 기능입니다."</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"저장"</string>
     <string name="permgroupdesc_storage" msgid="9203302214915355774">"SD 카드에 액세스합니다."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"상태 표시줄 사용 중지 또는 수정"</string>
-    <string name="permdesc_statusBar" msgid="1365473595331989732">"응용프로그램이 상태 표시줄을 사용 중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 합니다."</string>
+    <string name="permdesc_statusBar" msgid="1365473595331989732">"애플리케이션이 상태 표시줄을 사용 중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 합니다."</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"상태 표시줄 확장/축소"</string>
-    <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"응용프로그램이 상태 표시줄을 확장하거나 축소할 수 있도록 합니다."</string>
+    <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"애플리케이션이 상태 표시줄을 확장하거나 축소할 수 있도록 합니다."</string>
     <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"발신전화 가로채기"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"응용프로그램이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"애플리케이션이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 합니다. 이 경우 악성 애플리케이션이 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
     <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS 수신"</string>
-    <string name="permdesc_receiveSms" msgid="6298292335965966117">"응용프로그램이 SMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+    <string name="permdesc_receiveSms" msgid="6298292335965966117">"애플리케이션이 SMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 애플리케이션이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
     <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS 수신"</string>
-    <string name="permdesc_receiveMms" msgid="4563346832000174373">"응용프로그램이 MMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+    <string name="permdesc_receiveMms" msgid="4563346832000174373">"애플리케이션이 MMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 애플리케이션이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
     <string name="permlab_sendSms" msgid="5600830612147671529">"SMS 메시지 보내기"</string>
-    <string name="permdesc_sendSms" msgid="1946540351763502120">"응용프로그램이 SMS 메시지를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 확인 없이 메시지를 전송하여 요금을 부과할 수 있습니다."</string>
+    <string name="permdesc_sendSms" msgid="1946540351763502120">"애플리케이션이 SMS 메시지를 보낼 수 있도록 합니다. 이 경우 악성 애플리케이션이 사용자의 확인 없이 메시지를 전송하여 요금을 부과할 수 있습니다."</string>
     <string name="permlab_readSms" msgid="4085333708122372256">"SMS 또는 MMS 읽기"</string>
-    <string name="permdesc_readSms" msgid="3002170087197294591">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 기밀 메시지를 읽을 수 있습니다."</string>
+    <string name="permdesc_readSms" msgid="3002170087197294591">"애플리케이션이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지를 읽을 수 있도록 합니다. 이 경우 악성 애플리케이션이 기밀 메시지를 읽을 수 있습니다."</string>
     <string name="permlab_writeSms" msgid="6881122575154940744">"SMS 또는 MMS 편집"</string>
-    <string name="permdesc_writeSms" msgid="6299398896177548095">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지에 쓸 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 메시지를 삭제할 수 있습니다."</string>
+    <string name="permdesc_writeSms" msgid="6299398896177548095">"애플리케이션이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지에 쓸 수 있도록 합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 메시지를 삭제할 수 있습니다."</string>
     <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP 수신"</string>
-    <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"응용프로그램이 WAP 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
-    <string name="permlab_getTasks" msgid="5005277531132573353">"실행 중인 응용프로그램 검색"</string>
-    <string name="permdesc_getTasks" msgid="7048711358713443341">"응용프로그램이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램에 대한 개인 정보를 검색할 수 있습니다."</string>
-    <string name="permlab_reorderTasks" msgid="5669588525059921549">"실행 중인 응용프로그램 순서 재지정"</string>
-    <string name="permdesc_reorderTasks" msgid="126252774270522835">"응용프로그램이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
-    <string name="permlab_setDebugApp" msgid="4339730312925176742">"응용프로그램 디버깅 사용"</string>
-    <string name="permdesc_setDebugApp" msgid="5584310661711990702">"응용프로그램이 다른 응용프로그램에 대해 디버깅을 사용할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+    <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"애플리케이션이 WAP 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 애플리케이션이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+    <string name="permlab_getTasks" msgid="5005277531132573353">"실행 중인 애플리케이션 검색"</string>
+    <string name="permdesc_getTasks" msgid="7048711358713443341">"애플리케이션이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션에 대한 개인 정보를 검색할 수 있습니다."</string>
+    <string name="permlab_reorderTasks" msgid="5669588525059921549">"실행 중인 애플리케이션 순서 재지정"</string>
+    <string name="permdesc_reorderTasks" msgid="126252774270522835">"애플리케이션이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 합니다. 이 경우 악성 애플리케이션이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
+    <string name="permlab_setDebugApp" msgid="4339730312925176742">"애플리케이션 디버깅 사용"</string>
+    <string name="permdesc_setDebugApp" msgid="5584310661711990702">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
-    <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"응용프로그램이 로케일 또는 전체 글꼴 크기와 같은 현재 구성을 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"애플리케이션이 로케일 또는 전체 글꼴 크기와 같은 현재 구성을 변경할 수 있도록 합니다."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"차량 모드 사용"</string>
-    <string name="permdesc_enableCarMode" msgid="5673461159384850628">"응용프로그램이 차량 모드를 사용할 수 있도록 합니다."</string>
+    <string name="permdesc_enableCarMode" msgid="5673461159384850628">"애플리케이션이 차량 모드를 사용할 수 있도록 합니다."</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"백그라운드 프로세스 종료"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"메모리가 부족하지 않은 경우에도 응용프로그램이 다른 응용프로그램의 백그라운드 프로세스를 중단할 수 있도록 합니다."</string>
-    <string name="permlab_forceStopPackages" msgid="1447830113260156236">"다른 응용프로그램 강제 종료"</string>
-    <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"응용프로그램이 다른 응용프로그램을 강제로 종료할 수 있도록 합니다."</string>
-    <string name="permlab_forceBack" msgid="1804196839880393631">"강제로 응용프로그램 닫기"</string>
-    <string name="permdesc_forceBack" msgid="6534109744159919013">"응용프로그램이 포그라운드에 있는 활동을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"메모리가 부족하지 않은 경우에도 애플리케이션이 다른 애플리케이션의 백그라운드 프로세스를 중단할 수 있도록 합니다."</string>
+    <string name="permlab_forceStopPackages" msgid="1447830113260156236">"다른 애플리케이션 강제 종료"</string>
+    <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"애플리케이션이 다른 애플리케이션을 강제로 종료할 수 있도록 합니다."</string>
+    <string name="permlab_forceBack" msgid="1804196839880393631">"강제로 애플리케이션 닫기"</string>
+    <string name="permdesc_forceBack" msgid="6534109744159919013">"애플리케이션이 포그라운드에 있는 활동을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_dump" msgid="1681799862438954752">"시스템 내부 상태 검색"</string>
-    <string name="permdesc_dump" msgid="2198776174276275220">"응용프로그램이 시스템의 내부 상태를 검색할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인정보와 보안정보를 검색할 수 있습니다."</string>
+    <string name="permdesc_dump" msgid="2198776174276275220">"애플리케이션이 시스템의 내부 상태를 검색할 수 있도록 합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인정보와 보안정보를 검색할 수 있습니다."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"부분 종료"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"작업 관리자를 종료 상태로 설정합니다. 전체 종료를 수행하지는 않습니다."</string>
-    <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"응용프로그램 전환 방지"</string>
-    <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"사용자가 다른 응용프로그램으로 전환하지 못하게 합니다."</string>
-    <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"실행 중인 모든 응용프로그램 모니터링 및 제어"</string>
-    <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"응용프로그램이 시스템에서 활동이 시작되는 방식을 모니터링하고 제어할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 휴대전화 사용 시에는 필요하지 않습니다."</string>
+    <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"애플리케이션 전환 방지"</string>
+    <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"사용자가 다른 애플리케이션으로 전환하지 못하게 합니다."</string>
+    <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"실행 중인 모든 애플리케이션 모니터링 및 제어"</string>
+    <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"애플리케이션이 시스템에서 활동이 시작되는 방식을 모니터링하고 제어할 수 있도록 합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 휴대전화 사용 시에는 필요하지 않습니다."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"패키지 제거 브로드캐스트 보내기"</string>
-    <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"응용프로그램이 응용프로그램 패키지가 삭제되었다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 실행 중인 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+    <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"애플리케이션이 애플리케이션 패키지가 삭제되었다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 애플리케이션이 실행 중인 다른 애플리케이션을 중지시킬 수 있습니다."</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS 수신 브로드캐스트 보내기"</string>
-    <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"응용프로그램이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 수신된 SMS 메시지처럼 위장할 수 있습니다."</string>
+    <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"애플리케이션이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 애플리케이션이 수신된 SMS 메시지처럼 위장할 수 있습니다."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
-    <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"응용프로그램이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
+    <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"애플리케이션이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 애플리케이션이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 중인 프로세스 수 제한"</string>
-    <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"응용프로그램이 실행할 최대 프로세스 수를 제어할 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
-    <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"모든 백그라운드 응용프로그램이 닫히도록 하기"</string>
-    <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"응용프로그램이 백그라운드로 이동한 활동을 항상 바로 종료할지 여부를 제어할 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"애플리케이션이 실행할 최대 프로세스 수를 제어할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
+    <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"모든 백그라운드 애플리케이션이 닫히도록 하기"</string>
+    <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"애플리케이션이 백그라운드로 이동한 활동을 항상 바로 종료할지 여부를 제어할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_batteryStats" msgid="7863923071360031652">"배터리 통계 수정"</string>
-    <string name="permdesc_batteryStats" msgid="5847319823772230560">"수집된 배터리 통계를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_batteryStats" msgid="5847319823772230560">"수집된 배터리 통계를 수정할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_backup" msgid="470013022865453920">"시스템 백업 및 복원 관리"</string>
-    <string name="permdesc_backup" msgid="4837493065154256525">"응용프로그램이 시스템의 백업 및 복원 매커니즘을 제어할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_backup" msgid="4837493065154256525">"애플리케이션이 시스템의 백업 및 복원 매커니즘을 제어할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"인증되지 않은 창 표시"</string>
-    <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"시스템 수준 경고 표시"</string>
-    <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"응용프로그램이 시스템 경고 창을 표시할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 화면 전체를 차지할 수 있습니다."</string>
+    <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"애플리케이션이 시스템 경고 창을 표시할 수 있도록 합니다. 이 경우 악성 애플리케이션이 휴대전화 화면 전체를 차지할 수 있습니다."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"전체 애니메이션 속도 수정"</string>
-    <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"응용프로그램이 언제든지 전체 애니메이션 속도를 빠르게 또는 느리게 변경할 수 있도록 합니다."</string>
-    <string name="permlab_manageAppTokens" msgid="17124341698093865">"응용프로그램 토큰 관리"</string>
-    <string name="permdesc_manageAppTokens" msgid="977127907524195988">"응용프로그램이 일반적인 Z-순서를 무시하여 자체 토큰을 만들고 관리할 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"애플리케이션이 언제든지 전체 애니메이션 속도를 빠르게 또는 느리게 변경할 수 있도록 합니다."</string>
+    <string name="permlab_manageAppTokens" msgid="17124341698093865">"애플리케이션 토큰 관리"</string>
+    <string name="permdesc_manageAppTokens" msgid="977127907524195988">"애플리케이션이 일반적인 Z-순서를 무시하여 자체 토큰을 만들고 관리할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"키 및 컨트롤 버튼 누르기"</string>
-    <string name="permdesc_injectEvents" msgid="3946098050410874715">"응용프로그램이 입력 이벤트(예: 키 누름)를 다른 응용프로그램에 전달할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화를 완전히 제어할 수 있습니다."</string>
+    <string name="permdesc_injectEvents" msgid="3946098050410874715">"애플리케이션이 입력 이벤트(예: 키 누름)를 다른 애플리케이션에 전달할 수 있도록 합니다. 이 경우 악성 애플리케이션이 휴대전화를 완전히 제어할 수 있습니다."</string>
     <string name="permlab_readInputState" msgid="469428900041249234">"사용자가 입력한 내용 및 수행한 작업 기록"</string>
-    <string name="permdesc_readInputState" msgid="5132879321450325445">"응용프로그램이 다른 응용프로그램과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_readInputState" msgid="5132879321450325445">"애플리케이션이 다른 애플리케이션과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"입력 방법 연결"</string>
-    <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"권한을 가진 프로그램이 입력 방법에 대한 최상위 인터페이스를 사용하도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"권한을 가진 프로그램이 입력 방법에 대한 최상위 인터페이스를 사용하도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
-    <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
-    <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"보유자가 기기 관리자에게 인텐트를 보낼 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"보유자가 기기 관리자에게 인텐트를 보낼 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
-    <string name="permdesc_setOrientation" msgid="6335814461615851863">"응용프로그램이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 응용프로그램에는 절대로 필요하지 않습니다."</string>
-    <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"응용프로그램에 Linux 시그널 보내기"</string>
-    <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"응용프로그램이 제공된 시그널을 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string>
-    <string name="permlab_persistentActivity" msgid="8659652042401085862">"응용프로그램이 항상 실행되도록 설정"</string>
-    <string name="permdesc_persistentActivity" msgid="5037199778265006008">"응용프로그램이 자신의 일부 구성 요소를 지속가능으로 설정하여 다른 응용프로그램에 사용할 수 없도록 합니다."</string>
-    <string name="permlab_deletePackages" msgid="3343439331576348805">"응용프로그램 삭제"</string>
-    <string name="permdesc_deletePackages" msgid="3634943677518723314">"응용프로그램이 Android 패키지를 삭제할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 응용프로그램을 삭제할 수 있습니다."</string>
-    <string name="permlab_clearAppUserData" msgid="2192134353540277878">"다른 응용프로그램의 데이터 삭제"</string>
-    <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"응용프로그램이 사용자 데이터를 지울 수 있도록 합니다."</string>
-    <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"다른 응용프로그램의 캐시 삭제"</string>
-    <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"응용프로그램이 캐시 파일을 삭제할 수 있도록 합니다."</string>
-    <string name="permlab_getPackageSize" msgid="4799785352306641460">"응용프로그램 저장공간 계산"</string>
-    <string name="permdesc_getPackageSize" msgid="5557253039670753437">"응용프로그램이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있도록 합니다."</string>
-    <string name="permlab_installPackages" msgid="335800214119051089">"응용프로그램 직접 설치"</string>
-    <string name="permdesc_installPackages" msgid="526669220850066132">"응용프로그램이 새로운 또는 업데이트된 Android 패키지를 설치할 수 있도록 합니다. 이 경우 악성 응용프로그램이 임의의 강력한 권한으로 새 응용프로그램을 추가할 수 있습니다."</string>
-    <string name="permlab_clearAppCache" msgid="4747698311163766540">"모든 응용프로그램 캐시 데이터 삭제"</string>
-    <string name="permdesc_clearAppCache" msgid="7740465694193671402">"응용프로그램이 응용프로그램 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
-    <string name="permlab_movePackage" msgid="728454979946503926">"응용프로그램 리소스 이동"</string>
-    <string name="permdesc_movePackage" msgid="6323049291923925277">"응용프로그램이 응용프로그램 리소스를 내부에서 외부 미디어로 또는 그 반대로 이동할 수 있도록 합니다."</string>
+    <string name="permdesc_setOrientation" msgid="6335814461615851863">"애플리케이션이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
+    <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"애플리케이션에 Linux 시그널 보내기"</string>
+    <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"애플리케이션이 제공된 시그널을 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string>
+    <string name="permlab_persistentActivity" msgid="8659652042401085862">"애플리케이션이 항상 실행되도록 설정"</string>
+    <string name="permdesc_persistentActivity" msgid="5037199778265006008">"애플리케이션이 자신의 일부 구성 요소를 지속가능으로 설정하여 다른 애플리케이션에 사용할 수 없도록 합니다."</string>
+    <string name="permlab_deletePackages" msgid="3343439331576348805">"애플리케이션 삭제"</string>
+    <string name="permdesc_deletePackages" msgid="3634943677518723314">"애플리케이션이 Android 패키지를 삭제할 수 있도록 합니다. 이 경우 악성 애플리케이션이 중요한 애플리케이션을 삭제할 수 있습니다."</string>
+    <string name="permlab_clearAppUserData" msgid="2192134353540277878">"다른 애플리케이션의 데이터 삭제"</string>
+    <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"애플리케이션이 사용자 데이터를 지울 수 있도록 합니다."</string>
+    <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"다른 애플리케이션의 캐시 삭제"</string>
+    <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"애플리케이션이 캐시 파일을 삭제할 수 있도록 합니다."</string>
+    <string name="permlab_getPackageSize" msgid="4799785352306641460">"애플리케이션 저장공간 계산"</string>
+    <string name="permdesc_getPackageSize" msgid="5557253039670753437">"애플리케이션이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있도록 합니다."</string>
+    <string name="permlab_installPackages" msgid="335800214119051089">"애플리케이션 직접 설치"</string>
+    <string name="permdesc_installPackages" msgid="526669220850066132">"애플리케이션이 새로운 또는 업데이트된 Android 패키지를 설치할 수 있도록 합니다. 이 경우 악성 애플리케이션이 임의의 강력한 권한으로 새 애플리케이션을 추가할 수 있습니다."</string>
+    <string name="permlab_clearAppCache" msgid="4747698311163766540">"모든 애플리케이션 캐시 데이터 삭제"</string>
+    <string name="permdesc_clearAppCache" msgid="7740465694193671402">"애플리케이션이 애플리케이션 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
+    <string name="permlab_movePackage" msgid="728454979946503926">"애플리케이션 리소스 이동"</string>
+    <string name="permdesc_movePackage" msgid="6323049291923925277">"애플리케이션이 애플리케이션 리소스를 내부에서 외부 미디어로 또는 그 반대로 이동할 수 있도록 합니다."</string>
     <string name="permlab_readLogs" msgid="4811921703882532070">"시스템 로그 파일 읽기"</string>
-    <string name="permdesc_readLogs" msgid="2257937955580475902">"응용프로그램이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 응용프로그램은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다. 하지만 로그 파일에 어떠한 개인정보도 포함되어서는 안 됩니다."</string>
+    <string name="permdesc_readLogs" msgid="2257937955580475902">"애플리케이션이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 애플리케이션은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다. 하지만 로그 파일에 어떠한 개인정보도 포함되어서는 안 됩니다."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
-    <string name="permdesc_diagnostic" msgid="3121238373951637049">"응용프로그램이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
-    <string name="permlab_changeComponentState" msgid="79425198834329406">"응용프로그램 구성 요소 사용 또는 사용 안함"</string>
-    <string name="permdesc_changeComponentState" msgid="4569107043246700630">"응용프로그램이 다른 응용프로그램 구성 요소 사용 여부를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 휴대전화 기능을 사용하지 않도록 설정할 수 있습니다. 이 권한을 설정할 경우 응용프로그램 구성 요소가 사용 불가능하게 되거나 일관성이 맞지 않거나 불안정해질 수 있으므로 주의해야 합니다."</string>
-    <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"기본 응용프로그램 설정"</string>
-    <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"응용프로그램이 기본 응용프로그램을 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 개인 정보를 수집하기 위해 기존 응용프로그램으로 위장하도록 실행되는 응용프로그램을 몰래 변경할 수 있습니다."</string>
+    <string name="permdesc_diagnostic" msgid="3121238373951637049">"애플리케이션이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
+    <string name="permlab_changeComponentState" msgid="79425198834329406">"애플리케이션 구성 요소 사용 또는 사용 안함"</string>
+    <string name="permdesc_changeComponentState" msgid="4569107043246700630">"애플리케이션이 다른 애플리케이션 구성 요소 사용 여부를 변경할 수 있도록 합니다. 이 경우 악성 애플리케이션이 중요한 휴대전화 기능을 사용하지 않도록 설정할 수 있습니다. 이 권한을 설정할 경우 애플리케이션 구성 요소가 사용 불가능하게 되거나 일관성이 맞지 않거나 불안정해질 수 있으므로 주의해야 합니다."</string>
+    <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"기본 애플리케이션 설정"</string>
+    <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"애플리케이션이 기본 애플리케이션을 수정할 수 있도록 합니다. 이 경우 악성 애플리케이션이 사용자의 개인 정보를 수집하기 위해 기존 애플리케이션으로 위장하도록 실행되는 애플리케이션을 몰래 변경할 수 있습니다."</string>
     <string name="permlab_writeSettings" msgid="1365523497395143704">"전체 시스템 설정 수정"</string>
-    <string name="permdesc_writeSettings" msgid="838789419871034696">"응용프로그램이 시스템의 설정 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 시스템 구성을 손상시킬 수 있습니다."</string>
+    <string name="permdesc_writeSettings" msgid="838789419871034696">"애플리케이션이 시스템의 설정 데이터를 수정할 수 있도록 합니다. 이 경우 악성 애플리케이션이 시스템 구성을 손상시킬 수 있습니다."</string>
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"보안 시스템 설정 수정"</string>
-    <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"응용프로그램이 시스템의 보안 설정값 데이터를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"애플리케이션이 시스템의 보안 설정값 데이터를 수정할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"Google 서비스 지도 수정"</string>
-    <string name="permdesc_writeGservices" msgid="6602362746516676175">"응용프로그램이 Google 서비스 지도를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_writeGservices" msgid="6602362746516676175">"애플리케이션이 Google 서비스 지도를 수정할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"부팅할 때 자동 시작"</string>
-    <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"응용프로그램이 시스템 부팅이 끝난 후 바로 시작할 수 있도록 합니다. 이 경우 휴대전화가 시작하는 데 시간이 오래 걸리고 응용프로그램이 항상 실행되어 전체 휴대전화 속도가 느려질 수 있습니다."</string>
+    <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"애플리케이션이 시스템 부팅이 끝난 후 바로 시작할 수 있도록 합니다. 이 경우 휴대전화가 시작하는 데 시간이 오래 걸리고 애플리케이션이 항상 실행되어 전체 휴대전화 속도가 느려질 수 있습니다."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"스티키 브로드캐스트 보내기"</string>
-    <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"응용프로그램이 브로드캐스트가 끝난 후에도 유지되는 스티키 브로드캐스트(Sticky Broadcast)를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화가 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
+    <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"애플리케이션이 브로드캐스트가 끝난 후에도 유지되는 스티키 브로드캐스트(Sticky Broadcast)를 보낼 수 있도록 합니다. 이 경우 악성 애플리케이션이 휴대전화가 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
     <string name="permlab_readContacts" msgid="6219652189510218240">"연락처 데이터 읽기"</string>
-    <string name="permdesc_readContacts" msgid="3371591512896545975">"응용프로그램이 휴대전화에 저장된 모든 연락처(주소) 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 데이터를 다른 사람에게 보낼 수 있습니다."</string>
+    <string name="permdesc_readContacts" msgid="3371591512896545975">"애플리케이션이 휴대전화에 저장된 모든 연락처(주소) 데이터를 읽을 수 있도록 합니다. 이 경우 악성 애플리케이션이 데이터를 다른 사람에게 보낼 수 있습니다."</string>
     <string name="permlab_writeContacts" msgid="644616215860933284">"연락처 데이터 작성"</string>
-    <string name="permdesc_writeContacts" msgid="3924383579108183601">"응용프로그램이 휴대전화에 저장된 연락처(주소) 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 연락처 데이터를 지우거나 수정할 수 있습니다."</string>
+    <string name="permdesc_writeContacts" msgid="3924383579108183601">"애플리케이션이 휴대전화에 저장된 연락처(주소) 데이터를 수정할 수 있도록 합니다. 이 경우 악성 애플리케이션이 연락처 데이터를 지우거나 수정할 수 있습니다."</string>
     <string name="permlab_writeOwnerData" msgid="4892555913849295393">"소유자 데이터 작성"</string>
-    <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"응용프로그램이 휴대전화에 저장된 소유자 데이터를 수정할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 소유자 데이터를 지우거나 수정할 수 있습니다."</string>
+    <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"애플리케이션이 휴대전화에 저장된 소유자 데이터를 수정할 수 있도록 합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 소유자 데이터를 지우거나 수정할 수 있습니다."</string>
     <string name="permlab_readOwnerData" msgid="6668525984731523563">"소유자 데이터 읽기"</string>
-    <string name="permdesc_readOwnerData" msgid="3088486383128434507">"응용프로그램이 휴대전화에 저장된 휴대전화 소유자 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 소유자 데이터를 읽을 수 있습니다."</string>
+    <string name="permdesc_readOwnerData" msgid="3088486383128434507">"애플리케이션이 휴대전화에 저장된 휴대전화 소유자 데이터를 읽을 수 있도록 합니다. 이 경우 악성 애플리케이션이 휴대전화 소유자 데이터를 읽을 수 있습니다."</string>
     <string name="permlab_readCalendar" msgid="6898987798303840534">"캘린더 일정 읽기"</string>
-    <string name="permdesc_readCalendar" msgid="5533029139652095734">"응용프로그램이 휴대전화에 저장된 모든 캘린더 일정을 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 캘린더 일정을 다른 사람에게 보낼 수 있습니다."</string>
+    <string name="permdesc_readCalendar" msgid="5533029139652095734">"애플리케이션이 휴대전화에 저장된 모든 캘린더 일정을 읽을 수 있도록 합니다. 이 경우 악성 애플리케이션이 캘린더 일정을 다른 사람에게 보낼 수 있습니다."</string>
     <string name="permlab_writeCalendar" msgid="3894879352594904361">"캘린더 일정 추가/수정 및 참석자에게 이메일 전송"</string>
-    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"응용프로그램이 캘린더에 일정을 추가하거나 변경할 수 있도록 합니다. 이렇게 하면 참석자에게 이메일을 보낼 수 있습니다. 악성 응용프로그램이 이를 사용하여 캘린더 일정을 삭제, 수정하거나 참석자에게 이메일을 보낼 수 있습니다."</string>
+    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"애플리케이션이 캘린더에 일정을 추가하거나 변경할 수 있도록 합니다. 이렇게 하면 참석자에게 이메일을 보낼 수 있습니다. 악성 애플리케이션이 이를 사용하여 캘린더 일정을 삭제, 수정하거나 참석자에게 이메일을 보낼 수 있습니다."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"테스트를 위해 위치 정보제공자로 가장"</string>
-    <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"테스트용 가짜 위치 정보 제공자를 만듭니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS, 네트워크 공급자 같은 실제 위치 정보제공자에서 반환한 위치 및/또는 상태를 덮어쓸 수 있습니다."</string>
+    <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"테스트용 가짜 위치 정보 제공자를 만듭니다. 단, 악성 애플리케이션이 이 기능을 이용하여 GPS, 네트워크 공급자 같은 실제 위치 정보제공자에서 반환한 위치 및/또는 상태를 덮어쓸 수 있습니다."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"추가 위치 제공업체 명령에 액세스"</string>
-    <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"추가적인 위치 제공 명령을 사용합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"추가적인 위치 제공 명령을 사용합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"위치 정보 공급자 설치 권한"</string>
-    <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"테스트용 가짜 위치 정보제공자를 만듭니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS, 네트워크 공급업체 같은 실제 위치 소스에서 반환한 위치 및/또는 상태를 덮어쓰거나 사용자의 위치를 모니터링하여 외부 소스로 보고할 수 있습니다."</string>
+    <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"테스트용 가짜 위치 정보제공자를 만듭니다. 단, 악성 애플리케이션이 이 기능을 이용하여 GPS, 네트워크 공급업체 같은 실제 위치 소스에서 반환한 위치 및/또는 상태를 덮어쓰거나 사용자의 위치를 모니터링하여 외부 소스로 보고할 수 있습니다."</string>
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"자세한 (GPS) 위치"</string>
-    <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"GPS 등의 자세한 위치 정보가 사용 가능한 경우 휴대전화에서 이를 사용합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 확인하고 추가 배터리 전원을 소비할 수 있습니다."</string>
+    <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"GPS 등의 자세한 위치 정보가 사용 가능한 경우 휴대전화에서 이를 사용합니다. 이 경우 악성 애플리케이션이 사용자의 위치를 확인하고 추가 배터리 전원을 소비할 수 있습니다."</string>
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"네트워크 기반의 대략적인 위치"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"휴대전화의 대략적인 위치를 측정하기 위해 셀룰러 네트워크 데이터베이스와 같은 광범위한 위치 정보를 사용합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 대략적으로 측정할 수 있습니다."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"휴대전화의 대략적인 위치를 측정하기 위해 셀룰러 네트워크 데이터베이스와 같은 광범위한 위치 정보를 사용합니다. 이 경우 악성 애플리케이션이 사용자의 위치를 대략적으로 측정할 수 있습니다."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger 액세스"</string>
-    <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"응용프로그램이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 합니다."</string>
+    <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"애플리케이션이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 합니다."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"프레임 버퍼 읽기"</string>
-    <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"응용프로그램이 프레임 버퍼의 내용을 읽을 수 있도록 합니다."</string>
+    <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"애플리케이션이 프레임 버퍼의 내용을 읽을 수 있도록 합니다."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"오디오 설정 변경"</string>
-    <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"응용프로그램이 볼륨 및 경로 지정 같은 전체 오디오 설정을 수정할 수 있도록 합니다."</string>
+    <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"애플리케이션이 볼륨 및 경로 지정 같은 전체 오디오 설정을 수정할 수 있도록 합니다."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"오디오 녹음"</string>
-    <string name="permdesc_recordAudio" msgid="6493228261176552356">"응용프로그램이 오디오 레코드 경로에 액세스할 수 있도록 합니다."</string>
+    <string name="permdesc_recordAudio" msgid="6493228261176552356">"애플리케이션이 오디오 레코드 경로에 액세스할 수 있도록 합니다."</string>
     <string name="permlab_camera" msgid="8059288807274039014">"사진 촬영"</string>
-    <string name="permdesc_camera" msgid="9013476258810982546">"응용프로그램이 카메라로 사진을 찍을 수 있도록 합니다. 이 경우 응용프로그램이 카메라에 보여지는 화면을 언제든지 수집할 수 있습니다."</string>
+    <string name="permdesc_camera" msgid="9013476258810982546">"애플리케이션이 카메라로 사진을 찍을 수 있도록 합니다. 이 경우 애플리케이션이 카메라에 보여지는 화면을 언제든지 수집할 수 있습니다."</string>
     <string name="permlab_brick" msgid="8337817093326370537">"휴대전화를 영구적으로 사용 중지"</string>
-    <string name="permdesc_brick" msgid="5569526552607599221">"응용프로그램이 휴대전화를 영구적으로 사용 중지할 수 있게 합니다. 이 기능은 매우 위험합니다."</string>
+    <string name="permdesc_brick" msgid="5569526552607599221">"애플리케이션이 휴대전화를 영구적으로 사용 중지할 수 있게 합니다. 이 기능은 매우 위험합니다."</string>
     <string name="permlab_reboot" msgid="2898560872462638242">"휴대전화 강제로 다시 부팅"</string>
-    <string name="permdesc_reboot" msgid="7914933292815491782">"응용프로그램이 휴대전화를 강제로 다시 부팅할 수 있도록 합니다."</string>
+    <string name="permdesc_reboot" msgid="7914933292815491782">"애플리케이션이 휴대전화를 강제로 다시 부팅할 수 있도록 합니다."</string>
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"파일시스템 마운트 및 마운트 해제"</string>
-    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"응용프로그램이 이동식 저장소의 파일 시스템을 마운트하고 마운트 해제할 수 있도록 합니다."</string>
+    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"애플리케이션이 이동식 저장소의 파일 시스템을 마운트하고 마운트 해제할 수 있도록 합니다."</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"외부 저장소 포맷"</string>
-    <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"응용프로그램이 이동식 저장소를 포맷할 수 있도록 합니다."</string>
+    <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"애플리케이션이 이동식 저장소를 포맷할 수 있도록 합니다."</string>
     <string name="permlab_asec_access" msgid="1070364079249834666">"보안 저장소에 대한 정보 가져오기"</string>
-    <string name="permdesc_asec_access" msgid="7691616292170590244">"응용프로그램이 보안 저장소의 정보를 가져올 수 있도록 합니다."</string>
+    <string name="permdesc_asec_access" msgid="7691616292170590244">"애플리케이션이 보안 저장소의 정보를 가져올 수 있도록 합니다."</string>
     <string name="permlab_asec_create" msgid="7312078032326928899">"보안 저장소 만들기"</string>
-    <string name="permdesc_asec_create" msgid="7041802322759014035">"응용프로그램이 보안 저장소를 만들 수 있도록 합니다."</string>
+    <string name="permdesc_asec_create" msgid="7041802322759014035">"애플리케이션이 보안 저장소를 만들 수 있도록 합니다."</string>
     <string name="permlab_asec_destroy" msgid="7787322878955261006">"보안 저장소 제거"</string>
-    <string name="permdesc_asec_destroy" msgid="5740754114967893169">"응용프로그램이 보안 저장소를 제거할 수 있도록 합니다."</string>
+    <string name="permdesc_asec_destroy" msgid="5740754114967893169">"애플리케이션이 보안 저장소를 제거할 수 있도록 합니다."</string>
     <string name="permlab_asec_mount_unmount" msgid="7517449694667828592">"보안 저장소 마운트/마운트 해제"</string>
-    <string name="permdesc_asec_mount_unmount" msgid="5438078121718738625">"응용프로그램이 보안 저장소를 마운트/마운트 해제할 수 있도록 합니다."</string>
+    <string name="permdesc_asec_mount_unmount" msgid="5438078121718738625">"애플리케이션이 보안 저장소를 마운트/마운트 해제할 수 있도록 합니다."</string>
     <string name="permlab_asec_rename" msgid="5685344390439934495">"보안 저장소 이름 바꾸기"</string>
-    <string name="permdesc_asec_rename" msgid="1387881770708872470">"응용프로그램이 보안 저장소의 이름을 바꿀 수 있도록 합니다."</string>
+    <string name="permdesc_asec_rename" msgid="1387881770708872470">"애플리케이션이 보안 저장소의 이름을 바꿀 수 있도록 합니다."</string>
     <string name="permlab_vibrate" msgid="7768356019980849603">"진동 제어"</string>
-    <string name="permdesc_vibrate" msgid="2886677177257789187">"응용프로그램이 진동을 제어할 수 있도록 합니다."</string>
+    <string name="permdesc_vibrate" msgid="2886677177257789187">"애플리케이션이 진동을 제어할 수 있도록 합니다."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
-    <string name="permdesc_flashlight" msgid="6433045942283802309">"응용프로그램이 카메라 플래시를 제어할 수 있도록 합니다."</string>
+    <string name="permdesc_flashlight" msgid="6433045942283802309">"애플리케이션이 카메라 플래시를 제어할 수 있도록 합니다."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"하드웨어 테스트"</string>
-    <string name="permdesc_hardware_test" msgid="3668894686500081699">"응용프로그램이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있도록 합니다."</string>
+    <string name="permdesc_hardware_test" msgid="3668894686500081699">"애플리케이션이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있도록 합니다."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
-    <string name="permdesc_callPhone" msgid="3369867353692722456">"응용프로그램이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램으로 인해 예상치 못한 통화 요금이 부과될 수 있습니다. 이 권한으로 응용프로그램이 비상 전화를 걸게 할 수는 없습니다."</string>
+    <string name="permdesc_callPhone" msgid="3369867353692722456">"애플리케이션이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 애플리케이션으로 인해 예상치 못한 통화 요금이 부과될 수 있습니다. 이 권한으로 애플리케이션이 비상 전화를 걸게 할 수는 없습니다."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"모든 전화번호 자동 연결"</string>
-    <string name="permdesc_callPrivileged" msgid="244405067160028452">"응용프로그램이 사용자의 조작 없이 비상 번호를 포함한 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램이 응급 서비스를 불필요하게 또는 불법적으로 호출할 수 있습니다."</string>
+    <string name="permdesc_callPrivileged" msgid="244405067160028452">"애플리케이션이 사용자의 조작 없이 비상 번호를 포함한 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 애플리케이션이 응급 서비스를 불필요하게 또는 불법적으로 호출할 수 있습니다."</string>
     <string name="permlab_performCdmaProvisioning" msgid="5604848095315421425">"직접 CDMA 전화 설정 시작"</string>
-    <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"응용프로그램이 CDMA 프로비저닝을 시작할 수 있도록 합니다. 이 경우 악성 응용프로그램이 불필요하게 CDMA 프로비저닝을 시작할 수 있습니다."</string>
+    <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"애플리케이션이 CDMA 프로비저닝을 시작할 수 있도록 합니다. 이 경우 악성 애플리케이션이 불필요하게 CDMA 프로비저닝을 시작할 수 있습니다."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"위치 업데이트 알림 제어"</string>
-    <string name="permdesc_locationUpdates" msgid="2300018303720930256">"무선의 위치 업데이트 알림을 사용하거나 사용 중지할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_locationUpdates" msgid="2300018303720930256">"무선의 위치 업데이트 알림을 사용하거나 사용 중지할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"체크인 속성 액세스"</string>
-    <string name="permdesc_checkinProperties" msgid="7150307006141883832">"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 접근을 허용합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_checkinProperties" msgid="7150307006141883832">"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 접근을 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"위젯 선택"</string>
-    <string name="permdesc_bindGadget" msgid="2098697834497452046">"응용프로그램이 어떤 응용프로그램에서 어떤 위젯을 사용할 수 있는 지를 시스템에 알릴 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 개인 정보에 대한 액세스 권한을 다른 응용프로그램에 부여할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_bindGadget" msgid="2098697834497452046">"애플리케이션이 어떤 애플리케이션에서 어떤 위젯을 사용할 수 있는 지를 시스템에 알릴 수 있도록 합니다. 이 권한을 갖는 애플리케이션은 개인 정보에 대한 액세스 권한을 다른 애플리케이션에 부여할 수 있습니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"휴대전화 상태 수정"</string>
-    <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"응용프로그램이 장치의 휴대전화 기능을 제어할 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나 휴대전화 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
+    <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"애플리케이션이 장치의 휴대전화 기능을 제어할 수 있도록 합니다. 이 권한을 갖는 애플리케이션은 사용자에게 알리지 않고 네트워크를 전환하거나 휴대전화 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
     <string name="permlab_readPhoneState" msgid="2326172951448691631">"휴대전화 상태 및 ID 읽기"</string>
-    <string name="permdesc_readPhoneState" msgid="188877305147626781">"응용프로그램이 장치의 휴대전화 기능에 접근할 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 휴대전화의 전화번호 및 일련번호, 통화가 활성인지 여부, 해당 통화가 연결된 번호 등을 확인할 수 있습니다."</string>
+    <string name="permdesc_readPhoneState" msgid="188877305147626781">"애플리케이션이 장치의 휴대전화 기능에 접근할 수 있도록 합니다. 이 권한을 갖는 애플리케이션은 휴대전화의 전화번호 및 일련번호, 통화가 활성인지 여부, 해당 통화가 연결된 번호 등을 확인할 수 있습니다."</string>
     <string name="permlab_wakeLock" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
-    <string name="permdesc_wakeLock" msgid="7584036471227467099">"응용프로그램이 휴대전화가 절전 모드로 전환되지 않도록 합니다."</string>
+    <string name="permdesc_wakeLock" msgid="7584036471227467099">"애플리케이션이 휴대전화가 절전 모드로 전환되지 않도록 합니다."</string>
     <string name="permlab_devicePower" msgid="4928622470980943206">"휴대전화 전원 켜고 끄기"</string>
-    <string name="permdesc_devicePower" msgid="4577331933252444818">"응용프로그램이 휴대전화를 켜거나 끌 수 있도록 합니다."</string>
+    <string name="permdesc_devicePower" msgid="4577331933252444818">"애플리케이션이 휴대전화를 켜거나 끌 수 있도록 합니다."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"출고 테스트 모드로 실행"</string>
     <string name="permdesc_factoryTest" msgid="8136644990319244802">"휴대전화 하드웨어에 대한 완전한 액세스를 허용하는 하위 수준의 제조업체 테스트로 실행됩니다. 휴대전화가 제조업체 테스트 모드로 실행 중일 때만 사용할 수 있습니다."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"배경화면 설정"</string>
-    <string name="permdesc_setWallpaper" msgid="6417041752170585837">"응용프로그램이 시스템 배경화면을 설정할 수 있도록 합니다."</string>
+    <string name="permdesc_setWallpaper" msgid="6417041752170585837">"애플리케이션이 시스템 배경화면을 설정할 수 있도록 합니다."</string>
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"배경화면 크기 힌트 설정"</string>
-    <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"응용프로그램이 시스템 배경화면 크기 힌트를 설정할 수 있도록 합니다."</string>
+    <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"애플리케이션이 시스템 배경화면 크기 힌트를 설정할 수 있도록 합니다."</string>
     <string name="permlab_masterClear" msgid="2315750423139697397">"시스템을 기본값으로 재설정"</string>
-    <string name="permdesc_masterClear" msgid="5033465107545174514">"응용프로그램이 모든 데이터, 구성 및 설치된 응용프로그램을 지워서 시스템을 완전히 초기화할 수 있도록 합니다."</string>
+    <string name="permdesc_masterClear" msgid="5033465107545174514">"애플리케이션이 모든 데이터, 구성 및 설치된 애플리케이션을 지워서 시스템을 완전히 초기화할 수 있도록 합니다."</string>
     <string name="permlab_setTime" msgid="2021614829591775646">"시간 설정"</string>
-    <string name="permdesc_setTime" msgid="667294309287080045">"응용프로그램이 휴대전화 시계의 시간을 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_setTime" msgid="667294309287080045">"애플리케이션이 휴대전화 시계의 시간을 변경할 수 있도록 합니다."</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"표준시간대 설정"</string>
-    <string name="permdesc_setTimeZone" msgid="1902540227418179364">"응용프로그램이 휴대전화의 표준시간대를 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_setTimeZone" msgid="1902540227418179364">"애플리케이션이 휴대전화의 표준시간대를 변경할 수 있도록 합니다."</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"AccountManagerService로 활동"</string>
-    <string name="permdesc_accountManagerService" msgid="6056903274106394752">"응용프로그램이 AccountAuthenticators으로 전화를 걸 수 있도록 합니다."</string>
+    <string name="permdesc_accountManagerService" msgid="6056903274106394752">"애플리케이션이 AccountAuthenticators으로 전화를 걸 수 있도록 합니다."</string>
     <string name="permlab_getAccounts" msgid="4549918644233460103">"알려진 계정 검색"</string>
-    <string name="permdesc_getAccounts" msgid="6839262446413155394">"응용프로그램이 휴대전화에 알려진 계정 목록을 가져올 수 있도록 합니다."</string>
+    <string name="permdesc_getAccounts" msgid="6839262446413155394">"애플리케이션이 휴대전화에 알려진 계정 목록을 가져올 수 있도록 합니다."</string>
     <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"계정 인증자로 활동"</string>
-    <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"응용프로그램이 계정 만들기, 비밀번호 가져오기 및 설정 등과 같은 AccountManager의 계정 인증자 기능을 사용할 수 있도록 합니다."</string>
+    <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"애플리케이션이 계정 만들기, 비밀번호 가져오기 및 설정 등과 같은 AccountManager의 계정 인증자 기능을 사용할 수 있도록 합니다."</string>
     <string name="permlab_manageAccounts" msgid="4440380488312204365">"계정 목록 관리"</string>
-    <string name="permdesc_manageAccounts" msgid="8804114016661104517">"응용프로그램이 계정 추가, 삭제 및 비밀번호 삭제 등의 작업을 수행할 수 있도록 합니다."</string>
+    <string name="permdesc_manageAccounts" msgid="8804114016661104517">"애플리케이션이 계정 추가, 삭제 및 비밀번호 삭제 등의 작업을 수행할 수 있도록 합니다."</string>
     <string name="permlab_useCredentials" msgid="6401886092818819856">"계정의 인증 자격증명 사용"</string>
-    <string name="permdesc_useCredentials" msgid="7416570544619546974">"응용프로그램이 인증 토큰을 요청하도록 합니다."</string>
+    <string name="permdesc_useCredentials" msgid="7416570544619546974">"애플리케이션이 인증 토큰을 요청하도록 합니다."</string>
     <string name="permlab_accessNetworkState" msgid="6865575199464405769">"네트워크 상태 보기"</string>
-    <string name="permdesc_accessNetworkState" msgid="558721128707712766">"응용프로그램이 모든 네트워크의 상태를 볼 수 있도록 합니다."</string>
+    <string name="permdesc_accessNetworkState" msgid="558721128707712766">"애플리케이션이 모든 네트워크의 상태를 볼 수 있도록 합니다."</string>
     <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"인터넷에 최대한 액세스"</string>
-    <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"응용프로그램이 네트워크 소켓을 만들 수 있도록 합니다."</string>
+    <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"애플리케이션이 네트워크 소켓을 만들 수 있도록 합니다."</string>
     <string name="permlab_writeApnSettings" msgid="7823599210086622545">"액세스포인트 이름(APN) 설정 쓰기"</string>
-    <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"응용프로그램이 APN의 프록시 및 포트 같은 APN 설정을 수정할 수 있도록 합니다."</string>
+    <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"애플리케이션이 APN의 프록시 및 포트 같은 APN 설정을 수정할 수 있도록 합니다."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"네트워크 연결 변경"</string>
-    <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"응용프로그램이 네트워크 연결 상태를 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"애플리케이션이 네트워크 연결 상태를 변경할 수 있도록 합니다."</string>
     <string name="permlab_changeTetherState" msgid="2702121155761140799">"테러링 연결 변경"</string>
-    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"응용프로그램이 테더링된 네트워크의 연결 상태를 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"애플리케이션이 테더링된 네트워크의 연결 상태를 변경할 수 있도록 합니다."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"백그라운드 데이터 사용 설정 변경"</string>
-    <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"응용프로그램이 백그라운드 데이터 사용 설정을 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"애플리케이션이 백그라운드 데이터 사용 설정을 변경할 수 있도록 합니다."</string>
     <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi 상태 보기"</string>
-    <string name="permdesc_accessWifiState" msgid="485796529139236346">"응용프로그램이 Wi-Fi의 상태에 대한 정보를 볼 수 있도록 합니다."</string>
+    <string name="permdesc_accessWifiState" msgid="485796529139236346">"애플리케이션이 Wi-Fi의 상태에 대한 정보를 볼 수 있도록 합니다."</string>
     <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi 상태 변경"</string>
-    <string name="permdesc_changeWifiState" msgid="2950383153656873267">"응용프로그램이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있도록 합니다."</string>
+    <string name="permdesc_changeWifiState" msgid="2950383153656873267">"애플리케이션이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있도록 합니다."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi 멀티캐스트 수신 허용"</string>
-    <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"응용프로그램이 휴대기기로 직접 주소가 지정되지 않은 패킷을 받을 수 있도록 합니다. 이 기능은 가까운 곳에서 제공되는 서비스를 검색할 때 유용하며 비멀티캐스트 모드보다 전원을 더 많이 소비합니다."</string>
+    <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"애플리케이션이 휴대기기로 직접 주소가 지정되지 않은 패킷을 받을 수 있도록 합니다. 이 기능은 가까운 곳에서 제공되는 서비스를 검색할 때 유용하며 비멀티캐스트 모드보다 전원을 더 많이 소비합니다."</string>
     <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth 관리"</string>
-    <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"응용프로그램이 로컬 Bluetooth 휴대전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있도록 합니다."</string>
+    <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"애플리케이션이 로컬 Bluetooth 휴대전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있도록 합니다."</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth 연결 만들기"</string>
-    <string name="permdesc_bluetooth" msgid="762515380679392945">"응용프로그램이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하며 연결을 수락할 수 있도록 합니다."</string>
+    <string name="permdesc_bluetooth" msgid="762515380679392945">"애플리케이션이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하며 연결을 수락할 수 있도록 합니다."</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"키 잠금 사용 중지"</string>
-    <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"응용프로그램이 키 잠금 및 관련 비밀번호 보안을 사용 중지할 수 있도록 합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용 중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
+    <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"애플리케이션이 키 잠금 및 관련 비밀번호 보안을 사용 중지할 수 있도록 합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용 중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
-    <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"응용프로그램이 주소록에 동기화를 사용할지 여부와 같은 동기화 설정을 읽을 수 있도록 합니다."</string>
+    <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"애플리케이션이 주소록에 동기화를 사용할지 여부와 같은 동기화 설정을 읽을 수 있도록 합니다."</string>
     <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"동기화 설정 쓰기"</string>
-    <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"응용프로그램이 주소록에 대해 동기화를 사용할지 여부 등의 동기화 설정을 수정할 수 있도록 합니다."</string>
+    <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"애플리케이션이 주소록에 대해 동기화를 사용할지 여부 등의 동기화 설정을 수정할 수 있도록 합니다."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"동기화 통계 읽기"</string>
-    <string name="permdesc_readSyncStats" msgid="7511448343374465000">"응용프로그램이 동기화 통계(예: 실행된 동기화 기록)을 읽을 수 있도록 합니다."</string>
+    <string name="permdesc_readSyncStats" msgid="7511448343374465000">"애플리케이션이 동기화 통계(예: 실행된 동기화 기록)을 읽을 수 있도록 합니다."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"가입된 피드 읽기"</string>
-    <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"응용프로그램이 현재 동기화된 피드에 대한 세부정보를 가져올 수 있도록 합니다."</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"애플리케이션이 현재 동기화된 피드에 대한 세부정보를 가져올 수 있도록 합니다."</string>
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"가입 피드 작성"</string>
-    <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"응용프로그램이 현재 동기화된 피드를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 동기화된 피드를 변경할 수 있습니다."</string>
+    <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"애플리케이션이 현재 동기화된 피드를 수정할 수 있도록 합니다. 이 경우 악성 애플리케이션이 동기화된 피드를 변경할 수 있습니다."</string>
     <string name="permlab_readDictionary" msgid="432535716804748781">"사용자 정의 사전 읽기"</string>
-    <string name="permdesc_readDictionary" msgid="1082972603576360690">"응용프로그램이 사용자 사전에 보관되어 있는 비공개 단어, 이름 및 구문을 읽도록 합니다."</string>
+    <string name="permdesc_readDictionary" msgid="1082972603576360690">"애플리케이션이 사용자 사전에 보관되어 있는 비공개 단어, 이름 및 구문을 읽도록 합니다."</string>
     <string name="permlab_writeDictionary" msgid="6703109511836343341">"사용자정의 사전에 작성"</string>
-    <string name="permdesc_writeDictionary" msgid="2241256206524082880">"응용프로그램이 사용자 사전에 새 단어를 입력할 수 있도록 합니다."</string>
+    <string name="permdesc_writeDictionary" msgid="2241256206524082880">"애플리케이션이 사용자 사전에 새 단어를 입력할 수 있도록 합니다."</string>
     <string name="permlab_sdcardWrite" msgid="8079403759001777291">"SD 카드 콘텐츠 수정/삭제"</string>
-    <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"응용프로그램이 SD 카드에 쓸 수 있도록 합니다."</string>
+    <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"애플리케이션이 SD 카드에 쓸 수 있도록 합니다."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"캐시 파일시스템 액세스"</string>
-    <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"응용프로그램이 캐시 파일시스템을 읽고 쓸 수 있도록 합니다."</string>
+    <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"애플리케이션이 캐시 파일시스템을 읽고 쓸 수 있도록 합니다."</string>
     <string name="policylab_limitPassword" msgid="4307861496302850201">"비밀번호 제한"</string>
     <string name="policydesc_limitPassword" msgid="1719877245692318299">"사용할 수 있는 비밀번호 유형을 제한합니다."</string>
     <string name="policylab_watchLogin" msgid="7374780712664285321">"로그인 시도 보기"</string>
@@ -571,8 +571,8 @@
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
     <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
     <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
-    <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+    <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="AMPM">%P</xliff:g> <xliff:g id="HOUR">%-l</xliff:g>:00"</string>
+    <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="AMPM">%p</xliff:g> <xliff:g id="HOUR">%-l</xliff:g>:00"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"지우기"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
@@ -593,11 +593,11 @@
     <string name="save_password_label" msgid="6860261758665825069">"확인"</string>
     <string name="double_tap_toast" msgid="1068216937244567247">"도움말: 축소/확대하려면 두 번 누릅니다."</string>
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"브라우저의 기록 및 북마크 읽기"</string>
-    <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"응용프로그램이 브라우저로 방문한 모든 URL과 브라우저의 모든 북마크를 읽도록 허용합니다."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"애플리케이션이 브라우저로 방문한 모든 URL과 브라우저의 모든 북마크를 읽도록 허용합니다."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"브라우저의 기록 및 북마크 쓰기"</string>
-    <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"응용프로그램이 휴대전화에 저장된 브라우저 기록 또는 북마크를 수정할 수 있도록 허용합니다. 이 경우 악성 응용프로그램이 브라우저의 데이터를 지우거나 수정할 수 있습니다."</string>
+    <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"애플리케이션이 휴대전화에 저장된 브라우저 기록 또는 북마크를 수정할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 브라우저의 데이터를 지우거나 수정할 수 있습니다."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="4715212655598275532">"브라우저 위치 정보 수정 권한"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"응용프로그램이 브라우저의 위치 정보 권한을 수정할 수 있도록 합니다. 악성 응용프로그램이 이를 사용하여 임의의 웹사이트에 위치 정보를 보낼 수도 있습니다."</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"애플리케이션이 브라우저의 위치 정보 권한을 수정할 수 있도록 합니다. 악성 애플리케이션이 이를 사용하여 임의의 웹사이트에 위치 정보를 보낼 수도 있습니다."</string>
     <string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
@@ -728,18 +728,18 @@
     <string name="dialog_alert_title" msgid="2049658708609043103">"주의"</string>
     <string name="capital_on" msgid="1544682755514494298">"사용"</string>
     <string name="capital_off" msgid="6815870386972805832">"사용 안함"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"작업을 수행할 때 사용하는 응용프로그램"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"작업을 수행할 때 사용하는 애플리케이션"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"이 작업에 대해 기본값으로 사용"</string>
-    <string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 &gt; 응용프로그램 &gt; 응용프로그램 관리에서 기본값을 지웁니다."</string>
+    <string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 &gt; 애플리케이션 &gt; 애플리케이션 관리에서 기본값을 지웁니다."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"작업 선택"</string>
-    <string name="noApplications" msgid="1691104391758345586">"작업을 수행할 수 있는 응용프로그램이 없습니다."</string>
+    <string name="noApplications" msgid="1691104391758345586">"작업을 수행할 수 있는 애플리케이션이 없습니다."</string>
     <string name="aerr_title" msgid="653922989522758100">"죄송합니다."</string>
-    <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
+    <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 애플리케이션(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
     <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
     <string name="anr_title" msgid="3100070910664756057">"죄송합니다."</string>
-    <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활동(<xliff:g id="ACTIVITY">%1$s</xliff:g> 응용프로그램)이 응답하지 않습니다."</string>
+    <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활동(<xliff:g id="ACTIVITY">%1$s</xliff:g> 애플리케이션)이 응답하지 않습니다."</string>
     <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
-    <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
+    <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> 애플리케이션(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
     <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."</string>
     <string name="force_close" msgid="3653416315450806396">"닫기"</string>
     <string name="report" msgid="4060218260984795706">"신고"</string>
@@ -768,7 +768,7 @@
     <item quantity="other" msgid="7915895323644292768">"개방형 Wi-Fi 네트워크 사용 가능"</item>
   </plurals>
     <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
-    <string name="sms_control_default_app_name" msgid="7630529934366549163">"알 수 없는 응용프로그램"</string>
+    <string name="sms_control_default_app_name" msgid="7630529934366549163">"알 수 없는 애플리케이션"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
     <string name="sms_control_message" msgid="1289331457999236205">"여러 개의 SMS 메시지를 보내는 중입니다. 계속하려면 \'확인\'을 선택하고 전송을 중지하려면 \'취소\'를 선택하세요."</string>
     <string name="sms_control_yes" msgid="2532062172402615953">"확인"</string>
@@ -792,7 +792,7 @@
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB 저장소 사용 안함"</string>
     <string name="usb_storage_stop_error_message" msgid="143881914840412108">"USB 저장소를 사용하지 않도록 설정하는 동안 문제가 발생했습니다. USB 호스트와 연결을 해제했는지 확인한 다음 다시 시도하세요."</string>
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"USB 저장소 사용"</string>
-    <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB 저장소를 사용 설정하면 사용 중인 일부 응용프로그램이 중지되고 USB 저장소를 사용 중지할 때까지 사용할 수 없게 됩니다."</string>
+    <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB 저장소를 사용 설정하면 사용 중인 일부 애플리케이션이 중지되고 USB 저장소를 사용 중지할 때까지 사용할 수 없게 됩니다."</string>
     <string name="dlg_error_title" msgid="8048999973837339174">"USB 작업 실패"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
     <string name="extmedia_format_title" msgid="8663247929551095854">"SD 카드 포맷"</string>
@@ -818,9 +818,9 @@
     <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD 카드가 없습니다.  SD 카드를 넣으세요."</string>
     <string name="activity_list_empty" msgid="4168820609403385789">"일치하는 활동이 없습니다."</string>
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"구성 요소 사용 통계 업데이트"</string>
-    <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"수집된 구성요소 사용 통계를 수정할 수 있는 권한을 부여합니다. 일반 응용프로그램은 이 권한을 사용하지 않습니다."</string>
-    <string name="permlab_copyProtectedData" msgid="1660908117394854464">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
-    <string name="permdesc_copyProtectedData" msgid="537780957633976401">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+    <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"수집된 구성요소 사용 통계를 수정할 수 있는 권한을 부여합니다. 일반 애플리케이션은 이 권한을 사용하지 않습니다."</string>
+    <string name="permlab_copyProtectedData" msgid="1660908117394854464">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
+    <string name="permdesc_copyProtectedData" msgid="537780957633976401">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"확대/축소하려면 두 번 탭하세요."</string>
     <string name="gadget_host_error_inflating" msgid="2613287218853846830">"위젯을 생성하는 과정(inflate)에 오류가 발생했습니다."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"이동"</string>
@@ -833,7 +833,7 @@
     <string name="create_contact_using" msgid="4947405226788104538">"전화번호부에"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
     <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"선택함"</string>
     <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"선택 안함"</string>
-    <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"현재 이후로 하나 이상의 다음 응용프로그램이 계정에 대한 액세스 권한을 요청합니다."</string>
+    <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"현재 이후로 하나 이상의 다음 애플리케이션이 계정에 대한 액세스 권한을 요청합니다."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"요청을 허용하시겠습니까?"</string>
     <string name="grant_permissions_header_text" msgid="2722567482180797717">"액세스 요청"</string>
     <string name="allow" msgid="7225948811296386551">"허용"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 02afb16..6acf4a6 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -780,7 +780,7 @@
     <string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
     <string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-masselagring"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB koblet til"</string>
-    <string name="usb_storage_message" msgid="4796759646167247178">"Du har koblet telefonen til datamaskinen via USB. Velg knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og SD-kortet i Android-telefonen."</string>
+    <string name="usb_storage_message" msgid="4796759646167247178">"Du har koblet telefonen til datamaskinen via USB. Velg knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og minnekortet i telefonen."</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"Slå på USB-lagring"</string>
     <string name="usb_storage_error_message" msgid="2534784751603345363">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB tilkoblet"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b7c5bbc..834a84c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -587,7 +587,7 @@
     <string name="factorytest_not_system" msgid="4435201656767276723">"只有在 /system/app 中安装的包支持 FACTORY_TEST 操作。"</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"未发现支持 FACTORY_TEST 操作的包。"</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"重新启动"</string>
-    <string name="js_dialog_title" msgid="8143918455087008109">"“<xliff:g id="TITLE">%s</xliff:g>”处的页面表明:"</string>
+    <string name="js_dialog_title" msgid="8143918455087008109">"来自“<xliff:g id="TITLE">%s</xliff:g>”的提示:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
     <string name="js_dialog_before_unload" msgid="1901675448179653089">"是否从该页面导航至它处?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定”继续,或选择“取消”留在当前页面。"</string>
     <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 66154cb..cac85e8 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -785,7 +785,7 @@
 
 <h3 id="ScreenCompatibility">Providing screen resource compatibility for Android 1.5</h3>
 
-<p>Android 1.5 (and lower) does not support the following resource qualifers:</p>
+<p>Android 1.5 (and lower) does not support the following configuration qualifers:</p>
 <dl>
   <dt><a href="#DensityQualifier">Density</a></dt>
     <dd>{@code ldpi}, {@code mdpi}, {@code ldpi}, and {@code nodpi}</dd>
@@ -795,11 +795,11 @@
     <dd>{@code long} and {@code notlong}</dd>
 </dl>
 
-<p>These resource qualifiers were introduced in Android 1.6, so Android 1.5 (API Level 3) and lower
-does not support them. If you use these configuration qualifiers and do not provide
+<p>These configuration qualifiers were introduced in Android 1.6, so Android 1.5 (API Level 3) and
+lower does not support them. If you use these configuration qualifiers and do not provide
 corresponding default resources, then an Android 1.5 device might use any one of the resource
-directories named with the above screen qualifiers, because it ignores the screen qualifiers and
-uses whichever otherwise-matching drawable resource it finds first.</p>
+directories named with the above screen configuration qualifiers, because it ignores these
+qualifiers and uses whichever otherwise-matching drawable resource it finds first.</p>
 
 <p>For example, if your application supports Android 1.5 and includes drawable resources for
 each density type ({@code drawable-ldpi/}, {@code drawable-mdpi/}, and {@code drawable-ldpi/}),
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 3ab985d..04e24d2 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -40,6 +40,9 @@
 
             int                 getCallingPid();
             int                 getCallingUid();
+
+            void                setStrictModePolicy(int32_t policy);
+            int32_t             getStrictModePolicy() const;
             
             int64_t             clearCallingIdentity();
             void                restoreCallingIdentity(int64_t token);
@@ -109,8 +112,9 @@
             status_t            mLastError;
             pid_t               mCallingPid;
             uid_t               mCallingUid;
+            int32_t             mStrictModePolicy;
 };
-    
+
 }; // namespace android
 
 // ---------------------------------------------------------------------------
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 66c34b2..2cc4db9 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -56,9 +56,12 @@
 
     bool                hasFileDescriptors() const;
 
+    // Writes the RPC header.
     status_t            writeInterfaceToken(const String16& interface);
+    // Parses the RPC header, returning true if the interface name
+    // in the header matches the expected interface from the caller.
     bool                enforceInterface(const String16& interface) const;
-    bool                checkInterface(IBinder*) const;    
+    bool                checkInterface(IBinder*) const;
 
     void                freeData();
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index c46df1e..ef537f4 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -102,6 +102,17 @@
 
     typedef void (*callback_t)(int event, void* user, void *info);
 
+    /* Returns the minimum frame count required for the successful creation of
+     * an AudioTrack object.
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - NO_INIT: audio server or audio hardware not initialized
+     */
+
+     static status_t getMinFrameCount(int* frameCount,
+                                      int streamType      =-1,
+                                      uint32_t sampleRate = 0);
+
     /* Constructs an uninitialized AudioTrack. No connection with
      * AudioFlinger takes place.
      */
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 92ff872..979d6e8 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -58,8 +58,6 @@
 /*
  * Flags that flow alongside events in the input dispatch system to help with certain
  * policy decisions such as waking from device sleep.
- *
- * TODO This enumeration should probably be split up or relabeled for clarity.
  */
 enum {
     /* These flags originate in RawEvents and are generally set in the key map. */
@@ -73,6 +71,8 @@
     POLICY_FLAG_MENU = 0x00000040,
     POLICY_FLAG_LAUNCHER = 0x00000080,
 
+    POLICY_FLAG_RAW_MASK = 0x0000ffff,
+
     /* These flags are set by the input reader policy as it intercepts each event. */
 
     // Indicates that the screen was off when the event was received and the event
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 80a20c9..511ad20 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -35,6 +35,28 @@
 namespace android {
 
 /*
+ * Constants used to report the outcome of input event injection.
+ */
+enum {
+    /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */
+    INPUT_EVENT_INJECTION_PENDING = -1,
+
+    /* Injection succeeded. */
+    INPUT_EVENT_INJECTION_SUCCEEDED = 0,
+
+    /* Injection failed because the injector did not have permission to inject
+     * into the application with input focus. */
+    INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1,
+
+    /* Injection failed because there were no available input targets. */
+    INPUT_EVENT_INJECTION_FAILED = 2,
+
+    /* Injection failed due to a timeout. */
+    INPUT_EVENT_INJECTION_TIMED_OUT = 3
+};
+
+
+/*
  * An input target specifies how an input event is to be dispatched to a particular window
  * including the window's input channel, control flags, a timeout, and an X / Y offset to
  * be added to input event coordinates to compensate for the absolute position of the
@@ -70,6 +92,7 @@
     float xOffset, yOffset;
 };
 
+
 /*
  * Input dispatcher policy interface.
  *
@@ -91,8 +114,11 @@
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
 
-    /* Notifies the system that an input channel is not responding. */
-    virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
+    /* Notifies the system that an input channel is not responding.
+     * Returns true and a new timeout value if the dispatcher should keep waiting.
+     * Otherwise returns false. */
+    virtual bool notifyInputChannelANR(const sp<InputChannel>& inputChannel,
+            nsecs_t& outNewTimeout) = 0;
 
     /* Notifies the system that an input channel recovered from ANR. */
     virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
@@ -100,12 +126,22 @@
     /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
     virtual nsecs_t getKeyRepeatTimeout() = 0;
 
-    /* Gets the input targets for a key event. */
-    virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+    /* Gets the input targets for a key event.
+     * If the event is being injected, injectorPid and injectorUid should specify the
+     * process id and used id of the injecting application, otherwise they should both
+     * be -1.
+     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
+    virtual int32_t getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+            int32_t injectorPid, int32_t injectorUid,
             Vector<InputTarget>& outTargets) = 0;
 
-    /* Gets the input targets for a motion event. */
-    virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    /* Gets the input targets for a motion event.
+     * If the event is being injected, injectorPid and injectorUid should specify the
+     * process id and used id of the injecting application, otherwise they should both
+     * be -1.
+     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
+    virtual int32_t getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+            int32_t injectorPid, int32_t injectorUid,
             Vector<InputTarget>& outTargets) = 0;
 };
 
@@ -139,6 +175,17 @@
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime) = 0;
 
+    /* Injects an input event and optionally waits for sync.
+     * 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.
+     * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
+     *
+     * This method may be called on any thread (usually by the input manager).
+     */
+    virtual int32_t injectInputEvent(const InputEvent* event,
+            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+
     /* Registers or unregister input channels that may be used as targets for input events.
      *
      * These methods may be called on any thread (usually by the input manager).
@@ -183,6 +230,9 @@
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
 
+    virtual int32_t injectInputEvent(const InputEvent* event,
+            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
+
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
 
@@ -205,7 +255,13 @@
         int32_t type;
         nsecs_t eventTime;
 
+        int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
+        int32_t injectorPid;     // -1 if not injected
+        int32_t injectorUid;     // -1 if not injected
+
         bool dispatchInProgress; // initially false, set to true while dispatching
+
+        inline bool isInjected() { return injectorPid >= 0; }
     };
 
     struct ConfigurationChangedEntry : EventEntry {
@@ -293,6 +349,7 @@
     struct CommandEntry;
     typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
 
+    class Connection;
     struct CommandEntry : Link<CommandEntry> {
         CommandEntry();
         ~CommandEntry();
@@ -300,7 +357,7 @@
         Command command;
 
         // parameters for the command (usage varies by command)
-        sp<InputChannel> inputChannel;
+        sp<Connection> connection;
     };
 
     // Generic queue implementation.
@@ -353,9 +410,16 @@
     public:
         Allocator();
 
-        ConfigurationChangedEntry* obtainConfigurationChangedEntry();
-        KeyEntry* obtainKeyEntry();
-        MotionEntry* obtainMotionEntry();
+        ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime);
+        KeyEntry* obtainKeyEntry(nsecs_t eventTime,
+                int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+                int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
+                int32_t repeatCount, nsecs_t downTime);
+        MotionEntry* obtainMotionEntry(nsecs_t eventTime,
+                int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+                int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
+                nsecs_t downTime, uint32_t pointerCount,
+                const int32_t* pointerIds, const PointerCoords* pointerCoords);
         DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
         CommandEntry* obtainCommandEntry(Command command);
 
@@ -367,7 +431,7 @@
         void releaseCommandEntry(CommandEntry* entry);
 
         void appendMotionSample(MotionEntry* motionEntry,
-                nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords);
+                nsecs_t eventTime, const PointerCoords* pointerCoords);
 
     private:
         Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
@@ -376,6 +440,8 @@
         Pool<MotionSample> mMotionSamplePool;
         Pool<DispatchEntry> mDispatchEntryPool;
         Pool<CommandEntry> mCommandEntryPool;
+
+        void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
     };
 
     /* Manages the dispatch state associated with a single input channel. */
@@ -439,6 +505,8 @@
         }
 
         status_t initialize();
+
+        void setNextTimeoutTime(nsecs_t currentTime, nsecs_t timeout);
     };
 
     sp<InputDispatcherPolicyInterface> mPolicy;
@@ -455,8 +523,17 @@
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
     // Active connections are connections that have a non-empty outbound queue.
+    // We don't use a ref-counted pointer here because we explicitly abort connections
+    // during unregistration which causes the connection's outbound queue to be cleared
+    // and the connection itself to be deactivated.
     Vector<Connection*> mActiveConnections;
 
+    // List of connections that have timed out.  Only used by dispatchOnce()
+    // We don't use a ref-counted pointer here because it is not possible for a connection
+    // to be unregistered while processing timed out connections since we hold the lock for
+    // the duration.
+    Vector<Connection*> mTimedOutConnections;
+
     // Preallocated key and motion event objects used only to ask the input dispatcher policy
     // for the targets of an event that is to be dispatched.
     KeyEvent mReusableKeyEvent;
@@ -468,6 +545,13 @@
     Vector<InputTarget> mCurrentInputTargets;
     bool mCurrentInputTargetsValid; // false while targets are being recomputed
 
+    // Event injection and synchronization.
+    Condition mInjectionResultAvailableCondition;
+    Condition mFullySynchronizedCondition;
+    bool isFullySynchronizedLocked();
+    EventEntry* createEntryFromInputEventLocked(const InputEvent* event);
+    void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
+
     // Key repeat tracking.
     // XXX Move this up to the input reader instead.
     struct KeyRepeatState {
@@ -500,13 +584,18 @@
             nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
 
     // Manage the dispatch cycle for a single connection.
-    void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
+    // These methods are deliberately not Interruptible because doing all of the work
+    // with the mutex held makes it easier to ensure that connection invariants are maintained.
+    // If needed, the methods post commands to run later once the critical bits are done.
+    void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             EventEntry* eventEntry, const InputTarget* inputTarget,
             bool resumeWithAppendedMotionSample);
-    void startDispatchCycleLocked(nsecs_t currentTime, Connection* connection);
-    void finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection);
-    bool timeoutDispatchCycleLocked(nsecs_t currentTime, Connection* connection);
-    bool abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
+    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+    void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+    void timeoutDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+    void resumeAfterTimeoutDispatchCycleLocked(nsecs_t currentTime,
+            const sp<Connection>& connection, nsecs_t newTimeout);
+    void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             bool broken);
     static bool handleReceiveCallback(int receiveFd, int events, void* data);
 
@@ -514,19 +603,17 @@
     void activateConnectionLocked(Connection* connection);
     void deactivateConnectionLocked(Connection* connection);
 
-    // Outbound policy interactions.
-    void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry);
-
     // Interesting events that we might like to log or tell the framework about.
     void onDispatchCycleStartedLocked(
-            nsecs_t currentTime, Connection* connection);
+            nsecs_t currentTime, const sp<Connection>& connection);
     void onDispatchCycleFinishedLocked(
-            nsecs_t currentTime, Connection* connection, bool recoveredFromANR);
+            nsecs_t currentTime, const sp<Connection>& connection, bool recoveredFromANR);
     void onDispatchCycleANRLocked(
-            nsecs_t currentTime, Connection* connection);
+            nsecs_t currentTime, const sp<Connection>& connection);
     void onDispatchCycleBrokenLocked(
-            nsecs_t currentTime, Connection* connection);
+            nsecs_t currentTime, const sp<Connection>& connection);
 
+    // Outbound policy interactions.
     void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
     void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
     void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index 3872c26..7509dd2 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -78,6 +78,15 @@
     /* Unregisters an input channel. */
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
 
+    /* Injects an input event and optionally waits for sync.
+     * 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.
+     * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
+     */
+    virtual int32_t injectInputEvent(const InputEvent* event,
+            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+
     /* Gets input device configuration. */
     virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
 
@@ -118,6 +127,9 @@
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
 
+    virtual int32_t injectInputEvent(const InputEvent* event,
+            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
+
     virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
             int32_t scanCode) const;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 0016503..28706ba 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -367,6 +367,16 @@
     return token;
 }
 
+void IPCThreadState::setStrictModePolicy(int32_t policy)
+{
+    mStrictModePolicy = policy;
+}
+
+
+int32_t IPCThreadState::getStrictModePolicy() const {
+    return mStrictModePolicy;
+}
+
 void IPCThreadState::restoreCallingIdentity(int64_t token)
 {
     mCallingUid = (int)(token>>32);
@@ -588,7 +598,8 @@
 }
 
 IPCThreadState::IPCThreadState()
-    : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
+    : mProcess(ProcessState::self()), mMyThreadId(androidGetTid()),
+      mStrictModePolicy(0)
 {
     pthread_setspecific(gTLS, this);
     clearCaller();
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 0cf41586..a3a3f0e 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -129,19 +129,19 @@
         : BpInterface<IServiceManager>(impl)
     {
     }
-        
+
     virtual sp<IBinder> getService(const String16& name) const
     {
         unsigned n;
         for (n = 0; n < 5; n++){
             sp<IBinder> svc = checkService(name);
             if (svc != NULL) return svc;
-            LOGI("Waiting for sevice %s...\n", String8(name).string());
+            LOGI("Waiting for service %s...\n", String8(name).string());
             sleep(1);
         }
         return NULL;
     }
-    
+
     virtual sp<IBinder> checkService( const String16& name) const
     {
         Parcel data, reply;
@@ -226,4 +226,3 @@
 }
 
 }; // namespace android
-
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 00d2210..c2574bd 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -19,6 +19,7 @@
 
 #include <binder/Parcel.h>
 
+#include <binder/IPCThreadState.h>
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
 #include <utils/Debug.h>
@@ -436,19 +437,22 @@
     return mHasFds;
 }
 
+// Write RPC headers.  (previously just the interface token)
 status_t Parcel::writeInterfaceToken(const String16& interface)
 {
+    writeInt32(IPCThreadState::self()->getStrictModePolicy());
     // currently the interface identification token is just its name as a string
     return writeString16(interface);
 }
 
 bool Parcel::checkInterface(IBinder* binder) const
 {
-    return enforceInterface(binder->getInterfaceDescriptor()); 
+    return enforceInterface(binder->getInterfaceDescriptor());
 }
 
 bool Parcel::enforceInterface(const String16& interface) const
 {
+    int32_t strict_policy = readInt32();
     const String16 str(readString16());
     if (str == interface) {
         return true;
@@ -457,7 +461,7 @@
                 String8(interface).string(), String8(str).string());
         return false;
     }
-} 
+}
 
 const size_t* Parcel::objects() const
 {
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index e7247bd..e606f71 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -160,6 +160,7 @@
     const uint32_t hwFlags = hw.getFlags();
     
     mFormat = format;
+    mReqFormat = format;
     mWidth  = w;
     mHeight = h;
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
@@ -232,7 +233,7 @@
         // if not everything below us is covered, we plug the holes!
         Region holes(clip.subtract(under));
         if (!holes.isEmpty()) {
-            clearWithOpenGL(holes);
+            clearWithOpenGL(holes, 0, 0, 0, 1);
         }
         return;
     }
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 1f66fd0..d5aa53f 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -324,16 +324,6 @@
     glEnable(GL_SCISSOR_TEST);
 
     onDraw(clip);
-
-    /*
-    glDisable(GL_TEXTURE_2D);
-    glDisable(GL_DITHER);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-    glColor4x(0, 0x8000, 0, 0x10000);
-    drawRegion(transparentRegionScreen);
-    glDisable(GL_BLEND);
-    */
 }
 
 void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@@ -343,7 +333,9 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
     glColor4f(red,green,blue,alpha);
-    glDisable(GL_TEXTURE_2D);
+
+    TextureManager::deactivateTextures();
+
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
 
@@ -371,11 +363,9 @@
     const State& s(drawingState());
     
     // bind our texture
-    validateTexture(texture.name);
+    TextureManager::activateTexture(texture, needsFiltering());
     uint32_t width  = texture.width; 
     uint32_t height = texture.height;
-    
-    glEnable(GL_TEXTURE_2D);
 
     GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
     if (UNLIKELY(s.alpha < 0xFF)) {
@@ -431,6 +421,12 @@
         glScalef(texture.wScale, texture.hScale, 1.0f);
     }
 
+    if (needsDithering()) {
+        glEnable(GL_DITHER);
+    } else {
+        glDisable(GL_DITHER);
+    }
+
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glVertexPointer(2, GL_FLOAT, 0, mVertices);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
@@ -444,26 +440,6 @@
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
-void LayerBase::validateTexture(GLint textureName) const
-{
-    glBindTexture(GL_TEXTURE_2D, textureName);
-    // TODO: reload the texture if needed
-    // this is currently done in loadTexture() below
-    if (needsFiltering()) {
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    } else {
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    }
-
-    if (needsDithering()) {
-        glEnable(GL_DITHER);
-    } else {
-        glDisable(GL_DITHER);
-    }
-}
-
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 1a07f32..4288cf7 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -260,7 +260,6 @@
 
 private:
     LayerBase(const LayerBase& rhs);
-    void validateTexture(GLint textureName) const;
 };
 
 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 4c8bae8..c1c440b 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -146,6 +146,9 @@
     Region::const_iterator it = clip.begin();
     Region::const_iterator const end = clip.end();
     if (it != end) {
+#if defined(GL_OES_texture_external)
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+#endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
 
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index d528d2f..906a583 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -119,6 +119,9 @@
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
         glColor4x(0, 0, 0, alpha);
         
+#if defined(GL_OES_texture_external)
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+#endif
 #if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
         if (sUseTexture) {
             glBindTexture(GL_TEXTURE_2D, sTexId);
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 4dea62f..96a5411 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -332,13 +332,6 @@
     dcblk->density      = hw.getDensity();
 
     // Initialize OpenGL|ES
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     glPixelStorei(GL_PACK_ALIGNMENT, 4); 
     glEnableClientState(GL_VERTEX_ARRAY);
@@ -918,17 +911,18 @@
 
 void SurfaceFlinger::debugFlashRegions()
 {
-     const DisplayHardware& hw(graphicPlane(0).displayHardware());
-     const uint32_t flags = hw.getFlags();
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t flags = hw.getFlags();
 
-     if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
-             (flags & DisplayHardware::BUFFER_PRESERVED))) {
-         const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
-                 mDirtyRegion.bounds() : hw.bounds());
-         composeSurfaces(repaint);
-     }
-    
-    glDisable(GL_TEXTURE_2D);
+    if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
+            (flags & DisplayHardware::BUFFER_PRESERVED))) {
+        const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
+                mDirtyRegion.bounds() : hw.bounds());
+        composeSurfaces(repaint);
+    }
+
+    TextureManager::deactivateTextures();
+
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
@@ -936,9 +930,9 @@
     static int toggle = 0;
     toggle = 1 - toggle;
     if (toggle) {
-        glColor4x(0x10000, 0, 0x10000, 0x10000);
+        glColor4f(1, 0, 1, 1);
     } else {
-        glColor4x(0x10000, 0x10000, 0, 0x10000);
+        glColor4f(1, 1, 0, 1);
     }
 
     Region::const_iterator it = mDirtyRegion.begin();
@@ -954,7 +948,7 @@
         glVertexPointer(2, GL_FLOAT, 0, vertices);
         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     }
-    
+
     if (mInvalidRegion.isEmpty()) {
         mDirtyRegion.dump("mDirtyRegion");
         mInvalidRegion.dump("mInvalidRegion");
@@ -962,7 +956,7 @@
     hw.flip(mInvalidRegion);
 
     if (mDebugRegion > 1)
-       usleep(mDebugRegion * 1000);
+        usleep(mDebugRegion * 1000);
 
     glEnable(GL_SCISSOR_TEST);
     //mDirtyRegion.dump("mDirtyRegion");
@@ -982,7 +976,7 @@
     glDisable(GL_DITHER);
 
     if (LIKELY(!mDebugBackground)) {
-        glClearColorx(0,0,0,0);
+        glClearColor(0,0,0,0);
         Region::const_iterator it = region.begin();
         Region::const_iterator const end = region.end();
         while (it != end) {
@@ -998,6 +992,9 @@
         glVertexPointer(2, GL_SHORT, 0, vertices);
         glTexCoordPointer(2, GL_SHORT, 0, tcoords);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#if defined(GL_OES_texture_external)
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+#endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index ee2159b..996a683 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -41,43 +41,112 @@
 {
 }
 
-GLuint TextureManager::createTexture()
+GLenum TextureManager::getTextureTarget(const Image* image) {
+#if defined(GL_OES_texture_external)
+    switch (image->target) {
+        case Texture::TEXTURE_EXTERNAL:
+            return GL_TEXTURE_EXTERNAL_OES;
+    }
+#endif
+    return GL_TEXTURE_2D;
+}
+
+status_t TextureManager::initTexture(Texture* texture)
 {
+    if (texture->name != -1UL)
+        return INVALID_OPERATION;
+
     GLuint textureName = -1;
     glGenTextures(1, &textureName);
-    glBindTexture(GL_TEXTURE_2D, textureName);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    return textureName;
+    texture->name = textureName;
+    texture->width = 0;
+    texture->height = 0;
+
+    const GLenum target = GL_TEXTURE_2D;
+    glBindTexture(target, textureName);
+    glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    return NO_ERROR;
+}
+
+status_t TextureManager::initTexture(Image* pImage, int32_t format)
+{
+    if (pImage->name != -1UL)
+        return INVALID_OPERATION;
+
+    GLuint textureName = -1;
+    glGenTextures(1, &textureName);
+    pImage->name = textureName;
+    pImage->width = 0;
+    pImage->height = 0;
+
+    GLenum target = GL_TEXTURE_2D;
+#if defined(GL_OES_texture_external)
+    if (format && isSupportedYuvFormat(format)) {
+        target = GL_TEXTURE_EXTERNAL_OES;
+        pImage->target = Texture::TEXTURE_EXTERNAL;
+    }
+#endif
+
+    glBindTexture(target, textureName);
+    glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    return NO_ERROR;
 }
 
 bool TextureManager::isSupportedYuvFormat(int format)
 {
+    // TODO: how to we know which YUV formats are supported by the GPU?
+
+    // Adreno 200 supports these
+    // YUVY_adreno
+    // UYVY_adreno
+    // NV21_adreno
+    // YV12_adreno
+    // Adreno 205 adds
+    // NV12_adreno_tiled
+    // NV21_adreno_tiled
+
+    // for now pretend we support them all, failure will happen when
+    // we try to use them.
+    return isYuvFormat(format);
+}
+
+bool TextureManager::isYuvFormat(int format)
+{
     switch (format) {
-        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_422_P:
-        case HAL_PIXEL_FORMAT_YCbCr_420_P:
-        case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        case HAL_PIXEL_FORMAT_YCbCr_420_I:
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            return true;
+    case HAL_PIXEL_FORMAT_NV16:
+    case HAL_PIXEL_FORMAT_NV21:
+    case HAL_PIXEL_FORMAT_IYUV:
+    case HAL_PIXEL_FORMAT_YUV9:
+    case HAL_PIXEL_FORMAT_YUY2:
+    case HAL_PIXEL_FORMAT_UYVY:
+    case HAL_PIXEL_FORMAT_NV12:
+    case HAL_PIXEL_FORMAT_NV61:
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_NV12_ADRENO_TILED:
+    case HAL_PIXEL_FORMAT_NV21_ADRENO_TILED:
+        return true;
     }
     return false;
 }
 
-status_t TextureManager::initEglImage(Image* texture,
+status_t TextureManager::initEglImage(Image* pImage,
         EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
 {
     status_t err = NO_ERROR;
-    if (!texture->dirty) return err;
+    if (!pImage->dirty) return err;
 
     // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
+    if (pImage->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, pImage->image);
+        pImage->image = EGL_NO_IMAGE_KHR;
     }
 
     // construct an EGL_NATIVE_BUFFER_ANDROID
@@ -88,29 +157,27 @@
             EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
             EGL_NONE,                   EGL_NONE
     };
-    texture->image = eglCreateImageKHR(
+    pImage->image = eglCreateImageKHR(
             dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
             (EGLClientBuffer)clientBuf, attrs);
 
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        if (texture->name == -1UL) {
-            texture->name = createTexture();
-            texture->width = 0;
-            texture->height = 0;
+    if (pImage->image != EGL_NO_IMAGE_KHR) {
+        if (pImage->name == -1UL) {
+            initTexture(pImage, buffer->format);
         }
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
+        const GLenum target = getTextureTarget(pImage);
+        glBindTexture(target, pImage->name);
+        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)pImage->image);
         GLint error = glGetError();
         if (error != GL_NO_ERROR) {
             LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
-                    texture->image, error);
+                    pImage->image, error);
             err = INVALID_OPERATION;
         } else {
             // Everything went okay!
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
+            pImage->dirty  = false;
+            pImage->width  = clientBuf->width;
+            pImage->height = clientBuf->height;
         }
     } else {
         LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
@@ -123,11 +190,14 @@
         const Region& dirty, const GGLSurface& t)
 {
     if (texture->name == -1UL) {
-        texture->name = createTexture();
-        texture->width = 0;
-        texture->height = 0;
+        status_t err = initTexture(texture);
+        LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
+        return err;
     }
 
+    if (texture->target != GL_TEXTURE_2D)
+        return INVALID_OPERATION;
+
     glBindTexture(GL_TEXTURE_2D, texture->name);
 
     /*
@@ -197,7 +267,7 @@
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA, texture->potWidth, texture->potHeight, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, data);
-        } else if (isSupportedYuvFormat(t.format)) {
+        } else if (isYuvFormat(t.format)) {
             // just show the Y plane of YUV buffers
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
@@ -225,7 +295,7 @@
                     0, bounds.top, t.width, bounds.height(),
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     t.data + bounds.top*t.stride*4);
-        } else if (isSupportedYuvFormat(t.format)) {
+        } else if (isYuvFormat(t.format)) {
             // just show the Y plane of YUV buffers
             glTexSubImage2D(GL_TEXTURE_2D, 0,
                     0, bounds.top, t.width, bounds.height(),
@@ -236,6 +306,38 @@
     return NO_ERROR;
 }
 
+void TextureManager::activateTexture(const Texture& texture, bool filter)
+{
+    const GLenum target = getTextureTarget(&texture);
+
+    glBindTexture(target, texture.name);
+    glEnable(target);
+
+#if defined(GL_OES_texture_external)
+    if (texture.target == Texture::TEXTURE_2D) {
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+    } else {
+        glDisable(GL_TEXTURE_2D);
+    }
+#endif
+
+    if (filter) {
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    } else {
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    }
+}
+
+void TextureManager::deactivateTextures()
+{
+    glDisable(GL_TEXTURE_2D);
+#if defined(GL_OES_texture_external)
+    glDisable(GL_TEXTURE_EXTERNAL_OES);
+#endif
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
index d0acfe9..1f7fe3f 100644
--- a/libs/surfaceflinger/TextureManager.h
+++ b/libs/surfaceflinger/TextureManager.h
@@ -37,31 +37,36 @@
 // ---------------------------------------------------------------------------
 
 struct Image {
+    enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
     Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
-        transform(0), dirty(true) { }
+        transform(0), dirty(1), target(TEXTURE_2D) { }
     GLuint        name;
     EGLImageKHR   image;
     GLuint        width;
     GLuint        height;
     uint32_t      transform;
-    bool          dirty;
+    unsigned      dirty     : 1;
+    unsigned      target    : 1;
 };
 
 struct Texture : public Image {
-    Texture() : Image(), NPOTAdjust(false)  { }
-    GLuint        potWidth;
-    GLuint        potHeight;
-    GLfloat       wScale;
-    GLfloat       hScale;
-    bool          NPOTAdjust;
+    Texture() : Image(), NPOTAdjust(0) { }
+    GLuint      potWidth;
+    GLuint      potHeight;
+    GLfloat     wScale;
+    GLfloat     hScale;
+    unsigned    NPOTAdjust  : 1;
 };
 
 // ---------------------------------------------------------------------------
 
 class TextureManager {
     uint32_t mFlags;
-    GLuint createTexture();
+    static status_t initTexture(Image* texture, int32_t format);
+    static status_t initTexture(Texture* texture);
     static bool isSupportedYuvFormat(int format);
+    static bool isYuvFormat(int format);
+    static GLenum getTextureTarget(const Image* pImage);
 public:
 
     TextureManager(uint32_t flags);
@@ -73,6 +78,12 @@
     // make active buffer an EGLImage if needed
     status_t initEglImage(Image* texture,
             EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
+
+    // activate a texture
+    static void activateTexture(const Texture& texture, bool filter);
+
+    // deactivate a texture
+    static void deactivateTextures();
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 14dcada..2ad3382 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -25,6 +25,9 @@
 // Log debug messages about performance statistics.
 #define DEBUG_PERFORMANCE_STATISTICS 1
 
+// Log debug messages about input event injection.
+#define DEBUG_INJECTION 1
+
 #include <cutils/log.h>
 #include <ui/InputDispatcher.h>
 
@@ -43,6 +46,10 @@
             || keyCode == KEYCODE_DPAD_RIGHT;
 }
 
+static inline nsecs_t now() {
+    return systemTime(SYSTEM_TIME_MONOTONIC);
+}
+
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
@@ -84,7 +91,7 @@
     nsecs_t nextWakeupTime = LONG_LONG_MAX;
     { // acquire lock
         AutoMutex _l(mLock);
-        currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        currentTime = now();
 
         // Reset the key repeat timer whenever we disallow key events, even if the next event
         // is not a key.  This is to ensure that we abort a key repeat if the device is just coming
@@ -94,33 +101,33 @@
             resetKeyRepeatLocked();
         }
 
-        // Process timeouts for all connections and determine if there are any synchronous
-        // event dispatches pending.
+        // Detect and process timeouts for all connections and determine if there are any
+        // synchronous event dispatches pending.  This step is entirely non-interruptible.
         bool hasPendingSyncTarget = false;
-        for (size_t i = 0; i < mActiveConnections.size(); ) {
+        size_t activeConnectionCount = mActiveConnections.size();
+        for (size_t i = 0; i < activeConnectionCount; i++) {
             Connection* connection = mActiveConnections.itemAt(i);
 
-            nsecs_t connectionTimeoutTime  = connection->nextTimeoutTime;
-            if (connectionTimeoutTime <= currentTime) {
-                bool deactivated = timeoutDispatchCycleLocked(currentTime, connection);
-                if (deactivated) {
-                    // Don't increment i because the connection has been removed
-                    // from mActiveConnections (hence, deactivated).
-                    continue;
-                }
-            }
-
-            if (connectionTimeoutTime < nextWakeupTime) {
-                nextWakeupTime = connectionTimeoutTime;
-            }
-
             if (connection->hasPendingSyncTarget()) {
                 hasPendingSyncTarget = true;
             }
 
-            i += 1;
+            nsecs_t connectionTimeoutTime  = connection->nextTimeoutTime;
+            if (connectionTimeoutTime <= currentTime) {
+                mTimedOutConnections.add(connection);
+            } else if (connectionTimeoutTime < nextWakeupTime) {
+                nextWakeupTime = connectionTimeoutTime;
+            }
         }
 
+        size_t timedOutConnectionCount = mTimedOutConnections.size();
+        for (size_t i = 0; i < timedOutConnectionCount; i++) {
+            Connection* connection = mTimedOutConnections.itemAt(i);
+            timeoutDispatchCycleLocked(currentTime, connection);
+            skipPoll = true;
+        }
+        mTimedOutConnections.clear();
+
         // If we don't have a pending sync target, then we can begin delivering a new event.
         // (Otherwise we wait for dispatch to complete for that target.)
         if (! hasPendingSyncTarget) {
@@ -177,6 +184,11 @@
 
         // Run any deferred commands.
         skipPoll |= runCommandsLockedInterruptible();
+
+        // Wake up synchronization waiters, if needed.
+        if (isFullySynchronizedLocked()) {
+            mFullySynchronizedCondition.broadcast();
+        }
     } // release lock
 
     // If we dispatched anything, don't poll just now.  Wait for the next iteration.
@@ -202,6 +214,7 @@
         Command command = commandEntry->command;
         (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
 
+        commandEntry->connection.clear();
         mAllocator.releaseCommandEntry(commandEntry);
     } while (! mCommandQueue.isEmpty());
     return true;
@@ -272,28 +285,23 @@
     // Synthesize a key repeat after the repeat timeout expired.
     // We reuse the previous key entry if otherwise unreferenced.
     KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
+    uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
     if (entry->refCount == 1) {
+        entry->eventTime = currentTime;
+        entry->downTime = currentTime;
+        entry->policyFlags = policyFlags;
         entry->repeatCount += 1;
     } else {
-        KeyEntry* newEntry = mAllocator.obtainKeyEntry();
-        newEntry->deviceId = entry->deviceId;
-        newEntry->nature = entry->nature;
-        newEntry->policyFlags = entry->policyFlags;
-        newEntry->action = entry->action;
-        newEntry->flags = entry->flags;
-        newEntry->keyCode = entry->keyCode;
-        newEntry->scanCode = entry->scanCode;
-        newEntry->metaState = entry->metaState;
-        newEntry->repeatCount = entry->repeatCount + 1;
+        KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime,
+                entry->deviceId, entry->nature, policyFlags,
+                entry->action, entry->flags, entry->keyCode, entry->scanCode,
+                entry->metaState, entry->repeatCount + 1, currentTime);
 
         mKeyRepeatState.lastKeyEntry = newEntry;
         mAllocator.releaseKeyEntry(entry);
 
         entry = newEntry;
     }
-    entry->eventTime = currentTime;
-    entry->downTime = currentTime;
-    entry->policyFlags = 0;
 
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
 
@@ -358,12 +366,15 @@
             entry->downTime, entry->eventTime);
 
     mCurrentInputTargets.clear();
-    mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags,
+    int32_t injectionResult = mPolicy->getKeyEventTargets(& mReusableKeyEvent,
+            entry->policyFlags, entry->injectorPid, entry->injectorUid,
             mCurrentInputTargets);
 
     mLock.lock();
     mCurrentInputTargetsValid = true;
 
+    setInjectionResultLocked(entry, injectionResult);
+
     dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
 }
 
@@ -384,12 +395,15 @@
             entry->firstSample.pointerCoords);
 
     mCurrentInputTargets.clear();
-    mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags,
+    int32_t injectionResult = mPolicy->getMotionEventTargets(& mReusableMotionEvent,
+            entry->policyFlags, entry->injectorPid, entry->injectorUid,
             mCurrentInputTargets);
 
     mLock.lock();
     mCurrentInputTargetsValid = true;
 
+    setInjectionResultLocked(entry, injectionResult);
+
     dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
 }
 
@@ -410,7 +424,7 @@
                 inputTarget.inputChannel->getReceivePipeFd());
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-            prepareDispatchCycleLocked(currentTime, connection.get(), eventEntry, & inputTarget,
+            prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
                     resumeWithAppendedMotionSample);
         } else {
             LOGW("Framework requested delivery of an input event to channel '%s' but it "
@@ -420,8 +434,8 @@
     }
 }
 
-void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
-        EventEntry* eventEntry, const InputTarget* inputTarget,
+void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
         bool resumeWithAppendedMotionSample) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "
@@ -547,12 +561,13 @@
 
     // If the outbound queue was previously empty, start the dispatch cycle going.
     if (wasEmpty) {
-        activateConnectionLocked(connection);
+        activateConnectionLocked(connection.get());
         startDispatchCycleLocked(currentTime, connection);
     }
 }
 
-void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ startDispatchCycle",
             connection->getInputChannelName());
@@ -682,13 +697,14 @@
     connection->lastDispatchTime = currentTime;
 
     nsecs_t timeout = dispatchEntry->timeout;
-    connection->nextTimeoutTime = (timeout >= 0) ? currentTime + timeout : LONG_LONG_MAX;
+    connection->setNextTimeoutTime(currentTime, timeout);
 
     // Notify other system components.
     onDispatchCycleStartedLocked(currentTime, connection);
 }
 
-void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
             "%01.1fms since dispatch",
@@ -756,31 +772,48 @@
     }
 
     // Outbound queue is empty, deactivate the connection.
-    deactivateConnectionLocked(connection);
+    deactivateConnectionLocked(connection.get());
 }
 
-bool InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ timeoutDispatchCycle",
             connection->getInputChannelName());
 #endif
 
     if (connection->status != Connection::STATUS_NORMAL) {
-        return false;
+        return;
     }
 
     // Enter the not responding state.
     connection->status = Connection::STATUS_NOT_RESPONDING;
     connection->lastANRTime = currentTime;
-    bool deactivated = abortDispatchCycleLocked(currentTime, connection, false /*(not) broken*/);
 
     // Notify other system components.
+    // This enqueues a command which will eventually either call
+    // resumeAfterTimeoutDispatchCycleLocked or abortDispatchCycleLocked.
     onDispatchCycleANRLocked(currentTime, connection);
-    return deactivated;
 }
 
-bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
-        bool broken) {
+void InputDispatcher::resumeAfterTimeoutDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection, nsecs_t newTimeout) {
+#if DEBUG_DISPATCH_CYCLE
+    LOGD("channel '%s' ~ resumeAfterTimeoutDispatchCycleLocked",
+            connection->getInputChannelName());
+#endif
+
+    if (connection->status != Connection::STATUS_NOT_RESPONDING) {
+        return;
+    }
+
+    // Resume normal dispatch.
+    connection->status = Connection::STATUS_NORMAL;
+    connection->setNextTimeoutTime(currentTime, newTimeout);
+}
+
+void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
+        const sp<Connection>& connection, bool broken) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
             connection->getInputChannelName(), broken ? "true" : "false");
@@ -790,14 +823,13 @@
     connection->nextTimeoutTime = LONG_LONG_MAX;
 
     // Clear the outbound queue.
-    bool deactivated = ! connection->outboundQueue.isEmpty();
-    if (deactivated) {
+    if (! connection->outboundQueue.isEmpty()) {
         do {
             DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
             mAllocator.releaseDispatchEntry(dispatchEntry);
         } while (! connection->outboundQueue.isEmpty());
 
-        deactivateConnectionLocked(connection);
+        deactivateConnectionLocked(connection.get());
     }
 
     // Handle the case where the connection appears to be unrecoverably broken.
@@ -811,8 +843,6 @@
             onDispatchCycleBrokenLocked(currentTime, connection);
         }
     }
-
-    return deactivated;
 }
 
 bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -828,13 +858,13 @@
             return false; // remove the callback
         }
 
-        nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        nsecs_t currentTime = now();
 
         sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
         if (events & (POLLERR | POLLHUP | POLLNVAL)) {
             LOGE("channel '%s' ~ Consumer closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+            d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
             return false; // remove the callback
         }
@@ -849,12 +879,12 @@
         if (status) {
             LOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
                     connection->getInputChannelName(), status);
-            d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+            d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
             return false; // remove the callback
         }
 
-        d->finishDispatchCycleLocked(currentTime, connection.get());
+        d->finishDispatchCycleLocked(currentTime, connection);
         d->runCommandsLockedInterruptible();
         return true;
     } // release lock
@@ -869,8 +899,7 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry();
-        newEntry->eventTime = eventTime;
+        ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry(eventTime);
 
         wasEmpty = mInboundQueue.isEmpty();
         mInboundQueue.enqueueAtTail(newEntry);
@@ -902,6 +931,9 @@
                     LOGV("Dropping movement key during app switch: keyCode=%d, action=%d",
                             keyEntry->keyCode, keyEntry->action);
                     mInboundQueue.dequeue(keyEntry);
+
+                    setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+
                     mAllocator.releaseKeyEntry(keyEntry);
                 } else {
                     // stop at last non-movement key
@@ -928,18 +960,10 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        KeyEntry* newEntry = mAllocator.obtainKeyEntry();
-        newEntry->eventTime = eventTime;
-        newEntry->deviceId = deviceId;
-        newEntry->nature = nature;
-        newEntry->policyFlags = policyFlags;
-        newEntry->action = action;
-        newEntry->flags = flags;
-        newEntry->keyCode = keyCode;
-        newEntry->scanCode = scanCode;
-        newEntry->metaState = metaState;
-        newEntry->repeatCount = 0;
-        newEntry->downTime = downTime;
+        int32_t repeatCount = 0;
+        KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime,
+                deviceId, nature, policyFlags, action, flags, keyCode, scanCode,
+                metaState, repeatCount, downTime);
 
         wasEmpty = mInboundQueue.isEmpty();
         mInboundQueue.enqueueAtTail(newEntry);
@@ -992,7 +1016,8 @@
                 }
 
                 if (motionEntry->action != MOTION_EVENT_ACTION_MOVE
-                        || motionEntry->pointerCount != pointerCount) {
+                        || motionEntry->pointerCount != pointerCount
+                        || motionEntry->isInjected()) {
                     // Last motion event in the queue for this device is not compatible for
                     // appending new samples.  Stop here.
                     goto NoBatchingOrStreaming;
@@ -1000,7 +1025,7 @@
 
                 // The last motion event is a move and is compatible for appending.
                 // Do the batching magic.
-                mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords);
+                mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
 #if DEBUG_BATCHING
                 LOGD("Appended motion sample onto batch for most recent "
                         "motion event for this device in the inbound queue.");
@@ -1053,18 +1078,19 @@
                                     dispatchEntry->eventEntry);
                             if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
                                     || syncedMotionEntry->deviceId != deviceId
-                                    || syncedMotionEntry->pointerCount != pointerCount) {
+                                    || syncedMotionEntry->pointerCount != pointerCount
+                                    || syncedMotionEntry->isInjected()) {
                                 goto NoBatchingOrStreaming;
                             }
 
                             // Found synced move entry.  Append sample and resume dispatch.
                             mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
-                                    pointerCount, pointerCoords);
+                                    pointerCoords);
     #if DEBUG_BATCHING
                             LOGD("Appended motion sample onto batch for most recent synchronously "
                                     "dispatched motion event for this device in the outbound queues.");
     #endif
-                            nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+                            nsecs_t currentTime = now();
                             dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
                                     true /*resumeWithAppendedMotionSample*/);
 
@@ -1079,24 +1105,10 @@
         }
 
         // Just enqueue a new motion event.
-        MotionEntry* newEntry = mAllocator.obtainMotionEntry();
-        newEntry->eventTime = eventTime;
-        newEntry->deviceId = deviceId;
-        newEntry->nature = nature;
-        newEntry->policyFlags = policyFlags;
-        newEntry->action = action;
-        newEntry->metaState = metaState;
-        newEntry->edgeFlags = edgeFlags;
-        newEntry->xPrecision = xPrecision;
-        newEntry->yPrecision = yPrecision;
-        newEntry->downTime = downTime;
-        newEntry->pointerCount = pointerCount;
-        newEntry->firstSample.eventTime = eventTime;
-        newEntry->lastSample = & newEntry->firstSample;
-        for (uint32_t i = 0; i < pointerCount; i++) {
-            newEntry->pointerIds[i] = pointerIds[i];
-            newEntry->firstSample.pointerCoords[i] = pointerCoords[i];
-        }
+        MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,
+                deviceId, nature, policyFlags, action, metaState, edgeFlags,
+                xPrecision, yPrecision, downTime,
+                pointerCount, pointerIds, pointerCoords);
 
         wasEmpty = mInboundQueue.isEmpty();
         mInboundQueue.enqueueAtTail(newEntry);
@@ -1107,6 +1119,133 @@
     }
 }
 
+int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
+        int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    LOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
+            "sync=%d, timeoutMillis=%d",
+            event->getType(), injectorPid, injectorUid, sync, timeoutMillis);
+#endif
+
+    nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
+
+    EventEntry* injectedEntry;
+    bool wasEmpty;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        injectedEntry = createEntryFromInputEventLocked(event);
+        injectedEntry->refCount += 1;
+        injectedEntry->injectorPid = injectorPid;
+        injectedEntry->injectorUid = injectorUid;
+
+        wasEmpty = mInboundQueue.isEmpty();
+        mInboundQueue.enqueueAtTail(injectedEntry);
+
+    } // release lock
+
+    if (wasEmpty) {
+        mPollLoop->wake();
+    }
+
+    int32_t injectionResult;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (;;) {
+            injectionResult = injectedEntry->injectionResult;
+            if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
+                break;
+            }
+
+            nsecs_t remainingTimeout = endTime - now();
+            if (remainingTimeout <= 0) {
+                injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
+                sync = false;
+                break;
+            }
+
+            mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
+        }
+
+        if (sync) {
+            while (! isFullySynchronizedLocked()) {
+                nsecs_t remainingTimeout = endTime - now();
+                if (remainingTimeout <= 0) {
+                    injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
+                    break;
+                }
+
+                mFullySynchronizedCondition.waitRelative(mLock, remainingTimeout);
+            }
+        }
+
+        mAllocator.releaseEventEntry(injectedEntry);
+    } // release lock
+
+    return injectionResult;
+}
+
+void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
+    if (entry->isInjected()) {
+#if DEBUG_INJECTION
+        LOGD("Setting input event injection result to %d.  "
+                "injectorPid=%d, injectorUid=%d",
+                 injectionResult, entry->injectorPid, entry->injectorUid);
+#endif
+
+        entry->injectionResult = injectionResult;
+        mInjectionResultAvailableCondition.broadcast();
+    }
+}
+
+bool InputDispatcher::isFullySynchronizedLocked() {
+    return mInboundQueue.isEmpty() && mActiveConnections.isEmpty();
+}
+
+InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
+        const InputEvent* event) {
+    switch (event->getType()) {
+    case INPUT_EVENT_TYPE_KEY: {
+        const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
+        uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
+
+        KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
+                keyEvent->getDeviceId(), keyEvent->getNature(), policyFlags,
+                keyEvent->getAction(), keyEvent->getFlags(),
+                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
+                keyEvent->getRepeatCount(), keyEvent->getDownTime());
+        return keyEntry;
+    }
+
+    case INPUT_EVENT_TYPE_MOTION: {
+        const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
+        uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
+
+        const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
+        const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
+        size_t pointerCount = motionEvent->getPointerCount();
+
+        MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
+                motionEvent->getDeviceId(), motionEvent->getNature(), policyFlags,
+                motionEvent->getAction(), motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
+                motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+                motionEvent->getDownTime(), uint32_t(pointerCount),
+                motionEvent->getPointerIds(), samplePointerCoords);
+        for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
+            sampleEventTimes += 1;
+            samplePointerCoords += pointerCount;
+            mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
+        }
+        return motionEntry;
+    }
+
+    default:
+        assert(false);
+        return NULL;
+    }
+}
+
 void InputDispatcher::resetKeyRepeatLocked() {
     if (mKeyRepeatState.lastKeyEntry) {
         mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry);
@@ -1169,8 +1308,8 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
-        nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+        nsecs_t currentTime = now();
+        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
 
         runCommandsLockedInterruptible();
     } // release lock
@@ -1202,11 +1341,11 @@
 }
 
 void InputDispatcher::onDispatchCycleStartedLocked(
-        nsecs_t currentTime, Connection* connection) {
+        nsecs_t currentTime, const sp<Connection>& connection) {
 }
 
 void InputDispatcher::onDispatchCycleFinishedLocked(
-        nsecs_t currentTime, Connection* connection, bool recoveredFromANR) {
+        nsecs_t currentTime, const sp<Connection>& connection, bool recoveredFromANR) {
     if (recoveredFromANR) {
         LOGI("channel '%s' ~ Recovered from ANR.  %01.1fms since event, "
                 "%01.1fms since dispatch, %01.1fms since ANR",
@@ -1217,12 +1356,12 @@
 
         CommandEntry* commandEntry = postCommandLocked(
                 & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible);
-        commandEntry->inputChannel = connection->inputChannel;
+        commandEntry->connection = connection;
     }
 }
 
 void InputDispatcher::onDispatchCycleANRLocked(
-        nsecs_t currentTime, Connection* connection) {
+        nsecs_t currentTime, const sp<Connection>& connection) {
     LOGI("channel '%s' ~ Not responding!  %01.1fms since event, %01.1fms since dispatch",
             connection->getInputChannelName(),
             connection->getEventLatencyMillis(currentTime),
@@ -1230,47 +1369,64 @@
 
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyInputChannelANRLockedInterruptible);
-    commandEntry->inputChannel = connection->inputChannel;
+    commandEntry->connection = connection;
 }
 
 void InputDispatcher::onDispatchCycleBrokenLocked(
-        nsecs_t currentTime, Connection* connection) {
+        nsecs_t currentTime, const sp<Connection>& connection) {
     LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
             connection->getInputChannelName());
 
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
-    commandEntry->inputChannel = connection->inputChannel;
+    commandEntry->connection = connection;
 }
 
 void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
         CommandEntry* commandEntry) {
-    mLock.unlock();
+    sp<Connection> connection = commandEntry->connection;
 
-    mPolicy->notifyInputChannelBroken(commandEntry->inputChannel);
-    commandEntry->inputChannel.clear();
+    if (connection->status != Connection::STATUS_ZOMBIE) {
+        mLock.unlock();
 
-    mLock.lock();
+        mPolicy->notifyInputChannelBroken(connection->inputChannel);
+
+        mLock.lock();
+    }
 }
 
 void InputDispatcher::doNotifyInputChannelANRLockedInterruptible(
         CommandEntry* commandEntry) {
-    mLock.unlock();
+    sp<Connection> connection = commandEntry->connection;
 
-    mPolicy->notifyInputChannelANR(commandEntry->inputChannel);
-    commandEntry->inputChannel.clear();
+    if (connection->status != Connection::STATUS_ZOMBIE) {
+        mLock.unlock();
 
-    mLock.lock();
+        nsecs_t newTimeout;
+        bool resume = mPolicy->notifyInputChannelANR(connection->inputChannel, newTimeout);
+
+        mLock.lock();
+
+        nsecs_t currentTime = now();
+        if (resume) {
+            resumeAfterTimeoutDispatchCycleLocked(currentTime, connection, newTimeout);
+        } else {
+            abortDispatchCycleLocked(currentTime, connection, false /*(not) broken*/);
+        }
+    }
 }
 
 void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible(
         CommandEntry* commandEntry) {
-    mLock.unlock();
+    sp<Connection> connection = commandEntry->connection;
 
-    mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel);
-    commandEntry->inputChannel.clear();
+    if (connection->status != Connection::STATUS_ZOMBIE) {
+        mLock.unlock();
 
-    mLock.lock();
+        mPolicy->notifyInputChannelRecoveredFromANR(connection->inputChannel);
+
+        mLock.lock();
+    }
 }
 
 
@@ -1279,29 +1435,69 @@
 InputDispatcher::Allocator::Allocator() {
 }
 
+void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type,
+        nsecs_t eventTime) {
+    entry->type = type;
+    entry->refCount = 1;
+    entry->dispatchInProgress = false;
+    entry->injectionResult = INPUT_EVENT_INJECTION_PENDING;
+    entry->injectorPid = -1;
+    entry->injectorUid = -1;
+}
+
 InputDispatcher::ConfigurationChangedEntry*
-InputDispatcher::Allocator::obtainConfigurationChangedEntry() {
+InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) {
     ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
-    entry->refCount = 1;
-    entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED;
-    entry->dispatchInProgress = false;
+    initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime);
     return entry;
 }
 
-InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry() {
+InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t eventTime,
+        int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+        int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
+        int32_t repeatCount, nsecs_t downTime) {
     KeyEntry* entry = mKeyEntryPool.alloc();
-    entry->refCount = 1;
-    entry->type = EventEntry::TYPE_KEY;
-    entry->dispatchInProgress = false;
+    initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime);
+
+    entry->deviceId = deviceId;
+    entry->nature = nature;
+    entry->policyFlags = policyFlags;
+    entry->action = action;
+    entry->flags = flags;
+    entry->keyCode = keyCode;
+    entry->scanCode = scanCode;
+    entry->metaState = metaState;
+    entry->repeatCount = repeatCount;
+    entry->downTime = downTime;
     return entry;
 }
 
-InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry() {
+InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime,
+        int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+        int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
+        nsecs_t downTime, uint32_t pointerCount,
+        const int32_t* pointerIds, const PointerCoords* pointerCoords) {
     MotionEntry* entry = mMotionEntryPool.alloc();
-    entry->refCount = 1;
-    entry->type = EventEntry::TYPE_MOTION;
+    initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime);
+
+    entry->eventTime = eventTime;
+    entry->deviceId = deviceId;
+    entry->nature = nature;
+    entry->policyFlags = policyFlags;
+    entry->action = action;
+    entry->metaState = metaState;
+    entry->edgeFlags = edgeFlags;
+    entry->xPrecision = xPrecision;
+    entry->yPrecision = yPrecision;
+    entry->downTime = downTime;
+    entry->pointerCount = pointerCount;
+    entry->firstSample.eventTime = eventTime;
     entry->firstSample.next = NULL;
-    entry->dispatchInProgress = false;
+    entry->lastSample = & entry->firstSample;
+    for (uint32_t i = 0; i < pointerCount; i++) {
+        entry->pointerIds[i] = pointerIds[i];
+        entry->firstSample.pointerCoords[i] = pointerCoords[i];
+    }
     return entry;
 }
 
@@ -1379,10 +1575,11 @@
 }
 
 void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
-        nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) {
+        nsecs_t eventTime, const PointerCoords* pointerCoords) {
     MotionSample* sample = mMotionSamplePool.alloc();
     sample->eventTime = eventTime;
-    for (int32_t i = 0; i < pointerCount; i++) {
+    uint32_t pointerCount = motionEntry->pointerCount;
+    for (uint32_t i = 0; i < pointerCount; i++) {
         sample->pointerCoords[i] = pointerCoords[i];
     }
 
@@ -1407,6 +1604,10 @@
     return inputPublisher.initialize();
 }
 
+void InputDispatcher::Connection::setNextTimeoutTime(nsecs_t currentTime, nsecs_t timeout) {
+    nextTimeoutTime = (timeout >= 0) ? currentTime + timeout : LONG_LONG_MAX;
+}
+
 const char* InputDispatcher::Connection::getStatusLabel() const {
     switch (status) {
     case STATUS_NORMAL:
diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp
index 7538dd0..32c58b4 100644
--- a/libs/ui/InputManager.cpp
+++ b/libs/ui/InputManager.cpp
@@ -80,6 +80,11 @@
     return mDispatcher->unregisterInputChannel(inputChannel);
 }
 
+int32_t InputManager::injectInputEvent(const InputEvent* event,
+        int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
+    return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, sync, timeoutMillis);
+}
+
 void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const {
     mReader->getCurrentInputConfiguration(outConfiguration);
 }
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 5a280ae..1824054 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -1444,7 +1444,7 @@
         case InputReaderPolicyInterface::ROTATION_90: {
             float xTemp = x;
             x = y;
-            y = mDisplayHeight - xTemp;
+            y = mDisplayWidth - xTemp;
             break;
         }
         case InputReaderPolicyInterface::ROTATION_180: {
@@ -1454,7 +1454,7 @@
         }
         case InputReaderPolicyInterface::ROTATION_270: {
             float xTemp = x;
-            x = mDisplayWidth - y;
+            x = mDisplayHeight - y;
             y = xTemp;
             break;
         }
@@ -1510,7 +1510,7 @@
 
     uint32_t fields = device->trackball.accumulator.fields;
     bool downChanged = fields & InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
-    bool deltaChanged = (fields & DELTA_FIELDS) == DELTA_FIELDS;
+    bool deltaChanged = fields & DELTA_FIELDS;
 
     bool down;
     if (downChanged) {
@@ -1546,10 +1546,10 @@
 
     int32_t pointerId = 0;
     PointerCoords pointerCoords;
-    pointerCoords.x = device->trackball.accumulator.relX
-            * device->trackball.precalculated.xScale;
-    pointerCoords.y = device->trackball.accumulator.relY
-            * device->trackball.precalculated.yScale;
+    pointerCoords.x = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_X
+            ? device->trackball.accumulator.relX * device->trackball.precalculated.xScale : 0;
+    pointerCoords.y = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_Y
+            ? device->trackball.accumulator.relY * device->trackball.precalculated.yScale : 0;
     pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
     pointerCoords.size = 0;
 
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index 9b41804..04c4779 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -70,8 +70,6 @@
     case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
     case HAL_PIXEL_FORMAT_YCrCb_420_SP_TILED:
     case HAL_PIXEL_FORMAT_YCbCr_420_P:
-    case HAL_PIXEL_FORMAT_YCbCr_420_I:
-    case HAL_PIXEL_FORMAT_CbYCrY_420_I:
         info->bitsPerPixel = 12;
      done:
         info->format = format;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 4b61131..2118f8f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -41,6 +41,35 @@
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
 namespace android {
+// ---------------------------------------------------------------------------
+
+// static
+status_t AudioTrack::getMinFrameCount(
+        int* frameCount,
+        int streamType,
+        uint32_t sampleRate)
+{
+    int afSampleRate;
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+    int afFrameCount;
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+    uint32_t afLatency;
+    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+
+    // Ensure that buffer depth covers at least audio hardware latency
+    uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
+    if (minBufCount < 2) minBufCount = 2;
+
+    *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
+              afFrameCount * minBufCount * sampleRate / afSampleRate;
+    return NO_ERROR;
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index 9596148..a5b3ead 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -211,6 +211,11 @@
 #define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5
 #endif
 
+/* GL_OES_texture_external */
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#endif
+
 /*------------------------------------------------------------------------*
  * AMD extension tokens
  *------------------------------------------------------------------------*/
@@ -777,6 +782,11 @@
 typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
 #endif
 
+/* GL_OES_texture_external */
+#ifndef GL_OES_texture_external
+#define GL_OES_texture_external 1
+#endif
+
 /*------------------------------------------------------------------------*
  * AMD extension functions
  *------------------------------------------------------------------------*/
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index d8c9f41..de5d65a 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -146,6 +146,11 @@
 #define GL_INT_10_10_10_2_OES                                   0x8DF7
 #endif
 
+/* GL_OES_texture_external */
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#endif
+
 /*------------------------------------------------------------------------*
  * AMD extension tokens
  *------------------------------------------------------------------------*/
@@ -541,6 +546,11 @@
 #define GL_OES_vertex_type_10_10_10_2 1
 #endif
 
+/* GL_OES_texture_external */
+#ifndef GL_OES_texture_external
+#define GL_OES_texture_external 1
+#endif
+
 /*------------------------------------------------------------------------*
  * AMD extension functions
  *------------------------------------------------------------------------*/
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);
         }
     }
 }
diff --git a/services/java/com/android/server/InputTargetList.java b/services/java/com/android/server/InputTargetList.java
index 1575612..83acc8f 100644
--- a/services/java/com/android/server/InputTargetList.java
+++ b/services/java/com/android/server/InputTargetList.java
@@ -29,7 +29,7 @@
  * 
  * @hide
  */
-public class InputTargetList {
+public final class InputTargetList {
     private InputTarget[] mArray;
     private int mCount;
     
@@ -55,7 +55,7 @@
             count -= 1;
             mArray[count].recycle();
         }
-        // mArray[0] could be set to null here but we do it in toNullTerminatedArray()
+        mArray[0] = null;
     }
     
     /**
@@ -91,7 +91,7 @@
         
         mArray[mCount] = inputTarget;
         mCount += 1;
-        // mArray[mCount] could be set to null here but we do it in toNullTerminatedArray()
+        mArray[mCount] = null;
     }
     
     /**
@@ -99,7 +99,6 @@
      * @return The input target array.
      */
     public InputTarget[] toNullTerminatedArray() {
-        mArray[mCount] = null;
         return mArray;
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 9493161..431cc39 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -44,6 +44,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.text.format.Time;
@@ -64,11 +65,13 @@
 
     private static final int MSG_UPDATE_TWILIGHT = 0;
     private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
+    private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
 
-    private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+    private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
+    private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
     private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
     private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
-    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS;
+    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 15 * DateUtils.MINUTE_IN_MILLIS;
     private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
 
     private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
@@ -215,6 +218,21 @@
         }
     };
 
+    private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+                if (!intent.getBooleanExtra("state", false)) {
+                    // Airplane mode is now off!
+                    mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
+                }
+            } else {
+                // Time zone has changed!
+                mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
+            }
+        }
+    };
+
     // A LocationListener to initialize the network location provider. The location updates
     // are handled through the passive location provider.
     private final LocationListener mEmptyLocationListener =  new LocationListener() {
@@ -304,6 +322,9 @@
                 new IntentFilter(Intent.ACTION_DOCK_EVENT));
         mContext.registerReceiver(mBatteryReceiver,
                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        mContext.registerReceiver(mUpdateLocationReceiver, filter);
 
         PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -586,7 +607,9 @@
 
         boolean mPassiveListenerEnabled;
         boolean mNetworkListenerEnabled;
-
+        boolean mDidFirstInit;
+        long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS;
+        
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -599,6 +622,25 @@
                         }
                     }
                     break;
+                case MSG_GET_NEW_LOCATION_UPDATE:
+                    if (!mNetworkListenerEnabled) {
+                        // Don't do anything -- we are still trying to get a
+                        // location.
+                        return;
+                    }
+                    if ((mLastNetworkRegisterTime+MIN_LOCATION_UPDATE_MS)
+                            >= SystemClock.elapsedRealtime()) {
+                        // Don't do anything -- it hasn't been long enough
+                        // since we last requested an update.
+                        return;
+                    }
+                    
+                    // Unregister the current location monitor, so we can
+                    // register a new one for it to get an immediate update.
+                    mNetworkListenerEnabled = false;
+                    mLocationManager.removeUpdates(mEmptyLocationListener);
+                    
+                    // Fall through to re-register listener.
                 case MSG_ENABLE_LOCATION_UPDATES:
                     // enable network provider to receive at least location updates for a given
                     // distance.
@@ -613,17 +655,21 @@
                     }
                     if (!mNetworkListenerEnabled && networkLocationEnabled) {
                         mNetworkListenerEnabled = true;
+                        mLastNetworkRegisterTime = SystemClock.elapsedRealtime();
                         mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                                 LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
 
-                        if (mLocation == null) {
-                            retrieveLocation();
-                        }
-                        synchronized (mLock) {
-                            if (isDoingNightMode() && mLocation != null
-                                    && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                                updateTwilightLocked();
-                                updateLocked(0, 0);
+                        if (!mDidFirstInit) {
+                            mDidFirstInit = true;
+                            if (mLocation == null) {
+                                retrieveLocation();
+                            }
+                            synchronized (mLock) {
+                                if (isDoingNightMode() && mLocation != null
+                                        && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+                                    updateTwilightLocked();
+                                    updateLocked(0, 0);
+                                }
                             }
                         }
                     }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9bc3931..95ab5bc 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -203,6 +203,10 @@
     /** Adjustment to time to perform a dim, to make it more dramatic.
      */
     static final int DIM_DURATION_MULTIPLIER = 6;
+    
+    // Maximum number of milliseconds to wait for input event injection.
+    // FIXME is this value reasonable?
+    private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
 
     static final int INJECT_FAILED = 0;
     static final int INJECT_SUCCEEDED = 1;
@@ -447,8 +451,6 @@
     final ArrayList<AppWindowToken> mToTopApps = new ArrayList<AppWindowToken>();
     final ArrayList<AppWindowToken> mToBottomApps = new ArrayList<AppWindowToken>();
 
-    //flag to detect fat touch events
-    boolean mFatTouch = false;
     Display mDisplay;
 
     H mH = new H();
@@ -5072,106 +5074,336 @@
         mPolicy.adjustConfigurationLw(config);
         return true;
     }
+    
+    /* Notifies the window manager about a broken input channel.
+     * 
+     * Called by the InputManager.
+     */
+    public void notifyInputChannelBroken(InputChannel inputChannel) {
+        synchronized (mWindowMap) {
+            WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
+            if (windowState == null) {
+                return; // irrelevant
+            }
+            
+            Slog.i(TAG, "WINDOW DIED " + windowState);
+            removeWindowLocked(windowState.mSession, windowState);
+        }
+    }
+    
+    /* Notifies the window manager about a broken input channel.
+     * 
+     * Called by the InputManager.
+     */
+    public long notifyInputChannelANR(InputChannel inputChannel) {
+        IApplicationToken appToken;
+        synchronized (mWindowMap) {
+            WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
+            if (windowState == null) {
+                return -2; // irrelevant, abort dispatching (-2)
+            }
+            
+            Slog.i(TAG, "Input event dispatching timed out sending to "
+                    + windowState.mAttrs.getTitle());
+            appToken = windowState.getAppToken();
+        }
+        
+        try {
+            // Notify the activity manager about the timeout and let it decide whether
+            // to abort dispatching or keep waiting.
+            boolean abort = appToken.keyDispatchingTimedOut();
+            if (abort) {
+                return -2; // abort dispatching
+            }
+            
+            // Return new timeout.
+            // We use -1 for infinite timeout to avoid clash with -2 magic number.
+            long newTimeout = appToken.getKeyDispatchingTimeout() * 1000000;
+            return newTimeout < 0 ? -1 : newTimeout;
+        } catch (RemoteException ex) {
+            return -2; // abort dispatching
+        }
+    }
+
+    /* Notifies the window manager about a broken input channel.
+     * 
+     * Called by the InputManager.
+     */
+    public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
+        // Nothing to do just now.
+        // Just wait for the user to dismiss the ANR dialog.
+        
+        // TODO We could try to automatically dismiss the ANR dialog on recovery
+        //      although that might be disorienting.
+    }
+    
+    private WindowState getWindowStateForInputChannelLocked(InputChannel inputChannel) {
+        int windowCount = mWindows.size();
+        for (int i = 0; i < windowCount; i++) {
+            WindowState windowState = (WindowState) mWindows.get(i);
+            if (windowState.mInputChannel == inputChannel) {
+                return windowState;
+            }
+        }
+        
+        return null;
+    }
 
     // -------------------------------------------------------------
     // Input Events and Focus Management
     // -------------------------------------------------------------
     
-    public void getKeyEventTargets(InputTargetList inputTargets,
-            KeyEvent event, int nature, int policyFlags) {
+    private boolean checkInjectionPermissionTd(WindowState focus,
+            int injectorPid, int injectorUid) {
+        if (injectorUid > 0 && (focus == null || injectorUid != focus.mSession.mUid)) {
+            if (mContext.checkPermission(
+                    android.Manifest.permission.INJECT_EVENTS, injectorPid, injectorUid)
+                    != PackageManager.PERMISSION_GRANTED) {
+                Slog.w(TAG, "Permission denied: injecting key event from pid "
+                        + injectorPid + " uid " + injectorUid + " to window " + focus
+                        + " owned by uid " + focus.mSession.mUid);
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /* Gets the input targets for a key event.
+     * 
+     * Called by the InputManager on the InputDispatcher thread.
+     */
+    public int getKeyEventTargetsTd(InputTargetList inputTargets,
+            KeyEvent event, int nature, int policyFlags, int injectorPid, int injectorUid) {
         if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
 
         // TODO what do we do with mDisplayFrozen?
         // TODO what do we do with focus.mToken.paused?
         
         WindowState focus = getFocusedWindow();
-        wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
         
-        addInputTarget(inputTargets, focus, InputTarget.FLAG_SYNC);
-    }
-    
-    // Target of Motion events
-    WindowState mTouchFocus;
-
-    // Windows above the target who would like to receive an "outside"
-    // touch event for any down events outside of them.
-    // (This is a linked list by way of WindowState.mNextOutsideTouch.)
-    WindowState mOutsideTouchTargets;
-    
-    private void clearTouchFocus() {
-        mTouchFocus = null;
-        mOutsideTouchTargets = null;
-    }
-    
-    public void getMotionEventTargets(InputTargetList inputTargets,
-            MotionEvent event, int nature, int policyFlags) {
-        if (nature == InputQueue.INPUT_EVENT_NATURE_TRACKBALL) {
-            // More or less the same as for keys...
-            WindowState focus = getFocusedWindow();
-            wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-            
-            addInputTarget(inputTargets, focus, InputTarget.FLAG_SYNC);
-            return;
+        if (! checkInjectionPermissionTd(focus, injectorPid, injectorUid)) {
+            return InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED;
         }
         
-        int action = event.getAction();
+        if (mPolicy.interceptKeyTi(focus, event.getKeyCode(), event.getMetaState(),
+                event.getAction() == KeyEvent.ACTION_DOWN,
+                event.getRepeatCount(), event.getFlags())) {
+            // Policy consumed the event.
+            return InputManager.INPUT_EVENT_INJECTION_SUCCEEDED;
+        }
+        
+        if (focus == null) {
+            return InputManager.INPUT_EVENT_INJECTION_FAILED;
+        }
+        
+        wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
+        
+        addInputTargetTd(inputTargets, focus, InputTarget.FLAG_SYNC);
+        return InputManager.INPUT_EVENT_INJECTION_SUCCEEDED;
+    }
+    
+    /* Gets the input targets for a motion event.
+     * 
+     * Called by the InputManager on the InputDispatcher thread.
+     */
+    public int getMotionEventTargetsTd(InputTargetList inputTargets,
+            MotionEvent event, int nature, int policyFlags, int injectorPid, int injectorUid) {
+        switch (nature) {
+            case InputQueue.INPUT_EVENT_NATURE_TRACKBALL:
+                return getMotionEventTargetsForTrackballTd(inputTargets, event, policyFlags,
+                        injectorPid, injectorUid);
+                
+            case InputQueue.INPUT_EVENT_NATURE_TOUCH:
+                return getMotionEventTargetsForTouchTd(inputTargets, event, policyFlags,
+                        injectorPid, injectorUid);
+                
+            default:
+                return InputManager.INPUT_EVENT_INJECTION_FAILED;
+        }
+    }
+    
+    /* Gets the input targets for a trackball event.
+     * 
+     * Called by the InputManager on the InputDispatcher thread.
+     */
+    private int getMotionEventTargetsForTrackballTd(InputTargetList inputTargets,
+            MotionEvent event, int policyFlags, int injectorPid, int injectorUid) {
+        WindowState focus = getFocusedWindow();
+        
+        if (! checkInjectionPermissionTd(focus, injectorPid, injectorUid)) {
+            return InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED;
+        }
+        
+        if (focus == null) {
+            return InputManager.INPUT_EVENT_INJECTION_FAILED;
+        }
+        
+        wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
+        
+        addInputTargetTd(inputTargets, focus, InputTarget.FLAG_SYNC);
+        return InputManager.INPUT_EVENT_INJECTION_SUCCEEDED;
+    }
+    
+    /* Set to true when a fat touch has been detected during the processing of a touch event.
+     * 
+     * Only used by getMotionEventTargetsForTouchTd.
+     * Set to true whenever a fat touch is detected and reset to false on ACTION_UP.
+     */
+    private boolean mFatTouch;
+    
+    /* Set to true when we think the touch event.
+     * 
+     * Only used by getMotionEventTargetsForTouchTd.
+     * Set to true on ACTION_DOWN and set to false on ACTION_UP.
+     */
+    private boolean mTouchDown;
+    
+    /* Current target of Motion events.
+     * 
+     * Only used by getMotionEventTargetsForTouchTd.
+     * Initialized on ACTION_DOWN and cleared on ACTION_UP.
+     */
+    private WindowState mTouchFocus;
 
-        // TODO detect cheek presses somewhere... either here or in native code
+    /* Windows above the target that would like to receive an "outside" touch event
+     * for any down events outside of them.
+     * 
+     * Only used by getMotionEventTargetsForTouchTd.
+     * Initialized on ACTION_DOWN and cleared immediately afterwards.
+     */
+    private ArrayList<WindowState> mOutsideTouchTargets = new ArrayList<WindowState>();
+    
+    /* Wallpaper windows that are currently receiving touch events.
+     * 
+     * Only used by getMotionEventTargetsForTouchTd.
+     * Initialized on ACTION_DOWN and cleared on ACTION_UP.
+     */
+    private ArrayList<WindowState> mWallpaperTouchTargets = new ArrayList<WindowState>();
+    
+    /* Gets the input targets for a touch event.
+     * 
+     * Called by the InputManager on the InputDispatcher thread.
+     */
+    private int getMotionEventTargetsForTouchTd(InputTargetList inputTargets,
+            MotionEvent event, int policyFlags, int injectorPid, int injectorUid) {
+        final int action = event.getAction();
+        
+        if (action == MotionEvent.ACTION_DOWN) {
+            updateTouchFocusBeforeDownTd(event, policyFlags);
+        } else {
+            updateTouchFocusBeforeNonDownTd(event, policyFlags);
+        }
+
+        boolean skipDelivery = false;
+        int touchTargetFlags = 0;
+        
+        int injectionResult = InputManager.INPUT_EVENT_INJECTION_SUCCEEDED;
+        WindowState focusedTouchTarget = mTouchFocus;
+        if (focusedTouchTarget == null) {
+            // In this case we are either dropping the event, or have received
+            // a move or up without a down.  It is common to receive move
+            // events in such a way, since this means the user is moving the
+            // pointer without actually pressing down.  All other cases should
+            // be atypical, so let's log them.
+            if (action != MotionEvent.ACTION_MOVE) {
+                Slog.w(TAG, "No window to dispatch pointer action " + action);
+                injectionResult = InputManager.INPUT_EVENT_INJECTION_FAILED;
+            }
+        } else {
+            // We have a valid focused touch target.
+            if (! checkInjectionPermissionTd(focusedTouchTarget, injectorPid, injectorUid)) {
+                return InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED;
+            }
+            
+            wakeupIfNeeded(focusedTouchTarget, eventType(event));
+            
+            if ((focusedTouchTarget.mAttrs.flags &
+                    WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
+                // Target wants to ignore fat touch events
+                boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(event);
+                
+                if (cheekPress) {
+                    if ((action == MotionEvent.ACTION_DOWN)) {
+                        mFatTouch = true;
+                        skipDelivery = true;
+                    } else {
+                        if (! mFatTouch) {
+                            // cancel the earlier event
+                            touchTargetFlags |= InputTarget.FLAG_CANCEL;
+                            mFatTouch = true;
+                        } else {
+                            skipDelivery = true;
+                        }
+                    }
+                }
+            }
+        }
+        
+        if (! skipDelivery) {
+            int outsideTargetCount = mOutsideTouchTargets.size();
+            for (int i = 0; i < outsideTargetCount; i++) {
+                WindowState outsideTouchTarget = mOutsideTouchTargets.get(i);
+                addInputTargetTd(inputTargets, outsideTouchTarget,
+                        InputTarget.FLAG_OUTSIDE | touchTargetFlags);
+            }
+            
+            int wallpaperTargetCount = mWallpaperTouchTargets.size();
+            for (int i = 0; i < wallpaperTargetCount; i++) {
+                WindowState wallpaperTouchTarget = mWallpaperTouchTargets.get(i);
+                addInputTargetTd(inputTargets, wallpaperTouchTarget,
+                        touchTargetFlags);
+            }
+            
+            if (focusedTouchTarget != null) {
+                addInputTargetTd(inputTargets, focusedTouchTarget,
+                        InputTarget.FLAG_SYNC | touchTargetFlags);
+            }
+        }
+
+        if (action == MotionEvent.ACTION_UP) {
+            updateTouchFocusAfterUpTd(event, policyFlags);
+        }
+        
+        return injectionResult;
+    }
+    
+    private void updateTouchFocusBeforeDownTd(MotionEvent event, int policyFlags) {
+        if (mTouchDown) {
+            // This is weird, we got a down, but we thought it was already down!
+            // XXX: We should probably send an ACTION_UP to the current target.
+            Slog.w(TAG, "Pointer down received while already down in: " + mTouchFocus);
+            updateTouchFocusAfterUpTd(event, policyFlags);
+        }
+        
+        mTouchDown = true;
+        mPowerManager.logPointerDownEvent();
         
         final boolean screenWasOff = (policyFlags & WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
-        
-        WindowState target = mTouchFocus;
-        
-        if (action == MotionEvent.ACTION_UP) {
-            // let go of our target
-            mPowerManager.logPointerUpEvent();
-            clearTouchFocus();
-        } else if (action == MotionEvent.ACTION_DOWN) {
-            // acquire a new target
-            mPowerManager.logPointerDownEvent();
-        
-            synchronized (mWindowMap) {
-                if (mTouchFocus != null) {
-                    // this is weird, we got a pen down, but we thought it was
-                    // already down!
-                    // XXX: We should probably send an ACTION_UP to the current
-                    // target.
-                    Slog.w(TAG, "Pointer down received while already down in: "
-                            + mTouchFocus);
-                    clearTouchFocus();
+        synchronized (mWindowMap) {
+            final int x = (int) event.getX();
+            final int y = (int) event.getY();
+
+            final ArrayList windows = mWindows;
+            final int N = windows.size();
+            WindowState topErrWindow = null;
+            final Rect tmpRect = mTempRect;
+            for (int i= N - 1; i >= 0; i--) {
+                WindowState child = (WindowState) windows.get(i);
+                //Slog.i(TAG, "Checking dispatch to: " + child);
+                
+                final int flags = child.mAttrs.flags;
+                if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
+                    if (topErrWindow == null) {
+                        topErrWindow = child;
+                    }
                 }
-
-                // ACTION_DOWN is special, because we need to lock next events to
-                // the window we'll land onto.
-                final int x = (int) event.getX();
-                final int y = (int) event.getY();
-
-                final ArrayList windows = mWindows;
-                final int N = windows.size();
-                WindowState topErrWindow = null;
-                final Rect tmpRect = mTempRect;
-                for (int i=N-1; i>=0; i--) {
-                    WindowState child = (WindowState)windows.get(i);
-                    //Slog.i(TAG, "Checking dispatch to: " + child);
-                    final int flags = child.mAttrs.flags;
-                    if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
-                        if (topErrWindow == null) {
-                            topErrWindow = child;
-                        }
-                    }
-                    if (!child.isVisibleLw()) {
-                        //Slog.i(TAG, "Not visible!");
-                        continue;
-                    }
-                    if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                        //Slog.i(TAG, "Not touchable!");
-                        if ((flags & WindowManager.LayoutParams
-                                .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                            child.mNextOutsideTouch = mOutsideTouchTargets;
-                            mOutsideTouchTargets = child;
-                        }
-                        continue;
-                    }
+                
+                if (!child.isVisibleLw()) {
+                    //Slog.i(TAG, "Not visible!");
+                    continue;
+                }
+                
+                if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 0) {
                     tmpRect.set(child.mFrame);
                     if (child.mTouchableInsets == ViewTreeObserver
                                 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
@@ -5197,7 +5429,7 @@
                         |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
                     if (tmpRect.contains(x, y) || touchFlags == 0) {
                         //Slog.i(TAG, "Using this target!");
-                        if (!screenWasOff || (flags &
+                        if (! screenWasOff || (flags &
                                 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
                             mTouchFocus = child;
                         } else {
@@ -5206,143 +5438,76 @@
                         }
                         break;
                     }
-
-                    if ((flags & WindowManager.LayoutParams
-                            .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                        child.mNextOutsideTouch = mOutsideTouchTargets;
-                        mOutsideTouchTargets = child;
-                        //Slog.i(TAG, "Adding to outside target list: " + child);
-                    }
                 }
 
-                // if there's an error window but it's not accepting
-                // focus (typically because it is not yet visible) just
-                // wait for it -- any other focused window may in fact
-                // be in ANR state.
-                if (topErrWindow != null && mTouchFocus != topErrWindow) {
-                    mTouchFocus = null;
+                if ((flags & WindowManager.LayoutParams
+                        .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
+                    //Slog.i(TAG, "Adding to outside target list: " + child);
+                    mOutsideTouchTargets.add(child);
                 }
             }
-            
-            target = mTouchFocus;
-        }
-        
-        if (target != null) {
-            wakeupIfNeeded(target, eventType(event));
-        }
-        
-        int targetFlags = 0;
-        if (target == null) {
-            // In this case we are either dropping the event, or have received
-            // a move or up without a down.  It is common to receive move
-            // events in such a way, since this means the user is moving the
-            // pointer without actually pressing down.  All other cases should
-            // be atypical, so let's log them.
-            if (action != MotionEvent.ACTION_MOVE) {
-                Slog.w(TAG, "No window to dispatch pointer action " + action);
-            }
-        } else {
-            if ((target.mAttrs.flags &
-                    WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
-                //target wants to ignore fat touch events
-                boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(event);
-                //explicit flag to return without processing event further
-                boolean returnFlag = false;
-                if((action == MotionEvent.ACTION_DOWN)) {
-                    mFatTouch = false;
-                    if(cheekPress) {
-                        mFatTouch = true;
-                        returnFlag = true;
-                    }
-                } else {
-                    if(action == MotionEvent.ACTION_UP) {
-                        if(mFatTouch) {
-                            //earlier even was invalid doesnt matter if current up is cheekpress or not
-                            mFatTouch = false;
-                            returnFlag = true;
-                        } else if(cheekPress) {
-                            //cancel the earlier event
-                            targetFlags |= InputTarget.FLAG_CANCEL;
-                            action = MotionEvent.ACTION_CANCEL;
-                        }
-                    } else if(action == MotionEvent.ACTION_MOVE) {
-                        if(mFatTouch) {
-                            //two cases here
-                            //an invalid down followed by 0 or moves(valid or invalid)
-                            //a valid down,  invalid move, more moves. want to ignore till up
-                            returnFlag = true;
-                        } else if(cheekPress) {
-                            //valid down followed by invalid moves
-                            //an invalid move have to cancel earlier action
-                            targetFlags |= InputTarget.FLAG_CANCEL;
-                            action = MotionEvent.ACTION_CANCEL;
-                            if (DEBUG_INPUT) Slog.v(TAG, "Sending cancel for invalid ACTION_MOVE");
-                            //note that the subsequent invalid moves will not get here
-                            mFatTouch = true;
-                        }
-                    }
-                } //else if action
-                if(returnFlag) {
-                    return;
-                }
-            } //end if target
-        }        
-        
-        synchronized (mWindowMap) {
-            if (target != null && ! target.isVisibleLw()) {
-                target = null;
+
+            // If there's an error window but it's not accepting focus (typically because
+            // it is not yet visible) just wait for it -- any other focused window may in fact
+            // be in ANR state.
+            if (topErrWindow != null && mTouchFocus != topErrWindow) {
+                mTouchFocus = null;
             }
             
-            if (action == MotionEvent.ACTION_DOWN) {
-                while (mOutsideTouchTargets != null) {
-                    addInputTarget(inputTargets, mOutsideTouchTargets,
-                            InputTarget.FLAG_OUTSIDE | targetFlags);
-                    mOutsideTouchTargets = mOutsideTouchTargets.mNextOutsideTouch;
-                }
+            // Drop the touch focus if the window is not visible.
+            if (mTouchFocus != null && ! mTouchFocus.isVisibleLw()) {
+                mTouchFocus = null;
             }
             
-            // If we sent an initial down to the wallpaper, then continue
-            // sending events until the final up.
-            // Alternately if we are on top of the wallpaper, then the wallpaper also
-            // gets to see this movement.
-            if (mSendingPointersToWallpaper ||
-                    (target != null && action == MotionEvent.ACTION_DOWN
-                            && mWallpaperTarget == target
-                            && target.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD)) {
+            // Determine wallpaper targets.
+            if (mTouchFocus != null
+                    && mTouchFocus == mWallpaperTarget
+                    && mTouchFocus.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
                 int curTokenIndex = mWallpaperTokens.size();
                 while (curTokenIndex > 0) {
                     curTokenIndex--;
                     WindowToken token = mWallpaperTokens.get(curTokenIndex);
+                    
                     int curWallpaperIndex = token.windows.size();
                     while (curWallpaperIndex > 0) {
                         curWallpaperIndex--;
                         WindowState wallpaper = token.windows.get(curWallpaperIndex);
                         if ((wallpaper.mAttrs.flags &
-                                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                            continue;
+                                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 0) {
+                            mWallpaperTouchTargets.add(wallpaper);
                         }
-                        
-                        switch (action) {
-                            case MotionEvent.ACTION_DOWN:
-                                mSendingPointersToWallpaper = true;
-                                break;
-                            case MotionEvent.ACTION_UP:
-                                mSendingPointersToWallpaper = false;
-                                break;
-                        }
-                        
-                        addInputTarget(inputTargets, wallpaper, targetFlags);
                     }
                 }
             }
-            
-            if (target != null) {
-                addInputTarget(inputTargets, target, InputTarget.FLAG_SYNC | targetFlags);
+        }
+    }
+
+    private void updateTouchFocusBeforeNonDownTd(MotionEvent event, int policyFlags) {
+        synchronized (mWindowMap) {
+            // Drop the touch focus if the window is not visible.
+            if (mTouchFocus != null && ! mTouchFocus.isVisibleLw()) {
+                mTouchFocus = null;
+                mWallpaperTouchTargets.clear();
             }
         }
     }
     
-    private void addInputTarget(InputTargetList inputTargets, WindowState window, int flags) {
+    private void updateTouchFocusAfterUpTd(MotionEvent event, int policyFlags) {
+        mFatTouch = false;
+        mTouchDown = false;
+        mTouchFocus = null;
+        mOutsideTouchTargets.clear();
+        mWallpaperTouchTargets.clear();
+        
+        mPowerManager.logPointerUpEvent();
+    }
+
+    /* Adds a window to a list of input targets.
+     * Do NOT call this method while holding any locks because the call to
+     * appToken.getKeyDispatchingTimeout() can potentially call into the ActivityManager
+     * and create a deadlock hazard.
+     */
+    private void addInputTargetTd(InputTargetList inputTargets, WindowState window, int flags) {
         if (window.mInputChannel == null) {
             return;
         }
@@ -5874,8 +6039,8 @@
         
         final int result;
         if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectKeyEvent(newEvent,
-                    InputQueue.INPUT_EVENT_NATURE_KEY, sync, pid, uid);
+            result = mInputManager.injectKeyEvent(newEvent, InputQueue.INPUT_EVENT_NATURE_KEY,
+                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         } else {
             result = dispatchKey(newEvent, pid, uid);
             if (sync) {
@@ -5884,14 +6049,7 @@
         }
         
         Binder.restoreCallingIdentity(ident);
-        switch (result) {
-            case INJECT_NO_PERMISSION:
-                throw new SecurityException(
-                        "Injecting to another application requires INJECT_EVENTS permission");
-            case INJECT_SUCCEEDED:
-                return true;
-        }
-        return false;
+        return reportInjectionResult(result);
     }
 
     /**
@@ -5910,8 +6068,8 @@
         
         final int result;
         if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev,
-                    InputQueue.INPUT_EVENT_NATURE_TOUCH, sync, pid, uid);
+            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TOUCH,
+                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         } else {
             result = dispatchPointer(null, ev, pid, uid);
             if (sync) {
@@ -5920,14 +6078,7 @@
         }
         
         Binder.restoreCallingIdentity(ident);
-        switch (result) {
-            case INJECT_NO_PERMISSION:
-                throw new SecurityException(
-                        "Injecting to another application requires INJECT_EVENTS permission");
-            case INJECT_SUCCEEDED:
-                return true;
-        }
-        return false;
+        return reportInjectionResult(result);
     }
 
     /**
@@ -5946,8 +6097,8 @@
         
         final int result;
         if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev,
-                    InputQueue.INPUT_EVENT_NATURE_TRACKBALL, sync, pid, uid);
+            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TRACKBALL,
+                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         } else {
             result = dispatchTrackball(null, ev, pid, uid);
             if (sync) {
@@ -5956,14 +6107,37 @@
         }
         
         Binder.restoreCallingIdentity(ident);
-        switch (result) {
-            case INJECT_NO_PERMISSION:
-                throw new SecurityException(
-                        "Injecting to another application requires INJECT_EVENTS permission");
-            case INJECT_SUCCEEDED:
-                return true;
+        return reportInjectionResult(result);
+    }
+    
+    private boolean reportInjectionResult(int result) {
+        if (ENABLE_NATIVE_INPUT_DISPATCH) {
+            switch (result) {
+                case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+                    Slog.w(TAG, "Input event injection permission denied.");
+                    throw new SecurityException(
+                            "Injecting to another application requires INJECT_EVENTS permission");
+                case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
+                    Slog.v(TAG, "Input event injection succeeded.");
+                    return true;
+                case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
+                    Slog.w(TAG, "Input event injection timed out.");
+                    return false;
+                case InputManager.INPUT_EVENT_INJECTION_FAILED:
+                default:
+                    Slog.w(TAG, "Input event injection failed.");
+                    return false;
+            }
+        } else {
+            switch (result) {
+                case INJECT_NO_PERMISSION:
+                    throw new SecurityException(
+                            "Injecting to another application requires INJECT_EVENTS permission");
+                case INJECT_SUCCEEDED:
+                    return true;
+            }
+            return false;
         }
-        return false;
     }
 
     private WindowState getFocusedWindow() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ec209eda..4d18191 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9538,7 +9538,7 @@
             sb.append("Subject: ").append(subject).append("\n");
         }
         sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
-        if (crashInfo.durationMillis != -1) {
+        if (crashInfo != null && crashInfo.durationMillis != -1) {
             sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n");
         }
         sb.append("\n");
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index ab3922f..1a6119a 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -50,6 +50,9 @@
     jmethodID isScreenBright;
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
+    jmethodID notifyInputChannelBroken;
+    jmethodID notifyInputChannelANR;
+    jmethodID notifyInputChannelRecoveredFromANR;
     jmethodID virtualKeyFeedback;
     jmethodID hackInterceptKey;
     jmethodID goToSleep;
@@ -73,6 +76,13 @@
     jfieldID height;
 } gVirtualKeyDefinitionClassInfo;
 
+static struct {
+    jclass clazz;
+
+    jmethodID ctor;
+    jfieldID mArray;
+} gInputTargetListClassInfo;
+
 // ----------------------------------------------------------------------------
 
 class NativeInputManager : public virtual RefBase,
@@ -89,6 +99,10 @@
     void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
     void setDisplayOrientation(int32_t displayId, int32_t orientation);
 
+    status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
+            jweak inputChannelObjWeak);
+    status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
+
     /* --- InputReaderPolicyInterface implementation --- */
 
     virtual bool getDisplayInfo(int32_t displayId,
@@ -112,18 +126,20 @@
 
     virtual void notifyConfigurationChanged(nsecs_t when);
     virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel);
-    virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel);
+    virtual bool notifyInputChannelANR(const sp<InputChannel>& inputChannel,
+            nsecs_t& outNewTimeout);
     virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel);
     virtual nsecs_t getKeyRepeatTimeout();
-    virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
-            Vector<InputTarget>& outTargets);
-    virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
-            Vector<InputTarget>& outTargets);
+    virtual int32_t getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+            int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
+    virtual int32_t getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+            int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
 
 private:
     sp<InputManager> mInputManager;
 
     jobject mCallbacksObj;
+    jobject mReusableInputTargetListObj;
 
     // Cached filtering policies.
     int32_t mFilterTouchEvents;
@@ -138,12 +154,20 @@
     bool isScreenOn();
     bool isScreenBright();
 
+    // Weak references to all currently registered input channels by receive fd.
+    Mutex mInputChannelRegistryLock;
+    KeyedVector<int, jweak> mInputChannelObjWeakByReceiveFd;
+
+    jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel);
+
     static inline JNIEnv* jniEnv() {
         return AndroidRuntime::getJNIEnv();
     }
 
     static bool isAppSwitchKey(int32_t keyCode);
-    static bool checkExceptionFromCallback(JNIEnv* env, const char* methodName);
+    static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
+    static void populateInputTargets(JNIEnv* env, jobject inputTargetListObj,
+            Vector<InputTarget>& outTargets);
 };
 
 // ----------------------------------------------------------------------------
@@ -155,6 +179,11 @@
 
     mCallbacksObj = env->NewGlobalRef(callbacksObj);
 
+    jobject inputTargetListObj = env->NewObject(gInputTargetListClassInfo.clazz,
+            gInputTargetListClassInfo.ctor);
+    mReusableInputTargetListObj = env->NewGlobalRef(inputTargetListObj);
+    env->DeleteLocalRef(inputTargetListObj);
+
     sp<EventHub> eventHub = new EventHub();
     mInputManager = new InputManager(eventHub, this, this);
 }
@@ -163,13 +192,14 @@
     JNIEnv* env = jniEnv();
 
     env->DeleteGlobalRef(mCallbacksObj);
+    env->DeleteGlobalRef(mReusableInputTargetListObj);
 }
 
 bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
     return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
 }
 
-bool NativeInputManager::checkExceptionFromCallback(JNIEnv* env, const char* methodName) {
+bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     if (env->ExceptionCheck()) {
         LOGE("An exception was thrown by callback '%s'.", methodName);
         LOGE_EX(env);
@@ -196,6 +226,86 @@
     }
 }
 
+status_t NativeInputManager::registerInputChannel(JNIEnv* env,
+        const sp<InputChannel>& inputChannel, jobject inputChannelObj) {
+    jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj);
+    if (! inputChannelObjWeak) {
+        LOGE("Could not create weak reference for input channel.");
+        LOGE_EX(env);
+        return NO_MEMORY;
+    }
+
+    status_t status;
+    {
+        AutoMutex _l(mInputChannelRegistryLock);
+
+        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
+                inputChannel->getReceivePipeFd());
+        if (index >= 0) {
+            LOGE("Input channel object '%s' has already been registered",
+                    inputChannel->getName().string());
+            status = INVALID_OPERATION;
+            goto DeleteWeakRef;
+        }
+
+        mInputChannelObjWeakByReceiveFd.add(inputChannel->getReceivePipeFd(),
+                inputChannelObjWeak);
+    }
+
+    status = mInputManager->registerInputChannel(inputChannel);
+    if (! status) {
+        return OK;
+    }
+
+    {
+        AutoMutex _l(mInputChannelRegistryLock);
+        mInputChannelObjWeakByReceiveFd.removeItem(inputChannel->getReceivePipeFd());
+    }
+
+DeleteWeakRef:
+    env->DeleteWeakGlobalRef(inputChannelObjWeak);
+    return status;
+}
+
+status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
+        const sp<InputChannel>& inputChannel) {
+    jweak inputChannelObjWeak;
+    {
+        AutoMutex _l(mInputChannelRegistryLock);
+
+        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
+                inputChannel->getReceivePipeFd());
+        if (index < 0) {
+            LOGE("Input channel object '%s' is not currently registered",
+                    inputChannel->getName().string());
+            return INVALID_OPERATION;
+        }
+
+        inputChannelObjWeak = mInputChannelObjWeakByReceiveFd.valueAt(index);
+        mInputChannelObjWeakByReceiveFd.removeItemsAt(index);
+    }
+
+    env->DeleteWeakGlobalRef(inputChannelObjWeak);
+
+    return mInputManager->unregisterInputChannel(inputChannel);
+}
+
+jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env,
+        const sp<InputChannel>& inputChannel) {
+    {
+        AutoMutex _l(mInputChannelRegistryLock);
+
+        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
+                inputChannel->getReceivePipeFd());
+        if (index < 0) {
+            return NULL;
+        }
+
+        jweak inputChannelObjWeak = mInputChannelObjWeakByReceiveFd.valueAt(index);
+        return env->NewLocalRef(inputChannelObjWeak);
+    }
+}
+
 bool NativeInputManager::getDisplayInfo(int32_t displayId,
         int32_t* width, int32_t* height, int32_t* orientation) {
     bool result = false;
@@ -216,7 +326,7 @@
     JNIEnv* env = jniEnv();
 
     jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenOn);
-    if (checkExceptionFromCallback(env, "isScreenOn")) {
+    if (checkAndClearExceptionFromCallback(env, "isScreenOn")) {
         return true;
     }
     return result;
@@ -226,7 +336,7 @@
     JNIEnv* env = jniEnv();
 
     jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenBright);
-    if (checkExceptionFromCallback(env, "isScreenBright")) {
+    if (checkAndClearExceptionFromCallback(env, "isScreenBright")) {
         return true;
     }
     return result;
@@ -245,7 +355,7 @@
 
     env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyFeedback,
             when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
-    checkExceptionFromCallback(env, "virtualKeyFeedback");
+    checkAndClearExceptionFromCallback(env, "virtualKeyFeedback");
 }
 
 int32_t NativeInputManager::interceptKey(nsecs_t when,
@@ -267,7 +377,7 @@
 
     jint wmActions = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.hackInterceptKey,
             deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
-    if (checkExceptionFromCallback(env, "hackInterceptKey")) {
+    if (checkAndClearExceptionFromCallback(env, "hackInterceptKey")) {
         wmActions = 0;
     }
 
@@ -284,12 +394,12 @@
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
         env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.goToSleep, when);
-        checkExceptionFromCallback(env, "goToSleep");
+        checkAndClearExceptionFromCallback(env, "goToSleep");
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
         env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.pokeUserActivityForKey, when);
-        checkExceptionFromCallback(env, "pokeUserActivityForKey");
+        checkAndClearExceptionFromCallback(env, "pokeUserActivityForKey");
     }
 
     if (wmActions & WM_ACTION_PASS_TO_USER) {
@@ -297,7 +407,7 @@
 
         if (down && isAppSwitchKey(keyCode)) {
             env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
-            checkExceptionFromCallback(env, "notifyAppSwitchComing");
+            checkAndClearExceptionFromCallback(env, "notifyAppSwitchComing");
 
             actions |= InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING;
         }
@@ -358,7 +468,7 @@
     case SW_LID:
         env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
                 when, switchValue == 0);
-        checkExceptionFromCallback(env, "notifyLidSwitchChanged");
+        checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
         break;
     }
 
@@ -371,7 +481,7 @@
 
         jboolean result = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.filterTouchEvents);
-        if (checkExceptionFromCallback(env, "filterTouchEvents")) {
+        if (checkAndClearExceptionFromCallback(env, "filterTouchEvents")) {
             result = false;
         }
 
@@ -386,7 +496,7 @@
 
         jboolean result = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.filterJumpyTouchEvents);
-        if (checkExceptionFromCallback(env, "filterJumpyTouchEvents")) {
+        if (checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) {
             result = false;
         }
 
@@ -400,10 +510,10 @@
     JNIEnv* env = jniEnv();
 
     jstring deviceNameStr = env->NewStringUTF(deviceName.string());
-    if (! checkExceptionFromCallback(env, "getVirtualKeyDefinitions")) {
+    if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions")) {
         jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
                 gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr));
-        if (! checkExceptionFromCallback(env, "getVirtualKeyDefinitions") && result) {
+        if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions") && result) {
             jsize length = env->GetArrayLength(result);
             for (jsize i = 0; i < length; i++) {
                 jobject item = env->GetObjectArrayElement(result, i);
@@ -433,7 +543,7 @@
 
     jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
             gCallbacksClassInfo.getExcludedDeviceNames));
-    if (! checkExceptionFromCallback(env, "getExcludedDeviceNames") && result) {
+    if (! checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && result) {
         jsize length = env->GetArrayLength(result);
         for (jsize i = 0; i < length; i++) {
             jstring item = jstring(env->GetObjectArrayElement(result, i));
@@ -460,7 +570,7 @@
 
     env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyConfigurationChanged,
             when, config.touchScreen, config.keyboard, config.navigation);
-    checkExceptionFromCallback(env, "notifyConfigurationChanged");
+    checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
 }
 
 void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) {
@@ -468,16 +578,47 @@
     LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string());
 #endif
 
-    // TODO
+    JNIEnv* env = jniEnv();
+
+    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
+    if (inputChannelObjLocal) {
+        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelBroken,
+                inputChannelObjLocal);
+        checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken");
+
+        env->DeleteLocalRef(inputChannelObjLocal);
+    }
 }
 
-void NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel) {
+bool NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel,
+        nsecs_t& outNewTimeout) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     LOGD("notifyInputChannelANR - inputChannel='%s'",
             inputChannel->getName().string());
 #endif
 
-    // TODO
+    JNIEnv* env = jniEnv();
+
+    jlong newTimeout;
+    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
+    if (inputChannelObjLocal) {
+        newTimeout = env->CallLongMethod(mCallbacksObj,
+                gCallbacksClassInfo.notifyInputChannelANR, inputChannelObjLocal);
+        if (checkAndClearExceptionFromCallback(env, "notifyInputChannelANR")) {
+            newTimeout = -2;
+        }
+
+        env->DeleteLocalRef(inputChannelObjLocal);
+    } else {
+        newTimeout = -2;
+    }
+
+    if (newTimeout == -2) {
+        return false; // abort
+    }
+
+    outNewTimeout = newTimeout;
+    return true; // resume
 }
 
 void NativeInputManager::notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) {
@@ -486,7 +627,16 @@
             inputChannel->getName().string());
 #endif
 
-    // TODO
+    JNIEnv* env = jniEnv();
+
+    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
+    if (inputChannelObjLocal) {
+        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelRecoveredFromANR,
+                inputChannelObjLocal);
+        checkAndClearExceptionFromCallback(env, "notifyInputChannelRecoveredFromANR");
+
+        env->DeleteLocalRef(inputChannelObjLocal);
+    }
 }
 
 nsecs_t NativeInputManager::getKeyRepeatTimeout() {
@@ -499,73 +649,83 @@
     }
 }
 
-void NativeInputManager::getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
-        Vector<InputTarget>& outTargets) {
+int32_t NativeInputManager::getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+        int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("getKeyEventTargets - policyFlags=%d", policyFlags);
+    LOGD("getKeyEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+            policyFlags, injectorPid, injectorUid);
 #endif
 
     JNIEnv* env = jniEnv();
 
+    jint injectionResult;
     jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
     if (! keyEventObj) {
         LOGE("Could not obtain DVM KeyEvent object to get key event targets.");
+        injectionResult = INPUT_EVENT_INJECTION_FAILED;
     } else {
-        jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
-                gCallbacksClassInfo.getKeyEventTargets,
-                keyEventObj, jint(keyEvent->getNature()), jint(policyFlags)));
-        if (! checkExceptionFromCallback(env, "getKeyEventTargets") && result) {
-            jsize length = env->GetArrayLength(result);
-            for (jsize i = 0; i < length; i++) {
-                jobject item = env->GetObjectArrayElement(result, i);
-                if (! item) {
-                    break; // found null element indicating end of used portion of the array
-                }
-
-                outTargets.add();
-                android_view_InputTarget_toNative(env, item, & outTargets.editTop());
-
-                env->DeleteLocalRef(item);
-            }
-            env->DeleteLocalRef(result);
+        jint injectionResult = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.getKeyEventTargets, mReusableInputTargetListObj,
+                keyEventObj, jint(keyEvent->getNature()), jint(policyFlags),
+                jint(injectorPid), jint(injectorUid));
+        if (checkAndClearExceptionFromCallback(env, "getKeyEventTargets")) {
+            injectionResult = INPUT_EVENT_INJECTION_FAILED;
+        } else {
+            populateInputTargets(env, mReusableInputTargetListObj, outTargets);
         }
         env->DeleteLocalRef(keyEventObj);
     }
+    return injectionResult;
 }
 
-void NativeInputManager::getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
-        Vector<InputTarget>& outTargets) {
+int32_t NativeInputManager::getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+        int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("getMotionEventTargets - policyFlags=%d", policyFlags);
+    LOGD("getMotionEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+            policyFlags, injectorPid, injectorUid);
 #endif
 
     JNIEnv* env = jniEnv();
 
+    jint injectionResult;
     jobject motionEventObj = android_view_MotionEvent_fromNative(env, motionEvent);
     if (! motionEventObj) {
         LOGE("Could not obtain DVM MotionEvent object to get key event targets.");
+        injectionResult = INPUT_EVENT_INJECTION_FAILED;
     } else {
-        jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
-                gCallbacksClassInfo.getMotionEventTargets,
-                motionEventObj, jint(motionEvent->getNature()), jint(policyFlags)));
-        if (! checkExceptionFromCallback(env, "getMotionEventTargets") && result) {
-            jsize length = env->GetArrayLength(result);
-            for (jsize i = 0; i < length; i++) {
-                jobject item = env->GetObjectArrayElement(result, i);
-                if (! item) {
-                    break; // found null element indicating end of used portion of the array
-                }
-
-                outTargets.add();
-                android_view_InputTarget_toNative(env, item, & outTargets.editTop());
-
-                env->DeleteLocalRef(item);
-            }
-            env->DeleteLocalRef(result);
+        jint injectionResult = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.getMotionEventTargets, mReusableInputTargetListObj,
+                motionEventObj, jint(motionEvent->getNature()), jint(policyFlags),
+                jint(injectorPid), jint(injectorUid));
+        if (checkAndClearExceptionFromCallback(env, "getMotionEventTargets")) {
+            injectionResult = INPUT_EVENT_INJECTION_FAILED;
+        } else {
+            populateInputTargets(env, mReusableInputTargetListObj, outTargets);
         }
         android_view_MotionEvent_recycle(env, motionEventObj);
         env->DeleteLocalRef(motionEventObj);
     }
+    return injectionResult;
+}
+
+void NativeInputManager::populateInputTargets(JNIEnv* env, jobject inputTargetListObj,
+        Vector<InputTarget>& outTargets) {
+    jobjectArray inputTargetArray = jobjectArray(env->GetObjectField(
+            inputTargetListObj, gInputTargetListClassInfo.mArray));
+
+    jsize length = env->GetArrayLength(inputTargetArray);
+    for (jsize i = 0; i < length; i++) {
+        jobject item = env->GetObjectArrayElement(inputTargetArray, i);
+        if (! item) {
+            break; // found null element indicating end of used portion of the array
+        }
+
+        outTargets.add();
+        android_view_InputTarget_toNative(env, item, & outTargets.editTop());
+
+        env->DeleteLocalRef(item);
+    }
+    env->DeleteLocalRef(inputTargetArray);
 }
 
 
@@ -686,7 +846,7 @@
             "the input manager!", inputChannel->getName().string());
 
     if (gNativeInputManager != NULL) {
-        gNativeInputManager->getInputManager()->unregisterInputChannel(inputChannel);
+        gNativeInputManager->unregisterInputChannel(env, inputChannel);
     }
 }
 
@@ -703,7 +863,9 @@
         return;
     }
 
-    status_t status = gNativeInputManager->getInputManager()->registerInputChannel(inputChannel);
+
+    status_t status = gNativeInputManager->registerInputChannel(
+            env, inputChannel, inputChannelObj);
     if (status) {
         jniThrowRuntimeException(env, "Failed to register input channel.  "
                 "Check logs for details.");
@@ -729,13 +891,41 @@
 
     android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
 
-    status_t status = gNativeInputManager->getInputManager()->unregisterInputChannel(inputChannel);
+    status_t status = gNativeInputManager->unregisterInputChannel(env, inputChannel);
     if (status) {
         jniThrowRuntimeException(env, "Failed to unregister input channel.  "
                 "Check logs for details.");
     }
 }
 
+static jint android_server_InputManager_nativeInjectKeyEvent(JNIEnv* env, jclass clazz,
+        jobject keyEventObj, jint nature, jint injectorPid, jint injectorUid,
+        jboolean sync, jint timeoutMillis) {
+    if (checkInputManagerUnitialized(env)) {
+        return INPUT_EVENT_INJECTION_FAILED;
+    }
+
+    KeyEvent keyEvent;
+    android_view_KeyEvent_toNative(env, keyEventObj, nature, & keyEvent);
+
+    return gNativeInputManager->getInputManager()->injectInputEvent(& keyEvent,
+            injectorPid, injectorUid, sync, timeoutMillis);
+}
+
+static jint android_server_InputManager_nativeInjectMotionEvent(JNIEnv* env, jclass clazz,
+        jobject motionEventObj, jint nature, jint injectorPid, jint injectorUid,
+        jboolean sync, jint timeoutMillis) {
+    if (checkInputManagerUnitialized(env)) {
+        return INPUT_EVENT_INJECTION_FAILED;
+    }
+
+    MotionEvent motionEvent;
+    android_view_MotionEvent_toNative(env, motionEventObj, nature, & motionEvent);
+
+    return gNativeInputManager->getInputManager()->injectInputEvent(& motionEvent,
+            injectorPid, injectorUid, sync, timeoutMillis);
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gInputManagerMethods[] = {
@@ -759,7 +949,11 @@
     { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V",
             (void*) android_server_InputManager_nativeRegisterInputChannel },
     { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
-            (void*) android_server_InputManager_nativeUnregisterInputChannel }
+            (void*) android_server_InputManager_nativeUnregisterInputChannel },
+    { "nativeInjectKeyEvent", "(Landroid/view/KeyEvent;IIIZI)I",
+            (void*) android_server_InputManager_nativeInjectKeyEvent },
+    { "nativeInjectMotionEvent", "(Landroid/view/MotionEvent;IIIZI)I",
+            (void*) android_server_InputManager_nativeInjectMotionEvent }
 };
 
 #define FIND_CLASS(var, className) \
@@ -796,6 +990,15 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz,
             "notifyLidSwitchChanged", "(JZ)V");
 
+    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
+            "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V");
+
+    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelANR, gCallbacksClassInfo.clazz,
+            "notifyInputChannelANR", "(Landroid/view/InputChannel;)J");
+
+    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelRecoveredFromANR, gCallbacksClassInfo.clazz,
+            "notifyInputChannelRecoveredFromANR", "(Landroid/view/InputChannel;)V");
+
     GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
             "virtualKeyFeedback", "(JIIIIIIJ)V");
 
@@ -825,10 +1028,12 @@
             "getExcludedDeviceNames", "()[Ljava/lang/String;");
 
     GET_METHOD_ID(gCallbacksClassInfo.getKeyEventTargets, gCallbacksClassInfo.clazz,
-            "getKeyEventTargets", "(Landroid/view/KeyEvent;II)[Landroid/view/InputTarget;");
+            "getKeyEventTargets",
+            "(Lcom/android/server/InputTargetList;Landroid/view/KeyEvent;IIII)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.getMotionEventTargets, gCallbacksClassInfo.clazz,
-            "getMotionEventTargets", "(Landroid/view/MotionEvent;II)[Landroid/view/InputTarget;");
+            "getMotionEventTargets",
+            "(Lcom/android/server/InputTargetList;Landroid/view/MotionEvent;IIII)I");
 
     // VirtualKeyDefinition
 
@@ -850,6 +1055,16 @@
     GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
             "height", "I");
 
+    // InputTargetList
+
+    FIND_CLASS(gInputTargetListClassInfo.clazz, "com/android/server/InputTargetList");
+
+    GET_METHOD_ID(gInputTargetListClassInfo.ctor, gInputTargetListClassInfo.clazz,
+            "<init>", "()V");
+
+    GET_FIELD_ID(gInputTargetListClassInfo.mArray, gInputTargetListClassInfo.clazz,
+            "mArray", "[Landroid/view/InputTarget;");
+
     return 0;
 }
 
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index fcb9d55..d9262f6 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -147,9 +147,6 @@
      * @param intent The Intent as if supplied to {@link android.content.Context#startService}.
      */
     protected void startService(Intent intent) {
-        assertFalse(mServiceStarted);
-        assertFalse(mServiceBound);
-        
         if (!mServiceAttached) {
             setupService();
         }
@@ -159,7 +156,7 @@
             mService.onCreate();
             mServiceCreated = true;
         }
-        mService.onStart(intent, mServiceId);
+        mService.onStartCommand(intent, 0, mServiceId);
         
         mServiceStarted = true;
     }
@@ -183,9 +180,6 @@
      * @return Return an IBinder for making further calls into the Service.
      */
     protected IBinder bindService(Intent intent) {
-        assertFalse(mServiceStarted);
-        assertFalse(mServiceBound);
-        
         if (!mServiceAttached) {
             setupService();
         }