Merge "Add OBB file helper class" into gingerbread
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 0a2899f..1100886 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -535,6 +535,7 @@
      * application does not need a particular callback, a null can be passed
      * instead of a callback method.
      *
+     * This method is only valid after {@link #startPreview()} has been called.
      * This method will stop the preview. Applications should not call {@link
      * #stopPreview()} before this. After jpeg callback is received,
      * applications can call {@link #startPreview()} to restart the preview.
@@ -562,6 +563,7 @@
      * application does not need a particular callback, a null can be passed
      * instead of a callback method.
      *
+     * This method is only valid after {@link #startPreview()} has been called.
      * This method will stop the preview. Applications should not call {@link
      * #stopPreview()} before this. After jpeg callback is received,
      * applications can call {@link #startPreview()} to restart the preview.
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e2f5ada..3490ac0 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -20,24 +20,32 @@
 /**
  * Class representing a sensor. Use {@link SensorManager#getSensorList} to get
  * the list of available Sensors.
+ *
+ * @see SensorManager
+ * @see SensorEventListener
+ * @see SensorEvent
+ *
  */
 public class Sensor {
 
     /**
      * A constant describing an accelerometer sensor type. See
-     * {@link android.hardware.SensorEvent SensorEvent} for more details.
+     * {@link android.hardware.SensorEvent#values SensorEvent.values} for more
+     * details.
      */
     public static final int TYPE_ACCELEROMETER = 1;
 
     /**
      * A constant describing a magnetic field sensor type. See
-     * {@link android.hardware.SensorEvent SensorEvent} for more details.
+     * {@link android.hardware.SensorEvent#values SensorEvent.values} 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.
+     * {@link android.hardware.SensorEvent#values SensorEvent.values} for more
+     * details.
      *
      * @deprecated use {@link android.hardware.SensorManager#getOrientation
      *             SensorManager.getOrientation()} instead.
@@ -50,7 +58,8 @@
 
     /**
      * A constant describing an light sensor type. See
-     * {@link android.hardware.SensorEvent SensorEvent} for more details.
+     * {@link android.hardware.SensorEvent#values SensorEvent.values} for more
+     * details.
      */
     public static final int TYPE_LIGHT = 5;
 
@@ -62,7 +71,8 @@
 
     /**
      * A constant describing an proximity sensor type. See
-     * {@link android.hardware.SensorEvent SensorEvent} for more details.
+     * {@link android.hardware.SensorEvent#values SensorEvent.values} for more
+     * details.
      */
     public static final int TYPE_PROXIMITY = 8;
 
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index dfefe7e..70519ff 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -28,17 +28,20 @@
  * </p>
  *
  * <p>
- * The coordinate space is defined relative to the screen of the phone in its
+ * The coordinate-system 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.
+ * The X axis is horizontal and points to the right, the Y axis is vertical and
+ * points up and the Z axis points towards the outside of the front face of the
+ * screen. In this system, coordinates behind the screen have negative Z values.
+ * </p>
+ *
+ * <p>
+ * <center><img src="../../../images/axis_device.png"
+ * alt="Sensors coordinate-system diagram." border="0" /></center>
  * </p>
  *
  * <p>
@@ -46,63 +49,139 @@
  * Android 2D APIs where the origin is in the top-left corner.
  * </p>
  *
- * <pre>
- *   x<0         x>0
- *                ^
- *                |
- *    +-----------+-->  y>0
- *    |           |
- *    |           |
- *    |           |
- *    |           |   / z<0
- *    |           |  /
- *    |           | /
- *    O-----------+/
- *    |[]  [ ]  []/
- *    +----------/+     y<0
- *              /
- *             /
- *           |/ z>0 (toward the sky)
+ * @see SensorManager
+ * @see SensorEvent
+ * @see Sensor
  *
- *    O: Origin (x=0,y=0,z=0)
- * </pre>
  */
 
 public class SensorEvent {
     /**
      * <p>
-     * The length and contents of the values array vary depending on which
-     * {@link android.hardware.Sensor sensor} type is being monitored (see also
-     * {@link SensorEvent} for a definition of the coordinate system used):
+     * The length and contents of the {@link #values values} array depends on
+     * which {@link android.hardware.Sensor sensor} type is being monitored (see
+     * also {@link SensorEvent} for a definition of the coordinate system used).
      * </p>
      *
-     * <h3>{@link android.hardware.Sensor#TYPE_ORIENTATION
-     * Sensor.TYPE_ORIENTATION}:</h3> All values are angles in degrees.
-     *
+     * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER
+     * Sensor.TYPE_ACCELEROMETER}:</h4> All values are in SI units (m/s^2)
+     * 
      * <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
-     *
+     * values[0]: Acceleration minus Gx on the x-axis
+     * </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.
-     *
+     * values[1]: Acceleration minus Gy on the y-axis
+     * </p>
      * <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.
+     * values[2]: Acceleration minus Gz on the z-axis
+     * </p>
      * </ul>
-     *
+     * 
      * <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).
-     *
+     * A sensor of this type measures the acceleration applied to the device
+     * (<b>Ad</b>). Conceptually, it does so by measuring forces applied to the
+     * sensor itself (<b>Fs</b>) using the relation:
+     * </p>
+     * 
+     * <b><center>Ad = - ·Fs / mass</center></b>
+     * 
+     * <p>
+     * In particular, the force of gravity is always influencing the measured
+     * acceleration:
+     * </p>
+     * 
+     * <b><center>Ad = -g - ·F / mass</center></b>
+     * 
+     * <p>
+     * For this reason, when the device is sitting on a table (and obviously not
+     * accelerating), the accelerometer reads a magnitude of <b>g</b> = 9.81
+     * m/s^2
+     * </p>
+     * 
+     * <p>
+     * Similarly, when the device is in free-fall and therefore dangerously
+     * accelerating towards to ground at 9.81 m/s^2, its accelerometer reads a
+     * magnitude of 0 m/s^2.
+     * </p>
+     * 
+     * <p>
+     * It should be apparent that in order to measure the real acceleration of
+     * the device, the contribution of the force of gravity must be eliminated.
+     * This can be achieved by applying a <i>high-pass</i> filter. Conversely, a
+     * <i>low-pass</i> filter can be used to isolate the force of gravity.
+     * </p>
+     * <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>
+     * 
+     * 
+     * <h4>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD
+     * Sensor.TYPE_MAGNETIC_FIELD}:</h4>
+     * All values are in micro-Tesla (uT) and measure the ambient magnetic field
+     * in the X, Y and Z axis.
+     * 
+     * <h4>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h4>
+     * 
+     * <ul>
+     * <p>
+     * values[0]: Ambient light level in SI lux units
+     * </ul>
+     * 
+     * <h4>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
+     * </h4>
+     * 
+     * <ul>
+     * <p>
+     * values[0]: Proximity sensor distance measured in centimeters
+     * </ul>
+     * 
+     * <p>
+     * <b>Note:</b> Some proximity sensors only support a binary <i>near</i> or
+     * <i>far</i> measurement. In this case, the sensor should report its
+     * {@link android.hardware.Sensor#getMaximumRange() maximum range} value in
+     * the <i>far</i> state and a lesser value in the <i>near</i> state.
+     * </p>
+     * 
+     * <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
+     * Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
+     * 
+     * <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>
+     * 
+     * <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>
+     * 
+     * <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>
+     * </ul>
+     * 
      * <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>
+     * 
      * <p>
      * <b>Note:</b> This sensor type exists for legacy reasons, please use
      * {@link android.hardware.SensorManager#getRotationMatrix
@@ -111,62 +190,16 @@
      * remapCoordinateSystem()} and
      * {@link android.hardware.SensorManager#getOrientation getOrientation()} to
      * compute these values instead.
-     *
-     * <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.
-     *
-     * <ul>
+     * </p>
+     * 
      * <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>
-     * <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.
+     * <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>
+     * 
+     * @see SensorEvent
+     * @see GeomagneticField
      */
     public final float[] values;
 
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f60e2d7..492f8cc 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -46,6 +46,30 @@
  * {@link android.content.Context#getSystemService(java.lang.String)
  * Context.getSystemService()} with the argument
  * {@link android.content.Context#SENSOR_SERVICE}.
+ *
+ * <pre class="prettyprint">
+ * public class SensorActivity extends Activity, implements SensorEventListener {
+ *     private final SensorManager mSensorManager;
+ *     private final Sensor mAccelerometer;
+ *
+ *     public SensorActivity() {
+ *         mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
+ *         mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ *         mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+ *     }
+ *
+ *     public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ *     }
+ *
+ *     public abstract void onSensorChanged(SensorEvent event) {
+ *     }
+ * }
+ * </pre>
+ *
+ * @see SensorEventListener
+ * @see SensorEvent
+ * @see Sensor
+ *
  */
 public class SensorManager
 {
@@ -57,7 +81,7 @@
     /**
      * A constant describing an orientation sensor. See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -66,7 +90,7 @@
     /**
      * A constant describing an accelerometer. See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -75,7 +99,7 @@
     /**
      * A constant describing a temperature sensor See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -84,7 +108,7 @@
     /**
      * A constant describing a magnetic sensor See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -93,7 +117,7 @@
     /**
      * 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
@@ -102,7 +126,7 @@
     /**
      * A constant describing a proximity sensor See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -111,7 +135,7 @@
     /**
      * A constant describing a Tricorder See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -120,7 +144,7 @@
     /**
      * A constant describing an orientation sensor. See
      * {@link android.hardware.SensorListener SensorListener} for more details.
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -128,7 +152,7 @@
 
     /**
      * A constant that includes all sensors
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -136,7 +160,7 @@
 
     /**
      * Smallest sensor ID
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -144,7 +168,7 @@
 
     /**
      * Largest sensor ID
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -154,7 +178,7 @@
     /**
      * Index of the X value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -163,7 +187,7 @@
     /**
      * Index of the Y value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -172,7 +196,7 @@
     /**
      * Index of the Z value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -181,7 +205,7 @@
     /**
      * Offset to the untransformed values in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged}
-     * 
+     *
      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
     @Deprecated
@@ -190,7 +214,7 @@
     /**
      * 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
@@ -199,7 +223,7 @@
     /**
      * 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
@@ -208,7 +232,7 @@
     /**
      * 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
@@ -250,7 +274,7 @@
     /** Minimum magnetic field on Earth's surface */
     public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
 
-    
+
     /** Maximum luminance of sunlight in lux */
     public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
     /** luminance of sunlight in lux */
@@ -268,7 +292,7 @@
     /** 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 */
@@ -673,11 +697,14 @@
      * 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.
+     *
+     * @see #getDefaultSensor(int)
+     * @see Sensor
      */
     public List<Sensor> getSensorList(int type) {
         // cache the returned lists the first time
@@ -707,11 +734,14 @@
      * 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
-     * 
+     *
      * @return the default sensors matching the asked type.
+     *
+     * @see #getSensorList(int)
+     * @see Sensor
      */
     public Sensor getDefaultSensor(int type) {
         // TODO: need to be smarter, for now, just return the 1st sensor
@@ -721,17 +751,17 @@
 
     /**
      * 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 <code>true</code> if the sensor is supported and successfully
      *         enabled
      */
@@ -742,24 +772,24 @@
 
     /**
      * 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 <code>true</code> if the sensor is supported and successfully
      *         enabled
      */
@@ -819,14 +849,14 @@
 
     /**
      * 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
      */
@@ -891,11 +921,11 @@
 
     /**
      * Unregisters a listener for all sensors.
-     * 
+     *
      * @deprecated This method is deprecated, use
      *             {@link SensorManager#unregisterListener(SensorEventListener)}
      *             instead.
-     * 
+     *
      * @param listener
      *        a SensorListener object
      */
@@ -906,12 +936,16 @@
 
     /**
      * Unregisters a listener for the sensors with which it is registered.
-     * 
+     *
      * @param listener
      *        a SensorEventListener object
+     *
      * @param sensor
      *        the sensor to unregister from
-     * 
+     *
+     * @see #unregisterListener(SensorEventListener)
+     * @see #registerListener(SensorEventListener, Sensor, int)
+     *
      */
     public void unregisterListener(SensorEventListener listener, Sensor sensor) {
         unregisterListener((Object)listener, sensor);
@@ -919,10 +953,13 @@
 
     /**
      * Unregisters a listener for all sensors.
-     * 
+     *
      * @param listener
      *        a SensorListener object
-     * 
+     *
+     * @see #unregisterListener(SensorEventListener, Sensor)
+     * @see #registerListener(SensorEventListener, Sensor, int)
+     *
      */
     public void unregisterListener(SensorEventListener listener) {
         unregisterListener((Object)listener);
@@ -931,14 +968,14 @@
     /**
      * 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
@@ -946,10 +983,14 @@
      *        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.
-     * 
+     *
+     * @see #registerListener(SensorEventListener, Sensor, int, Handler)
+     * @see #unregisterListener(SensorEventListener)
+     * @see #unregisterListener(SensorEventListener, Sensor)
+     *
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
         return registerListener(listener, sensor, rate, null);
@@ -958,14 +999,14 @@
     /**
      * 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
@@ -973,14 +1014,18 @@
      *        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.
-     * 
+     *
+     * @see #registerListener(SensorEventListener, Sensor, int)
+     * @see #unregisterListener(SensorEventListener)
+     * @see #unregisterListener(SensorEventListener, Sensor)
+     *
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
             Handler handler) {
@@ -1107,7 +1152,7 @@
      * 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>
@@ -1115,6 +1160,12 @@
      * points towards the magnetic North Pole.</li>
      * <li>Z points towards the sky and is perpendicular to the ground.</li>
      * </ul>
+     *
+     * <p>
+     * <center><img src="../../../images/axis_globe.png"
+     * alt="Sensors coordinate-system diagram." border="0" /></center>
+     * </p>
+     *
      * <p>
      * <hr>
      * <p>
@@ -1129,27 +1180,27 @@
      * 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}.
      * <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>
-     * 
+     *
      * <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)}.
@@ -1161,44 +1212,44 @@
      * 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>
-     * 
+     *
      * <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
      * 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
@@ -1208,7 +1259,7 @@
      *        {@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
@@ -1217,10 +1268,14 @@
      *        {@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.
+     *
+     * @see #getInclination(float[])
+     * @see #getOrientation(float[], float[])
+     * @see #remapCoordinateSystem(float[], int, int, float[])
      */
 
     public static boolean getRotationMatrix(float[] R, float[] I,
@@ -1289,16 +1344,22 @@
     /**
      * 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}.
+     *
      * @return The geomagnetic inclination angle in radians.
+     *
+     * @see #getRotationMatrix(float[], float[], float[], float[])
+     * @see #getOrientation(float[], float[])
+     * @see GeomagneticField
+     *
      */
     public static float getInclination(float[] I) {
         if (I.length == 9) {
             return (float)Math.atan2(I[5], I[4]);
         } else {
-            return (float)Math.atan2(I[6], I[5]);            
+            return (float)Math.atan2(I[6], I[5]);
         }
     }
 
@@ -1309,7 +1370,7 @@
      * 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,
@@ -1319,60 +1380,62 @@
      * 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>
      * <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 <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.
+     *
+     * @see #getRotationMatrix(float[], float[], float[], float[])
      */
 
     public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
@@ -1464,14 +1527,23 @@
      * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li>
      * </ul>
      * <p>
+     * <center><img src="../../../images/axis_device.png"
+     * alt="Sensors coordinate-system diagram." border="0" /></center>
+     * </p>
+     * <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.
+     * 
      * @return The array values passed as argument.
+     * 
+     * @see #getRotationMatrix(float[], float[], float[], float[])
+     * @see GeomagneticField
      */
    public static float[] getOrientation(float[] R, float values[]) {
         /*
@@ -1480,12 +1552,12 @@
          *   |  R[ 4]   R[ 5]   R[ 6]   0  |
          *   |  R[ 8]   R[ 9]   R[10]   0  |
          *   \      0       0       0   1  /
-         *   
+         *
          * 3x3 (length=9) case:
          *   /  R[ 0]   R[ 1]   R[ 2]  \
          *   |  R[ 3]   R[ 4]   R[ 5]  |
          *   \  R[ 6]   R[ 7]   R[ 8]  /
-         * 
+         *
          */
         if (R.length == 9) {
             values[0] = (float)Math.atan2(R[1], R[4]);
@@ -1647,7 +1719,7 @@
             }
         }
     }
-    
+
     class LmsFilter {
         private static final int SENSORS_RATE_MS = 20;
         private static final int COUNT = 12;
@@ -1715,7 +1787,7 @@
         }
     }
 
-    
+
     private static native void nativeClassInit();
 
     private static native int sensors_module_init();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 249ad62..6f12f19 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -216,20 +216,7 @@
             @Override
             public void handleTouch(MotionEvent event, Runnable finishedCallback) {
                 try {
-                    synchronized (mLock) {
-                        if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                            if (mPendingMove != null) {
-                                mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                                mPendingMove.recycle();
-                            }
-                            mPendingMove = event;
-                        } else {
-                            mPendingMove = null;
-                        }
-                        Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                                event);
-                        mCaller.sendMessage(msg);
-                    }
+                    dispatchPointer(event);
                 } finally {
                     finishedCallback.run();
                 }
@@ -238,26 +225,6 @@
         
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public boolean onDispatchPointer(MotionEvent event, long eventTime,
-                    boolean callWhenDone) {
-                synchronized (mLock) {
-                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                        if (mPendingMove != null) {
-                            mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                            mPendingMove.recycle();
-                        }
-                        mPendingMove = event;
-                    } else {
-                        mPendingMove = null;
-                    }
-                    Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                            event);
-                    mCaller.sendMessage(msg);
-                }
-                return false;
-            }
-            
-            @Override
             public void resized(int w, int h, Rect coveredInsets,
                     Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
@@ -466,6 +433,22 @@
          */
         public void onSurfaceDestroyed(SurfaceHolder holder) {
         }
+        
+        private void dispatchPointer(MotionEvent event) {
+            synchronized (mLock) {
+                if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                    if (mPendingMove != null) {
+                        mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
+                        mPendingMove.recycle();
+                    }
+                    mPendingMove = event;
+                } else {
+                    mPendingMove = null;
+                }
+                Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
+                mCaller.sendMessage(msg);
+            }
+        }
 
         void updateSurface(boolean forceRelayout, boolean forceReport) {
             if (mDestroyed) {
@@ -523,10 +506,8 @@
                                 mInputChannel);
                         mCreated = true;
 
-                        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                            InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                    Looper.myQueue());
-                        }
+                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                                Looper.myQueue());
                     }
                     
                     mSurfaceHolder.mSurfaceLock.lock();
@@ -770,10 +751,8 @@
                     if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
                             + mSurfaceHolder.getSurface() + " of: " + this);
                     
-                    if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                        if (mInputChannel != null) {
-                            InputQueue.unregisterInputChannel(mInputChannel);
-                        }
+                    if (mInputChannel != null) {
+                        InputQueue.unregisterInputChannel(mInputChannel);
                     }
                     
                     mSession.remove(mWindow);
@@ -782,13 +761,11 @@
                 mSurfaceHolder.mSurface.release();
                 mCreated = false;
                 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    // Dispose the input channel after removing the window so the Window Manager
-                    // doesn't interpret the input channel being closed as an abnormal termination.
-                    if (mInputChannel != null) {
-                        mInputChannel.dispose();
-                        mInputChannel = null;
-                    }
+                // Dispose the input channel after removing the window so the Window Manager
+                // doesn't interpret the input channel being closed as an abnormal termination.
+                if (mInputChannel != null) {
+                    mInputChannel.dispose();
+                    mInputChannel = null;
                 }
             }
         }
@@ -841,7 +818,7 @@
 
         public void dispatchPointer(MotionEvent event) {
             if (mEngine != null) {
-                mEngine.mWindow.onDispatchPointer(event, event.getEventTime(), false);
+                mEngine.dispatchPointer(event);
             }
         }
         
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3b09808..921018a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,9 +46,6 @@
 
     void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
             boolean reportDraw, in Configuration newConfig);
-    void dispatchKey(in KeyEvent event);
-    void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
-    void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
 
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4647fb4..7f10b76 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -109,10 +109,6 @@
     void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
     
     void finishDrawing(IWindow window);
-
-    void finishKey(IWindow window);
-    MotionEvent getPendingPointerMove(IWindow window);
-    MotionEvent getPendingTrackballMove(IWindow window);
     
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
deleted file mode 100644
index 3bbfea8..0000000
--- a/core/java/android/view/RawInputEvent.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-/**
- * @hide
- * This really belongs in services.jar; WindowManagerPolicy should go there too.
- */
-public class RawInputEvent {
-    // Event class as defined by EventHub.
-    public static final int CLASS_KEYBOARD = 0x00000001;
-    public static final int CLASS_ALPHAKEY = 0x00000002;
-    public static final int CLASS_TOUCHSCREEN = 0x00000004;
-    public static final int CLASS_TRACKBALL = 0x00000008;
-    public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
-    public static final int CLASS_DPAD = 0x00000020;
-    
-    // More special classes for QueuedEvent below.
-    public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
-    
-    // Event types.
-
-    public static final int EV_SYN = 0x00;
-    public static final int EV_KEY = 0x01;
-    public static final int EV_REL = 0x02;
-    public static final int EV_ABS = 0x03;
-    public static final int EV_MSC = 0x04;
-    public static final int EV_SW = 0x05;
-    public static final int EV_LED = 0x11;
-    public static final int EV_SND = 0x12;
-    public static final int EV_REP = 0x14;
-    public static final int EV_FF = 0x15;
-    public static final int EV_PWR = 0x16;
-    public static final int EV_FF_STATUS = 0x17;
-
-    // Platform-specific event types.
-    
-    public static final int EV_DEVICE_ADDED = 0x10000000;
-    public static final int EV_DEVICE_REMOVED = 0x20000000;
-    
-    // Special key (EV_KEY) scan codes for pointer buttons.
-
-    public static final int BTN_FIRST = 0x100;
-
-    public static final int BTN_MISC = 0x100;
-    public static final int BTN_0 = 0x100;
-    public static final int BTN_1 = 0x101;
-    public static final int BTN_2 = 0x102;
-    public static final int BTN_3 = 0x103;
-    public static final int BTN_4 = 0x104;
-    public static final int BTN_5 = 0x105;
-    public static final int BTN_6 = 0x106;
-    public static final int BTN_7 = 0x107;
-    public static final int BTN_8 = 0x108;
-    public static final int BTN_9 = 0x109;
-
-    public static final int BTN_MOUSE = 0x110;
-    public static final int BTN_LEFT = 0x110;
-    public static final int BTN_RIGHT = 0x111;
-    public static final int BTN_MIDDLE = 0x112;
-    public static final int BTN_SIDE = 0x113;
-    public static final int BTN_EXTRA = 0x114;
-    public static final int BTN_FORWARD = 0x115;
-    public static final int BTN_BACK = 0x116;
-    public static final int BTN_TASK = 0x117;
-
-    public static final int BTN_JOYSTICK = 0x120;
-    public static final int BTN_TRIGGER = 0x120;
-    public static final int BTN_THUMB = 0x121;
-    public static final int BTN_THUMB2 = 0x122;
-    public static final int BTN_TOP = 0x123;
-    public static final int BTN_TOP2 = 0x124;
-    public static final int BTN_PINKIE = 0x125;
-    public static final int BTN_BASE = 0x126;
-    public static final int BTN_BASE2 = 0x127;
-    public static final int BTN_BASE3 = 0x128;
-    public static final int BTN_BASE4 = 0x129;
-    public static final int BTN_BASE5 = 0x12a;
-    public static final int BTN_BASE6 = 0x12b;
-    public static final int BTN_DEAD = 0x12f;
-
-    public static final int BTN_GAMEPAD = 0x130;
-    public static final int BTN_A = 0x130;
-    public static final int BTN_B = 0x131;
-    public static final int BTN_C = 0x132;
-    public static final int BTN_X = 0x133;
-    public static final int BTN_Y = 0x134;
-    public static final int BTN_Z = 0x135;
-    public static final int BTN_TL = 0x136;
-    public static final int BTN_TR = 0x137;
-    public static final int BTN_TL2 = 0x138;
-    public static final int BTN_TR2 = 0x139;
-    public static final int BTN_SELECT = 0x13a;
-    public static final int BTN_START = 0x13b;
-    public static final int BTN_MODE = 0x13c;
-    public static final int BTN_THUMBL = 0x13d;
-    public static final int BTN_THUMBR = 0x13e;
-
-    public static final int BTN_DIGI = 0x140;
-    public static final int BTN_TOOL_PEN = 0x140;
-    public static final int BTN_TOOL_RUBBER = 0x141;
-    public static final int BTN_TOOL_BRUSH = 0x142;
-    public static final int BTN_TOOL_PENCIL = 0x143;
-    public static final int BTN_TOOL_AIRBRUSH = 0x144;
-    public static final int BTN_TOOL_FINGER = 0x145;
-    public static final int BTN_TOOL_MOUSE = 0x146;
-    public static final int BTN_TOOL_LENS = 0x147;
-    public static final int BTN_TOUCH = 0x14a;
-    public static final int BTN_STYLUS = 0x14b;
-    public static final int BTN_STYLUS2 = 0x14c;
-    public static final int BTN_TOOL_DOUBLETAP = 0x14d;
-    public static final int BTN_TOOL_TRIPLETAP = 0x14e;
-
-    public static final int BTN_WHEEL = 0x150;
-    public static final int BTN_GEAR_DOWN = 0x150;
-    public static final int BTN_GEAR_UP = 0x151;
-
-    public static final int BTN_LAST = 0x15f;
-
-    // Relative axes (EV_REL) scan codes.
-
-    public static final int REL_X = 0x00;
-    public static final int REL_Y = 0x01;
-    public static final int REL_Z = 0x02;
-    public static final int REL_RX = 0x03;
-    public static final int REL_RY = 0x04;
-    public static final int REL_RZ = 0x05;
-    public static final int REL_HWHEEL = 0x06;
-    public static final int REL_DIAL = 0x07;
-    public static final int REL_WHEEL = 0x08;
-    public static final int REL_MISC = 0x09;
-    public static final int REL_MAX = 0x0f;
-
-    // Absolute axes (EV_ABS) scan codes.
-
-    public static final int ABS_X = 0x00;
-    public static final int ABS_Y = 0x01;
-    public static final int ABS_Z = 0x02;
-    public static final int ABS_RX = 0x03;
-    public static final int ABS_RY = 0x04;
-    public static final int ABS_RZ = 0x05;
-    public static final int ABS_THROTTLE = 0x06;
-    public static final int ABS_RUDDER = 0x07;
-    public static final int ABS_WHEEL = 0x08;
-    public static final int ABS_GAS = 0x09;
-    public static final int ABS_BRAKE = 0x0a;
-    public static final int ABS_HAT0X = 0x10;
-    public static final int ABS_HAT0Y = 0x11;
-    public static final int ABS_HAT1X = 0x12;
-    public static final int ABS_HAT1Y = 0x13;
-    public static final int ABS_HAT2X = 0x14;
-    public static final int ABS_HAT2Y = 0x15;
-    public static final int ABS_HAT3X = 0x16;
-    public static final int ABS_HAT3Y = 0x17;
-    public static final int ABS_PRESSURE = 0x18;
-    public static final int ABS_DISTANCE = 0x19;
-    public static final int ABS_TILT_X = 0x1a;
-    public static final int ABS_TILT_Y = 0x1b;
-    public static final int ABS_TOOL_WIDTH = 0x1c;
-    public static final int ABS_VOLUME = 0x20;
-    public static final int ABS_MISC = 0x28;
-    public static final int ABS_MT_TOUCH_MAJOR = 0x30;
-    public static final int ABS_MT_TOUCH_MINOR = 0x31;
-    public static final int ABS_MT_WIDTH_MAJOR = 0x32;
-    public static final int ABS_MT_WIDTH_MINOR = 0x33;
-    public static final int ABS_MT_ORIENTATION = 0x34;
-    public static final int ABS_MT_POSITION_X = 0x35;
-    public static final int ABS_MT_POSITION_Y = 0x36;
-    public static final int ABS_MT_TOOL_TYPE = 0x37;
-    public static final int ABS_MT_BLOB_ID = 0x38;
-    public static final int ABS_MAX = 0x3f;
-
-    // Switch events
-    public static final int SW_LID = 0x00;
-
-    public static final int SYN_REPORT = 0;
-    public static final int SYN_CONFIG = 1;
-    public static final int SYN_MT_REPORT = 2;
-    
-    public int deviceId;
-    public int type;
-    public int scancode;
-    public int keycode;
-    public int flags;
-    public int value;
-    public long when;
-}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d1a0f75..e4d1ae1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -625,41 +625,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            SurfaceView surfaceView = mSurfaceView.get();
-            if (surfaceView != null) {
-                //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
-                if (surfaceView.mSession != null && surfaceView.mSurface != null) {
-                    try {
-                        surfaceView.mSession.finishKey(surfaceView.mWindow);
-                    } catch (RemoteException ex) {
-                    }
-                }
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             // The point of SurfaceView is to let the app control the surface.
         }
@@ -686,7 +651,6 @@
     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
         
         private static final String LOG_TAG = "SurfaceHolder";
-        private int mSaveCount;
         
         public boolean isCreating() {
             return mIsCreating;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 1dc82e8..e980b17 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -556,18 +556,16 @@
                         "Unable to add window -- unknown error code " + res);
                 }
 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (view instanceof RootViewSurfaceTaker) {
-                        mInputQueueCallback =
-                            ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
-                    }
-                    if (mInputQueueCallback != null) {
-                        mInputQueue = new InputQueue(mInputChannel);
-                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
-                    } else {
-                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                Looper.myQueue());
-                    }
+                if (view instanceof RootViewSurfaceTaker) {
+                    mInputQueueCallback =
+                        ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
+                }
+                if (mInputQueueCallback != null) {
+                    mInputQueue = new InputQueue(mInputChannel);
+                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
+                } else {
+                    InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                            Looper.myQueue());
                 }
                 
                 view.assignParent(this);
@@ -1745,16 +1743,12 @@
         }
         mSurface.release();
 
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mInputChannel != null) {
-                if (mInputQueueCallback != null) {
-                    mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
-                    mInputQueueCallback = null;
-                } else {
-                    InputQueue.unregisterInputChannel(mInputChannel);
-                }
-                mInputChannel.dispose();
-                mInputChannel = null;
+        if (mInputChannel != null) {
+            if (mInputQueueCallback != null) {
+                mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
+                mInputQueueCallback = null;
+            } else {
+                InputQueue.unregisterInputChannel(mInputChannel);
             }
         }
         
@@ -1763,13 +1757,11 @@
         } catch (RemoteException e) {
         }
         
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            // Dispose the input channel after removing the window so the Window Manager
-            // doesn't interpret the input channel being closed as an abnormal termination.
-            if (mInputChannel != null) {
-                mInputChannel.dispose();
-                mInputChannel = null;
-            }
+        // Dispose the input channel after removing the window so the Window Manager
+        // doesn't interpret the input channel being closed as an abnormal termination.
+        if (mInputChannel != null) {
+            mInputChannel.dispose();
+            mInputChannel = null;
         }
     }
 
@@ -1869,105 +1861,22 @@
             deliverKeyEvent((KeyEvent)msg.obj, true);
             break;
         case DISPATCH_POINTER: {
-            MotionEvent event = (MotionEvent)msg.obj;
-            boolean callWhenDone = msg.arg1 != 0;
-            
-            if (event == null) {
-                long timeBeforeGettingEvents;
-                if (MEASURE_LATENCY) {
-                    timeBeforeGettingEvents = System.nanoTime();
-                }
-
-                event = getPendingPointerMotionEvent();
-
-                if (MEASURE_LATENCY && event != null) {
-                    lt.sample("9 Client got events      ", System.nanoTime() - event.getEventTimeNano());
-                    lt.sample("8 Client getting events  ", timeBeforeGettingEvents - event.getEventTimeNano());
-                }
-                callWhenDone = false;
-            }
-            if (event != null && mTranslator != null) {
-                mTranslator.translateEventInScreenToAppWindow(event);
-            }
+            MotionEvent event = (MotionEvent) msg.obj;
             try {
-                boolean handled;
-                if (mView != null && mAdded && event != null) {
-
-                    // enter touch mode on the down
-                    boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
-                    if (isDown) {
-                        ensureTouchMode(true);
-                    }
-                    if(Config.LOGV) {
-                        captureMotionLog("captureDispatchPointer", event);
-                    }
-                    if (mCurScrollY != 0) {
-                        event.offsetLocation(0, mCurScrollY);
-                    }
-                    if (MEASURE_LATENCY) {
-                        lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
-                    }
-                    handled = mView.dispatchTouchEvent(event);
-                    if (MEASURE_LATENCY) {
-                        lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
-                    }
-                    if (!handled && isDown) {
-                        int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
-
-                        final int edgeFlags = event.getEdgeFlags();
-                        int direction = View.FOCUS_UP;
-                        int x = (int)event.getX();
-                        int y = (int)event.getY();
-                        final int[] deltas = new int[2];
-
-                        if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
-                            direction = View.FOCUS_DOWN;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
-                            direction = View.FOCUS_UP;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                            direction = View.FOCUS_RIGHT;
-                        } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                            direction = View.FOCUS_LEFT;
-                        }
-
-                        if (edgeFlags != 0 && mView instanceof ViewGroup) {
-                            View nearest = FocusFinder.getInstance().findNearestTouchable(
-                                    ((ViewGroup) mView), x, y, direction, deltas);
-                            if (nearest != null) {
-                                event.offsetLocation(deltas[0], deltas[1]);
-                                event.setEdgeFlags(0);
-                                mView.dispatchTouchEvent(event);
-                            }
-                        }
-                    }
-                }
+                deliverPointerEvent(event);
             } finally {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
+                event.recycle();
                 if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
-                // Let the exception fall through -- the looper will catch
-                // it and take care of the bad app for us.
             }
         } break;
-        case DISPATCH_TRACKBALL:
-            deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
-            break;
+        case DISPATCH_TRACKBALL: {
+            MotionEvent event = (MotionEvent) msg.obj;
+            try {
+                deliverTrackballEvent(event);
+            } finally {
+                event.recycle();
+            }
+        } break;
         case DISPATCH_APP_VISIBILITY:
             handleAppVisibility(msg.arg1 != 0);
             break;
@@ -2101,61 +2010,12 @@
     }
     
     private void finishKeyEvent(KeyEvent event) {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mFinishedCallback != null) {
-                mFinishedCallback.run();
-                mFinishedCallback = null;
-            }
-        } else {
-            try {
-                sWindowSession.finishKey(mWindow);
-            } catch (RemoteException e) {
-            }
+        if (mFinishedCallback != null) {
+            mFinishedCallback.run();
+            mFinishedCallback = null;
         }
     }
     
-    private void finishMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            sWindowSession.finishKey(mWindow);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void recycleMotionEvent(MotionEvent event) {
-        if (event != null) {
-            event.recycle();
-        }
-    }
-    
-    private MotionEvent getPendingPointerMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingPointerMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    private MotionEvent getPendingTrackballMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingTrackballMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-    
-    
     /**
      * Something in the current window tells us we need to change the touch mode.  For
      * example, we are not in touch mode, and the user touches the screen.
@@ -2277,42 +2137,95 @@
         return false;
     }
 
-
-    private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
-        if (event == null) {
-            event = getPendingTrackballMotionEvent();
-            callWhenDone = false;
+    private void deliverPointerEvent(MotionEvent event) {
+        if (mTranslator != null) {
+            mTranslator.translateEventInScreenToAppWindow(event);
         }
+        
+        boolean handled;
+        if (mView != null && mAdded) {
 
+            // enter touch mode on the down
+            boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
+            if (isDown) {
+                ensureTouchMode(true);
+            }
+            if(Config.LOGV) {
+                captureMotionLog("captureDispatchPointer", event);
+            }
+            if (mCurScrollY != 0) {
+                event.offsetLocation(0, mCurScrollY);
+            }
+            if (MEASURE_LATENCY) {
+                lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+            }
+            handled = mView.dispatchTouchEvent(event);
+            if (MEASURE_LATENCY) {
+                lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+            }
+            if (!handled && isDown) {
+                int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
+
+                final int edgeFlags = event.getEdgeFlags();
+                int direction = View.FOCUS_UP;
+                int x = (int)event.getX();
+                int y = (int)event.getY();
+                final int[] deltas = new int[2];
+
+                if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
+                    direction = View.FOCUS_DOWN;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
+                    direction = View.FOCUS_UP;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                    direction = View.FOCUS_RIGHT;
+                } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                    direction = View.FOCUS_LEFT;
+                }
+
+                if (edgeFlags != 0 && mView instanceof ViewGroup) {
+                    View nearest = FocusFinder.getInstance().findNearestTouchable(
+                            ((ViewGroup) mView), x, y, direction, deltas);
+                    if (nearest != null) {
+                        event.offsetLocation(deltas[0], deltas[1]);
+                        event.setEdgeFlags(0);
+                        mView.dispatchTouchEvent(event);
+                    }
+                }
+            }
+        }
+    }
+
+    private void deliverTrackballEvent(MotionEvent event) {
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
         boolean handled = false;
-        try {
-            if (event == null) {
-                handled = true;
-            } else if (mView != null && mAdded) {
-                handled = mView.dispatchTrackballEvent(event);
-                if (!handled) {
-                    // we could do something here, like changing the focus
-                    // or something?
-                }
-            }
-        } finally {
+        if (mView != null && mAdded) {
+            handled = mView.dispatchTrackballEvent(event);
             if (handled) {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
                 // If we reach this, we delivered a trackball event to mView and
                 // mView consumed it. Because we will not translate the trackball
                 // event into a key event, touch mode will not exit, so we exit
                 // touch mode here.
                 ensureTouchMode(false);
-                //noinspection ReturnInsideFinallyBlock
                 return;
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            
+            // Otherwise we could do something here, like changing the focus
+            // or something?
         }
 
         final TrackballAxis x = mTrackballAxisX;
@@ -2327,95 +2240,86 @@
             mLastTrackballTime = curTime;
         }
 
-        try {
-            final int action = event.getAction();
-            final int metastate = event.getMetaState();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-                case MotionEvent.ACTION_UP:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-            }
+        final int action = event.getAction();
+        final int metastate = event.getMetaState();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+            case MotionEvent.ACTION_UP:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+        }
 
-            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
-                    + x.step + " dir=" + x.dir + " acc=" + x.acceleration
-                    + " move=" + event.getX()
-                    + " / Y=" + y.position + " step="
-                    + y.step + " dir=" + y.dir + " acc=" + y.acceleration
-                    + " move=" + event.getY());
-            final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
-            final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
+        if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
+                + x.step + " dir=" + x.dir + " acc=" + x.acceleration
+                + " move=" + event.getX()
+                + " / Y=" + y.position + " step="
+                + y.step + " dir=" + y.dir + " acc=" + y.acceleration
+                + " move=" + event.getY());
+        final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
+        final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
 
-            // Generate DPAD events based on the trackball movement.
-            // We pick the axis that has moved the most as the direction of
-            // the DPAD.  When we generate DPAD events for one axis, then the
-            // other axis is reset -- we don't want to perform DPAD jumps due
-            // to slight movements in the trackball when making major movements
-            // along the other axis.
-            int keycode = 0;
-            int movement = 0;
-            float accel = 1;
-            if (xOff > yOff) {
-                movement = x.generate((2/event.getXPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
-                            : KeyEvent.KEYCODE_DPAD_LEFT;
-                    accel = x.acceleration;
-                    y.reset(2);
-                }
-            } else if (yOff > 0) {
-                movement = y.generate((2/event.getYPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
-                            : KeyEvent.KEYCODE_DPAD_UP;
-                    accel = y.acceleration;
-                    x.reset(2);
-                }
+        // Generate DPAD events based on the trackball movement.
+        // We pick the axis that has moved the most as the direction of
+        // the DPAD.  When we generate DPAD events for one axis, then the
+        // other axis is reset -- we don't want to perform DPAD jumps due
+        // to slight movements in the trackball when making major movements
+        // along the other axis.
+        int keycode = 0;
+        int movement = 0;
+        float accel = 1;
+        if (xOff > yOff) {
+            movement = x.generate((2/event.getXPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
+                        : KeyEvent.KEYCODE_DPAD_LEFT;
+                accel = x.acceleration;
+                y.reset(2);
             }
+        } else if (yOff > 0) {
+            movement = y.generate((2/event.getYPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
+                        : KeyEvent.KEYCODE_DPAD_UP;
+                accel = y.acceleration;
+                x.reset(2);
+            }
+        }
 
-            if (keycode != 0) {
-                if (movement < 0) movement = -movement;
-                int accelMovement = (int)(movement * accel);
-                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
-                        + " accelMovement=" + accelMovement
-                        + " accel=" + accel);
-                if (accelMovement > movement) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_MULTIPLE, keycode,
-                            accelMovement-movement, metastate), false);
-                }
-                while (movement > 0) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    curTime = SystemClock.uptimeMillis();
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, keycode, 0, metastate), false);
-                }
-                mLastTrackballTime = curTime;
+        if (keycode != 0) {
+            if (movement < 0) movement = -movement;
+            int accelMovement = (int)(movement * accel);
+            if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                    + " accelMovement=" + accelMovement
+                    + " accel=" + accel);
+            if (accelMovement > movement) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_MULTIPLE, keycode,
+                        accelMovement-movement, metastate), false);
             }
-        } finally {
-            if (callWhenDone) {
-                finishMotionEvent();
-                recycleMotionEvent(event);
+            while (movement > 0) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                curTime = SystemClock.uptimeMillis();
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, keycode, 0, metastate), false);
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            mLastTrackballTime = curTime;
         }
     }
 
@@ -2862,45 +2766,20 @@
     private final InputHandler mInputHandler = new InputHandler() {
         public void handleKey(KeyEvent event, Runnable finishedCallback) {
             mFinishedCallback = finishedCallback;
-            
-            if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                //noinspection ConstantConditions
-                if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                    if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
-                    debug();
 
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                }
-            }
-
-            Message msg = obtainMessage(DISPATCH_KEY);
-            msg.obj = event;
-
-            if (LOCAL_LOGV) Log.v(
-                "ViewRoot", "sending key " + event + " to " + mView);
-
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchKey(event);
         }
 
         public void handleTouch(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_POINTER);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchPointer(event);
         }
 
         public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_TRACKBALL);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchTrackball(event);
         }
     };
 
@@ -2927,22 +2806,18 @@
         sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchPointer(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_POINTER);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchTrackball(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_TRACKBALL);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
-
+    
     public void dispatchAppVisibility(boolean visible) {
         Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
         msg.arg1 = visible ? 1 : 0;
@@ -3073,56 +2948,11 @@
         }
     }
 
-    class EventCompletion extends Handler {
-        final IWindow mWindow;
-        final KeyEvent mKeyEvent;
-        final boolean mIsPointer;
-        final MotionEvent mMotionEvent;
-
-        EventCompletion(Looper looper, IWindow window, KeyEvent key,
-                boolean isPointer, MotionEvent motion) {
-            super(looper);
-            mWindow = window;
-            mKeyEvent = key;
-            mIsPointer = isPointer;
-            mMotionEvent = motion;
-            sendEmptyMessage(0);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (mKeyEvent != null) {
-                finishKeyEvent(mKeyEvent);
-           } else if (mIsPointer) {
-                boolean didFinish;
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingPointerMotionEvent();
-                    didFinish = true;
-                } else {
-                    didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
-                }
-                if (!didFinish) {
-                    finishMotionEvent();
-                }
-            } else {
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingTrackballMotionEvent();
-                } else {
-                    finishMotionEvent();
-                }
-            }
-        }
-    }
-
     static class W extends IWindow.Stub {
         private final WeakReference<ViewRoot> mViewRoot;
-        private final Looper mMainLooper;
 
         public W(ViewRoot viewRoot, Context context) {
             mViewRoot = new WeakReference<ViewRoot>(viewRoot);
-            mMainLooper = context.getMainLooper();
         }
 
         public void resized(int w, int h, Rect coveredInsets,
@@ -3134,40 +2964,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchKey(event);
-            } else {
-                Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
-                viewRoot.new EventCompletion(mMainLooper, this, event, false, null);
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {                
-                if (MEASURE_LATENCY) {
-                    // Note: eventTime is in milliseconds
-                    ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000);
-                }
-                viewRoot.dispatchPointer(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, true, event);
-            }
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, false, event);
-            }
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index be1f6d2..33757f0 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -78,12 +78,6 @@
     public final static int FLAG_BRIGHT_HERE = 0x20000000;
 
     public final static boolean WATCH_POINTER = false;
-    
-    /**
-     * Temporary flag added during the transition to the new native input dispatcher.
-     * This will be removed when the old input dispatch code is deleted.
-     */
-    public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = true;
 
     // flags for interceptKeyTq
     /**
@@ -555,23 +549,26 @@
     public Animation createForceHideEnterAnimation();
     
     /**
-     * Called from the key queue thread before a key is dispatched to the
-     * input thread.
+     * Called from the input reader thread before a key is enqueued.
      *
      * <p>There are some actions that need to be handled here because they
      * affect the power state of the device, for example, the power keys.
      * Generally, it's best to keep as little as possible in the queue thread
      * because it's the most fragile.
+     * @param whenNanos The event time in uptime nanoseconds.
+     * @param keyCode The key code.
+     * @param down True if the key is down.
+     * @param policyFlags The policy flags associated with the key.
+     * @param isScreenOn True if the screen is already on
      *
-     * @param event the raw input event as read from the driver
-     * @param screenIsOn true if the screen is already on
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
      *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
-    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn);
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
+            boolean isScreenOn);
     
     /**
-     * Called from the input thread before a key is dispatched to a window.
+     * Called from the input dispatcher thread before a key is dispatched to a window.
      *
      * <p>Allows you to define
      * behavior for keys that can not be overridden by applications or redirect
@@ -583,16 +580,17 @@
      * 
      * @param win The window that currently has focus.  This is where the key
      *            event will normally go.
-     * @param code Key code.
-     * @param metaKeys bit mask of meta keys that are held.
-     * @param down Is this a key press (true) or release (false)?
+     * @param action The key event action.
+     * @param flags The key event flags.
+     * @param keyCode The key code.
+     * @param metaState bit mask of meta keys that are held.
      * @param repeatCount Number of times a key down has repeated.
-     * @param flags event's flags.
+     * @param policyFlags The policy flags associated with the key.
      * @return Returns true if the policy consumed the event and it should
      * not be further dispatched.
      */
-    public boolean interceptKeyTi(WindowState win, int code,
-                               int metaKeys, boolean down, int repeatCount, int flags);
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, int metaState, int repeatCount, int policyFlags);
 
     /**
      * Called when layout of the windows is about to start.
@@ -701,85 +699,15 @@
      * Return whether the screen is currently on.
      */
     public boolean isScreenOn();
-    
+
     /**
-     * Perform any initial processing of a low-level input event before the
-     * window manager handles special keys and generates a high-level event
-     * that is dispatched to the application.
-     * 
-     * @param event The input event that has occurred.
-     * 
-     * @return Return true if you have consumed the event and do not want
-     * further processing to occur; return false for normal processing.
+     * Tell the policy that the lid switch has changed state.
+     * @param whenNanos The time when the change occurred in uptime nanoseconds.
+     * @param lidOpen True if the lid is now open.
      */
-    public boolean preprocessInputEventTq(RawInputEvent event);
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
     
     /**
-     * Determine whether a given key code is used to cause an app switch
-     * to occur (most often the HOME key, also often ENDCALL).  If you return
-     * true, then the system will go into a special key processing state
-     * where it drops any pending events that it cans and adjusts timeouts to
-     * try to get to this key as quickly as possible.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread, with either/or the window or input lock held; be very careful
-     * about what you do here.  You absolutely should never acquire a lock
-     * that you would ever hold elsewhere while calling out into the window
-     * manager or view hierarchy.
-     * 
-     * @param keycode The key that should be checked for performing an
-     * app switch before delivering to the application.
-     * 
-     * @return Return true if this is an app switch key and special processing
-     * should happen; return false for normal processing.
-     */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode);
-    
-    /**
-     * Determine whether a given key code is used for movement within a UI,
-     * and does not generally cause actions to be performed (normally the DPAD
-     * movement keys, NOT the DPAD center press key).  This is called
-     * when {@link #isAppSwitchKeyTiLi} returns true to remove any pending events
-     * in the key queue that are not needed to switch applications.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread; be very careful about what you do here.
-     * 
-     * @param keycode The key that is waiting to be delivered to the
-     * application.
-     * 
-     * @return Return true if this is a purely navigation key and can be
-     * dropped without negative consequences; return false to keep it.
-     */
-    public boolean isMovementKeyTi(int keycode);
-    
-    /**
-     * Given the current state of the world, should this relative movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
-     * Given the current state of the world, should this absolute movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
      * Tell the policy if anyone is requesting that keyguard not come on.
      *
      * @param enabled Whether keyguard can be on or not.  does not actually
@@ -852,18 +780,6 @@
     public void enableScreenAfterBoot();
     
     /**
-     * Returns true if the user's cheek has been pressed against the phone. This is 
-     * determined by comparing the event's size attribute with a threshold value.
-     * For example for a motion event like down or up or move, if the size exceeds
-     * the threshold, it is considered as cheek press.
-     * @param ev the motion event generated when the cheek is pressed 
-     * against the phone
-     * @return Returns true if the user's cheek has been pressed against the phone
-     * screen resulting in an invalid motion event
-     */
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev);
-    
-    /**
      * Called every time the window manager is dispatching a pointer event.
      */
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY);
@@ -876,13 +792,6 @@
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
     
     /**
-     * A special function that is called from the very low-level input queue
-     * to provide feedback to the user.  Currently only called for virtual
-     * keys.
-     */
-    public void keyFeedbackFromInput(KeyEvent event);
-    
-    /**
      * Called when we have stopped keeping the screen on because a window
      * requesting this is no longer visible.
      */
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index b13d656..4da74e6 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -43,59 +43,6 @@
         }
     }
 
-    public void dispatchKey(KeyEvent event) {
-        try {
-            mSession.finishKey(this);
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingPointerMove(this);
-                onDispatchPointer(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchPointer(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchPointer(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingTrackballMove(this);
-                onDispatchTrackball(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchTrackball(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchTrackball(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     public void dispatchAppVisibility(boolean visible) {
     }
 
diff --git a/docs/html/images/axis_device.png b/docs/html/images/axis_device.png
new file mode 100644
index 0000000..f1f666a
--- /dev/null
+++ b/docs/html/images/axis_device.png
Binary files differ
diff --git a/docs/html/images/axis_globe.png b/docs/html/images/axis_globe.png
new file mode 100644
index 0000000..dccb58b
--- /dev/null
+++ b/docs/html/images/axis_globe.png
Binary files differ
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 66670f3..e9ff8a3 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -307,29 +307,18 @@
             int32_t     priority() const { return mPriority; }
 
 
-    /* Enables the effect engine.
+    /* Enables or disables the effect engine.
      *
      * Parameters:
-     *      None.
+     *  enabled: requested enable state.
      *
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
-     *  - INVALID_OPERATION: the application does not have control of the effect engine
+     *  - INVALID_OPERATION: the application does not have control of the effect engine or the
+     *  effect is already in the requested state.
      */
-            status_t    enable();
-
-    /* Disables the effect engine.
-     *
-     * Parameters:
-     *      None.
-     *
-     * Returned status (from utils/Errors.h) can be:
-     *  - NO_ERROR: successful operation
-     *  - INVALID_OPERATION: the application does not have control of the effect engine
-     */
-             status_t    disable();
-
-             bool        isEnabled() const;
+    virtual status_t    setEnabled(bool enabled);
+            bool        getEnabled() const;
 
     /* Sets a parameter value.
      *
@@ -342,7 +331,7 @@
      *  - BAD_VALUE: invalid parameter identifier or value.
      *  - DEAD_OBJECT: the effect engine has been deleted.
      */
-             status_t   setParameter(effect_param_t *param);
+     virtual status_t   setParameter(effect_param_t *param);
 
     /* Prepare a new parameter value that will be set by next call to
      * setParameterCommit(). This method can be used to set multiple parameters
@@ -359,7 +348,7 @@
      *  - NO_MEMORY: no more space available in shared memory used for deferred parameter
      *  setting.
      */
-             status_t   setParameterDeferred(effect_param_t *param);
+     virtual status_t   setParameterDeferred(effect_param_t *param);
 
      /* Commit all parameter values previously prepared by setParameterDeferred().
       *
@@ -373,7 +362,7 @@
       *     as to which of the parameters caused this error.
       *  - DEAD_OBJECT: the effect engine has been deleted.
       */
-             status_t   setParameterCommit();
+     virtual status_t   setParameterCommit();
 
     /* Gets a parameter value.
      *
@@ -387,13 +376,17 @@
      *  - BAD_VALUE: invalid parameter identifier.
      *  - DEAD_OBJECT: the effect engine has been deleted.
      */
-             status_t   getParameter(effect_param_t *param);
+     virtual status_t   getParameter(effect_param_t *param);
 
      /* Sends a command and receives a response to/from effect engine.
       *     See EffectApi.h for details on effect command() function, valid command codes
       *     and formats.
       */
-             status_t command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData);
+     virtual status_t command(int32_t cmdCode,
+                              int32_t cmdSize,
+                              void *cmdData,
+                              int32_t *replySize,
+                              void *replyData);
 
 
      /*
@@ -409,6 +402,17 @@
       */
      static status_t guidToString(const effect_uuid_t *guid, char *str, size_t maxLen);
 
+protected:
+     volatile int32_t        mEnabled;           // enable state
+     int32_t                 mSessionId;         // audio session ID
+     int32_t                 mPriority;          // priority for effect control
+     status_t                mStatus;            // effect status
+     effect_callback_t       mCbf;               // callback function for status, control and
+                                                 // parameter changes notifications
+     void*                   mUserData;          // client context for callback function
+     effect_descriptor_t     mDescriptor;        // effect descriptor
+     int32_t                 mId;                // system wide unique effect engine instance ID
+
 private:
 
      // Implements the IEffectClient interface
@@ -419,9 +423,17 @@
         EffectClient(AudioEffect *effect) : mEffect(effect){}
 
         // IEffectClient
-        virtual void controlStatusChanged(bool controlGranted) {mEffect->controlStatusChanged(controlGranted);}
-        virtual void enableStatusChanged(bool enabled) {mEffect->enableStatusChanged(enabled);}
-        virtual void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) {
+        virtual void controlStatusChanged(bool controlGranted) {
+            mEffect->controlStatusChanged(controlGranted);
+        }
+        virtual void enableStatusChanged(bool enabled) {
+            mEffect->enableStatusChanged(enabled);
+        }
+        virtual void commandExecuted(int cmdCode,
+                                     int cmdSize,
+                                     void *pCmdData,
+                                     int replySize,
+                                     void *pReplyData) {
             mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
         }
 
@@ -446,14 +458,6 @@
     sp<EffectClient>        mIEffectClient;     // IEffectClient implementation
     sp<IMemory>             mCblkMemory;        // shared memory for deferred parameter setting
     effect_param_cblk_t*    mCblk;              // control block for deferred parameter setting
-    int32_t                 mPriority;          // priority for effect control
-    status_t                mStatus;            // effect status
-    volatile int32_t        mEnabled;           // enable state
-    effect_callback_t       mCbf;               // callback function for status, control, parameter changes notifications
-    void*                   mUserData;          // client context for callback function
-    effect_descriptor_t     mDescriptor;        // effect descriptor
-    int32_t                 mId;                // system wide unique effect engine instance identifier
-    int32_t                 mSessionId;         // audio session ID
 };
 
 
diff --git a/include/media/EffectVisualizerApi.h b/include/media/EffectVisualizerApi.h
new file mode 100644
index 0000000..1155db8
--- /dev/null
+++ b/include/media/EffectVisualizerApi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EFFECTVISUALIZERAPI_H_
+#define ANDROID_EFFECTVISUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+//TODO replace by openSL ES include when available
+static const effect_uuid_t SL_IID_VISUALIZATION_ =
+    { 0xe46b26a0, 0xdddd, 0x11db, 0x8afd, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VISUALIZATION = &SL_IID_VISUALIZATION_;
+
+#define VISUALIZER_CAPTURE_SIZE_MAX 1024  // maximum capture size in samples
+#define VISUALIZER_CAPTURE_SIZE_MIN 128   // minimum capture size in samples
+
+/* enumerated parameters for Visualizer effect */
+typedef enum
+{
+    VISU_PARAM_CAPTURE_SIZE,        // Sets the number PCM samples in the capture.
+} t_visualizer_params;
+
+/* commands */
+typedef enum
+{
+    VISU_CMD_CAPTURE = EFFECT_CMD_FIRST_PROPRIETARY, // Gets the latest PCM capture.
+}t_visualizer_cmds;
+
+// VISU_CMD_CAPTURE retrieves the latest PCM snapshot captured by the visualizer engine.
+// It returns the number of samples specified by VISU_PARAM_CAPTURE_SIZE
+// in 8 bit unsigned format (0 = 0x80)
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVISUALIZERAPI_H_*/
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index e892875..9416ca1 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -48,10 +48,6 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IOMX>            getOMX() = 0;
-
-    // Take a peek at currently playing audio, for visualization purposes.
-    // This returns a buffer of 16 bit mono PCM data, or NULL if no visualization buffer is currently available.
-    virtual sp<IMemory>         snoop() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
new file mode 100644
index 0000000..5d51de8
--- /dev/null
+++ b/include/media/Visualizer.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_VISUALIZER_H
+#define ANDROID_MEDIA_VISUALIZER_H
+
+#include <media/AudioEffect.h>
+#include <media/EffectVisualizerApi.h>
+#include <string.h>
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:
+ * - If the session is 0, the audio output mix is visualized
+ * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
+ *   using this audio session is visualized
+ * Two types of representation of audio content can be captured:
+ * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
+ * - Frequency data: 8-bit magnitude FFT by using the getFft() method
+ *
+ * The length of the capture can be retrieved or specified by calling respectively
+ * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by getMinCaptureSize() and getMaxCaptureSize().
+ * In addition to the polling capture mode, a callback mode is also available by installing a
+ * callback function by use of the setCaptureCallBack() method. The rate at which the callback
+ * is called as well as the type of data returned is specified.
+ * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ */
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Visualizer: public AudioEffect {
+public:
+
+    enum callback_flags {
+        CAPTURE_WAVEFORM = 0x00000001,  // capture callback returns a PCM wave form
+        CAPTURE_FFT = 0x00000002,       // apture callback returns a frequency representation
+        CAPTURE_CALL_JAVA = 0x00000004  // the callback thread can call java
+    };
+
+
+    /* Constructor.
+     * See AudioEffect constructor for details on parameters.
+     */
+                        Visualizer(int32_t priority = 0,
+                                   effect_callback_t cbf = 0,
+                                   void* user = 0,
+                                   int sessionId = 0);
+
+                        ~Visualizer();
+
+    virtual status_t    setEnabled(bool enabled);
+
+    // maximum capture size in samples
+    static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
+    // minimum capture size in samples
+    static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
+    // maximum capture rate in millihertz
+    static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
+
+    // callback used to return periodic PCM or FFT captures to the application. Either one or both
+    // types of data are returned (PCM and FFT) according to flags indicated when installing the
+    // callback. When a type of data is not present, the corresponding size (waveformSize or
+    // fftSize) is 0.
+    typedef void (*capture_cbk_t)(void* user,
+                                    uint32_t waveformSize,
+                                    uint8_t *waveform,
+                                    uint32_t fftSize,
+                                    uint8_t *fft,
+                                    uint32_t samplingrate);
+
+    // install a callback to receive periodic captures. The capture rate is specified in milliHertz
+    // and the capture format is according to flags  (see callback_flags).
+    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
+
+    // set the capture size capture size must be a power of two in the range
+    // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
+    // must be called when the visualizer is not enabled
+    status_t setCaptureSize(uint32_t size);
+    uint32_t getCaptureSize() { return mCaptureSize; }
+
+    // returns the capture rate indicated when installing the callback
+    uint32_t getCaptureRate() { return mCaptureRate; }
+
+    // returns the sampling rate of the audio being captured
+    uint32_t getSamplingRate() { return mSampleRate; }
+
+    // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
+    // getCaptureSize()
+    status_t getWaveForm(uint8_t *waveform);
+
+    // return a capture in FFT 8 bit signed format. The size of the capture is equal to
+    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
+    // are returned
+    status_t getFft(uint8_t *fft);
+
+private:
+
+    static const uint32_t CAPTURE_RATE_MAX = 20000;
+    static const uint32_t CAPTURE_RATE_DEF = 10000;
+    static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
+
+    /* internal class to handle the callback */
+    class CaptureThread : public Thread
+    {
+    public:
+        CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava = false);
+
+    private:
+        friend class Visualizer;
+        virtual bool        threadLoop();
+        virtual status_t    readyToRun();
+        virtual void        onFirstRef();
+        Visualizer& mReceiver;
+        Mutex       mLock;
+        uint32_t mSleepTimeUs;
+    };
+
+    status_t doFft(uint8_t *fft, uint8_t *waveform);
+    void periodicCapture();
+    uint32_t initCaptureSize();
+
+    Mutex mLock;
+    uint32_t mCaptureRate;
+    uint32_t mCaptureSize;
+    uint32_t mSampleRate;
+    capture_cbk_t mCaptureCallBack;
+    void *mCaptureCbkUser;
+    sp<CaptureThread> mCaptureThread;
+    uint32_t mCaptureFlags;
+    void *mFftTable;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 62a4e50..4963f73 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -166,7 +166,6 @@
             void            notify(int msg, int ext1, int ext2);
     static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-    static  int             snoop(short *data, int len, int kind);
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
             status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 95fe6f6..73f5547 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -69,6 +69,10 @@
     kKeyDate              = 'date',  // cstring
     kKeyWriter            = 'writ',  // cstring
 
+    // video profile and level
+    kKeyVideoProfile      = 'vprf',  // int32_t
+    kKeyVideoLevel        = 'vlev',  // int32_t
+
     // Set this key to enable authoring files in 64-bit offset
     kKey64BitFileOffset   = 'fobt',  // int32_t (bool)
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 99ec8e6..214f43a 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -27,6 +27,7 @@
 
 class MemoryDealer;
 struct OMXCodecObserver;
+struct CodecProfileLevel;
 
 struct OMXCodec : public MediaSource,
                   public MediaBufferObserver {
@@ -178,6 +179,12 @@
     status_t setupMPEG4EncoderParameters(const sp<MetaData>& meta);
     status_t setupAVCEncoderParameters(const sp<MetaData>& meta);
 
+    // If profile/level is set in the meta data, its value in the meta
+    // data will be used; otherwise, the default value will be used.
+    status_t getVideoProfileLevel(const sp<MetaData>& meta,
+            const CodecProfileLevel& defaultProfileLevel,
+            CodecProfileLevel& profileLevel);
+
     status_t setVideoOutputFormat(
             const char *mime, OMX_U32 width, OMX_U32 height);
 
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 781da35..03c8112 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -250,7 +250,13 @@
         nsecs_t downTime;
 
         struct CurrentVirtualKeyState {
-            bool down;
+            enum Status {
+                STATUS_UP,
+                STATUS_DOWN,
+                STATUS_CANCELED
+            };
+
+            Status status;
             nsecs_t downTime;
             int32_t keyCode;
             int32_t scanCode;
@@ -295,6 +301,7 @@
         void calculatePointerIds();
 
         bool isPointInsideDisplay(int32_t x, int32_t y) const;
+        const InputDevice::VirtualKey* findVirtualKeyHit() const;
     };
 
     InputDevice(int32_t id, uint32_t classes, String8 name);
@@ -390,11 +397,9 @@
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Provides feedback for a virtual key.
+    /* Provides feedback for a virtual key down.
      */
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+    virtual void virtualKeyDownFeedback() = 0;
 
     /* Intercepts a key event.
      * The policy can use this method as an opportunity to perform power management functions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 48c04a6..e6f46ce 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -17,7 +17,8 @@
 
 
 #define LOG_TAG "AudioFlinger"
-//#define LOG_NDEBUG 0
+//
+#define LOG_NDEBUG 0
 
 #include <math.h>
 #include <signal.h>
@@ -52,6 +53,7 @@
 #endif
 
 #include <media/EffectsFactoryApi.h>
+#include <media/EffectVisualizerApi.h>
 
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
@@ -4498,6 +4500,11 @@
     return EffectGetDescriptor(pUuid, descriptor);
 }
 
+
+// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp
+static const effect_uuid_t VISUALIZATION_UUID_ =
+    {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
 sp<IEffect> AudioFlinger::createEffect(pid_t pid,
         effect_descriptor_t *pDesc,
         const sp<IEffectClient>& effectClient,
@@ -4525,6 +4532,15 @@
     {
         Mutex::Autolock _l(mLock);
 
+        // check recording permission for visualizer
+        if (memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
+            memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) {
+            if (!recordingAllowed()) {
+                lStatus = PERMISSION_DENIED;
+                goto Exit;
+            }
+        }
+
         if (!EffectIsNullUuid(&pDesc->uuid)) {
             // if uuid is specified, request effect descriptor
             lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);
@@ -5089,7 +5105,7 @@
         if (mState != ACTIVE) {
             switch (mState) {
             case RESET:
-                reset();
+                reset_l();
                 mState = STARTING;
                 // clear auxiliary effect input buffer for next accumulation
                 if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5097,14 +5113,14 @@
                 }
                 return;
             case STARTING:
-                start();
+                start_l();
                 mState = ACTIVE;
                 break;
             case STOPPING:
                 mState = STOPPED;
                 break;
             case STOPPED:
-                stop();
+                stop_l();
                 mState = IDLE;
                 return;
             }
@@ -5132,7 +5148,7 @@
     }
 }
 
-void AudioFlinger::EffectModule::reset()
+void AudioFlinger::EffectModule::reset_l()
 {
     if (mEffectInterface == NULL) {
         return;
@@ -5205,6 +5221,7 @@
 
 status_t AudioFlinger::EffectModule::init()
 {
+    Mutex::Autolock _l(mLock);
     if (mEffectInterface == NULL) {
         return NO_INIT;
     }
@@ -5217,7 +5234,7 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::start()
+status_t AudioFlinger::EffectModule::start_l()
 {
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5231,7 +5248,7 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::stop()
+status_t AudioFlinger::EffectModule::stop_l()
 {
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5247,7 +5264,8 @@
 
 status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
 {
-    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
+    Mutex::Autolock _l(mLock);
+//    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
 
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5255,7 +5273,6 @@
     status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
     if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
         int size = (replySize == NULL) ? 0 : *replySize;
-        Mutex::Autolock _l(mLock);
         for (size_t i = 1; i < mHandles.size(); i++) {
             sp<EffectHandle> h = mHandles[i].promote();
             if (h != 0) {
@@ -5322,6 +5339,7 @@
 
 status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
 {
+    Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
 
     // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
@@ -5347,6 +5365,7 @@
 
 status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
 {
+    Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
     if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
         // convert device bit field from AudioSystem to EffectApi format.
@@ -5366,6 +5385,7 @@
 
 status_t AudioFlinger::EffectModule::setMode(uint32_t mode)
 {
+    Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
     if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) {
         // convert audio mode from AudioSystem to EffectApi format.
@@ -5586,7 +5606,7 @@
 
 status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
 {
-    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+//    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
 
     // only get parameter command is permitted for applications not controlling the effect
     if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 42dca4c..ec3d7f1 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -916,7 +916,7 @@
         void process();
         status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
 
-        void reset();
+        void reset_l();
         status_t configure();
         status_t init();
         uint32_t state() {
@@ -951,8 +951,8 @@
         EffectModule(const EffectModule&);
         EffectModule& operator = (const EffectModule&);
 
-        status_t start();
-        status_t stop();
+        status_t start_l();
+        status_t stop_l();
 
         // update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
         static const uint32_t sDeviceConvTable[];
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 8f6d1fe..42a7fc6 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -299,14 +299,13 @@
     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(currentTime,
                 entry->deviceId, entry->nature, policyFlags,
                 entry->action, entry->flags, entry->keyCode, entry->scanCode,
-                entry->metaState, entry->repeatCount + 1, currentTime);
+                entry->metaState, entry->repeatCount + 1, entry->downTime);
 
         mKeyRepeatState.lastKeyEntry = newEntry;
         mAllocator.releaseKeyEntry(entry);
@@ -314,6 +313,10 @@
         entry = newEntry;
     }
 
+    if (entry->repeatCount == 1) {
+        entry->flags |= KEY_EVENT_FLAG_LONG_PRESS;
+    }
+
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 899027c..fced15c 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -189,7 +189,7 @@
 void InputDevice::TouchScreenState::reset() {
     lastTouch.clear();
     downTime = 0;
-    currentVirtualKey.down = false;
+    currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
 
     for (uint32_t i = 0; i < MAX_POINTERS; i++) {
         averagingTouchFilter.historyStart[i] = 0;
@@ -746,6 +746,29 @@
         && y <= parameters.yAxis.maxValue;
 }
 
+const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
+    int32_t x = currentTouch.pointers[0].x;
+    int32_t y = currentTouch.pointers[0].y;
+    for (size_t i = 0; i < virtualKeys.size(); i++) {
+        const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
+
+#if DEBUG_VIRTUAL_KEYS
+        LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+                "left=%d, top=%d, right=%d, bottom=%d",
+                x, y,
+                virtualKey.keyCode, virtualKey.scanCode,
+                virtualKey.hitLeft, virtualKey.hitTop,
+                virtualKey.hitRight, virtualKey.hitBottom);
+#endif
+
+        if (virtualKey.isHit(x, y)) {
+            return & virtualKey;
+        }
+    }
+
+    return NULL;
+}
+
 
 // --- InputDevice::SingleTouchScreenState ---
 
@@ -1269,81 +1292,76 @@
 
 bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
         InputDevice* device, uint32_t policyFlags) {
-    if (device->touchScreen.currentVirtualKey.down) {
+    switch (device->touchScreen.currentVirtualKey.status) {
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED:
         if (device->touchScreen.currentTouch.pointerCount == 0) {
-            // Pointer went up while virtual key was down.  Send key up event.
-            device->touchScreen.currentVirtualKey.down = false;
+            // Pointer went up after virtual key canceled.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
+        }
+        return true; // consumed
 
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN:
+        if (device->touchScreen.currentTouch.pointerCount == 0) {
+            // Pointer went up while virtual key was down.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
 #if DEBUG_VIRTUAL_KEYS
             LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                     device->touchScreen.currentVirtualKey.keyCode,
                     device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
             dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
                     KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
             return true; // consumed
         }
 
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        if (device->touchScreen.isPointInsideDisplay(x, y)
-                || device->touchScreen.currentTouch.pointerCount != 1) {
-            // Pointer moved inside the display area or another pointer also went down.
-            // Send key cancellation.
-            device->touchScreen.currentVirtualKey.down = false;
-
-#if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
-                    device->touchScreen.currentVirtualKey.keyCode,
-                    device->touchScreen.currentVirtualKey.scanCode);
-#endif
-
-            dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
-                    KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-                            | KEY_EVENT_FLAG_CANCELED);
-
-            // Clear the last touch data so we will consider the pointer as having just been
-            // pressed down when generating subsequent motion events.
-            device->touchScreen.lastTouch.clear();
-            return false; // not consumed
+        if (device->touchScreen.currentTouch.pointerCount == 1) {
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey
+                    && virtualKey->keyCode == device->touchScreen.currentVirtualKey.keyCode) {
+                // Pointer is still within the space of the virtual key.
+                return true; // consumed
+            }
         }
-    } else if (device->touchScreen.currentTouch.pointerCount == 1
-            && device->touchScreen.lastTouch.pointerCount == 0) {
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        for (size_t i = 0; i < device->touchScreen.virtualKeys.size(); i++) {
-            const InputDevice::VirtualKey& virtualKey = device->touchScreen.virtualKeys[i];
 
+        // Pointer left virtual key area or another pointer also went down.
+        // Send key cancellation.
+        device->touchScreen.currentVirtualKey.status =
+                InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED;
 #if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
-                    "left=%d, top=%d, right=%d, bottom=%d",
-                    x, y,
-                    virtualKey.keyCode, virtualKey.scanCode,
-                    virtualKey.hitLeft, virtualKey.hitTop,
-                    virtualKey.hitRight, virtualKey.hitBottom);
+        LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
+                device->touchScreen.currentVirtualKey.keyCode,
+                device->touchScreen.currentVirtualKey.scanCode);
 #endif
+        dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
+                KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+                        | KEY_EVENT_FLAG_CANCELED);
+        return true; // consumed
 
-            if (virtualKey.isHit(x, y)) {
-                device->touchScreen.currentVirtualKey.down = true;
+    default:
+        if (device->touchScreen.currentTouch.pointerCount == 1
+                && device->touchScreen.lastTouch.pointerCount == 0) {
+            // Pointer just went down.  Check for virtual key hit.
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey) {
+                device->touchScreen.currentVirtualKey.status =
+                        InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN;
                 device->touchScreen.currentVirtualKey.downTime = when;
-                device->touchScreen.currentVirtualKey.keyCode = virtualKey.keyCode;
-                device->touchScreen.currentVirtualKey.scanCode = virtualKey.scanCode;
-
+                device->touchScreen.currentVirtualKey.keyCode = virtualKey->keyCode;
+                device->touchScreen.currentVirtualKey.scanCode = virtualKey->scanCode;
 #if DEBUG_VIRTUAL_KEYS
-                    LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
-                            device->touchScreen.currentVirtualKey.keyCode,
-                            device->touchScreen.currentVirtualKey.scanCode);
+                LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
+                        device->touchScreen.currentVirtualKey.keyCode,
+                        device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
                 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_DOWN,
                         KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
                 return true; // consumed
             }
         }
+        return false; // not consumed
     }
-
-    return false; // not consumed
 }
 
 void InputReader::dispatchVirtualKey(nsecs_t when,
@@ -1356,8 +1374,9 @@
     nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
     int32_t metaState = globalMetaState();
 
-    mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
-            keyCode, scanCode, metaState, downTime);
+    if (keyEventAction == KEY_EVENT_ACTION_DOWN) {
+        mPolicy->virtualKeyDownFeedback();
+    }
 
     int32_t policyActions = mPolicy->interceptKey(when, device->id,
             keyEventAction == KEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
@@ -1852,7 +1871,7 @@
         uint32_t flags;
         if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
                 & keyCode, & flags)) {
-            LOGI("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+            LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
             device->touchScreen.virtualKeys.pop(); // drop the key
             continue;
         }
@@ -1933,7 +1952,8 @@
     for (size_t i = 0; i < mDevices.size(); i++) {
         InputDevice* device = mDevices.valueAt(i);
         if (device->isTouchScreen()) {
-            if (device->touchScreen.currentVirtualKey.down) {
+            if (device->touchScreen.currentVirtualKey.status
+                    == InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN) {
                 keyCode = device->touchScreen.currentVirtualKey.keyCode;
                 scanCode = device->touchScreen.currentVirtualKey.scanCode;
             }
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index b1b7fed..053cc22 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -27,22 +27,25 @@
 import java.util.UUID;
 
 /**
- * AudioEffect is the base class for implementing audio effect control in Java applications.
- * Creating an AudioEffect object will create the effect engine in audio framework if no
- * instance of the same effect type exists in the specified audio session.
- * If one exists, this instance will be used. The application creating the AudioEffect object
- * (or a derived class) will either receive control of the effect engine or not depending
- * on the priority parameter. If priority is higher than the priority used by the current
- * effect engine owner, the control will be transfered to the new object. Otherwise
- * control will remain with the previous object. In this case, the new application will be
- * notified of changes in effect engine state or control ownership by the appropiate listener.
- * If the effect is to be applied to a specific AudioTrack or MediaPlayer instance,
- * the application must specify the audio session ID of that instance.
+ * AudioEffect is the base class for implementing audio effect control in Java
+ * applications.
+ * <p>Creating an AudioEffect object will create the effect engine in
+ * audio framework if no instance of the same effect type exists in the
+ * specified audio session. If one exists, this instance will be used.
+ * <p>The application creating the AudioEffect object (or a derived class) will either
+ * receive control of the effect engine or not depending on the priority
+ * parameter. If priority is higher than the priority used by the current effect
+ * engine owner, the control will be transfered to the new object. Otherwise
+ * control will remain with the previous object. In this case, the new
+ * application will be notified of changes in effect engine state or control
+ * ownership by the appropiate listener.
+ * <p>If the effect is to be applied to a specific AudioTrack or MediaPlayer instance,
+ * the application must specify the audio session ID of that instance when calling the AudioEffect
+ * constructor.
  *
- * {@hide Pending API council review}
+ * { @hide Pending API council review }
  */
-public class AudioEffect
-{
+public class AudioEffect {
     static {
         System.loadLibrary("audioeffect_jni");
         native_init();
@@ -51,31 +54,60 @@
     private final static String TAG = "AudioEffect-JAVA";
 
     /**
-     * The following UUIDs define effect types corresponding to standard audio effects
-     * whose implementation and interface conform to the OpenSL ES specification.
-     * The definitions match the corresponding interface IDs in OpenSLES_IID.h
+     * The following UUIDs define effect types corresponding to standard audio
+     * effects whose implementation and interface conform to the OpenSL ES
+     * specification. The definitions match the corresponding interface IDs in
+     * OpenSLES_IID.h
      */
-    public static final UUID EFFECT_TYPE_ENV_REVERB = UUID.fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
-    public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID.fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
-    public static final UUID EFFECT_TYPE_EQUALIZER = UUID.fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
-    public static final UUID EFFECT_TYPE_BASS_BOOST = UUID.fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
-    public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID.fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
-
-    public static final UUID EFFECT_TYPE_INVALID = UUID.fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
 
     /**
-     * State of an AudioEffect object that was not successfully initialized upon creation
+     * UUID for environmental reverb effect
+     */
+    public static final UUID EFFECT_TYPE_ENV_REVERB = UUID
+            .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
+    /**
+     * UUID for preset reverb effect
+     */
+    public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID
+            .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
+    /**
+     * UUID for equalizer effect
+     */
+    public static final UUID EFFECT_TYPE_EQUALIZER = UUID
+            .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
+    /**
+     * UUID for bass boost effect
+     */
+    public static final UUID EFFECT_TYPE_BASS_BOOST = UUID
+            .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
+    /**
+     * UUID for virtualizer effect
+     */
+    public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID
+            .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
+
+    /**
+     * Null effect UUID. Used when the UUID for effect type of
+     */
+    public static final UUID EFFECT_TYPE_NULL = UUID
+            .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
+
+    /**
+     * State of an AudioEffect object that was not successfully initialized upon
+     * creation
      */
     public static final int STATE_UNINITIALIZED = 0;
     /**
      * State of an AudioEffect object that is ready to be used.
      */
-    public static final int STATE_INITIALIZED   = 1;
+    public static final int STATE_INITIALIZED = 1;
 
+    // to keep in sync with
+    // frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
     /**
      * Event id for engine state change notification.
      */
-    protected static final int NATIVE_EVENT_ENABLED_STATUS  = 0;
+    protected static final int NATIVE_EVENT_ENABLED_STATUS = 0;
     /**
      * Event id for engine control ownership change notification.
      */
@@ -85,56 +117,89 @@
      */
     protected static final int NATIVE_EVENT_PARAMETER_CHANGED = 2;
 
+    /**
+     * Successful operation.
+     */
+    public static final int SUCCESS = 0;
+    /**
+     * Unspecified error.
+     */
+    public static final int ERROR = -1;
+    /**
+     * Internal opreation status. Not returned by any method.
+     */
+    public static final int ALREADY_EXISTS = -2;
+    /**
+     * Operation failed due to bad object initialization.
+     */
+    public static final int ERROR_NO_INIT = -3;
+    /**
+     * Operation failed due to bad parameter value.
+     */
+    public static final int ERROR_BAD_VALUE = -4;
+    /**
+     * Operation failed because it was requested in wrong state.
+     */
+    public static final int ERROR_INVALID_OPERATION = -5;
+    /**
+     * Operation failed due to lack of memory.
+     */
+    public static final int ERROR_NO_MEMORY = -6;
+    /**
+     * Operation failed due to dead remote object.
+     */
+    public static final int ERROR_DEAD_OBJECT = -7;
 
-    // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
-    public  static final int SUCCESS              = 0;
-    public  static final int ERROR                = -1;
-    public  static final int ALREADY_EXISTS       = -2;
-    public  static final int NO_INIT              = -3;
-    public  static final int BAD_VALUE            = -4;
-    public  static final int INVALID_OPERATION    = -5;
-    public  static final int NO_MEMORY            = -6;
-    public  static final int DEAD_OBJECT          = -7;
+    /**
+     * The effect descriptor contains necessary information to facilitate
+     * effects enumeration:<br>
+     * <ul>
+     *  <li>mType: UUID corresponding to the OpenSL ES interface implemented by this effect</li>
+     *  <li>mUuid: UUID for this particular implementation</li>
+     *  <li>mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
+     *  <li>mName: human readable effect name</li>
+     *  <li>mImplementor: human readable effect implementor name</li>
+     * </ul>
+     */
+    public static class Descriptor {
 
+        public Descriptor() {
+        }
 
-     /**
-      * The effect descriptor contains necessary information to facilitate
-      * effects enumeration:
-      * mType: UUID corresponding to the OpenSL ES interface implemented by this effect
-      * mUuid: UUID for this particular implementation
-      * mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
-      * mName: human readable effect name
-      * mImplementor: human readable effect implementor name
-      */
-     public static class Descriptor {
+        public Descriptor(String type, String uuid, String connectMode,
+                String name, String implementor) {
+            mType = UUID.fromString(type);
+            mUuid = UUID.fromString(uuid);
+            mConnectMode = connectMode;
+            mName = name;
+            mImplementor = implementor;
+        }
 
-         public Descriptor() {
-         }
-         public Descriptor(String type,
-                           String uuid,
-                           String connectMode,
-                           String name,
-                           String implementor) {
-             mType = UUID.fromString(type);
-             mUuid = UUID.fromString(uuid);
-             mConnectMode = connectMode;
-             mName = name;
-             mImplementor = implementor;
-         }
+        public UUID mType;
+        public UUID mUuid;
+        public String mConnectMode;
+        public String mName;
+        public String mImplementor;
+    };
 
-         public UUID mType;
-         public UUID mUuid;
-         public String mConnectMode;
-         public String mName;
-         public String mImplementor;
-     };
+    /**
+     * Effect connection mode is insert. Specifying an audio session ID when creating the effect
+     * will insert this effect after all players in the same audio session.
+     */
+    public static final String EFFECT_INSERT = "Insert";
+    /**
+     * Effect connection mode is auxiliary.
+     * <p>Auxiliary effects must be created on session 0 (global output mix). In order for a
+     * MediaPlayer or AudioTrack to be fed into this effect, they must be explicitely attached to
+     * this effect and a send level must be specified.
+     * <p>Use the effect ID returned by {@link #getId()} to designate this particular effect when
+     * attaching it to the MediaPlayer or AudioTrack.
+     */
+    public static final String EFFECT_AUXILIARY = "Auxiliary";
 
-     public static final String EFFECT_INSERT = "Insert";
-     public static final String EFFECT_AUXILIARY = "Auxiliary";
-
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Member variables
-    //--------------------
+    // --------------------
     /**
      * Indicates the state of the AudioEffect instance
      */
@@ -159,17 +224,20 @@
 
     /**
      * Listener for effect engine state change notifications.
-     *  @see #setEnableStatusListener(OnEnableStatusChangeListener)
+     *
+     * @see #setEnableStatusListener(OnEnableStatusChangeListener)
      */
     protected OnEnableStatusChangeListener mEnableStatusChangeListener = null;
     /**
      * Listener for effect engine control ownership change notifications.
-     *  @see #setControlStatusListener(OnControlStatusChangeListener)
+     *
+     * @see #setControlStatusListener(OnControlStatusChangeListener)
      */
     protected OnControlStatusChangeListener mControlChangeStatusListener = null;
     /**
      * Listener for effect engine control ownership change notifications.
-     *  @see #setParameterListener(OnParameterChangeListener)
+     *
+     * @see #setParameterListener(OnParameterChangeListener)
      */
     protected OnParameterChangeListener mParameterChangeListener = null;
     /**
@@ -181,32 +249,36 @@
      */
     protected NativeEventHandler mNativeEventHandler = null;
 
-
-
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Constructor, Finalize
-    //--------------------
+    // --------------------
     /**
      * Class constructor.
-     * @param type:  type of effect engine created. See
-     *   {@link #EFFECT_TYPE_ENV_REVERB}, {@link #EFFECT_TYPE_EQUALIZER} ...
-     *   Types corresponding to built-in effects are defined by AudioEffect class.
-     *   Other types can be specified provided they correspond an existing OpenSL ES
-     *   interface ID and the corresponsing effect is available on the platform.
-     *   If an unspecified effect type is requested, the constructor with throw the
-     *   IllegalArgumentException.
-     * @param uuid:  unique identifier of a particular effect implementation. Must be
-     *  specified if the caller wants to use a particular implementation of an effect type.
-     *  This parameter can be set to null in which case only the type will be used to select
-     *  the effect.
-     * @param priority:  the priority level requested by the application for controlling
-     *  the effect engine. As the same effect engine can be shared by several applications,
-     *  this parameter indicates how much the requesting application needs control of
-     *  effect parameters. The normal priority is 0, above normal is a positive number,
-     *  below normal a negative number.
-     * @param audioSession:  System wide unique audio session identifier. If audioSession
-     *  is not 0, the effect will be attached to the MediaPlayer or AudioTrack in the
-     *  same audio session. Otherwise, the effect will apply to the output mix.
+     *
+     * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB},
+     *            {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to
+     *            built-in effects are defined by AudioEffect class. Other types
+     *            can be specified provided they correspond an existing OpenSL
+     *            ES interface ID and the corresponsing effect is available on
+     *            the platform. If an unspecified effect type is requested, the
+     *            constructor with throw the IllegalArgumentException. This
+     *            parameter can be set to {@link #EFFECT_TYPE_NULL} in which
+     *            case only the uuid will be used to select the effect.
+     * @param uuid unique identifier of a particular effect implementation.
+     *            Must be specified if the caller wants to use a particular
+     *            implementation of an effect type. This parameter can be set to
+     *            {@link #EFFECT_TYPE_NULL} in which case only the type will
+     *            be used to select the effect.
+     * @param priority the priority level requested by the application for
+     *            controlling the effect engine. As the same effect engine can
+     *            be shared by several applications, this parameter indicates
+     *            how much the requesting application needs control of effect
+     *            parameters. The normal priority is 0, above normal is a
+     *            positive number, below normal a negative number.
+     * @param audioSession System wide unique audio session identifier. If audioSession
+     *            is not 0, the effect will be attached to the MediaPlayer or
+     *            AudioTrack in the same audio session. Otherwise, the effect
+     *            will apply to the output mix.
      *
      * @throws java.lang.IllegalArgumentException
      * @throws java.lang.UnsupportedOperationException
@@ -214,22 +286,28 @@
      */
 
     public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
-    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+            throws IllegalArgumentException, UnsupportedOperationException,
+            RuntimeException {
         int[] id = new int[1];
         Descriptor[] desc = new Descriptor[1];
         // native initialization
         int initResult = native_setup(new WeakReference<AudioEffect>(this),
-                type.toString(), uuid.toString(), priority, audioSession, id, desc);
+                type.toString(), uuid.toString(), priority, audioSession, id,
+                desc);
         if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
-            Log.e(TAG, "Error code "+initResult+" when initializing AudioEffect.");
+            Log.e(TAG, "Error code " + initResult
+                    + " when initializing AudioEffect.");
             switch (initResult) {
-            case BAD_VALUE:
-                throw (new IllegalArgumentException("Effect type: "+type+ " not supported."));
-            case INVALID_OPERATION:
-                throw (new UnsupportedOperationException("Effect library not loaded"));
+            case ERROR_BAD_VALUE:
+                throw (new IllegalArgumentException("Effect type: " + type
+                        + " not supported."));
+            case ERROR_INVALID_OPERATION:
+                throw (new UnsupportedOperationException(
+                        "Effect library not loaded"));
             default:
-                throw (new RuntimeException("Cannot initialize effect engine for type: "+type+
-                        "Error: "+ initResult));
+                throw (new RuntimeException(
+                        "Cannot initialize effect engine for type: " + type
+                                + "Error: " + initResult));
             }
         }
         mId = id[0];
@@ -240,9 +318,9 @@
     }
 
     /**
-     * Releases the native AudioEffect resources. It is a good practice to release the
-     * effect engine when not in use as control can be returned to other applications
-     * or the native resources released.
+     * Releases the native AudioEffect resources. It is a good practice to
+     * release the effect engine when not in use as control can be returned to
+     * other applications or the native resources released.
      */
     public void release() {
         synchronized (mStateLock) {
@@ -258,119 +336,115 @@
 
     /**
      * Get the effect descriptor.
-     * {@see #Descriptor}.
+     *
+     //TODO when AudioEffect class is unhidden @ see android.media.AudioEffect.Descriptor
      * @throws IllegalStateException
      */
-    public Descriptor getDescriptor()
-    throws IllegalStateException {
+    public Descriptor getDescriptor() throws IllegalStateException {
         checkState("getDescriptor()");
         return mDescriptor;
     }
 
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Effects Enumeration
-    //--------------------
+    // --------------------
 
     /**
      * Query all effects available on the platform. Returns an array of
-     * {@link #Descriptor} objects
+     //TODO when AudioEffect class is unhidden: {@ link android.media.AudioEffect.Descriptor} objects
      *
      * @throws IllegalStateException
      */
 
     static public Descriptor[] queryEffects() {
-        return (Descriptor[])native_query_effects();
+        return (Descriptor[]) native_query_effects();
     }
 
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Control methods
-    //--------------------
+    // --------------------
 
     /**
-     * Enable effect engine.
-     * @return {@link #NO_ERROR} in case of success,
-     * {@link #INVALID_OPERATION} or {@link #DEAD_OBJECT} in case of failure.
+     * Enable or disable effect engine.
+     *
+     * @param enabled the requested enable state
+     * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
+     *         or {@link #ERROR_DEAD_OBJECT} in case of failure.
      * @throws IllegalStateException
      */
-    public int enable()
-    throws IllegalStateException {
-        checkState("enable()");
-        return native_enable();
-    }
-
-    /**
-     * Disable effect engine.
-     * @return NO_ERROR in case of success,
-     * INVALID_OPERATION or DEAD_OBJECT in case of failure.
-     * @throws IllegalStateException
-     */
-    public int disable()
-    throws IllegalStateException {
-        checkState("disable()");
-        return native_disable();
+    public int setEnabled(boolean enabled) throws IllegalStateException {
+        checkState("setEnabled()");
+        return native_setEnabled(enabled);
     }
 
     /**
      * Set effect parameter. The setParameter method is provided in several
-     * forms addressing most common parameter formats. This form is the
-     * most generic one where the parameter and its value are both specified
-     * as an array of bytes. The parameter and value type and length are therefore
-     * totally free. For standard effect defined by OpenSL ES, the parameter format
-     * and values must match the definitions in the corresponding OpenSL ES interface.
+     * forms addressing most common parameter formats. This form is the most
+     * generic one where the parameter and its value are both specified as an
+     * array of bytes. The parameter and value type and length are therefore
+     * totally free. For standard effect defined by OpenSL ES, the parameter
+     * format and values must match the definitions in the corresponding OpenSL
+     * ES interface.
      *
-     * @param param:  the identifier of the parameter to set
-     * @param value:  the new value for the specified parameter
-     * @return NO_ERROR in case of success,
-     * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
+     * @param param the identifier of the parameter to set
+     * @param value the new value for the specified parameter
+     * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+     *         {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+     *         {@link #ERROR_DEAD_OBJECT} in case of failure
      * @throws IllegalStateException
      */
     public int setParameter(byte[] param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         checkState("setParameter()");
         return native_setParameter(param.length, param, value.length, value);
     }
 
     /**
      * Set effect parameter. The parameter and its value are integers.
-     *  @see #setParameter(byte[], byte[])
+     *
+     * @see #setParameter(byte[], byte[])
      */
-    public int setParameter(int param, int value)
-    throws IllegalStateException {
+    public int setParameter(int param, int value) throws IllegalStateException {
         byte[] p = intToByteArray(param);
         byte[] v = intToByteArray(value);
         return setParameter(p, v);
     }
 
     /**
-     * Set effect parameter. The parameter is an integer and the value is a short integer.
-     *  @see #setParameter(byte[], byte[])
+     * Set effect parameter. The parameter is an integer and the value is a
+     * short integer.
+     *
+     * @see #setParameter(byte[], byte[])
      */
     public int setParameter(int param, short value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         byte[] p = intToByteArray(param);
         byte[] v = shortToByteArray(value);
         return setParameter(p, v);
     }
 
     /**
-     * Set effect parameter. The parameter is an integer and the value is an array of bytes.
-     *  @see #setParameter(byte[], byte[])
+     * Set effect parameter. The parameter is an integer and the value is an
+     * array of bytes.
+     *
+     * @see #setParameter(byte[], byte[])
      */
     public int setParameter(int param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         byte[] p = intToByteArray(param);
         return setParameter(p, value);
     }
 
     /**
-     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is also an array of 1 or 2 integers
-     *  @see #setParameter(byte[], byte[])
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is also an array of 1 or 2 integers
+     *
+     * @see #setParameter(byte[], byte[])
      */
     public int setParameter(int[] param, int[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2 || value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -386,14 +460,15 @@
     }
 
     /**
-     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is an array of 1 or 2 short integers
-     *  @see #setParameter(byte[], byte[])
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is an array of 1 or 2 short integers
+     *
+     * @see #setParameter(byte[], byte[])
      */
     public int setParameter(int[] param, short[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2 || value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -410,14 +485,15 @@
     }
 
     /**
-     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is an array of bytes
-     *  @see #setParameter(byte[], byte[])
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is an array of bytes
+     *
+     * @see #setParameter(byte[], byte[])
      */
     public int setParameter(int[] param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -429,20 +505,23 @@
 
     /**
      * Get effect parameter. The getParameter method is provided in several
-     * forms addressing most common parameter formats. This form is the
-     * most generic one where the parameter and its value are both specified
-     * as an array of bytes. The parameter and value type and length are therefore
+     * forms addressing most common parameter formats. This form is the most
+     * generic one where the parameter and its value are both specified as an
+     * array of bytes. The parameter and value type and length are therefore
      * totally free.
-     * @param param:  the identifier of the parameter to set
-     * @param value:  the new value for the specified parameter
-     * @return NO_ERROR in case of success,
-     * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
-     * When called, value.length indicates the maximum size of the returned parameters value.
-     * When returning, value.length is updated with the actual size of the returned value.
+     *
+     * @param param the identifier of the parameter to set
+     * @param value the new value for the specified parameter
+     * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+     *         {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+     *         {@link #ERROR_DEAD_OBJECT} in case of failure When called, value.length
+     *         indicates the maximum size of the returned parameters value. When
+     *         returning, value.length is updated with the actual size of the
+     *         returned value.
      * @throws IllegalStateException
      */
     public int getParameter(byte[] param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         checkState("getParameter()");
         int[] vSize = new int[1];
         vSize[0] = value.length;
@@ -456,25 +535,28 @@
     }
 
     /**
-     * Get effect parameter. The parameter is an integer and the value is an array of bytes.
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an integer and the value is an
+     * array of bytes.
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         byte[] p = intToByteArray(param);
 
         return getParameter(p, value);
     }
 
     /**
-     * Get effect parameter. The parameter is an integer and the value
-     *  is an array of 1 or 2 integers
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an integer and the value is an
+     * array of 1 or 2 integers
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int param, int[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param);
 
@@ -490,14 +572,15 @@
     }
 
     /**
-     * Get effect parameter. The parameter is an integer and the value
-     *  is an array of 1 or 2 short integers
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an integer and the value is an
+     * array of 1 or 2 short integers
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int param, short[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param);
 
@@ -513,14 +596,15 @@
     }
 
     /**
-     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is also an array of 1 or 2 integers
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is also an array of 1 or 2 integers
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int[] param, int[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2 || value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -539,14 +623,15 @@
     }
 
     /**
-     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is an array of 1 or 2 short integers
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is an array of 1 or 2 short integers
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int[] param, short[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2 || value.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -565,14 +650,15 @@
     }
 
     /**
-     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
-     *  is an array of bytes
-     *  @see #getParameter(byte[], byte[])
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and
+     * the value is an array of bytes
+     *
+     * @see #getParameter(byte[], byte[])
      */
     public int getParameter(int[] param, byte[] value)
-    throws IllegalStateException {
+            throws IllegalStateException {
         if (param.length > 2) {
-            return BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         byte[] p = intToByteArray(param[0]);
         if (param.length > 1) {
@@ -583,19 +669,19 @@
         return getParameter(p, value);
     }
 
-
     /**
-     * Send a command to the effect engine. This method is intended to send proprietary
-     * commands to a particular effect implementation.
+     * Send a command to the effect engine. This method is intended to send
+     * proprietary commands to a particular effect implementation.
      *
      */
     public int command(int cmdCode, byte[] command, byte[] reply)
-    throws IllegalStateException {
+            throws IllegalStateException {
         checkState("command()");
         int[] replySize = new int[1];
         replySize[0] = reply.length;
 
-        int status = native_command(cmdCode, command.length, command, replySize, reply);
+        int status = native_command(cmdCode, command.length, command,
+                replySize, reply);
 
         if (reply.length > replySize[0]) {
             byte[] resizedReply = new byte[replySize[0]];
@@ -605,51 +691,53 @@
         return status;
     }
 
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Getters
-    //--------------------
+    // --------------------
 
     /**
-     * Returns effect unique identifier. This system wide unique identifier
-     * can be used to attach this effect to a MediaPlayer or an AudioTrack
-     * when the effect is an auxiliary effect (Reverb)
+     * Returns effect unique identifier. This system wide unique identifier can
+     * be used to attach this effect to a MediaPlayer or an AudioTrack when the
+     * effect is an auxiliary effect (Reverb)
+     *
      * @return the effect identifier.
      * @throws IllegalStateException
      */
-    public int getId()
-    throws IllegalStateException {
+    public int getId() throws IllegalStateException {
         checkState("getId()");
         return mId;
     }
 
     /**
      * Returns effect engine enable state
+     *
      * @return true if the effect is enabled, false otherwise.
      * @throws IllegalStateException
      */
-    public boolean getEnable()
-    throws IllegalStateException {
-        checkState("getEnable()");
-        return native_getEnable();
+    public boolean getEnabled() throws IllegalStateException {
+        checkState("getEnabled()");
+        return native_getEnabled();
     }
 
     /**
      * Checks if this AudioEffect object is controlling the effect engine.
-     * @return true if this instance has control of effect engine, false otherwise.
+     *
+     * @return true if this instance has control of effect engine, false
+     *         otherwise.
      * @throws IllegalStateException
      */
-    public boolean hasControl()
-    throws IllegalStateException {
+    public boolean hasControl() throws IllegalStateException {
         checkState("hasControl()");
         return native_hasControl();
     }
 
-    //--------------------------------------------------------------------------
+    // --------------------------------------------------------------------------
     // Initialization / configuration
-    //--------------------
+    // --------------------
     /**
      * Sets the listener AudioEffect notifies when the effect engine is enabled
      * or disabled.
+     *
      * @param listener
      */
     public void setEnableStatusListener(OnEnableStatusChangeListener listener) {
@@ -662,8 +750,9 @@
     }
 
     /**
-     * Sets the listener AudioEffect notifies when the effect engine control
-     * is taken or returned.
+     * Sets the listener AudioEffect notifies when the effect engine control is
+     * taken or returned.
+     *
      * @param listener
      */
     public void setControlStatusListener(OnControlStatusChangeListener listener) {
@@ -677,6 +766,7 @@
 
     /**
      * Sets the listener AudioEffect notifies when a parameter is changed.
+     *
      * @param listener
      */
     public void setParameterListener(OnParameterChangeListener listener) {
@@ -691,7 +781,7 @@
     // Convenience method for the creation of the native event handler
     // It is called only when a non-null event listener is set.
     // precondition:
-    //    mNativeEventHandler is null
+    // mNativeEventHandler is null
     private void createNativeEventHandler() {
         Looper looper;
         if ((looper = Looper.myLooper()) != null) {
@@ -703,52 +793,62 @@
         }
     }
 
-    //---------------------------------------------------------
+    // ---------------------------------------------------------
     // Interface definitions
-    //--------------------
+    // --------------------
     /**
-     * Interface definition for a callback to be invoked when the
-     * effect engine is enabled or disabled.
+     * The OnParameterChangeListener interface defines a method called by the AudioEffect
+     * when a the enabled state of the effect engine was changed by the controlling application.
      */
-    public interface OnEnableStatusChangeListener  {
+    public interface OnEnableStatusChangeListener {
         /**
-         * Called on the listener to notify it that the effect engine
-         * has been enabled or disabled.
+         * Called on the listener to notify it that the effect engine has been
+         * enabled or disabled.
+         * @param effect the effect on which the interface is registered.
+         * @param enabled new effect state.
          */
         void onEnableStatusChange(AudioEffect effect, boolean enabled);
     }
 
     /**
-     * Interface definition for a callback to be invoked when the
-     * effect engine control is taken or returned.
+     * The OnControlStatusChangeListener interface defines a method called by the AudioEffect
+     * when a the control of the effect engine is gained or lost by the application
      */
-    public interface OnControlStatusChangeListener  {
+    public interface OnControlStatusChangeListener {
         /**
-         * Called on the listener to notify it that the effect engine
-         * control has been taken or returned.
+         * Called on the listener to notify it that the effect engine control
+         * has been taken or returned.
+         * @param effect the effect on which the interface is registered.
+         * @param controlGranted true if the application has been granted control of the effect
+         * engine, false otherwise.
          */
         void onControlStatusChange(AudioEffect effect, boolean controlGranted);
     }
 
     /**
-     * Interface definition for a callback to be invoked when a
-     * parameter value has changed.
+     * The OnParameterChangeListener interface defines a method called by the AudioEffect
+     * when a parameter is changed in the effect engine by the controlling application.
      */
-    public interface OnParameterChangeListener  {
+    public interface OnParameterChangeListener {
         /**
          * Called on the listener to notify it that a parameter value has changed.
+         * @param effect the effect on which the interface is registered.
+         * @param status status of the set parameter operation.
+         * @param param ID of the modified parameter.
+         * @param value the new parameter value.
          */
-        void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value);
+        void onParameterChange(AudioEffect effect, int status, byte[] param,
+                byte[] value);
     }
 
-    //---------------------------------------------------------
+    // ---------------------------------------------------------
     // Inner classes
-    //--------------------
+    // --------------------
     /**
-     * Helper class to handle the forwarding of native events to the appropriate listeners
+     * Helper class to handle the forwarding of native events to the appropriate
+     * listeners
      */
-    private class NativeEventHandler extends Handler
-    {
+    private class NativeEventHandler extends Handler {
         private AudioEffect mAudioEffect;
 
         public NativeEventHandler(AudioEffect ae, Looper looper) {
@@ -761,14 +861,15 @@
             if (mAudioEffect == null) {
                 return;
             }
-            switch(msg.what) {
+            switch (msg.what) {
             case NATIVE_EVENT_ENABLED_STATUS:
                 OnEnableStatusChangeListener enableStatusChangeListener = null;
                 synchronized (mListenerLock) {
                     enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener;
                 }
                 if (enableStatusChangeListener != null) {
-                    enableStatusChangeListener.onEnableStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+                    enableStatusChangeListener.onEnableStatusChange(
+                            mAudioEffect, (boolean) (msg.arg1 != 0));
                 }
                 break;
             case NATIVE_EVENT_CONTROL_STATUS:
@@ -777,7 +878,8 @@
                     controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener;
                 }
                 if (controlStatusChangeListener != null) {
-                    controlStatusChangeListener.onControlStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+                    controlStatusChangeListener.onControlStatusChange(
+                            mAudioEffect, (boolean) (msg.arg1 != 0));
                 }
                 break;
             case NATIVE_EVENT_PARAMETER_CHANGED:
@@ -786,10 +888,12 @@
                     parameterChangeListener = mAudioEffect.mParameterChangeListener;
                 }
                 if (parameterChangeListener != null) {
-                    // arg1 contains offset of parameter value from start of byte array
+                    // arg1 contains offset of parameter value from start of
+                    // byte array
                     int vOffset = msg.arg1;
-                    byte[] p = (byte[])msg.obj;
-                    // See effect_param_t in EffectApi.h for psize and vsize fields offsets
+                    byte[] p = (byte[]) msg.obj;
+                    // See effect_param_t in EffectApi.h for psize and vsize
+                    // fields offsets
                     int status = byteArrayToInt(p, 0);
                     int psize = byteArrayToInt(p, 4);
                     int vsize = byteArrayToInt(p, 8);
@@ -798,90 +902,76 @@
                     System.arraycopy(p, 12, param, 0, psize);
                     System.arraycopy(p, vOffset, value, 0, vsize);
 
-                    parameterChangeListener.onParameterChange(mAudioEffect, status, param, value);
+                    parameterChangeListener.onParameterChange(mAudioEffect,
+                            status, param, value);
                 }
                 break;
 
-             default:
+            default:
                 Log.e(TAG, "handleMessage() Unknown event type: " + msg.what);
                 break;
             }
         }
     }
 
-
-    //---------------------------------------------------------
+    // ---------------------------------------------------------
     // Java methods called from the native side
-    //--------------------
+    // --------------------
     @SuppressWarnings("unused")
-    private static void postEventFromNative(Object effect_ref,
-            int what, int arg1, int arg2, Object obj) {
-        AudioEffect effect = (AudioEffect)((WeakReference)effect_ref).get();
+    private static void postEventFromNative(Object effect_ref, int what,
+            int arg1, int arg2, Object obj) {
+        AudioEffect effect = (AudioEffect) ((WeakReference) effect_ref).get();
         if (effect == null) {
             return;
         }
 
         if (effect.mNativeEventHandler != null) {
-            Message m = effect.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+            Message m = effect.mNativeEventHandler.obtainMessage(what, arg1,
+                    arg2, obj);
             effect.mNativeEventHandler.sendMessage(m);
         }
 
     }
 
-
-    //---------------------------------------------------------
+    // ---------------------------------------------------------
     // Native methods called from the Java side
-    //--------------------
+    // --------------------
 
     private static native final void native_init();
 
-    private native final int native_setup(Object audioeffect_this,
-                                          String type,
-                                          String uuid,
-                                          int priority,
-                                          int audioSession,
-                                          int[] id,
-                                          Object[] desc);
+    private native final int native_setup(Object audioeffect_this, String type,
+            String uuid, int priority, int audioSession, int[] id, Object[] desc);
 
     private native final void native_finalize();
 
     private native final void native_release();
 
-    private native final int native_enable();
+    private native final int native_setEnabled(boolean enabled);
 
-    private native final int native_disable();
-
-    private native final boolean native_getEnable();
+    private native final boolean native_getEnabled();
 
     private native final boolean native_hasControl();
 
-    private native final int native_setParameter(int psize,
-                                                 byte[] param,
-                                                 int vsize,
-                                                 byte[] value);
+    private native final int native_setParameter(int psize, byte[] param,
+            int vsize, byte[] value);
 
-    private native final int native_getParameter(int psize,
-                                                 byte[] param,
-                                                 int[] vsize,
-                                                 byte[] value);
+    private native final int native_getParameter(int psize, byte[] param,
+            int[] vsize, byte[] value);
 
-    private native final int native_command(int cmdCode,
-                                            int cmdSize,
-                                            byte[] cmdData,
-                                            int[] repSize,
-                                            byte[] repData);
+    private native final int native_command(int cmdCode, int cmdSize,
+            byte[] cmdData, int[] repSize, byte[] repData);
 
     private static native Object[] native_query_effects();
 
-    //---------------------------------------------------------
+    // ---------------------------------------------------------
     // Utility methods
-    //------------------
+    // ------------------
 
-    protected void checkState(String methodName)
-        throws IllegalStateException {
+    protected void checkState(String methodName) throws IllegalStateException {
         synchronized (mStateLock) {
             if (mState != STATE_INITIALIZED) {
-                throw(new IllegalStateException(methodName+" called on uninitialized AudioEffect."));
+                throw (new IllegalStateException(methodName
+                        + " called on uninitialized AudioEffect."));
             }
         }
     }
@@ -890,10 +980,12 @@
         switch (status) {
         case AudioEffect.SUCCESS:
             break;
-        case AudioEffect.BAD_VALUE:
-            throw (new IllegalArgumentException("AudioEffect: bad parameter value"));
-        case AudioEffect.INVALID_OPERATION:
-            throw (new UnsupportedOperationException("AudioEffect: invalid parameter operation"));
+        case AudioEffect.ERROR_BAD_VALUE:
+            throw (new IllegalArgumentException(
+                    "AudioEffect: bad parameter value"));
+        case AudioEffect.ERROR_INVALID_OPERATION:
+            throw (new UnsupportedOperationException(
+                    "AudioEffect: invalid parameter operation"));
         default:
             throw (new RuntimeException("AudioEffect: set/get parameter error"));
         }
@@ -903,6 +995,7 @@
         return byteArrayToInt(valueBuf, 0);
 
     }
+
     protected int byteArrayToInt(byte[] valueBuf, int offset) {
         ByteBuffer converter = ByteBuffer.wrap(valueBuf);
         converter.order(ByteOrder.nativeOrder());
@@ -931,12 +1024,12 @@
     protected byte[] shortToByteArray(short value) {
         ByteBuffer converter = ByteBuffer.allocate(2);
         converter.order(ByteOrder.nativeOrder());
-        short sValue = (short)value;
+        short sValue = (short) value;
         converter.putShort(sValue);
         return converter.array();
     }
 
-    protected byte[] concatArrays(byte[] ...arrays) {
+    protected byte[] concatArrays(byte[]... arrays) {
         int len = 0;
         for (byte[] a : arrays) {
             len += a.length;
diff --git a/media/java/android/media/Visualizer.java b/media/java/android/media/Visualizer.java
new file mode 100755
index 0000000..cdd3cdf
--- /dev/null
+++ b/media/java/android/media/Visualizer.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.io.IOException;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * <p>The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:<br>
+ * <ul>
+ *   <li>If the session is 0, the audio output mix is visualized</li>
+ *   <li>If the session is not 0, the audio from a particular {@link MediaPlayer} or
+ *   {@link AudioTrack}
+ *   using this audio session is visualized </li>
+ * </ul>
+ * <p>Two types of representation of audio content can be captured: <br>
+ * <ul>
+ *   <li>Waveform data: consecutive 8-bit (unsigned) mono samples by using the
+ *   {@link #getWaveForm(byte[])} method</li>
+ *   <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
+ * </ul>
+ * <p>The length of the capture can be retrieved or specified by calling respectively
+ * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by {@link #getCaptureSizeRange()}.
+ * <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
+ *  {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
+ *  use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ *  The rate at which the listener capture method is called as well as the type of data returned is
+ *  specified.
+ * <p>Before capturing data, the Visualizer must be enabled by calling the
+ * {@link #setEnabled(boolean)} method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ * <p>It is good practice to call the {@link #release()} method when the Visualizer is not used
+ * anymore to free up native resources associated to the Visualizer instance.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Visualizer {
+
+    static {
+        System.loadLibrary("audioeffect_jni");
+        native_init();
+    }
+
+    private final static String TAG = "Visualizer-JAVA";
+
+    /**
+     * State of a Visualizer object that was not successfully initialized upon creation
+     */
+    public static final int STATE_UNINITIALIZED = 0;
+    /**
+     * State of a Visualizer object that is ready to be used.
+     */
+    public static final int STATE_INITIALIZED   = 1;
+    /**
+     * State of a Visualizer object that is active.
+     */
+    public static final int STATE_ENABLED   = 2;
+
+    // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
+    protected static final int NATIVE_EVENT_PCM_CAPTURE = 0;
+    protected static final int NATIVE_EVENT_FFT_CAPTURE = 1;
+
+    // Error codes:
+    /**
+     * Successful operation.
+     */
+    public  static final int SUCCESS              = 0;
+    /**
+     * Unspecified error.
+     */
+    public  static final int ERROR                = -1;
+    /**
+     * Internal opreation status. Not returned by any method.
+     */
+    public  static final int ALREADY_EXISTS       = -2;
+    /**
+     * Operation failed due to bad object initialization.
+     */
+    public  static final int ERROR_NO_INIT              = -3;
+    /**
+     * Operation failed due to bad parameter value.
+     */
+    public  static final int ERROR_BAD_VALUE            = -4;
+    /**
+     * Operation failed because it was requested in wrong state.
+     */
+    public  static final int ERROR_INVALID_OPERATION    = -5;
+    /**
+     * Operation failed due to lack of memory.
+     */
+    public  static final int ERROR_NO_MEMORY            = -6;
+    /**
+     * Operation failed due to dead remote object.
+     */
+    public  static final int ERROR_DEAD_OBJECT          = -7;
+
+    //--------------------------------------------------------------------------
+    // Member variables
+    //--------------------
+    /**
+     * Indicates the state of the Visualizer instance
+     */
+    protected int mState = STATE_UNINITIALIZED;
+    /**
+     * Lock to synchronize access to mState
+     */
+    protected final Object mStateLock = new Object();
+    /**
+     * System wide unique Identifier of the visualizer engine used by this Visualizer instance
+     */
+    protected int mId;
+
+    /**
+     * Lock to protect listeners updates against event notifications
+     */
+    protected final Object mListenerLock = new Object();
+    /**
+     * Handler for events coming from the native code
+     */
+    protected NativeEventHandler mNativeEventHandler = null;
+    /**
+     *  PCM and FFT capture listener registered by client
+     */
+    protected OnDataCaptureListener mCaptureListener = null;
+
+    // accessed by native methods
+    private int mNativeVisualizer;
+    private int mJniData;
+
+    //--------------------------------------------------------------------------
+    // Constructor, Finalize
+    //--------------------
+    /**
+     * Class constructor.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the visualizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Visualizer will apply to the output mix.
+     *
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+
+    public Visualizer(int audioSession)
+    throws UnsupportedOperationException, RuntimeException {
+        int[] id = new int[1];
+
+        synchronized (mStateLock) {
+            mState = STATE_UNINITIALIZED;
+            // native initialization
+            int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id);
+            if (result != SUCCESS && result != ALREADY_EXISTS) {
+                Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
+                switch (result) {
+                case ERROR_INVALID_OPERATION:
+                    throw (new UnsupportedOperationException("Effect library not loaded"));
+                default:
+                    throw (new RuntimeException("Cannot initialize Visualizer engine, error: "
+                            +result));
+                }
+            }
+            mId = id[0];
+            if (native_getEnabled()) {
+                mState = STATE_ENABLED;
+            } else {
+                mState = STATE_INITIALIZED;
+            }
+        }
+    }
+
+    /**
+     * Releases the native Visualizer resources. It is a good practice to release the
+     * visualization engine when not in use.
+     */
+    public void release() {
+        synchronized (mStateLock) {
+            native_release();
+            mState = STATE_UNINITIALIZED;
+        }
+    }
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    /**
+     * Enable or disable the visualization engine.
+     * @param enabled requested enable state
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     * @throws IllegalStateException
+     */
+    public int setEnabled(boolean enabled)
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if ((enabled && mState != STATE_INITIALIZED) ||
+                    (!enabled && mState != STATE_ENABLED)) {
+                throw(new IllegalStateException("setEnabled() called in wrong state: "+mState));
+            }
+            int status = native_setEnabled(enabled);
+            if (status == SUCCESS) {
+                mState = enabled ? STATE_ENABLED : STATE_INITIALIZED;
+            }
+            return status;
+        }
+    }
+
+    /**
+     * Get current activation state of the visualizer.
+     * @return true if the visualizer is active, false otherwise
+     */
+    public boolean getEnabled()
+    {
+        synchronized (mStateLock) {
+            if (mState == STATE_UNINITIALIZED) {
+                throw(new IllegalStateException("getEnabled() called in wrong state: "+mState));
+            }
+            return native_getEnabled();
+        }
+    }
+
+    /**
+     * Returns the capture size range.
+     * @return the mininum capture size is returned in first array element and the maximum in second
+     * array element.
+     */
+    public static native int[] getCaptureSizeRange();
+
+    /**
+     * Returns the maximum capture rate for the callback capture method. This is the maximum value
+     * for the rate parameter of the
+     * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+     * @return the maximum capture rate expressed in milliHertz
+     */
+    public static native int getMaxCaptureRate();
+
+    /**
+     * Sets the capture size, i.e. the number of bytes returned by {@link #getWaveForm(byte[])} and
+     * {@link #getFft(byte[])} methods. The capture size must be a power of 2 in the range returned
+     * by {@link #getCaptureSizeRange()}.
+     * This method must not be called when the Visualizer is enabled.
+     * @param size requested capture size
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR_BAD_VALUE} in case of failure.
+     * @throws IllegalStateException
+     */
+    public int setCaptureSize(int size)
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState != STATE_INITIALIZED) {
+                throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
+            }
+            return native_setCaptureSize(size);
+        }
+    }
+
+    /**
+     * Returns current capture size.
+     * @return the capture size in bytes.
+     */
+    public int getCaptureSize()
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState == STATE_UNINITIALIZED) {
+                throw(new IllegalStateException("getCaptureSize() called in wrong state: "+mState));
+            }
+            return native_getCaptureSize();
+        }
+    }
+
+    /**
+     * Returns the sampling rate of the captured audio.
+     * @return the sampling rate in milliHertz.
+     */
+    public int getSamplingRate()
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState == STATE_UNINITIALIZED) {
+                throw(new IllegalStateException("getSamplingRate() called in wrong state: "+mState));
+            }
+            return native_getSamplingRate();
+        }
+    }
+
+    /**
+     * Returns a waveform capture of currently playing audio content. The capture consists in
+     * a number of consecutive 8-bit (unsigned) mono PCM samples equal to the capture size returned
+     * by {@link #getCaptureSize()}.
+     * <p>This method must be called when the Visualizer is enabled.
+     * @param waveform array of bytes where the waveform should be returned
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+     * in case of failure.
+     * @throws IllegalStateException
+     */
+    public int getWaveForm(byte[] waveform)
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState != STATE_ENABLED) {
+                throw(new IllegalStateException("getWaveForm() called in wrong state: "+mState));
+            }
+            return native_getWaveForm(waveform);
+        }
+    }
+    /**
+     * Returns a frequency capture of currently playing audio content. The capture is a 8-bit
+     * magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
+     * sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
+     * {@see #getCaptureSize()}.
+     * <p>This method must be called when the Visualizer is enabled.
+     * @param fft array of bytes where the FFT should be returned
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+     * in case of failure.
+     * @throws IllegalStateException
+     */
+    public int getFft(byte[] fft)
+    throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState != STATE_ENABLED) {
+                throw(new IllegalStateException("getFft() called in wrong state: "+mState));
+            }
+            return native_getFft(fft);
+        }
+    }
+
+    //---------------------------------------------------------
+    // Interface definitions
+    //--------------------
+    /**
+     * The OnDataCaptureListener interface defines methods called by the Visualizer to periodically
+     * update the audio visualization capture.
+     * The client application can implement this interface and register the listener with the
+     * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+     */
+    public interface OnDataCaptureListener  {
+        /**
+         * Method called when a new waveform capture is available.
+         * @param visualizer Visualizer object on which the listener is registered.
+         * @param waveform array of bytes containing the waveform representation.
+         * @param samplingRate sampling rate of the audio visualized.
+         */
+        void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
+
+        /**
+         * Method called when a new frequency capture is available.
+         * @param visualizer Visualizer object on which the listener is registered.
+         * @param fft array of bytes containing the frequency representation.
+         * @param samplingRate sampling rate of the audio visualized.
+         */
+        void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
+    }
+
+    /**
+     * Registers an OnDataCaptureListener interface and specifies the rate at which the capture
+     * should be updated as well as the type of capture requested.
+     * <p>Call this method with a null listener to stop receiving the capture updates.
+     * @param listener OnDataCaptureListener registered
+     * @param rate rate in milliHertz at which the capture should be updated
+     * @param waveform true if a waveform capture is requested: the onWaveFormDataCapture()
+     * method will be called on the OnDataCaptureListener interface.
+     * @param fft true if a frequency capture is requested: the onFftDataCapture() method will be
+     * called on the OnDataCaptureListener interface.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR_NO_INIT} or {@link #ERROR_BAD_VALUE} in case of failure.
+     */
+    public int setDataCaptureListener(OnDataCaptureListener listener,
+            int rate, boolean waveform, boolean fft) {
+        synchronized (mListenerLock) {
+            mCaptureListener = listener;
+        }
+        if (listener == null) {
+            // make sure capture callback is stopped in native code
+            waveform = false;
+            fft = false;
+        }
+        int status = native_setPeriodicCapture(rate, waveform, fft);
+        if (status == SUCCESS) {
+            if ((listener != null) && (mNativeEventHandler == null)) {
+                Looper looper;
+                if ((looper = Looper.myLooper()) != null) {
+                    mNativeEventHandler = new NativeEventHandler(this, looper);
+                } else if ((looper = Looper.getMainLooper()) != null) {
+                    mNativeEventHandler = new NativeEventHandler(this, looper);
+                } else {
+                    mNativeEventHandler = null;
+                    status = ERROR_NO_INIT;
+                }
+            }
+        }
+        return status;
+    }
+
+    /**
+     * Helper class to handle the forwarding of native events to the appropriate listeners
+     */
+    private class NativeEventHandler extends Handler
+    {
+        private Visualizer mVisualizer;
+
+        public NativeEventHandler(Visualizer v, Looper looper) {
+            super(looper);
+            mVisualizer = v;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (mVisualizer == null) {
+                return;
+            }
+            OnDataCaptureListener l = null;
+            synchronized (mListenerLock) {
+                l = mVisualizer.mCaptureListener;
+            }
+
+            if (l != null) {
+                byte[] data = (byte[])msg.obj;
+                int samplingRate = msg.arg1;
+                switch(msg.what) {
+                case NATIVE_EVENT_PCM_CAPTURE:
+                    l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
+                    break;
+                case NATIVE_EVENT_FFT_CAPTURE:
+                    l.onFftDataCapture(mVisualizer, data, samplingRate);
+                    break;
+                default:
+                    Log.e(TAG,"Unknown native event: "+msg.what);
+                    break;
+                }
+            }
+        }
+    }
+
+    //---------------------------------------------------------
+    // Interface definitions
+    //--------------------
+
+    private static native final void native_init();
+
+    private native final int native_setup(Object audioeffect_this,
+                                          int audioSession,
+                                          int[] id);
+
+    private native final void native_finalize();
+
+    private native final void native_release();
+
+    private native final int native_setEnabled(boolean enabled);
+
+    private native final boolean native_getEnabled();
+
+    private native final int native_setCaptureSize(int size);
+
+    private native final int native_getCaptureSize();
+
+    private native final int native_getSamplingRate();
+
+    private native final int native_getWaveForm(byte[] waveform);
+
+    private native final int native_getFft(byte[] fft);
+
+    private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
+
+    //---------------------------------------------------------
+    // Java methods called from the native side
+    //--------------------
+    @SuppressWarnings("unused")
+    private static void postEventFromNative(Object effect_ref,
+            int what, int arg1, int arg2, Object obj) {
+        Visualizer visu = (Visualizer)((WeakReference)effect_ref).get();
+        if (visu == null) {
+            return;
+        }
+
+        if (visu.mNativeEventHandler != null) {
+            Message m = visu.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+            visu.mNativeEventHandler.sendMessage(m);
+        }
+
+    }
+
+}
+
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c5250d7..aedb54a 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -681,18 +681,6 @@
 }
 
 static jint
-android_media_MediaPlayer_snoop(JNIEnv* env, jobject thiz, jobject data, jint kind) {
-    jshort* ar = (jshort*)env->GetPrimitiveArrayCritical((jarray)data, 0);
-    jsize len = env->GetArrayLength((jarray)data);
-    int ret = 0;
-    if (ar) {
-        ret = MediaPlayer::snoop(ar, len, kind);
-        env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
-    }
-    return ret;
-}
-
-static jint
 android_media_MediaPlayer_native_suspend_resume(
         JNIEnv *env, jobject thiz, jboolean isSuspend) {
     LOGV("suspend_resume(%d)", isSuspend);
@@ -757,7 +745,6 @@
     {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
-    {"snoop",               "([SI)I",                           (void *)android_media_MediaPlayer_snoop},
     {"native_suspend_resume", "(Z)I",                           (void *)android_media_MediaPlayer_native_suspend_resume},
     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index d03b63b..4c5cf71 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -2,7 +2,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_AudioEffect.cpp
+	android_media_AudioEffect.cpp \
+	android_media_Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 17f2d8f..02474a4 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -455,9 +455,8 @@
     env->SetIntField(thiz, fields.fidJniData, 0);
 }
 
-
 static jint
-android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz)
+android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
 {
     // retrieve the AudioEffect object
     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
@@ -469,29 +468,11 @@
         return AUDIOEFFECT_ERROR_NO_INIT;
     }
 
-    return translateError(lpAudioEffect->enable());
+    return translateError(lpAudioEffect->setEnabled(enabled));
 }
 
-
-static jint
-android_media_AudioEffect_native_disable(JNIEnv *env, jobject thiz)
-{
-    // retrieve the AudioEffect object
-    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
-        thiz, fields.fidNativeAudioEffect);
-
-    if (lpAudioEffect == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioEffect pointer for disable()");
-        return AUDIOEFFECT_ERROR_NO_INIT;
-    }
-
-    return translateError(lpAudioEffect->disable());
-}
-
-
 static jboolean
-android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz)
+android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
 {
     // retrieve the AudioEffect object
     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
@@ -503,7 +484,7 @@
         return false;
     }
 
-    return (jboolean)lpAudioEffect->isEnabled();
+    return (jboolean)lpAudioEffect->getEnabled();
 }
 
 
@@ -516,7 +497,7 @@
 
     if (lpAudioEffect == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioEffect pointer for getEnabled()");
+            "Unable to retrieve AudioEffect pointer for hasControl()");
         return false;
     }
 
@@ -817,9 +798,8 @@
                                          (void *)android_media_AudioEffect_native_setup},
     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
-    {"native_enable",        "()I",      (void *)android_media_AudioEffect_native_enable},
-    {"native_disable",       "()I",      (void *)android_media_AudioEffect_native_disable},
-    {"native_getEnable",     "()Z",      (void *)android_media_AudioEffect_native_getEnable},
+    {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
+    {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
     {"native_getParameter",  "(I[B[I[B)I",  (void *)android_media_AudioEffect_native_getParameter},
@@ -830,6 +810,8 @@
 
 // ----------------------------------------------------------------------------
 
+extern int register_android_media_visualizer(JNIEnv *env);
+
 int register_android_media_AudioEffect(JNIEnv *env)
 {
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
@@ -852,6 +834,11 @@
         goto bail;
     }
 
+    if (register_android_media_visualizer(env) < 0) {
+        LOGE("ERROR: Visualizer native registration failed\n");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
new file mode 100644
index 0000000..31119f8
--- /dev/null
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "visualizers-JNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "media/Visualizer.h"
+
+using namespace android;
+
+#define VISUALIZER_SUCCESS                      0
+#define VISUALIZER_ERROR                       -1
+#define VISUALIZER_ERROR_ALREADY_EXISTS        -2
+#define VISUALIZER_ERROR_NO_INIT               -3
+#define VISUALIZER_ERROR_BAD_VALUE             -4
+#define VISUALIZER_ERROR_INVALID_OPERATION     -5
+#define VISUALIZER_ERROR_NO_MEMORY             -6
+#define VISUALIZER_ERROR_DEAD_OBJECT           -7
+
+#define NATIVE_EVENT_PCM_CAPTURE                0
+#define NATIVE_EVENT_FFT_CAPTURE                1
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/Visualizer";
+
+struct fields_t {
+    // these fields provide access from C++ to the...
+    jclass    clazzEffect;          // Visualizer class
+    jmethodID midPostNativeEvent;   // event post callback method
+    jfieldID  fidNativeVisualizer; // stores in Java the native Visualizer object
+    jfieldID  fidJniData;           // stores in Java additional resources used by the native Visualizer
+};
+static fields_t fields;
+
+struct visualizer_callback_cookie {
+    jclass      visualizer_class;  // Visualizer class
+    jobject     visualizer_ref;    // Visualizer object instance
+ };
+
+// ----------------------------------------------------------------------------
+class visualizerJniStorage {
+    public:
+        visualizer_callback_cookie mCallbackData;
+
+    visualizerJniStorage() {
+    }
+
+    ~visualizerJniStorage() {
+    }
+
+};
+
+
+static jint translateError(int code) {
+    switch(code) {
+    case NO_ERROR:
+        return VISUALIZER_SUCCESS;
+    case ALREADY_EXISTS:
+        return VISUALIZER_ERROR_ALREADY_EXISTS;
+    case NO_INIT:
+        return VISUALIZER_ERROR_NO_INIT;
+    case BAD_VALUE:
+        return VISUALIZER_ERROR_BAD_VALUE;
+    case INVALID_OPERATION:
+        return VISUALIZER_ERROR_INVALID_OPERATION;
+    case NO_MEMORY:
+        return VISUALIZER_ERROR_NO_MEMORY;
+    case DEAD_OBJECT:
+        return VISUALIZER_ERROR_DEAD_OBJECT;
+    default:
+        return VISUALIZER_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static void captureCallback(void* user,
+        uint32_t waveformSize,
+        uint8_t *waveform,
+        uint32_t fftSize,
+        uint8_t *fft,
+        uint32_t samplingrate) {
+
+    int arg1 = 0;
+    int arg2 = 0;
+    size_t size;
+
+    visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    LOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
+            callbackInfo,
+            callbackInfo->visualizer_ref,
+            callbackInfo->visualizer_class);
+
+    if (!user || !env) {
+        LOGW("captureCallback error user %p, env %p", user, env);
+        return;
+    }
+
+    if (waveformSize != 0 && waveform != NULL) {
+        jbyteArray jArray = env->NewByteArray(waveformSize);
+        if (jArray != NULL) {
+            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+            memcpy(nArray, waveform, waveformSize);
+            env->ReleaseByteArrayElements(jArray, nArray, 0);
+            env->CallStaticVoidMethod(
+                callbackInfo->visualizer_class,
+                fields.midPostNativeEvent,
+                callbackInfo->visualizer_ref,
+                NATIVE_EVENT_PCM_CAPTURE,
+                samplingrate,
+                0,
+                jArray);
+        }
+    }
+
+    if (fftSize != 0 && fft != NULL) {
+        jbyteArray jArray = env->NewByteArray(fftSize);
+        if (jArray != NULL) {
+            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+            memcpy(nArray, fft, fftSize);
+            env->ReleaseByteArrayElements(jArray, nArray, 0);
+            env->CallStaticVoidMethod(
+                callbackInfo->visualizer_class,
+                fields.midPostNativeEvent,
+                callbackInfo->visualizer_ref,
+                NATIVE_EVENT_FFT_CAPTURE,
+                samplingrate,
+                0,
+                jArray);
+            env->DeleteLocalRef(jArray);
+        }
+    }
+
+    if (env->ExceptionCheck()) {
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+}
+
+static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
+{
+    Visualizer *v = (Visualizer *)env->GetIntField(
+        thiz, fields.fidNativeVisualizer);
+    if (v == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve Visualizer pointer");
+    }
+    return v;
+}
+
+// ----------------------------------------------------------------------------
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in Visualizer, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_visualizer_native_init(JNIEnv *env)
+{
+
+    LOGV("android_media_visualizer_native_init");
+
+    fields.clazzEffect = NULL;
+
+    // Get the Visualizer class
+    jclass clazz = env->FindClass(kClassPathName);
+    if (clazz == NULL) {
+        LOGE("Can't find %s", kClassPathName);
+        return;
+    }
+
+    fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
+
+    // Get the postEvent method
+    fields.midPostNativeEvent = env->GetStaticMethodID(
+            fields.clazzEffect,
+            "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (fields.midPostNativeEvent == NULL) {
+        LOGE("Can't find Visualizer.%s", "postEventFromNative");
+        return;
+    }
+
+    // Get the variables fields
+    //      nativeTrackInJavaObj
+    fields.fidNativeVisualizer = env->GetFieldID(
+            fields.clazzEffect,
+            "mNativeVisualizer", "I");
+    if (fields.fidNativeVisualizer == NULL) {
+        LOGE("Can't find Visualizer.%s", "mNativeVisualizer");
+        return;
+    }
+    //      fidJniData;
+    fields.fidJniData = env->GetFieldID(
+            fields.clazzEffect,
+            "mJniData", "I");
+    if (fields.fidJniData == NULL) {
+        LOGE("Can't find Visualizer.%s", "mJniData");
+        return;
+    }
+
+}
+
+
+static jint
+android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+        jint sessionId, jintArray jId)
+{
+    LOGV("android_media_visualizer_native_setup");
+    visualizerJniStorage* lpJniStorage = NULL;
+    int lStatus = VISUALIZER_ERROR_NO_MEMORY;
+    Visualizer* lpVisualizer = NULL;
+    jint* nId = NULL;
+
+    lpJniStorage = new visualizerJniStorage();
+    if (lpJniStorage == NULL) {
+        LOGE("setup: Error creating JNI Storage");
+        goto setup_failure;
+    }
+
+    lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
+    // we use a weak reference so the Visualizer object can be garbage collected.
+    lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
+
+    LOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
+            lpJniStorage,
+            lpJniStorage->mCallbackData.visualizer_ref,
+            lpJniStorage->mCallbackData.visualizer_class,
+            &lpJniStorage->mCallbackData);
+
+    if (jId) {
+        nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
+        if (nId == NULL) {
+            LOGE("setup: Error retrieving id pointer");
+            lStatus = VISUALIZER_ERROR_BAD_VALUE;
+            goto setup_failure;
+        }
+    } else {
+        LOGE("setup: NULL java array for id pointer");
+        lStatus = VISUALIZER_ERROR_BAD_VALUE;
+        goto setup_failure;
+    }
+
+    // create the native Visualizer object
+    lpVisualizer = new Visualizer(0,
+                                  NULL,
+                                  NULL,
+                                  sessionId);
+    if (lpVisualizer == NULL) {
+        LOGE("Error creating Visualizer");
+        goto setup_failure;
+    }
+
+    lStatus = translateError(lpVisualizer->initCheck());
+    if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
+        LOGE("Visualizer initCheck failed %d", lStatus);
+        goto setup_failure;
+    }
+
+    nId[0] = lpVisualizer->id();
+
+    env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+    nId = NULL;
+
+    env->SetIntField(thiz, fields.fidNativeVisualizer, (int)lpVisualizer);
+
+    env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
+
+    return VISUALIZER_SUCCESS;
+
+    // failures:
+setup_failure:
+
+    if (nId != NULL) {
+        env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+    }
+
+    if (lpVisualizer) {
+        delete lpVisualizer;
+    }
+    env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
+
+    if (lpJniStorage) {
+        delete lpJniStorage;
+    }
+    env->SetIntField(thiz, fields.fidJniData, 0);
+
+    return lStatus;
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
+    LOGV("android_media_visualizer_native_finalize jobject: %x\n", (int)thiz);
+
+    // delete the Visualizer object
+    Visualizer* lpVisualizer = (Visualizer *)env->GetIntField(
+        thiz, fields.fidNativeVisualizer);
+    if (lpVisualizer) {
+        LOGV("deleting Visualizer: %x\n", (int)lpVisualizer);
+        delete lpVisualizer;
+    }
+
+    // delete the JNI data
+    visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
+        thiz, fields.fidJniData);
+    if (lpJniStorage) {
+        LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
+        delete lpJniStorage;
+    }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
+
+    // do everything a call to finalize would
+    android_media_visualizer_native_finalize(env, thiz);
+    // + reset the native resources in the Java object so any attempt to access
+    // them after a call to release fails.
+    env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
+    env->SetIntField(thiz, fields.fidJniData, 0);
+}
+
+static jint
+android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+
+    return translateError(lpVisualizer->setEnabled(enabled));
+}
+
+static jboolean
+android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return false;
+    }
+
+    return (jboolean)lpVisualizer->getEnabled();
+}
+
+static jintArray
+android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz)
+{
+    jintArray jRange = env->NewIntArray(2);
+    jint *nRange = env->GetIntArrayElements(jRange, NULL);
+    nRange[0] = Visualizer::getMinCaptureSize();
+    nRange[1] = Visualizer::getMaxCaptureSize();
+    LOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
+    env->ReleaseIntArrayElements(jRange, nRange, 0);
+    return jRange;
+}
+
+static jint
+android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
+{
+    return Visualizer::getMaxCaptureRate();
+}
+
+static jint
+android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+
+    return translateError(lpVisualizer->setCaptureSize(size));
+}
+
+static jint
+android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return -1;
+    }
+    return lpVisualizer->getCaptureSize();
+}
+
+static jint
+android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return -1;
+    }
+    return lpVisualizer->getSamplingRate();
+}
+
+static jint
+android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+
+    jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
+    if (nWaveform == NULL) {
+        return VISUALIZER_ERROR_NO_MEMORY;
+    }
+    jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
+
+    env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
+
+    return status;
+}
+
+static jint
+android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+
+    jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
+    if (nFft == NULL) {
+        return VISUALIZER_ERROR_NO_MEMORY;
+    }
+    jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
+
+    env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
+
+    return status;
+}
+
+static jint
+android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+    visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(thiz,
+            fields.fidJniData);
+    if (lpJniStorage == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+
+    LOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
+            rate,
+            jWaveform,
+            jFft);
+
+    uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
+    if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
+    if (jFft) flags |= Visualizer::CAPTURE_FFT;
+    Visualizer::capture_cbk_t cbk = captureCallback;
+    if (!jWaveform && !jFft) cbk = NULL;
+
+    return translateError(lpVisualizer->setCaptureCallBack(cbk,
+                                                &lpJniStorage->mCallbackData,
+                                                flags,
+                                                rate));
+}
+
+// ----------------------------------------------------------------------------
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+    {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
+    {"native_setup",           "(Ljava/lang/Object;I[I)I",
+                                          (void *)android_media_visualizer_native_setup},
+    {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
+    {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
+    {"native_setEnabled",        "(Z)I",  (void *)android_media_visualizer_native_setEnabled},
+    {"native_getEnabled",        "()Z",   (void *)android_media_visualizer_native_getEnabled},
+    {"getCaptureSizeRange",      "()[I",  (void *)android_media_visualizer_native_getCaptureSizeRange},
+    {"getMaxCaptureRate",        "()I",   (void *)android_media_visualizer_native_getMaxCaptureRate},
+    {"native_setCaptureSize",    "(I)I",  (void *)android_media_visualizer_native_setCaptureSize},
+    {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
+    {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
+    {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
+    {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
+    {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
+};
+
+// ----------------------------------------------------------------------------
+
+int register_android_media_visualizer(JNIEnv *env)
+{
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
diff --git a/media/libeffects/Android.mk b/media/libeffects/Android.mk
index b5f1d42..54e87f3 100644
--- a/media/libeffects/Android.mk
+++ b/media/libeffects/Android.mk
@@ -94,3 +94,33 @@
 include $(BUILD_SHARED_LIBRARY)
 
 endif
+
+
+# Visualizer library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	EffectVisualizer.cpp
+
+LOCAL_CFLAGS+= -O2
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libvisualizer
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, graphics corecg)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/EffectVisualizer.cpp b/media/libeffects/EffectVisualizer.cpp
new file mode 100644
index 0000000..f27e296
--- /dev/null
+++ b/media/libeffects/EffectVisualizer.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Visualizer"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <media/EffectVisualizerApi.h>
+
+namespace android {
+
+// effect_interface_t interface implementation for visualizer effect
+extern "C" const struct effect_interface_s gVisualizerInterface;
+
+// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
+const effect_descriptor_t gVisualizerDescriptor = {
+        {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+        {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+        EFFECT_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+        0, // TODO
+        1,
+        "Visualizer",
+        "Google Inc.",
+};
+
+enum visualizer_state_e {
+    VISUALIZER_STATE_UNINITIALIZED,
+    VISUALIZER_STATE_INITIALIZED,
+    VISUALIZER_STATE_ACTIVE,
+};
+
+struct VisualizerContext {
+    const struct effect_interface_s *mItfe;
+    effect_config_t mConfig;
+    uint32_t mState;
+    uint32_t mCaptureIdx;
+    uint32_t mCaptureSize;
+    uint32_t mCurrentBuf;
+    uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
+};
+
+
+//
+//--- Local functions
+//
+
+void Visualizer_reset(VisualizerContext *pContext)
+{
+    pContext->mCaptureIdx = 0;
+    pContext->mCurrentBuf = 0;
+    memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+    memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+}
+
+//----------------------------------------------------------------------------
+// Visualizer_configure()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig)
+{
+    LOGV("Visualizer_configure start");
+
+    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
+    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
+    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
+    if (pConfig->inputCfg.channels != CHANNEL_STEREO) return -EINVAL;
+    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
+            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
+    if (pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15) return -EINVAL;
+
+    memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
+
+    Visualizer_reset(pContext);
+
+    return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// Visualizer_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_init(VisualizerContext *pContext)
+{
+    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    pContext->mConfig.inputCfg.channels = CHANNEL_STEREO;
+    pContext->mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+    pContext->mConfig.inputCfg.samplingRate = 44100;
+    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    pContext->mConfig.outputCfg.channels = CHANNEL_STEREO;
+    pContext->mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
+    pContext->mConfig.outputCfg.samplingRate = 44100;
+    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
+
+    Visualizer_configure(pContext, &pContext->mConfig);
+
+    return 0;
+}
+
+//
+//--- Effect Library Interface Implementation
+//
+
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
+    *pNumEffects = 1;
+    return 0;
+}
+
+extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
+    if (pDescriptor == NULL) {
+        return -EINVAL;
+    }
+    if (index > 0) {
+        return -EINVAL;
+    }
+    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+    return 0;
+}
+
+extern "C" int EffectCreate(effect_uuid_t *uuid,
+        int32_t sessionId,
+        int32_t ioId,
+        effect_interface_t *pInterface) {
+    int ret;
+    int i;
+
+    if (pInterface == NULL || uuid == NULL) {
+        return -EINVAL;
+    }
+
+    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
+        return -EINVAL;
+    }
+
+    VisualizerContext *pContext = new VisualizerContext;
+
+    pContext->mItfe = &gVisualizerInterface;
+    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+
+    ret = Visualizer_init(pContext);
+    if (ret < 0) {
+        LOGW("EffectCreate() init failed");
+        delete pContext;
+        return ret;
+    }
+
+    *pInterface = (effect_interface_t)pContext;
+
+    pContext->mState = VISUALIZER_STATE_INITIALIZED;
+
+    LOGV("EffectCreate %p", pContext);
+
+    return 0;
+
+}
+
+extern "C" int EffectRelease(effect_interface_t interface) {
+    VisualizerContext * pContext = (VisualizerContext *)interface;
+
+    LOGV("EffectRelease %p", interface);
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+    delete pContext;
+
+    return 0;
+}
+
+//
+//--- Effect Control Interface Implementation
+//
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+extern "C" int Visualizer_process(
+        effect_interface_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+    android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+    if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+        return -ENOSYS;
+    }
+
+    if (inBuffer == NULL || inBuffer->raw == NULL ||
+        outBuffer == NULL || outBuffer->raw == NULL ||
+        inBuffer->frameCount != outBuffer->frameCount ||
+        inBuffer->frameCount == 0) {
+        return -EINVAL;
+    }
+
+    // all code below assumes stereo 16 bit PCM output and input
+    uint32_t captIdx;
+    uint32_t inIdx;
+    uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
+    for (inIdx = 0, captIdx = pContext->mCaptureIdx;
+         inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
+         inIdx++, captIdx++) {
+        int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
+        smp = (smp + (1 << 8)) >> 9;
+        buf[captIdx] = ((uint8_t)smp)^0x80;
+    }
+    pContext->mCaptureIdx = captIdx;
+
+    // go to next buffer when buffer full
+    if (pContext->mCaptureIdx == pContext->mCaptureSize) {
+        pContext->mCurrentBuf ^= 1;
+        pContext->mCaptureIdx = 0;
+    }
+
+    if (inBuffer->raw != outBuffer->raw) {
+        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
+            }
+        } else {
+            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
+        }
+    }
+    return 0;
+}   // end Visualizer_process
+
+extern "C" int Visualizer_command(effect_interface_t self, int cmdCode, int cmdSize,
+        void *pCmdData, int *replySize, void *pReplyData) {
+
+    android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+    int retsize;
+
+    if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+
+//    LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
+
+    switch (cmdCode) {
+    case EFFECT_CMD_INIT:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = Visualizer_init(pContext);
+        break;
+    case EFFECT_CMD_CONFIGURE:
+        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = Visualizer_configure(pContext,
+                (effect_config_t *) pCmdData);
+        break;
+    case EFFECT_CMD_RESET:
+        Visualizer_reset(pContext);
+        break;
+    case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pContext->mState = VISUALIZER_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_DISABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pContext->mState = VISUALIZER_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_GET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL ||
+            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
+            return -EINVAL;
+        }
+        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
+        effect_param_t *p = (effect_param_t *)pReplyData;
+        p->status = 0;
+        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
+        if (p->psize != sizeof(uint32_t) ||
+            *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+            p->status = -EINVAL;
+            break;
+        }
+        LOGV("get mCaptureSize = %d", pContext->mCaptureSize);
+        *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
+        p->vsize = sizeof(uint32_t);
+        *replySize += sizeof(uint32_t);
+        } break;
+    case EFFECT_CMD_SET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL || *replySize != sizeof(int32_t)) {
+            return -EINVAL;
+        }
+        *(int32_t *)pReplyData = 0;
+        effect_param_t *p = (effect_param_t *)pCmdData;
+        if (p->psize != sizeof(uint32_t) ||
+            p->vsize != sizeof(uint32_t) ||
+            *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+            *(int32_t *)pReplyData = -EINVAL;
+            break;;
+        }
+        pContext->mCaptureSize = *((uint32_t *)p->data + 1);
+        LOGV("set mCaptureSize = %d", pContext->mCaptureSize);
+        } break;
+    case EFFECT_CMD_SET_DEVICE:
+    case EFFECT_CMD_SET_VOLUME:
+    case EFFECT_CMD_SET_AUDIO_MODE:
+        break;
+
+
+    case VISU_CMD_CAPTURE:
+        if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) {
+            LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
+                    *replySize, pContext->mCaptureSize);
+            return -EINVAL;
+        }
+        if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
+            memcpy(pReplyData,
+                   pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+                   pContext->mCaptureSize);
+        } else {
+            memset(pReplyData, 0x80, pContext->mCaptureSize);
+        }
+        break;
+
+    default:
+        LOGW("Visualizer_command invalid command %d",cmdCode);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+// effect_interface_t interface implementation for visualizer effect
+const struct effect_interface_s gVisualizerInterface = {
+        Visualizer_process,
+        Visualizer_command
+};
+
+} // namespace
+
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index de9e51d..977e6be 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,7 +30,8 @@
     MediaProfiles.cpp \
     IEffect.cpp \
     IEffectClient.cpp \
-    AudioEffect.cpp
+    AudioEffect.cpp \
+    Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 4afa2dc..783249d 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -171,7 +171,7 @@
     LOGV("Destructor %p", this);
 
     if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
-        disable();
+        setEnabled(false);
         if (mIEffect != NULL) {
             mIEffect->disconnect();
             mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
@@ -196,36 +196,28 @@
     return mDescriptor;
 }
 
-bool AudioEffect::isEnabled() const
+bool AudioEffect::getEnabled() const
 {
     return (mEnabled != 0);
 }
 
-status_t AudioEffect::enable()
+status_t AudioEffect::setEnabled(bool enabled)
 {
     if (mStatus != NO_ERROR) {
         return INVALID_OPERATION;
     }
-    LOGV("enable %p", this);
 
-    if (android_atomic_or(1, &mEnabled) == 0) {
-       return mIEffect->enable();
+    if (enabled) {
+        LOGV("enable %p", this);
+        if (android_atomic_or(1, &mEnabled) == 0) {
+           return mIEffect->enable();
+        }
+    } else {
+        LOGV("disable %p", this);
+        if (android_atomic_and(~1, &mEnabled) == 1) {
+           return mIEffect->disable();
+        }
     }
-
-    return INVALID_OPERATION;
-}
-
-status_t AudioEffect::disable()
-{
-    if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
-    }
-    LOGV("disable %p", this);
-
-    if (android_atomic_and(~1, &mEnabled) == 1) {
-       return mIEffect->disable();
-    }
-
     return INVALID_OPERATION;
 }
 
@@ -349,7 +341,7 @@
 
 void AudioEffect::enableStatusChanged(bool enabled)
 {
-    LOGV("enableStatusChanged %p enabled %d", this, enabled);
+    LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
     if (mStatus == ALREADY_EXISTS) {
         mEnabled = enabled;
         if (mCbf) {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 1ae222e..4abfa75 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,8 +35,7 @@
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
-    GET_OMX,
-    SNOOP
+    GET_OMX
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -134,14 +133,6 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
-    virtual sp<IMemory> snoop()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        remote()->transact(SNOOP, data, &reply);
-        return interface_cast<IMemory>(reply.readStrongBinder());
-    }
-
     virtual sp<IOMX> getOMX() {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -221,12 +212,6 @@
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
-        case SNOOP: {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            sp<IMemory> snooped_audio = snoop();
-            reply->writeStrongBinder(snooped_audio->asBinder());
-            return NO_ERROR;
-        } break;
         case CREATE_MEDIA_RECORDER: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             pid_t pid = data.readInt32();
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
new file mode 100644
index 0000000..47e96e5
--- /dev/null
+++ b/media/libmedia/Visualizer.cpp
@@ -0,0 +1,330 @@
+/*
+**
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Visualizer"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <media/Visualizer.h>
+
+extern "C" {
+#define FLOATING_POINT 1
+#include "fftwrap.h"
+}
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Visualizer::Visualizer (int32_t priority,
+         effect_callback_t cbf,
+         void* user,
+         int sessionId)
+    :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
+        mCaptureRate(CAPTURE_RATE_DEF),
+        mCaptureSize(CAPTURE_SIZE_DEF),
+        mSampleRate(44100000),
+        mCaptureCallBack(NULL),
+        mCaptureCbkUser(NULL)
+{
+    initCaptureSize();
+    if (mCaptureSize != 0) {
+        mFftTable = spx_fft_init(mCaptureSize);
+    } else {
+        mFftTable = NULL;
+    }
+}
+
+Visualizer::~Visualizer()
+{
+    if (mFftTable != NULL) {
+        spx_fft_destroy(mFftTable);
+    }
+}
+
+status_t Visualizer::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+
+    sp<CaptureThread> t = mCaptureThread;
+    if (t != 0) {
+        if (enabled) {
+            if (t->exitPending()) {
+                if (t->requestExitAndWait() == WOULD_BLOCK) {
+                    LOGE("Visualizer::enable() called from thread");
+                    return INVALID_OPERATION;
+                }
+            }
+        }
+        t->mLock.lock();
+     }
+
+    status_t status = AudioEffect::setEnabled(enabled);
+
+    if (status == NO_ERROR) {
+        if (t != 0) {
+            if (enabled) {
+                t->run("AudioTrackThread");
+            } else {
+                t->requestExit();
+            }
+        }
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    return status;
+}
+
+status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
+{
+    if (rate > CAPTURE_RATE_MAX) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    sp<CaptureThread> t = mCaptureThread;
+    if (t != 0) {
+        t->mLock.lock();
+    }
+    mCaptureThread.clear();
+    mCaptureCallBack = cbk;
+    mCaptureCbkUser = user;
+    mCaptureFlags = flags;
+    mCaptureRate = rate;
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    if (cbk != NULL) {
+        mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+        if (mCaptureThread == 0) {
+            LOGE("Could not create callback thread");
+            return NO_INIT;
+        }
+    }
+    LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
+            rate, mCaptureThread.get(), mCaptureFlags);
+    return NO_ERROR;
+}
+
+status_t Visualizer::setCaptureSize(uint32_t size)
+{
+    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
+        size < VISUALIZER_CAPTURE_SIZE_MIN ||
+        AudioSystem::popCount(size) != 1) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+    *((int32_t *)p->data + 1)= size;
+    status_t status = setParameter(p);
+
+    LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+    }
+    if (status == NO_ERROR) {
+        mCaptureSize = size;
+        if (mFftTable != NULL) {
+            spx_fft_destroy(mFftTable);
+        }
+        mFftTable = spx_fft_init(mCaptureSize);
+        LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable);
+    }
+
+    return status;
+}
+
+status_t Visualizer::getWaveForm(uint8_t *waveform)
+{
+    if (waveform == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        int32_t replySize = mCaptureSize;
+        status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+        if (replySize == 0) {
+            status = NOT_ENOUGH_DATA;
+        }
+    } else {
+        memset(waveform, 0x80, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::getFft(uint8_t *fft)
+{
+    if (fft == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        uint8_t buf[mCaptureSize];
+        status_t status = getWaveForm(buf);
+        if (status == NO_ERROR) {
+            status = doFft(fft, buf);
+        }
+    } else {
+        memset(fft, 0, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
+{
+    if (mFftTable == NULL) {
+        return NO_INIT;
+    }
+
+    float fsrc[mCaptureSize];
+    for (uint32_t i = 0; i < mCaptureSize; i++) {
+        fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8;
+    }
+    float fdst[mCaptureSize];
+    spx_fft_float(mFftTable, fsrc, fdst);
+    for (uint32_t i = 0; i < mCaptureSize; i++) {
+        fft[i] = (uint8_t)((int32_t)fdst[i] >> 8);
+    }
+    return NO_ERROR;
+}
+
+void Visualizer::periodicCapture()
+{
+    Mutex::Autolock _l(mLock);
+    LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
+            this, mCaptureCallBack, mCaptureFlags);
+    if (mCaptureCallBack != NULL &&
+        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
+        mCaptureSize != 0) {
+        uint8_t waveform[mCaptureSize];
+        status_t status = getWaveForm(waveform);
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t fft[mCaptureSize];
+        if (mCaptureFlags & CAPTURE_FFT) {
+            status = doFft(fft, waveform);
+        }
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t *wavePtr = NULL;
+        uint8_t *fftPtr = NULL;
+        uint32_t waveSize = 0;
+        uint32_t fftSize = 0;
+        if (mCaptureFlags & CAPTURE_WAVEFORM) {
+            wavePtr = waveform;
+            waveSize = mCaptureSize;
+        }
+        if (mCaptureFlags & CAPTURE_FFT) {
+            fftPtr = fft;
+            fftSize = mCaptureSize;
+        }
+        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
+    }
+}
+
+uint32_t Visualizer::initCaptureSize()
+{
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+    status_t status = getParameter(p);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+    }
+
+    uint32_t size = 0;
+    if (status == NO_ERROR) {
+        size = *((int32_t *)p->data + 1);
+    }
+    mCaptureSize = size;
+
+    LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
+
+    return size;
+}
+
+//-------------------------------------------------------------------------
+
+Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
+{
+    mSleepTimeUs = 1000000000 / captureRate;
+    LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
+}
+
+bool Visualizer::CaptureThread::threadLoop()
+{
+    LOGV("CaptureThread %p enter", this);
+    while (!exitPending())
+    {
+        usleep(mSleepTimeUs);
+        mReceiver.periodicCapture();
+    }
+    LOGV("CaptureThread %p exiting", this);
+    return false;
+}
+
+status_t Visualizer::CaptureThread::readyToRun()
+{
+    return NO_ERROR;
+}
+
+void Visualizer::CaptureThread::onFirstRef()
+{
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d5a3c13..b43f75f 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -658,61 +658,4 @@
 
 }
 
-extern "C" {
-#define FLOATING_POINT 1
-#include "fftwrap.h"
-}
-
-static void *ffttable = NULL;
-
-// peeks at the audio data and fills 'data' with the requested kind
-// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
-// 256 point FFT data). Return value is number of samples returned,
-// which may be 0.
-/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
-
-    sp<IMemory> p;
-    const sp<IMediaPlayerService>& service = getMediaPlayerService();
-    if (service != 0) {
-        // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
-        p = service->snoop();
-
-        if (p == NULL) {
-            return 0;
-        }
-
-        if (kind == 0) { // return waveform data
-            int plen = p->size();
-            len *= 2; // number of shorts -> number of bytes
-            short *src = (short*) p->pointer();
-            if (plen > len) {
-                plen = len;
-            }
-            memcpy(data, src, plen);
-            return plen / sizeof(short); // return number of samples
-        } else if (kind == 1) {
-            // TODO: use a more efficient FFT
-            // Right now this uses the speex library, which is compiled to do a float FFT
-            if (!ffttable) ffttable = spx_fft_init(512);
-            short *usrc = (short*) p->pointer();
-            float fsrc[512];
-            for (int i=0;i<512;i++)
-                fsrc[i] = usrc[i];
-            float fdst[512];
-            spx_fft_float(ffttable, fsrc, fdst);
-            if (len > 512) {
-                len = 512;
-            }
-            len /= 2; // only half the output data is valid
-            for (int i=0; i < len; i++)
-                data[i] = fdst[i];
-            return len;
-        }
-
-    } else {
-        LOGE("Unable to locate media service");
-    }
-    return 0;
-}
-
 }; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 82d5c14..4872047 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1265,98 +1265,6 @@
     return mem;
 }
 
-/*
- * Avert your eyes, ugly hack ahead.
- * The following is to support music visualizations.
- */
-
-static const int NUMVIZBUF = 32;
-static const int VIZBUFFRAMES = 1024;
-static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
-static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC;
-
-static bool gotMem = false;
-static sp<MemoryHeapBase> heap; 
-static sp<MemoryBase> mem[NUMVIZBUF];
-static uint64_t endTime;
-static uint64_t lastReadTime;
-static uint64_t lastWriteTime;
-static int writeIdx = 0;
-
-static void allocVizBufs() {
-    if (!gotMem) {
-        heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper");
-        for (int i=0;i<NUMVIZBUF;i++) {
-            mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2);
-        }
-        endTime = 0;
-        gotMem = true;
-    }
-}
-
-
-/*
- * Get a buffer of audio data that is about to be played.
- * We don't synchronize this because in practice the writer
- * is ahead of the reader, and even if we did happen to catch
- * a buffer while it's being written, it's just a visualization,
- * so no harm done.
- */
-static sp<MemoryBase> getVizBuffer() {
-
-    allocVizBufs();
-
-    lastReadTime = uptimeMillis();
-
-    // if there is no recent buffer (yet), just return empty handed
-    if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) {
-        //LOGI("@@@@    no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime);
-        return NULL;
-    }
-
-    int timedelta = endTime - lastReadTime;
-    if (timedelta < 0) timedelta = 0;
-    int framedelta = timedelta * 44100 / 1000;
-    int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1;
-    while (headIdx < 0) {
-        headIdx += NUMVIZBUF;
-    }
-    return mem[headIdx];
-}
-
-// Append the data to the vizualization buffer
-static void makeVizBuffers(const char *data, int len, uint64_t time) {
-
-    allocVizBufs();
-
-    uint64_t startTime = time;
-    const int frameSize = 4; // 16 bit stereo sample is 4 bytes
-    int offset = writeIdx;
-    int maxoff = heap->getSize() / 2; // in shorts
-    short *base = (short*)heap->getBase();
-    short *src = (short*)data;
-    while (len > 0) {
-        
-        // Degrade quality by mixing to mono and clearing the lowest 3 bits.
-        // This should still be good enough for a visualization
-        base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7;
-        src += 2;
-        len -= frameSize;
-        if (offset >= maxoff) {
-            offset = 0;
-        }
-    }
-    writeIdx = offset;
-    endTime = time + (len / frameSize) / 44;
-    //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time));
-}
-
-sp<IMemory> MediaPlayerService::snoop()
-{
-    sp<MemoryBase> mem = getVizBuffer();
-    return mem;
-}
-
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
@@ -1371,7 +1279,6 @@
     mRightVolume = 1.0;
     mLatency = 0;
     mMsecsPerFrame = 0;
-    mNumFramesWritten = 0;
     setMinBufferCount();
 }
 
@@ -1516,30 +1423,9 @@
     if (mTrack) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
         mTrack->start();
-        mTrack->getPosition(&mNumFramesWritten);
     }
 }
 
-void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) {
-    // Only make visualization buffers if anyone recently requested visualization data
-    uint64_t now = uptimeMillis();
-    if (lastReadTime + TOTALBUFTIMEMSEC >= now) {
-        // Based on the current play counter, the number of frames written and
-        // the current real time we can calculate the approximate real start
-        // time of the buffer we're about to write.
-        uint32_t pos;
-        mTrack->getPosition(&pos);
-
-        // we're writing ahead by this many frames:
-        int ahead = mNumFramesWritten - pos;
-        //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency());
-        // which is this many milliseconds, assuming 44100 Hz:
-        ahead /= 44;
-
-        makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency());
-        lastWriteTime = now;
-    }
-}
 
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
@@ -1548,9 +1434,7 @@
 
     //LOGV("write(%p, %u)", buffer, size);
     if (mTrack) {
-        snoopWrite(buffer, size);
         ssize_t ret = mTrack->write(buffer, size);
-        mNumFramesWritten += ret / 4; // assume 16 bit stereo
         return ret;
     }
     return NO_INIT;
@@ -1560,7 +1444,6 @@
 {
     LOGV("stop");
     if (mTrack) mTrack->stop();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::flush()
@@ -1573,7 +1456,6 @@
 {
     LOGV("pause");
     if (mTrack) mTrack->pause();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::close()
@@ -1609,9 +1491,6 @@
 
     buffer->size = actualSize;
 
-    if (actualSize > 0) {
-        me->snoopWrite(buffer->raw, actualSize);
-    }
 }
 
 #undef LOG_TAG
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60b91c6..39f525e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -113,9 +113,6 @@
         static bool             mIsOnEmulator;
         static int              mMinBufferCount;  // 12 for emulator; otherwise 4
 
-        public: // visualization hack support
-        uint32_t                mNumFramesWritten;
-        void                    snoopWrite(const void*, size_t);
     };
 
     class AudioCache : public MediaPlayerBase::AudioSink
@@ -191,7 +188,6 @@
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-    virtual sp<IMemory>         snoop();
     virtual sp<IOMX>            getOMX();
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 91c5b92..50f74f2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -426,6 +426,24 @@
     return OK;
 }
 
+status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
+    LOGV("setParamVideoEncoderProfile: %d", profile);
+
+    // Additional check will be done later when we load the encoder.
+    // For now, we are accepting values defined in OpenMAX IL.
+    mVideoEncoderProfile = profile;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
+    LOGV("setParamVideoEncoderLevel: %d", level);
+
+    // Additional check will be done later when we load the encoder.
+    // For now, we are accepting values defined in OpenMAX IL.
+    mVideoEncoderLevel = level;
+    return OK;
+}
+
 status_t StagefrightRecorder::setParameter(
         const String8 &key, const String8 &value) {
     LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
@@ -484,6 +502,16 @@
         if (safe_strtoi32(value.string(), &interval)) {
             return setParamVideoIFramesInterval(interval);
         }
+    } else if (key == "video-param-encoder-profile") {
+        int32_t profile;
+        if (safe_strtoi32(value.string(), &profile)) {
+            return setParamVideoEncoderProfile(profile);
+        }
+    } else if (key == "video-param-encoder-level") {
+        int32_t level;
+        if (safe_strtoi32(value.string(), &level)) {
+            return setParamVideoEncoderLevel(level);
+        }
     } else if (key == "video-param-camera-id") {
         int32_t cameraId;
         if (safe_strtoi32(value.string(), &cameraId)) {
@@ -851,6 +879,12 @@
     enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
     enc_meta->setInt32(kKeyStride, stride);
     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+    if (mVideoEncoderProfile != -1) {
+        enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
+    }
+    if (mVideoEncoderLevel != -1) {
+        enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
+    }
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
@@ -992,6 +1026,10 @@
     mAudioSourceNode = 0;
     mUse64BitFileOffset = false;
     mCameraId        = 0;
+    mVideoEncoderProfile = -1;
+    mVideoEncoderLevel   = -1;
+    mMaxFileDurationUs = 0;
+    mMaxFileSizeBytes = 0;
     mTrackEveryNumberOfFrames = 0;
     mTrackEveryTimeDurationUs = 0;
     mEncoderProfiles = MediaProfiles::getInstance();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index cb05571..85d2557 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -82,6 +82,8 @@
     int32_t mInterleaveDurationUs;
     int32_t mIFramesInterval;
     int32_t mCameraId;
+    int32_t mVideoEncoderProfile;
+    int32_t mVideoEncoderLevel;
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int32_t mTrackEveryNumberOfFrames;
@@ -108,6 +110,8 @@
     status_t setParamAudioSamplingRate(int32_t sampleRate);
     status_t setParamVideoEncodingBitRate(int32_t bitRate);
     status_t setParamVideoIFramesInterval(int32_t interval);
+    status_t setParamVideoEncoderProfile(int32_t profile);
+    status_t setParamVideoEncoderLevel(int32_t level);
     status_t setParamVideoCameraId(int32_t cameraId);
     status_t setParamTrackTimeStatus(int64_t timeDurationUs);
     status_t setParamTrackFrameStatus(int32_t nFrames);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4a1580f..ffed74f 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -371,9 +371,6 @@
     }
     mAudioSource.clear();
 
-    if (mTimeSource != mAudioPlayer) {
-        delete mTimeSource;
-    }
     mTimeSource = NULL;
 
     delete mAudioPlayer;
@@ -494,22 +491,35 @@
     }
     mStreamDoneEventPending = false;
 
-    if (mStreamDoneStatus == ERROR_END_OF_STREAM && (mFlags & LOOPING)) {
+    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
+        LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
+
+        notifyListener_l(
+                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
+
+        pause_l();
+
+        mFlags |= AT_EOS;
+        return;
+    }
+
+    const bool allDone =
+        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
+            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
+
+    if (!allDone) {
+        return;
+    }
+
+    if (mFlags & LOOPING) {
         seekTo_l(0);
 
         if (mVideoSource != NULL) {
             postVideoEvent_l();
         }
     } else {
-        if (mStreamDoneStatus == ERROR_END_OF_STREAM) {
-            LOGV("MEDIA_PLAYBACK_COMPLETE");
-            notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
-        } else {
-            LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
-
-            notifyListener_l(
-                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
-        }
+        LOGV("MEDIA_PLAYBACK_COMPLETE");
+        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
 
         pause_l();
 
@@ -563,7 +573,6 @@
                     return err;
                 }
 
-                delete mTimeSource;
                 mTimeSource = mAudioPlayer;
 
                 deferredAudioSeek = true;
@@ -579,7 +588,7 @@
     }
 
     if (mTimeSource == NULL && mAudioPlayer == NULL) {
-        mTimeSource = new SystemTimeSource;
+        mTimeSource = &mSystemTimeSource;
     }
 
     if (mVideoSource != NULL) {
@@ -744,7 +753,7 @@
     mSeeking = true;
     mSeekNotificationSent = false;
     mSeekTimeUs = timeUs;
-    mFlags &= ~AT_EOS;
+    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
 
     seekAudioIfNecessary_l();
 
@@ -924,6 +933,7 @@
                     continue;
                 }
 
+                mFlags |= VIDEO_AT_EOS;
                 postStreamDoneEvent_l(err);
                 return;
             }
@@ -968,19 +978,21 @@
         mSeekNotificationSent = false;
     }
 
+    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
+
     if (mFlags & FIRST_FRAME) {
         mFlags &= ~FIRST_FRAME;
 
-        mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
+        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
     }
 
     int64_t realTimeUs, mediaTimeUs;
-    if (mAudioPlayer != NULL
+    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
         && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
         mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
     }
 
-    int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
+    int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
 
     int64_t latenessUs = nowUs - timeUs;
 
@@ -1081,6 +1093,8 @@
     status_t finalStatus;
     if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
         mWatchForAudioEOS = false;
+        mFlags |= AUDIO_AT_EOS;
+        mFlags |= FIRST_FRAME;
         postStreamDoneEvent_l(finalStatus);
     }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index dacb8d3..83f7040 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -831,7 +831,7 @@
 
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
-    video_def->xFramerate = (frameRate << 16);  // Q16 format
+    video_def->xFramerate = 0;      // No need for output port
     video_def->nBitrate = bitRate;  // Q16 format
     video_def->eCompressionFormat = compressionFormat;
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
@@ -918,6 +918,52 @@
     return OK;
 }
 
+status_t OMXCodec::getVideoProfileLevel(
+        const sp<MetaData>& meta,
+        const CodecProfileLevel& defaultProfileLevel,
+        CodecProfileLevel &profileLevel) {
+    CODEC_LOGV("Default profile: %ld, level %ld",
+            defaultProfileLevel.mProfile, defaultProfileLevel.mLevel);
+
+    // Are the default profile and level overwriten?
+    int32_t profile, level;
+    if (!meta->findInt32(kKeyVideoProfile, &profile)) {
+        profile = defaultProfileLevel.mProfile;
+    }
+    if (!meta->findInt32(kKeyVideoLevel, &level)) {
+        level = defaultProfileLevel.mLevel;
+    }
+    CODEC_LOGV("Target profile: %d, level: %d", profile, level);
+
+    // Are the target profile and level supported by the encoder?
+    OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexOutput;
+    for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+        status_t err = mOMX->getParameter(
+                mNode, OMX_IndexParamVideoProfileLevelQuerySupported,
+                &param, sizeof(param));
+
+        if (err != OK) return err;
+
+        int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
+        int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
+        CODEC_LOGV("Supported profile: %ld, level %ld",
+            supportedProfile, supportedLevel);
+
+        if (profile == supportedProfile &&
+            level == supportedLevel) {
+            profileLevel.mProfile = profile;
+            profileLevel.mLevel = level;
+            return OK;
+        }
+    }
+
+    CODEC_LOGE("Target profile (%d) and level (%d) is not supported",
+            profile, level);
+    return BAD_VALUE;
+}
+
 status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) {
     int32_t iFramesInterval, frameRate, bitRate;
     bool success = meta->findInt32(kKeyBitRate, &bitRate);
@@ -941,8 +987,14 @@
     }
     h263type.nBFrames = 0;
 
-    h263type.eProfile = OMX_VIDEO_H263ProfileBaseline;
-    h263type.eLevel = OMX_VIDEO_H263Level45;
+    // Check profile and level parameters
+    CodecProfileLevel defaultProfileLevel, profileLevel;
+    defaultProfileLevel.mProfile = OMX_VIDEO_H263ProfileBaseline;
+    defaultProfileLevel.mLevel = OMX_VIDEO_H263Level45;
+    err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
+    if (err != OK) return err;
+    h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profileLevel.mProfile);
+    h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(profileLevel.mLevel);
 
     h263type.bPLUSPTYPEAllowed = OMX_FALSE;
     h263type.bForceRoundingTypeToZero = OMX_FALSE;
@@ -992,8 +1044,14 @@
     mpeg4type.nHeaderExtension = 0;
     mpeg4type.bReversibleVLC = OMX_FALSE;
 
-    mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
-    mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
+    // Check profile and level parameters
+    CodecProfileLevel defaultProfileLevel, profileLevel;
+    defaultProfileLevel.mProfile = OMX_VIDEO_MPEG4ProfileSimple;
+    defaultProfileLevel.mLevel = OMX_VIDEO_MPEG4Level2;
+    err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
+    if (err != OK) return err;
+    mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile);
+    mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel);
 
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
@@ -1029,22 +1087,39 @@
     if (h264type.nPFrames == 0) {
         h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
     }
-    h264type.bUseHadamard = OMX_TRUE;
-    h264type.nRefFrames = 1;
-    h264type.nRefIdx10ActiveMinus1 = 0;
-    h264type.nRefIdx11ActiveMinus1 = 0;
+
+    // Check profile and level parameters
+    CodecProfileLevel defaultProfileLevel, profileLevel;
+    defaultProfileLevel.mProfile = h264type.eProfile;
+    defaultProfileLevel.mLevel = h264type.eLevel;
+    err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
+    if (err != OK) return err;
+    h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
+    h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
+
+    if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
+        h264type.bUseHadamard = OMX_TRUE;
+        h264type.nRefFrames = 1;
+        h264type.nRefIdx10ActiveMinus1 = 0;
+        h264type.nRefIdx11ActiveMinus1 = 0;
+        h264type.bEntropyCodingCABAC = OMX_FALSE;
+        h264type.bWeightedPPrediction = OMX_FALSE;
+        h264type.bconstIpred = OMX_FALSE;
+        h264type.bDirect8x8Inference = OMX_FALSE;
+        h264type.bDirectSpatialTemporal = OMX_FALSE;
+        h264type.nCabacInitIdc = 0;
+    }
+
+    if (h264type.nBFrames != 0) {
+        h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
+    }
+
     h264type.bEnableUEP = OMX_FALSE;
     h264type.bEnableFMO = OMX_FALSE;
     h264type.bEnableASO = OMX_FALSE;
     h264type.bEnableRS = OMX_FALSE;
     h264type.bFrameMBsOnly = OMX_TRUE;
     h264type.bMBAFF = OMX_FALSE;
-    h264type.bEntropyCodingCABAC = OMX_FALSE;
-    h264type.bWeightedPPrediction = OMX_FALSE;
-    h264type.bconstIpred = OMX_FALSE;
-    h264type.bDirect8x8Inference = OMX_FALSE;
-    h264type.bDirectSpatialTemporal = OMX_FALSE;
-    h264type.nCabacInitIdc = 0;
     h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
 
     err = mOMX->setParameter(
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 2a9f21b..8d0877c 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -24,6 +24,7 @@
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/OMXClient.h>
+#include <media/stagefright/TimeSource.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -33,7 +34,6 @@
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
-struct TimeSource;
 struct NuCachedSource2;
 
 struct ALooper;
@@ -102,6 +102,8 @@
         AT_EOS              = 32,
         PREPARE_CANCELLED   = 64,
         CACHE_UNDERRUN      = 128,
+        AUDIO_AT_EOS        = 256,
+        VIDEO_AT_EOS        = 512,
     };
 
     mutable Mutex mLock;
@@ -115,6 +117,7 @@
     sp<ISurface> mISurface;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
+    SystemTimeSource mSystemTimeSource;
     TimeSource *mTimeSource;
 
     String8 mUri;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index 056537d..b1ad315 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -34,10 +34,12 @@
     private static final List<AudioDecoder> audioDecoders = DecoderCapabilities.getAudioDecoders();
     private static final List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
     private static final List<AudioEncoderCap> audioEncoders = EncoderCapabilities.getAudioEncoders();
-    private static final HashMap<Integer, String> encoderMap = new HashMap<Integer, String>();
+    private static final HashMap<Integer, String> videoEncoderMap = new HashMap<Integer, String>();
+    private static final HashMap<Integer, String> audioEncoderMap = new HashMap<Integer, String>();
 
     static {
-        initEncoderMap();
+        initAudioEncoderMap();
+        initVideoEncoderMap();
     };
 
     public static List<VideoEncoderCap> getVideoEncoders() {
@@ -79,7 +81,7 @@
             videoEncoder != MediaRecorder.VideoEncoder.MPEG_4_SP) {
             throw new IllegalArgumentException("Unsupported video encoder " + videoEncoder);
         }
-        return encoderMap.get(videoEncoder);
+        return videoEncoderMap.get(videoEncoder);
     }
 
     public static String getAudioCodecName(int audioEncoder) {
@@ -90,22 +92,24 @@
             audioEncoder != MediaRecorder.AudioEncoder.EAAC_PLUS) {
             throw new IllegalArgumentException("Unsupported audio encodeer " + audioEncoder);
         }
-        return encoderMap.get(audioEncoder);
+        return audioEncoderMap.get(audioEncoder);
     }
 
     private MediaProfileReader() {} // Don't call me
 
-    private static void initEncoderMap() {
+    private static void initVideoEncoderMap() {
         // video encoders
-        encoderMap.put(MediaRecorder.VideoEncoder.H263, "h263");
-        encoderMap.put(MediaRecorder.VideoEncoder.H264, "h264");
-        encoderMap.put(MediaRecorder.VideoEncoder.MPEG_4_SP, "m4v");
+        videoEncoderMap.put(MediaRecorder.VideoEncoder.H263, "h263");
+        videoEncoderMap.put(MediaRecorder.VideoEncoder.H264, "h264");
+        videoEncoderMap.put(MediaRecorder.VideoEncoder.MPEG_4_SP, "m4v");
+    }
 
+    private static void initAudioEncoderMap() {
         // audio encoders
-        encoderMap.put(MediaRecorder.AudioEncoder.AMR_NB, "amrnb");
-        encoderMap.put(MediaRecorder.AudioEncoder.AMR_WB, "amrwb");
-        encoderMap.put(MediaRecorder.AudioEncoder.AAC, "aac");
-        encoderMap.put(MediaRecorder.AudioEncoder.AAC_PLUS, "aacplus");
-        encoderMap.put(MediaRecorder.AudioEncoder.EAAC_PLUS, "eaacplus");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AMR_NB, "amrnb");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AMR_WB, "amrwb");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC, "aac");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC_PLUS, "aacplus");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.EAAC_PLUS, "eaacplus");
     }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index a52fd76..2332657 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -121,8 +121,8 @@
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         String filename = ("/sdcard/" + videoEncoder + "_" + audioEncoder + "_" + highQuality + ".3gp");
         try {
-            Log.v(TAG, "video encoder :" + videoEncoder);
-            Log.v(TAG, "audio encoder :" + audioEncoder);
+            Log.v(TAG, "video encoder : " + videoEncoder);
+            Log.v(TAG, "audio encoder : " + audioEncoder);
             Log.v(TAG, "quality : " + (highQuality?"high": "low"));
             Log.v(TAG, "encoder : " + MediaProfileReader.getVideoCodecName(videoEncoder));
             Log.v(TAG, "audio : " + MediaProfileReader.getAudioCodecName(audioEncoder));
diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/intruder_alert.xml
index 24eb960..ba4a774 100644
--- a/packages/SystemUI/res/layout/intruder_alert.xml
+++ b/packages/SystemUI/res/layout/intruder_alert.xml
@@ -44,7 +44,7 @@
             android:id="@+id/alertIcon"
             android:layout_width="25dip"
             android:layout_height="25dip"
-            android:paddingLeft="6dip"
+            android:layout_marginLeft="6dip"
             android:layout_marginRight="8dip"
             />
         <TextView
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a01e25b..83d9c47 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -60,7 +60,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.WindowOrientationListener;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -153,8 +152,6 @@
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
     static final int APPLICATION_PANEL_SUBLAYER = 1;
     static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
-    static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
     
     // Debugging: set this to have the system act like there is no hard keyboard.
     static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
@@ -164,6 +161,10 @@
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
+    // Useful scan codes.
+    private static final int SW_LID = 0x00;
+    private static final int BTN_MOUSE = 0x110;
+    
     final Object mLock = new Object();
     
     Context mContext;
@@ -690,7 +691,7 @@
     
     void readLidState() {
         try {
-            int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID);
+            int sw = mWindowManager.getSwitchState(SW_LID);
             if (sw >= 0) {
                 mLidOpen = sw == 0;
             }
@@ -727,19 +728,6 @@
                 : Configuration.KEYBOARDHIDDEN_YES;
     }
     
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
-        if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-            return true;
-        }
-        int size = ev.getHistorySize();
-        for(int i = 0; i < size; i++) {
-            if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) {
         if (mPointerLocationView == null) {
             return;
@@ -1034,19 +1022,22 @@
         };
 
     /** {@inheritDoc} */
-    public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 
-            int repeatCount, int flags) {
-        boolean keyguardOn = keyguardOn();
+    @Override
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, int metaState, int repeatCount, int policyFlags) {
+        final boolean keyguardOn = keyguardOn();
+        final boolean down = (action == KeyEvent.ACTION_DOWN);
+        final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
 
         if (false) {
-            Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
+            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
                     + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
         }
 
         // Clear a pending HOME longpress if the user releases Home
         // TODO: This could probably be inside the next bit of logic, but that code
         // turned out to be a bit fragile so I'm doing it here explicitly, for now.
-        if ((code == KeyEvent.KEYCODE_HOME) && !down) {
+        if ((keyCode == KeyEvent.KEYCODE_HOME) && !down) {
             mHandler.removeCallbacks(mHomeLongPress);
         }
 
@@ -1056,11 +1047,11 @@
             
             // If we have released the home key, and didn't do anything else
             // while it was pressed, then it is time to go home!
-            if (code == KeyEvent.KEYCODE_HOME) {
+            if (keyCode == KeyEvent.KEYCODE_HOME) {
                 if (!down) {
                     mHomePressed = false;
                     
-                    if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
+                    if (! canceled) {
                         // If an incoming call is ringing, HOME is totally disabled.
                         // (The user is already on the InCallScreen at this point,
                         // and his ONLY options are to answer or reject the call.)
@@ -1094,7 +1085,7 @@
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        if (code == KeyEvent.KEYCODE_HOME) {
+        if (keyCode == KeyEvent.KEYCODE_HOME) {
 
             // If a system window has focus, then it doesn't make sense
             // right now to interact with applications.
@@ -1122,17 +1113,17 @@
                 mHomePressed = true;
             }
             return true;
-        } else if (code == KeyEvent.KEYCODE_MENU) {
+        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
             // Hijack modified menu keys for debugging features
             final int chordBug = KeyEvent.META_SHIFT_ON;
 
             if (down && repeatCount == 0) {
-                if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
+                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
                     Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
                     mContext.sendOrderedBroadcast(intent, null);
                     return true;
                 } else if (SHOW_PROCESSES_ON_ALT_MENU &&
-                        (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
                     Intent service = new Intent();
                     service.setClassName(mContext, "com.android.server.LoadAverageService");
                     ContentResolver res = mContext.getContentResolver();
@@ -1148,7 +1139,7 @@
                     return true;
                 }
             }
-        } else if (code == KeyEvent.KEYCODE_SEARCH) {
+        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             if (down) {
                 if (repeatCount == 0) {
                     mSearchKeyPressed = true;
@@ -1167,7 +1158,7 @@
         // Shortcuts are invoked through Search+key, so intercept those here
         if (mSearchKeyPressed) {
             if (down && repeatCount == 0 && !keyguardOn) {
-                Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
+                Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
                 if (shortcutIntent != null) {
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(shortcutIntent);
@@ -1606,42 +1597,6 @@
     }
 
     /** {@inheritDoc} */
-    public boolean preprocessInputEventTq(RawInputEvent event) {
-        switch (event.type) {
-            case RawInputEvent.EV_SW:
-                if (event.keycode == RawInputEvent.SW_LID) {
-                    // lid changed state
-                    mLidOpen = event.value == 0;
-                    boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
-                    updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
-                    if (awakeNow) {
-                        // If the lid opening and we don't have to keep the
-                        // keyguard up, then we can turn on the screen
-                        // immediately.
-                        mKeyguardMediator.pokeWakelock();
-                    } else if (keyguardIsShowingTq()) {
-                        if (mLidOpen) {
-                            // If we are opening the lid and not hiding the
-                            // keyguard, then we need to have it turn on the
-                            // screen once it is shown.
-                            mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
-                                    KeyEvent.KEYCODE_POWER);
-                        }
-                    } else {
-                        // Light up the keyboard if we are sliding up.
-                        if (mLidOpen) {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.BUTTON_EVENT);
-                        } else {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.OTHER_EVENT);
-                        }
-                    }
-                }
-        }
-        return false;
-    }
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
         // lid changed state
         mLidOpen = lidOpen;
@@ -1672,26 +1627,6 @@
         }
     }
 
-    
-    /** {@inheritDoc} */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
-        return keycode == KeyEvent.KEYCODE_HOME
-                || keycode == KeyEvent.KEYCODE_ENDCALL;
-    }
-    
-    /** {@inheritDoc} */
-    public boolean isMovementKeyTi(int keycode) {
-        switch (keycode) {
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                return true;
-        }
-        return false;
-    }
-
-
     /**
      * @return Whether a telephone call is in progress right now.
      */
@@ -1762,60 +1697,63 @@
     }
  
     /** {@inheritDoc} */
-    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
+    @Override
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+            int policyFlags, boolean isScreenOn) {
         int result = ACTION_PASS_TO_USER;
-        final boolean isWakeKey = isWakeKeyTq(event);
+        
+        final boolean isWakeKey = (policyFlags
+                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+        
         // If screen is off then we treat the case where the keyguard is open but hidden
         // the same as if it were open and in front.
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (screenIsOn ?
+        final boolean keyguardActive = (isScreenOn ?
                                         mKeyguardMediator.isShowingAndNotHidden() :
                                         mKeyguardMediator.isShowing());
 
         if (false) {
-            Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
-                  + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
+            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
 
         if (keyguardActive) {
-            if (screenIsOn) {
+            if (isScreenOn) {
                 // when the screen is on, always give the event to the keyguard
                 result |= ACTION_PASS_TO_USER;
             } else {
                 // otherwise, don't pass it to the user
                 result &= ~ACTION_PASS_TO_USER;
 
-                final boolean isKeyDown =
-                        (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
-                if (isWakeKey && isKeyDown) {
+                if (isWakeKey && down) {
 
                     // tell the mediator about a wake key, it may decide to
                     // turn on the screen depending on whether the key is
                     // appropriate.
-                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
-                            && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
+                            && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
                         // when keyguard is showing and screen off, we need
                         // to handle the volume key for calls and  music here
                         if (isInCall()) {
-                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
                         } else if (isMusicActive()) {
-                            handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
                         }
                     }
                 }
             }
-        } else if (!screenIsOn) {
+        } else if (!isScreenOn) {
             // If we are in-call with screen off and keyguard is not showing,
             // then handle the volume key ourselves.
             // This is necessary because the phone app will disable the keyguard
             // when the proximity sensor is in use.
-            if (isInCall() && event.type == RawInputEvent.EV_KEY &&
-                     (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+            if (isInCall() &&
+                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
                 result &= ~ACTION_PASS_TO_USER;
-                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
             }
             if (isWakeKey) {
                 // a wake key has a sole purpose of waking the device; don't pass
@@ -1825,156 +1763,151 @@
             }
         }
 
-        int type = event.type;
-        int code = event.keycode;
-        boolean down = event.value != 0;
-
-        if (type == RawInputEvent.EV_KEY) {
-            if (code == KeyEvent.KEYCODE_ENDCALL
-                    || code == KeyEvent.KEYCODE_POWER) {
-                if (down) {
-                    boolean handled = false;
-                    boolean hungUp = false;
-                    // key repeats are generated by the window manager, and we don't see them
-                    // here, so unless the driver is doing something it shouldn't be, we know
-                    // this is the real press event.
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        try {
-                            if (code == KeyEvent.KEYCODE_ENDCALL) {
+        if (keyCode == KeyEvent.KEYCODE_ENDCALL
+                || keyCode == KeyEvent.KEYCODE_POWER) {
+            if (down) {
+                boolean handled = false;
+                boolean hungUp = false;
+                // key repeats are generated by the window manager, and we don't see them
+                // here, so unless the driver is doing something it shouldn't be, we know
+                // this is the real press event.
+                ITelephony phoneServ = getPhoneInterface();
+                if (phoneServ != null) {
+                    try {
+                        if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
+                            handled = hungUp = phoneServ.endCall();
+                        } else if (keyCode == KeyEvent.KEYCODE_POWER) {
+                            if (phoneServ.isRinging()) {
+                                // Pressing Power while there's a ringing incoming
+                                // call should silence the ringer.
+                                phoneServ.silenceRinger();
+                                handled = true;
+                            } else if (phoneServ.isOffhook() &&
+                                       ((mIncallPowerBehavior
+                                         & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
+                                        != 0)) {
+                                // Otherwise, if "Power button ends call" is enabled,
+                                // the Power button will hang up any current active call.
                                 handled = hungUp = phoneServ.endCall();
-                            } else if (code == KeyEvent.KEYCODE_POWER) {
-                                if (phoneServ.isRinging()) {
-                                    // Pressing Power while there's a ringing incoming
-                                    // call should silence the ringer.
-                                    phoneServ.silenceRinger();
-                                    handled = true;
-                                } else if (phoneServ.isOffhook() &&
-                                           ((mIncallPowerBehavior
-                                             & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
-                                            != 0)) {
-                                    // Otherwise, if "Power button ends call" is enabled,
-                                    // the Power button will hang up any current active call.
-                                    handled = hungUp = phoneServ.endCall();
-                                }
                             }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException" + ex);
                         }
-                    } else {
-                        Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-                    }
-
-                    if (!screenIsOn
-                            || (handled && code != KeyEvent.KEYCODE_POWER)
-                            || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {
-                        mShouldTurnOffOnKeyUp = false;
-                    } else {
-                        // only try to turn off the screen if we didn't already hang up
-                        mShouldTurnOffOnKeyUp = true;
-                        mHandler.postDelayed(mPowerLongPress,
-                                ViewConfiguration.getGlobalActionKeyTimeout());
-                        result &= ~ACTION_PASS_TO_USER;
+                    } catch (RemoteException ex) {
+                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
                     }
                 } else {
-                    mHandler.removeCallbacks(mPowerLongPress);
-                    if (mShouldTurnOffOnKeyUp) {
-                        mShouldTurnOffOnKeyUp = false;
-                        boolean gohome, sleeps;
-                        if (code == KeyEvent.KEYCODE_ENDCALL) {
-                            gohome = (mEndcallBehavior
-                                      & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
-                            sleeps = (mEndcallBehavior
-                                      & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
-                        } else {
-                            gohome = false;
-                            sleeps = true;
-                        }
-                        if (keyguardActive
-                                || (sleeps && !gohome)
-                                || (gohome && !goHome() && sleeps)) {
-                            // they must already be on the keyguad or home screen,
-                            // go to sleep instead
-                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-                                    + Integer.toHexString(mEndcallBehavior));
-                            result &= ~ACTION_POKE_USER_ACTIVITY;
-                            result |= ACTION_GO_TO_SLEEP;
-                        }
-                        result &= ~ACTION_PASS_TO_USER;
-                    }
+                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
                 }
-            } else if (isMediaKey(code)) {
-                // This key needs to be handled even if the screen is off.
-                // If others need to be handled while it's off, this is a reasonable
-                // pattern to follow.
-                if ((result & ACTION_PASS_TO_USER) == 0) {
-                    // Only do this if we would otherwise not pass it to the user. In that
-                    // case, the PhoneWindow class will do the same thing, except it will
-                    // only do it if the showing app doesn't process the key on its own.
-                    KeyEvent keyEvent = new KeyEvent(event.when, event.when,
-                            down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                            code, 0);
-                    mBroadcastWakeLock.acquire();
-                    mHandler.post(new PassHeadsetKey(keyEvent));
+
+                if (!isScreenOn
+                        || (handled && keyCode != KeyEvent.KEYCODE_POWER)
+                        || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
+                    mShouldTurnOffOnKeyUp = false;
+                } else {
+                    // only try to turn off the screen if we didn't already hang up
+                    mShouldTurnOffOnKeyUp = true;
+                    mHandler.postDelayed(mPowerLongPress,
+                            ViewConfiguration.getGlobalActionKeyTimeout());
+                    result &= ~ACTION_PASS_TO_USER;
                 }
-            } else if (code == KeyEvent.KEYCODE_CALL) {
-                // If an incoming call is ringing, answer it!
-                // (We handle this key here, rather than in the InCallScreen, to make
-                // sure we'll respond to the key even if the InCallScreen hasn't come to
-                // the foreground yet.)
-
-                // We answer the call on the DOWN event, to agree with
-                // the "fallback" behavior in the InCallScreen.
-                if (down) {
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            if (phoneServ.isRinging()) {
-                                Log.i(TAG, "interceptKeyTq:"
-                                      + " CALL key-down while ringing: Answer the call!");
-                                phoneServ.answerRingingCall();
-
-                                // And *don't* pass this key thru to the current activity
-                                // (which is presumably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } else {
-                            Log.w(TAG, "CALL button: Unable to find ITelephony interface");
-                        }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
+            } else {
+                mHandler.removeCallbacks(mPowerLongPress);
+                if (mShouldTurnOffOnKeyUp) {
+                    mShouldTurnOffOnKeyUp = false;
+                    boolean gohome, sleeps;
+                    if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
+                        gohome = (mEndcallBehavior
+                                  & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
+                        sleeps = (mEndcallBehavior
+                                  & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
+                    } else {
+                        gohome = false;
+                        sleeps = true;
                     }
+                    if (keyguardActive
+                            || (sleeps && !gohome)
+                            || (gohome && !goHome() && sleeps)) {
+                        // they must already be on the keyguad or home screen,
+                        // go to sleep instead
+                        Log.d(TAG, "I'm tired mEndcallBehavior=0x"
+                                + Integer.toHexString(mEndcallBehavior));
+                        result &= ~ACTION_POKE_USER_ACTIVITY;
+                        result |= ACTION_GO_TO_SLEEP;
+                    }
+                    result &= ~ACTION_PASS_TO_USER;
                 }
-            } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
-                       || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-                // If an incoming call is ringing, either VOLUME key means
-                // "silence ringer".  We handle these keys here, rather than
-                // in the InCallScreen, to make sure we'll respond to them
-                // even if the InCallScreen hasn't come to the foreground yet.
+            }
+        } else if (isMediaKey(keyCode)) {
+            // This key needs to be handled even if the screen is off.
+            // If others need to be handled while it's off, this is a reasonable
+            // pattern to follow.
+            if ((result & ACTION_PASS_TO_USER) == 0) {
+                // Only do this if we would otherwise not pass it to the user. In that
+                // case, the PhoneWindow class will do the same thing, except it will
+                // only do it if the showing app doesn't process the key on its own.
+                long when = whenNanos / 1000000;
+                KeyEvent keyEvent = new KeyEvent(when, when,
+                        down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
+                        keyCode, 0);
+                mBroadcastWakeLock.acquire();
+                mHandler.post(new PassHeadsetKey(keyEvent));
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_CALL) {
+            // If an incoming call is ringing, answer it!
+            // (We handle this key here, rather than in the InCallScreen, to make
+            // sure we'll respond to the key even if the InCallScreen hasn't come to
+            // the foreground yet.)
 
-                // Look for the DOWN event here, to agree with the "fallback"
-                // behavior in the InCallScreen.
-                if (down) {
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            if (phoneServ.isRinging()) {
-                                Log.i(TAG, "interceptKeyTq:"
-                                      + " VOLUME key-down while ringing: Silence ringer!");
-                                // Silence the ringer.  (It's safe to call this
-                                // even if the ringer has already been silenced.)
-                                phoneServ.silenceRinger();
+            // We answer the call on the DOWN event, to agree with
+            // the "fallback" behavior in the InCallScreen.
+            if (down) {
+                try {
+                    ITelephony phoneServ = getPhoneInterface();
+                    if (phoneServ != null) {
+                        if (phoneServ.isRinging()) {
+                            Log.i(TAG, "interceptKeyTq:"
+                                  + " CALL key-down while ringing: Answer the call!");
+                            phoneServ.answerRingingCall();
 
-                                // And *don't* pass this key thru to the current activity
-                                // (which is probably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } else {
-                            Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
+                            // And *don't* pass this key thru to the current activity
+                            // (which is presumably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
+                    } else {
+                        Log.w(TAG, "CALL button: Unable to find ITelephony interface");
                     }
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
+                }
+            }
+        } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
+                   || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
+            // If an incoming call is ringing, either VOLUME key means
+            // "silence ringer".  We handle these keys here, rather than
+            // in the InCallScreen, to make sure we'll respond to them
+            // even if the InCallScreen hasn't come to the foreground yet.
+
+            // Look for the DOWN event here, to agree with the "fallback"
+            // behavior in the InCallScreen.
+            if (down) {
+                try {
+                    ITelephony phoneServ = getPhoneInterface();
+                    if (phoneServ != null) {
+                        if (phoneServ.isRinging()) {
+                            Log.i(TAG, "interceptKeyTq:"
+                                  + " VOLUME key-down while ringing: Silence ringer!");
+                            // Silence the ringer.  (It's safe to call this
+                            // even if the ringer has already been silenced.)
+                            phoneServ.silenceRinger();
+
+                            // And *don't* pass this key thru to the current activity
+                            // (which is probably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
+                        }
+                    } else {
+                        Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
+                    }
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
                 }
             }
         }
@@ -2024,35 +1957,6 @@
     };
 
     /** {@inheritDoc} */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /** {@inheritDoc} */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /**
-     * Given the current state of the world, should this key wake up the device?
-     */
-    protected boolean isWakeKeyTq(RawInputEvent event) {
-        // There are not key maps for trackball devices, but we'd still
-        // like to have pressing it wake the device up, so force it here.
-        int keycode = event.keycode;
-        int flags = event.flags;
-        if (keycode == RawInputEvent.BTN_MOUSE) {
-            flags |= WindowManagerPolicy.FLAG_WAKE;
-        }
-        return (flags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-    }
-
-    /** {@inheritDoc} */
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
         mKeyguardMediator.onScreenTurnedOff(why);
@@ -2165,7 +2069,7 @@
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
             int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
             int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
-            int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE);
+            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
             mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
             performHapticFeedbackLw(null, mSafeMode
                     ? HapticFeedbackConstants.SAFE_MODE_ENABLED
@@ -2413,13 +2317,6 @@
         return true;
     }
     
-    public void keyFeedbackFromInput(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-    }
-    
     public void screenOnStoppedLw() {
         if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
             long curTime = SystemClock.uptimeMillis();
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
deleted file mode 100644
index 414b69f..0000000
--- a/services/java/com/android/server/InputDevice.java
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.util.Slog;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import java.io.PrintWriter;
-
-public class InputDevice {
-    static final boolean DEBUG_POINTERS = false;
-    static final boolean DEBUG_HACKS = false;
-    
-    /** Amount that trackball needs to move in order to generate a key event. */
-    static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
-
-    /** Maximum number of pointers we will track and report. */
-    static final int MAX_POINTERS = 10;
-    
-    /**
-     * Slop distance for jumpy pointer detection.
-     * The vertical range of the screen divided by this is our epsilon value.
-     */
-    private static final int JUMPY_EPSILON_DIVISOR = 212;
-    
-    /** Number of jumpy points to drop for touchscreens that need it. */
-    private static final int JUMPY_TRANSITION_DROPS = 3;
-    private static final int JUMPY_DROP_LIMIT = 3;
-    
-    final int id;
-    final int classes;
-    final String name;
-    final AbsoluteInfo absX;
-    final AbsoluteInfo absY;
-    final AbsoluteInfo absPressure;
-    final AbsoluteInfo absSize;
-    
-    long mKeyDownTime = 0;
-    int mMetaKeysState = 0;
-    
-    // For use by KeyInputQueue for keeping track of the current touch
-    // data in the old non-multi-touch protocol.
-    final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
-    
-    final MotionState mAbs = new MotionState(0, 0);
-    final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
-            TRACKBALL_MOVEMENT_THRESHOLD);
-    
-    static class MotionState {
-        int xPrecision;
-        int yPrecision;
-        float xMoveScale;
-        float yMoveScale;
-        MotionEvent currentMove = null;
-        boolean changed = false;
-        boolean everChanged = false;
-        long mDownTime = 0;
-        
-        // The currently assigned pointer IDs, corresponding to the last data.
-        int[] mPointerIds = new int[MAX_POINTERS];
-        
-        // This is the last generated pointer data, ordered to match
-        // mPointerIds.
-        boolean mSkipLastPointers;
-        int mLastNumPointers = 0;
-        final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is the next set of pointer data being generated.  It is not
-        // in any known order, and will be propagated in to mLastData
-        // as part of mapping it to the appropriate pointer IDs.
-        // Note that we have one extra sample of data here, to help clients
-        // avoid doing bounds checking.
-        int mNextNumPointers = 0;
-        final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        + MotionEvent.NUM_SAMPLE_DATA];
-        
-        // Used to determine whether we dropped bad data, to avoid doing
-        // it repeatedly.
-        final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
-
-        // Used to count the number of jumpy points dropped.
-        private int mJumpyPointsDropped = 0;
-        
-        // Used to perform averaging of reported coordinates, to smooth
-        // the data and filter out transients during a release.
-        static final int HISTORY_SIZE = 5;
-        int[] mHistoryDataStart = new int[MAX_POINTERS];
-        int[] mHistoryDataEnd = new int[MAX_POINTERS];
-        final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        * HISTORY_SIZE];
-        final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // Temporary data structures for doing the pointer ID mapping.
-        final int[] mLast2Next = new int[MAX_POINTERS];
-        final int[] mNext2Last = new int[MAX_POINTERS];
-        final long[] mNext2LastDistance = new long[MAX_POINTERS];
-        
-        // Temporary data structure for generating the final motion data.
-        final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is not used here, but can be used by callers for state tracking.
-        int mAddingPointerOffset = 0;
-        final boolean[] mDown = new boolean[MAX_POINTERS];
-        
-        void dumpIntArray(PrintWriter pw, int[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i]);
-            }
-            pw.print("]");
-        }
-        
-        void dumpBooleanArray(PrintWriter pw, boolean[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i] ? "true" : "false");
-            }
-            pw.print("]");
-        }
-        
-        void dump(PrintWriter pw, String prefix) {
-            pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
-                    pw.print(" yPrecision="); pw.println(yPrecision);
-            pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
-                    pw.print(" yMoveScale="); pw.println(yMoveScale);
-            if (currentMove != null) {
-                pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
-            }
-            if (changed || mDownTime != 0) {
-                pw.print(prefix); pw.print("changed="); pw.print(changed);
-                        pw.print(" mDownTime="); pw.println(mDownTime);
-            }
-            pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
-                    pw.println("");
-            if (mSkipLastPointers || mLastNumPointers != 0) {
-                pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
-                        pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
-                pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
-                        pw.println("");
-            }
-            if (mNextNumPointers != 0) {
-                pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
-                pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
-                        pw.println("");
-            }
-            pw.print(prefix); pw.print("mDroppedBadPoint=");
-                    dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
-            pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
-            pw.print(prefix); pw.print("mDown=");
-                    dumpBooleanArray(pw, mDown); pw.println("");
-        }
-        
-        MotionState(int mx, int my) {
-            xPrecision = mx;
-            yPrecision = my;
-            xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
-            yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
-            for (int i=0; i<MAX_POINTERS; i++) {
-                mPointerIds[i] = i;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: if one of the
-         * points has moved more than a screen height from the last position,
-         * then drop it.
-         */
-        void dropBadPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            // Don't do anything if a finger is going down or up.  We run
-            // here before assigning pointer IDs, so there isn't a good
-            // way to do per-finger matching.
-            if (mNextNumPointers != mLastNumPointers) {
-                return;
-            }
-            
-            // We consider a single movement across more than a 7/16 of
-            // the long size of the screen to be bad.  This was a magic value
-            // determined by looking at the maximum distance it is feasible
-            // to actually move in one sample.
-            final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
-            
-            // Look through all new points and see if any are farther than
-            // acceptable from all previous points.
-            for (int i=mNextNumPointers-1; i>=0; i--) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
-                final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
-                boolean dropped = false;
-                if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
-                    dropped = true;
-                    int closestDy = -1;
-                    int closestY = -1;
-                    // We will drop this new point if it is sufficiently
-                    // far away from -all- last points.
-                    for (int j=mLastNumPointers-1; j>=0; j--) {
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
-                        int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
-                        //if (dx < 0) dx = -dx;
-                        if (dy < 0) dy = -dy;
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j
-                                + ": y=" + mLastData[joff] + " dy=" + dy);
-                        if (dy < maxDy) {
-                            dropped = false;
-                            break;
-                        } else if (closestDy < 0 || dy < closestDy) {
-                            closestDy = dy;
-                            closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
-                        }
-                    }
-                    if (dropped) {
-                        dropped = true;
-                        Slog.i("InputDevice", "Dropping bad point #" + i
-                                + ": newY=" + y + " closestDy=" + closestDy
-                                + " maxDy=" + maxDy);
-                        mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
-                        break;
-                    }
-                }
-                mDroppedBadPoint[i] = dropped;
-            }
-        }
-        
-        void dropJumpyPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR;
-            
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            final int[] nextData = mNextData;
-            final int[] lastData = mLastData;
-            
-            if (nextNumPointers != mLastNumPointers) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Different pointer count " + lastNumPointers + 
-                            " -> " + nextNumPointers);
-                    for (int i = 0; i < nextNumPointers; i++) {
-                        int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                        Slog.d("InputDevice", "Pointer " + i + " (" + 
-                                mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                    }
-                }
-                
-                // Just drop the first few events going from 1 to 2 pointers.
-                // They're bad often enough that they're not worth considering.
-                if (lastNumPointers == 1 && nextNumPointers == 2
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    mNextNumPointers = 1;
-                    mJumpyPointsDropped++;
-                } else if (lastNumPointers == 2 && nextNumPointers == 1
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    // The event when we go from 2 -> 1 tends to be messed up too
-                    System.arraycopy(lastData, 0, nextData, 0, 
-                            lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
-                    mNextNumPointers = lastNumPointers;
-                    mJumpyPointsDropped++;
-                    
-                    if (DEBUG_HACKS) {
-                        for (int i = 0; i < mNextNumPointers; i++) {
-                            int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                            Slog.d("InputDevice", "Pointer " + i + " replaced (" + 
-                                    mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                    mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                        }
-                    }
-                } else {
-                    mJumpyPointsDropped = 0;
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Transition - drop limit reset");
-                    }
-                }
-                return;
-            }
-            
-            // A 'jumpy' point is one where the coordinate value for one axis
-            // has jumped to the other pointer's location. No need to do anything
-            // else if we only have one pointer.
-            if (nextNumPointers < 2) {
-                return;
-            }
-            
-            int badPointerIndex = -1;
-            int badPointerReplaceXWith = 0;
-            int badPointerReplaceYWith = 0;
-            int badPointerDistance = Integer.MIN_VALUE;
-            for (int i = nextNumPointers - 1; i >= 0; i--) {
-                boolean dropx = false;
-                boolean dropy = false;
-                
-                // Limit how many times a jumpy point can get dropped.
-                if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
-                    final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                    final int x = nextData[ioff + MotionEvent.SAMPLE_X];
-                    final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
-                    }
-
-                    // Check if a touch point is too close to another's coordinates
-                    for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) {
-                        if (j == i) {
-                            continue;
-                        }
-
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        final int xOther = nextData[joff + MotionEvent.SAMPLE_X];
-                        final int yOther = nextData[joff + MotionEvent.SAMPLE_Y];
-
-                        dropx = Math.abs(x - xOther) <= jumpyEpsilon;
-                        dropy = Math.abs(y - yOther) <= jumpyEpsilon;
-                    }
-                    
-                    if (dropx) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(yreplace - y);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lasty = lastData[joff + MotionEvent.SAMPLE_Y];   
-                            int currDist = Math.abs(lasty - y);
-                            if (currDist < distance) {
-                                xreplace = lastData[joff + MotionEvent.SAMPLE_X];
-                                yreplace = lasty;
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badXDelta = Math.abs(xreplace - x);
-                        if (badXDelta > badPointerDistance) {
-                            badPointerDistance = badXDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    } else if (dropy) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(xreplace - x);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lastx = lastData[joff + MotionEvent.SAMPLE_X];   
-                            int currDist = Math.abs(lastx - x);
-                            if (currDist < distance) {
-                                xreplace = lastx;
-                                yreplace = lastData[joff + MotionEvent.SAMPLE_Y];
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badYDelta = Math.abs(yreplace - y);
-                        if (badYDelta > badPointerDistance) {
-                            badPointerDistance = badYDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    }
-                }
-            }
-            if (badPointerIndex >= 0) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex +
-                            " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith +
-                            ")");
-                }
-
-                final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA;
-                nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith;
-                nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith;
-                mJumpyPointsDropped++;
-            } else {
-                mJumpyPointsDropped = 0;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: aggregate and
-         * compute averages of the coordinate data, to reduce the amount of
-         * jitter seen by applications.
-         */
-        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
-                int nextNumPointers) {
-            final int numPointers = mLastNumPointers;
-            final int[] rawData = mLastData;
-            if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers
-                    + " numPointers=" + numPointers);
-            for (int i=0; i<numPointers; i++) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                // We keep the average data in offsets based on the pointer
-                // ID, so we don't need to move it around as fingers are
-                // pressed and released.
-                final int p = mPointerIds[i];
-                final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
-                if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
-                    if (lastNumPointers < nextNumPointers) {
-                        // This pointer is going down.  Clear its history
-                        // and start fresh.
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        // The pointer is going up.  Just fall through to
-                        // recompute the last averaged point (and don't add
-                        // it as a new point to include in the average).
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                    }
-                } else {
-                    int end = mHistoryDataEnd[i];
-                    int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                    int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
-                    int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
-                    int newX = rawData[ioff + MotionEvent.SAMPLE_X];
-                    int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
-                    int dx = newX-oldX;
-                    int dy = newY-oldY;
-                    int delta = dx*dx + dy*dy;
-                    if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta);
-                    if (delta >= (75*75)) {
-                        // Magic number, if moving farther than this, turn
-                        // off filtering to avoid lag in response.
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        end++;
-                        if (end >= HISTORY_SIZE) {
-                            end -= HISTORY_SIZE;
-                        }
-                        mHistoryDataEnd[i] = end;
-                        int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                        mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
-                        mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
-                        mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
-                                = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                        int start = mHistoryDataStart[i];
-                        if (end == start) {
-                            start++;
-                            if (start >= HISTORY_SIZE) {
-                                start -= HISTORY_SIZE;
-                            }
-                            mHistoryDataStart[i] = start;
-                        }
-                    }
-                }
-                
-                // Now compute the average.
-                int start = mHistoryDataStart[i];
-                int end = mHistoryDataEnd[i];
-                int x=0, y=0;
-                int totalPressure = 0;
-                while (start != end) {
-                    int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
-                    int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
-                    if (pressure <= 0) pressure = 1;
-                    x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
-                    y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
-                    totalPressure += pressure;
-                    start++;
-                    if (start >= HISTORY_SIZE) start = 0;
-                }
-                int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
-                if (pressure <= 0) pressure = 1;
-                x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
-                y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
-                totalPressure += pressure;
-                x /= totalPressure;
-                y /= totalPressure;
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure
-                        + " weight: (" + x + "," + y + ")");
-                mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
-                mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
-                mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] =
-                        rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] =
-                        rawData[ioff + MotionEvent.SAMPLE_SIZE];
-            }
-            return mAveragedData;
-        }
-        
-        private boolean assignPointer(int nextIndex, boolean allowOverlap) {
-            final int lastNumPointers = mLastNumPointers;
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            final int[] last2Next = mLast2Next;
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
-                    + nextIndex + " dataOff=" + id);
-            final int x1 = nextData[id + MotionEvent.SAMPLE_X];
-            final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
-            
-            long bestDistance = -1;
-            int bestIndex = -1;
-            for (int j=0; j<lastNumPointers; j++) {
-                // If we are not allowing multiple new points to be assigned
-                // to the same old pointer, then skip this one if it is already
-                // detected as a conflict (-2).
-                if (!allowOverlap && last2Next[j] < -1) {
-                    continue;
-                }
-                final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
-                final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
-                final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
-                final long distance = xd*(long)xd + yd*(long)yd;
-                if (bestDistance == -1 || distance < bestDistance) {
-                    bestDistance = distance;
-                    bestIndex = j;
-                }
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
-                    + " best old index=" + bestIndex + " (distance="
-                    + bestDistance + ")");
-            next2Last[nextIndex] = bestIndex;
-            next2LastDistance[nextIndex] = bestDistance;
-            
-            if (bestIndex < 0) {
-                return true;
-            }
-            
-            if (last2Next[bestIndex] == -1) {
-                last2Next[bestIndex] = nextIndex;
-                return false;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
-                    + " has multiple best new pointers!");
-            
-            last2Next[bestIndex] = -2;
-            return true;
-        }
-        
-        private int updatePointerIdentifiers() {
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            
-            if (nextNumPointers == 1 && lastNumPointers == 1) {
-                System.arraycopy(nextData, 0, lastData, 0,
-                        MotionEvent.NUM_SAMPLE_DATA);
-                return -1;
-            }
-            
-            // Clear our old state.
-            final int[] last2Next = mLast2Next;
-            for (int i=0; i<lastNumPointers; i++) {
-                last2Next[i] = -1;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                    "Update pointers: lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers);
-            
-            // Figure out the closes new points to the previous points.
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            boolean conflicts = false;
-            for (int i=0; i<nextNumPointers; i++) {
-                conflicts |= assignPointer(i, true);
-            }
-            
-            // Resolve ambiguities in pointer mappings, when two or more
-            // new pointer locations find their best previous location is
-            // the same.
-            if (conflicts) {
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
-                
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] != -2) {
-                        continue;
-                    }
-                    
-                    // Note that this algorithm is far from perfect.  Ideally
-                    // we should do something like the one described at
-                    // http://portal.acm.org/citation.cfm?id=997856
-                    
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Resolving last index #" + i);
-                    
-                    int numFound;
-                    do {
-                        numFound = 0;
-                        long worstDistance = 0;
-                        int worstJ = -1;
-                        for (int j=0; j<nextNumPointers; j++) {
-                            if (next2Last[j] != i) {
-                                continue;
-                            }
-                            numFound++;
-                            if (worstDistance < next2LastDistance[j]) {
-                                worstDistance = next2LastDistance[j];
-                                worstJ = j;
-                            }
-                        }
-                        
-                        if (worstJ >= 0) {
-                            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                    "Worst new pointer: " + worstJ
-                                    + " (distance=" + worstDistance + ")");
-                            if (assignPointer(worstJ, false)) {
-                                // In this case there is no last pointer
-                                // remaining for this new one!
-                                next2Last[worstJ] = -1;
-                            }
-                        }
-                    } while (numFound > 2);
-                }
-            }
-            
-            int retIndex = -1;
-            
-            if (lastNumPointers < nextNumPointers) {
-                // We have one or more new pointers that are down.  Create a
-                // new pointer identifier for one of them.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer");
-                int nextId = 0;
-                int i=0;
-                while (i < lastNumPointers) {
-                    if (mPointerIds[i] > nextId) {
-                        // Found a hole, insert the pointer here.
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Inserting new pointer at hole " + i);
-                        System.arraycopy(mPointerIds, i, mPointerIds,
-                                i+1, lastNumPointers-i);
-                        System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
-                                lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
-                                (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(next2Last, i, next2Last,
-                                i+1, lastNumPointers-i);
-                        break;
-                    }
-                    i++;
-                    nextId++;
-                }
-                
-                if (DEBUG_POINTERS) Slog.v("InputDevice",
-                        "New pointer id " + nextId + " at index " + i);
-                
-                mLastNumPointers++;
-                retIndex = i;
-                mPointerIds[i] = nextId;
-                
-                // And assign this identifier to the first new pointer.
-                for (int j=0; j<nextNumPointers; j++) {
-                    if (next2Last[j] < 0) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Assigning new id to new pointer index " + j);
-                        next2Last[j] = i;
-                        break;
-                    }
-                }
-            }
-            
-            // Propagate all of the current data into the appropriate
-            // location in the old data to match the pointer ID that was
-            // assigned to it.
-            for (int i=0; i<nextNumPointers; i++) {
-                int lastIndex = next2Last[i];
-                if (lastIndex >= 0) {
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Copying next pointer index " + i
-                            + " to last index " + lastIndex);
-                    System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
-                            lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
-                            MotionEvent.NUM_SAMPLE_DATA);
-                }
-            }
-            
-            if (lastNumPointers > nextNumPointers) {
-                // One or more pointers has gone up.  Find the first one,
-                // and adjust accordingly.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer");
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] == -1) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Removing old pointer at index " + i);
-                        retIndex = i;
-                        break;
-                    }
-                }
-            }
-            
-            return retIndex;
-        }
-        
-        void removeOldPointer(int index) {
-            final int lastNumPointers = mLastNumPointers;
-            if (index >= 0 && index < lastNumPointers) {
-                System.arraycopy(mPointerIds, index+1, mPointerIds,
-                        index, lastNumPointers-index-1);
-                System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
-                        mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
-                        (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
-                mLastNumPointers--;
-            }
-        }
-        
-        MotionEvent generateAbsMotion(InputDevice device, long curTime,
-                long curTimeNano, Display display, int orientation,
-                int metaState) {
-            
-            if (mSkipLastPointers) {
-                mSkipLastPointers = false;
-                mLastNumPointers = 0;
-            }
-            
-            if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
-                return null;
-            }
-            
-            final int lastNumPointers = mLastNumPointers;
-            final int nextNumPointers = mNextNumPointers;
-            if (mNextNumPointers > MAX_POINTERS) {
-                Slog.w("InputDevice", "Number of pointers " + mNextNumPointers
-                        + " exceeded maximum of " + MAX_POINTERS);
-                mNextNumPointers = MAX_POINTERS;
-            }
-            
-            int upOrDownPointer = updatePointerIdentifiers();
-            
-            final float[] reportData = mReportData;
-            final int[] rawData;
-            if (KeyInputQueue.BAD_TOUCH_HACK) {
-                rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
-                        nextNumPointers);
-            } else {
-                rawData = mLastData;
-            }
-            
-            final int numPointers = mLastNumPointers;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
-                    + numPointers + " pointers (going from " + lastNumPointers
-                    + " to " + nextNumPointers + ")");
-            
-            for (int i=0; i<numPointers; i++) {
-                final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
-                reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
-                reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
-                reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
-                reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
-            }
-            
-            int action;
-            int edgeFlags = 0;
-            if (nextNumPointers != lastNumPointers) {
-                if (nextNumPointers > lastNumPointers) {
-                    if (lastNumPointers == 0) {
-                        action = MotionEvent.ACTION_DOWN;
-                        mDownTime = curTime;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_DOWN
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                } else {
-                    if (numPointers == 1) {
-                        action = MotionEvent.ACTION_UP;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_UP
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                }
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            final int dispW = display.getWidth()-1;
-            final int dispH = display.getHeight()-1;
-            int w = dispW;
-            int h = dispH;
-            if (orientation == Surface.ROTATION_90
-                    || orientation == Surface.ROTATION_270) {
-                int tmp = w;
-                w = h;
-                h = tmp;
-            }
-            
-            final AbsoluteInfo absX = device.absX;
-            final AbsoluteInfo absY = device.absY;
-            final AbsoluteInfo absPressure = device.absPressure;
-            final AbsoluteInfo absSize = device.absSize;
-            for (int i=0; i<numPointers; i++) {
-                final int j = i * MotionEvent.NUM_SAMPLE_DATA;
-            
-                if (absX != null) {
-                    reportData[j + MotionEvent.SAMPLE_X] =
-                            ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
-                                / absX.range) * w;
-                }
-                if (absY != null) {
-                    reportData[j + MotionEvent.SAMPLE_Y] =
-                            ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
-                                / absY.range) * h;
-                }
-                if (absPressure != null) {
-                    reportData[j + MotionEvent.SAMPLE_PRESSURE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
-                                / (float)absPressure.range);
-                }
-                if (absSize != null) {
-                    reportData[j + MotionEvent.SAMPLE_SIZE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
-                                / (float)absSize.range);
-                }
-                
-                switch (orientation) {
-                    case Surface.ROTATION_90: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
-                        break;
-                    }
-                    case Surface.ROTATION_180: {
-                        reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        break;
-                    }
-                    case Surface.ROTATION_270: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = temp;
-                        break;
-                    }
-                }
-            }
-            
-            // We only consider the first pointer when computing the edge
-            // flags, since they are global to the event.
-            if (action == MotionEvent.ACTION_DOWN) {
-                if (reportData[MotionEvent.SAMPLE_X] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_LEFT;
-                } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
-                    edgeFlags |= MotionEvent.EDGE_RIGHT;
-                }
-                if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_TOP;
-                } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
-                    edgeFlags |= MotionEvent.EDGE_BOTTOM;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + reportData[MotionEvent.SAMPLE_X]
-                        + " y=" + reportData[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, reportData, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, numPointers, mPointerIds, reportData,
-                    metaState, xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            
-            if (nextNumPointers < lastNumPointers) {
-                removeOldPointer(upOrDownPointer);
-            }
-            
-            return me;
-        }
-        
-        boolean hasMore() {
-            return mLastNumPointers != mNextNumPointers;
-        }
-        
-        void finish() {
-            mNextNumPointers = mAddingPointerOffset = 0;
-            mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
-        }
-        
-        MotionEvent generateRelMotion(InputDevice device, long curTime,
-                long curTimeNano, int orientation, int metaState) {
-            
-            final float[] scaled = mReportData;
-            
-            // For now we only support 1 pointer with relative motions.
-            scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
-            scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
-            scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
-            scaled[MotionEvent.SAMPLE_SIZE] = 0;
-            int edgeFlags = 0;
-            
-            int action;
-            if (mNextNumPointers != mLastNumPointers) {
-                mNextData[MotionEvent.SAMPLE_X] =
-                        mNextData[MotionEvent.SAMPLE_Y] = 0;
-                if (mNextNumPointers > 0 && mLastNumPointers == 0) {
-                    action = MotionEvent.ACTION_DOWN;
-                    mDownTime = curTime;
-                } else if (mNextNumPointers == 0) {
-                    action = MotionEvent.ACTION_UP;
-                } else {
-                    action = MotionEvent.ACTION_MOVE;
-                }
-                mLastNumPointers = mNextNumPointers;
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
-            scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
-            switch (orientation) {
-                case Surface.ROTATION_90: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = -temp;
-                    break;
-                }
-                case Surface.ROTATION_180: {
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
-                    break;
-                }
-                case Surface.ROTATION_270: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = temp;
-                    break;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + scaled[MotionEvent.SAMPLE_X]
-                        + " y=" + scaled[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, scaled, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, 1, mPointerIds, scaled, metaState,
-                    xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            return me;
-        }
-    }
-    
-    static class AbsoluteInfo {
-        int minValue;
-        int maxValue;
-        int range;
-        int flat;
-        int fuzz;
-        
-        final void dump(PrintWriter pw) {
-            pw.print("minValue="); pw.print(minValue);
-            pw.print(" maxValue="); pw.print(maxValue);
-            pw.print(" range="); pw.print(range);
-            pw.print(" flat="); pw.print(flat);
-            pw.print(" fuzz="); pw.print(fuzz);
-        }
-    };
-    
-    InputDevice(int _id, int _classes, String _name,
-            AbsoluteInfo _absX, AbsoluteInfo _absY,
-            AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
-        id = _id;
-        classes = _classes;
-        name = _name;
-        absX = _absX;
-        absY = _absY;
-        absPressure = _absPressure;
-        absSize = _absSize;
-    }
-};
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 2ba2914..cdae27c 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -56,7 +56,6 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    private final WindowManagerPolicy mWindowManagerPolicy;
     private final PowerManager mPowerManager;
     private final PowerManagerService mPowerManagerService;
     
@@ -103,12 +102,10 @@
     
     public InputManager(Context context,
             WindowManagerService windowManagerService,
-            WindowManagerPolicy windowManagerPolicy,
             PowerManager powerManager,
             PowerManagerService powerManagerService) {
         this.mContext = context;
         this.mWindowManagerService = windowManagerService;
-        this.mWindowManagerPolicy = windowManagerPolicy;
         this.mPowerManager = powerManager;
         this.mPowerManagerService = powerManagerService;
         
@@ -325,23 +322,8 @@
         private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
         
         @SuppressWarnings("unused")
-        public boolean isScreenOn() {
-            return mPowerManagerService.isScreenOn();
-        }
-        
-        @SuppressWarnings("unused")
-        public boolean isScreenBright() {
-            return mPowerManagerService.isScreenBright();
-        }
-        
-        @SuppressWarnings("unused")
-        public void virtualKeyFeedback(long whenNanos, int deviceId, int action, int flags,
-                int keyCode, int scanCode, int metaState, long downTimeNanos) {
-            KeyEvent keyEvent = new KeyEvent(downTimeNanos / 1000000,
-                    whenNanos / 1000000, action, keyCode, 0, metaState, scanCode, deviceId,
-                    flags);
-            
-            mWindowManagerService.virtualKeyFeedback(keyEvent);
+        public void virtualKeyDownFeedback() {
+            mWindowManagerService.mInputMonitor.virtualKeyDownFeedback();
         }
         
         @SuppressWarnings("unused")
@@ -356,7 +338,7 @@
         
         @SuppressWarnings("unused")
         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-            mWindowManagerPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+            mWindowManagerService.mInputMonitor.notifyLidSwitchChanged(whenNanos, lidOpen);
         }
         
         @SuppressWarnings("unused")
@@ -380,17 +362,17 @@
         }
         
         @SuppressWarnings("unused")
-        public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(deviceId, type,
-                    scanCode, keyCode, policyFlags, value, whenNanos, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
+                    whenNanos, keyCode, down, policyFlags, isScreenOn);
         }
         
         @SuppressWarnings("unused")
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
+                int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
-                    keyCode, metaState, down, repeatCount, policyFlags);
+                    action, flags, keyCode, metaState, repeatCount, policyFlags);
         }
         
         @SuppressWarnings("unused")
@@ -401,18 +383,6 @@
         }
         
         @SuppressWarnings("unused")
-        public void goToSleep(long whenNanos) {
-            long when = whenNanos / 1000000;
-            mPowerManager.goToSleep(when);
-        }
-        
-        @SuppressWarnings("unused")
-        public void pokeUserActivity(long eventTimeNanos, int eventType) {
-            long eventTime = eventTimeNanos / 1000000;
-            mPowerManagerService.userActivity(eventTime, false, eventType, false);
-        }
-        
-        @SuppressWarnings("unused")
         public void notifyAppSwitchComing() {
             mWindowManagerService.mInputMonitor.notifyAppSwitchComing();
         }
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
deleted file mode 100644
index f62c7ee..0000000
--- a/services/java/com/android/server/KeyInputQueue.java
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Environment;
-import android.os.LatencyTimer;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.Xml;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.RawInputEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-public abstract class KeyInputQueue {
-    static final String TAG = "KeyInputQueue";
-
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_VIRTUAL_KEYS = false;
-    static final boolean DEBUG_POINTERS = false;
-    
-    /**
-     * Turn on some hacks we have to improve the touch interaction with a
-     * certain device whose screen currently is not all that good.
-     */
-    static boolean BAD_TOUCH_HACK = false;
-    
-    /**
-     * Turn on some hacks to improve touch interaction with another device
-     * where touch coordinate data can get corrupted.
-     */
-    static boolean JUMPY_TOUCH_HACK = false;
-    
-    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
-
-    final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
-    final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
-    final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
-    final HapticFeedbackCallback mHapticFeedbackCallback;
-    
-    int mGlobalMetaState = 0;
-    boolean mHaveGlobalMetaState = false;
-    
-    final QueuedEvent mFirst;
-    final QueuedEvent mLast;
-    QueuedEvent mCache;
-    int mCacheCount;
-
-    Display mDisplay = null;
-    int mDisplayWidth;
-    int mDisplayHeight;
-    
-    int mOrientation = Surface.ROTATION_0;
-    int[] mKeyRotationMap = null;
-    
-    VirtualKey mPressedVirtualKey = null;
-    
-    PowerManager.WakeLock mWakeLock;
-
-    static final int[] KEY_90_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    static final int[] KEY_180_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
-    };
-    
-    static final int[] KEY_270_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    public static final int FILTER_REMOVE = 0;
-    public static final int FILTER_KEEP = 1;
-    public static final int FILTER_ABORT = -1;
-
-    private static final boolean MEASURE_LATENCY = false;
-    private LatencyTimer lt;
-
-    public interface FilterCallback {
-        int filterEvent(QueuedEvent ev);
-    }
-    
-    public interface HapticFeedbackCallback {
-        void virtualKeyFeedback(KeyEvent event);
-    }
-    
-    static class QueuedEvent {
-        InputDevice inputDevice;
-        long whenNano;
-        int flags; // From the raw event
-        int classType; // One of the class constants in InputEvent
-        Object event;
-        boolean inQueue;
-
-        void copyFrom(QueuedEvent that) {
-            this.inputDevice = that.inputDevice;
-            this.whenNano = that.whenNano;
-            this.flags = that.flags;
-            this.classType = that.classType;
-            this.event = that.event;
-        }
-
-        @Override
-        public String toString() {
-            return "QueuedEvent{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + event + "}";
-        }
-        
-        // not copied
-        QueuedEvent prev;
-        QueuedEvent next;
-    }
-
-    /**
-     * A key that exists as a part of the touch-screen, outside of the normal
-     * display area of the screen.
-     */
-    static class VirtualKey {
-        int scancode;
-        int centerx;
-        int centery;
-        int width;
-        int height;
-        
-        int hitLeft;
-        int hitTop;
-        int hitRight;
-        int hitBottom;
-        
-        InputDevice lastDevice;
-        int lastKeycode;
-        
-        boolean checkHit(int x, int y) {
-            return (x >= hitLeft && x <= hitRight
-                    && y >= hitTop && y <= hitBottom);
-        }
-        
-        void computeHitRect(InputDevice dev, int dw, int dh) {
-            if (dev == lastDevice) {
-                return;
-            }
-            
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
-                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
-            
-            lastDevice = dev;
-            
-            int minx = dev.absX.minValue;
-            int maxx = dev.absX.maxValue;
-            
-            int halfw = width/2;
-            int left = centerx - halfw;
-            int right = centerx + halfw;
-            hitLeft = minx + ((left*maxx-minx)/dw);
-            hitRight = minx + ((right*maxx-minx)/dw);
-            
-            int miny = dev.absY.minValue;
-            int maxy = dev.absY.maxValue;
-            
-            int halfh = height/2;
-            int top = centery - halfh;
-            int bottom = centery + halfh;
-            hitTop = miny + ((top*maxy-miny)/dh);
-            hitBottom = miny + ((bottom*maxy-miny)/dh);
-        }
-    }
-
-    private void readVirtualKeys(String deviceName) {
-        try {
-            FileInputStream fis = new FileInputStream(
-                    "/sys/board_properties/virtualkeys." + deviceName);
-            InputStreamReader isr = new InputStreamReader(fis);
-            BufferedReader br = new BufferedReader(isr, 2048);
-            String str = br.readLine();
-            if (str != null) {
-                String[] it = str.split(":");
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
-                final int N = it.length-6;
-                for (int i=0; i<=N; i+=6) {
-                    if (!"0x01".equals(it[i])) {
-                        Slog.w(TAG, "Unknown virtual key type at elem #" + i
-                                + ": " + it[i]);
-                        continue;
-                    }
-                    try {
-                        VirtualKey sb = new VirtualKey();
-                        sb.scancode = Integer.parseInt(it[i+1]);
-                        sb.centerx = Integer.parseInt(it[i+2]);
-                        sb.centery = Integer.parseInt(it[i+3]);
-                        sb.width = Integer.parseInt(it[i+4]);
-                        sb.height = Integer.parseInt(it[i+5]);
-                        if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
-                                + sb.scancode + ": center=" + sb.centerx + ","
-                                + sb.centery + " size=" + sb.width + "x"
-                                + sb.height);
-                        mVirtualKeys.add(sb);
-                    } catch (NumberFormatException e) {
-                        Slog.w(TAG, "Bad number at region " + i + " in: "
-                                + str, e);
-                    }
-                }
-            }
-            br.close();
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "No virtual keys found");
-        } catch (IOException e) {
-            Slog.w(TAG, "Error reading virtual keys", e);
-        }
-    }
-
-    private void readExcludedDevices() {
-        // Read partner-provided list of excluded input devices
-        XmlPullParser parser = null;
-        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
-        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
-        FileReader confreader = null;
-        try {
-            confreader = new FileReader(confFile);
-            parser = Xml.newPullParser();
-            parser.setInput(confreader);
-            XmlUtils.beginDocument(parser, "devices");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (!"device".equals(parser.getName())) {
-                    break;
-                }
-                String name = parser.getAttributeValue(null, "name");
-                if (name != null) {
-                    if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
-                    addExcludedDevice(name);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // It's ok if the file does not exist.
-        } catch (Exception e) {
-            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
-        } finally {
-            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
-        }
-    }
-
-    KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
-        if (MEASURE_LATENCY) {
-            lt = new LatencyTimer(100, 1000);
-        }
-
-        Resources r = context.getResources();
-        BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
-        
-        JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
-        
-        mHapticFeedbackCallback = hapticFeedbackCallback;
-        
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            readExcludedDevices();
-        }
-        
-        PowerManager pm = (PowerManager)context.getSystemService(
-                                                        Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                        "KeyInputQueue");
-        mWakeLock.setReferenceCounted(false);
-
-        mFirst = new QueuedEvent();
-        mLast = new QueuedEvent();
-        mFirst.next = mLast;
-        mLast.prev = mFirst;
-
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            mThread.start();
-        }
-    }
-
-    public void setDisplay(Display display) {
-        mDisplay = display;
-        
-        // We assume at this point that the display dimensions reflect the
-        // natural, unrotated display.  We will perform hit tests for soft
-        // buttons based on that display.
-        mDisplayWidth = display.getWidth();
-        mDisplayHeight = display.getHeight();
-    }
-    
-    public void getInputConfiguration(Configuration config) {
-        synchronized (mFirst) {
-            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-            config.keyboard = Configuration.KEYBOARD_NOKEYS;
-            config.navigation = Configuration.NAVIGATION_NONAV;
-            
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice d = mDevices.valueAt(i);
-                if (d != null) {
-                    if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                        config.touchscreen
-                                = Configuration.TOUCHSCREEN_FINGER;
-                        //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
-                        config.keyboard
-                                = Configuration.KEYBOARD_QWERTY;
-                        //Slog.i("foo", "***** HAVE QWERTY!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_TRACKBALL;
-                        //Slog.i("foo", "***** HAVE TRACKBALL!");
-                    } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_DPAD;
-                        //Slog.i("foo", "***** HAVE DPAD!");
-                    }
-                }
-            }
-        }
-    }
-    
-    public int getScancodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(code);
-        }
-    }
-    
-    public int getScancodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getKeycodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(code);
-        }
-    }
-    
-    public int getKeycodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public static native String getDeviceName(int deviceId);
-    public static native int getDeviceClasses(int deviceId);
-    public static native void addExcludedDevice(String deviceName);
-    public static native boolean getAbsoluteInfo(int deviceId, int axis,
-            InputDevice.AbsoluteInfo outInfo);
-    public static native int getSwitchState(int sw);
-    public static native int getSwitchState(int deviceId, int sw);
-    public static native int nativeGetScancodeState(int code);
-    public static native int nativeGetScancodeState(int deviceId, int code);
-    public static native int nativeGetKeycodeState(int code);
-    public static native int nativeGetKeycodeState(int deviceId, int code);
-    public static native int scancodeToKeycode(int deviceId, int scancode);
-    public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
-    
-    public static KeyEvent newKeyEvent(InputDevice device, long downTime,
-            long eventTime, boolean down, int keycode, int repeatCount,
-            int scancode, int flags) {
-        return new KeyEvent(
-                downTime, eventTime,
-                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                keycode, repeatCount,
-                device != null ? device.mMetaKeysState : 0,
-                device != null ? device.id : -1, scancode,
-                flags | KeyEvent.FLAG_FROM_SYSTEM);
-    }
-    
-    Thread mThread = new Thread("InputDeviceReader") {
-        public void run() {
-            if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-            
-            RawInputEvent ev = new RawInputEvent();
-            while (true) {
-                try {
-                    InputDevice di;
-
-                    // block, doesn't release the monitor
-                    readEvent(ev);
-
-                    boolean send = false;
-                    boolean configChanged = false;
-                    
-                    if (false) {
-                        Slog.i(TAG, "Input event: dev=0x"
-                                + Integer.toHexString(ev.deviceId)
-                                + " type=0x" + Integer.toHexString(ev.type)
-                                + " scancode=" + ev.scancode
-                                + " keycode=" + ev.keycode
-                                + " value=" + ev.value);
-                    }
-                    
-                    if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
-                        synchronized (mFirst) {
-                            di = newInputDevice(ev.deviceId);
-                            if (di.classes != 0) {
-                                // If this device is some kind of input class,
-                                // we care about it.
-                                mDevices.put(ev.deviceId, di);
-                                if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                                    readVirtualKeys(di.name);
-                                }
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else {
-                                // We won't do anything with this device.
-                                mIgnoredDevices.put(ev.deviceId, di);
-                                Slog.i(TAG, "Ignoring non-input device: id=0x"
-                                        + Integer.toHexString(di.id)
-                                        + ", name=" + di.name);
-                            }
-                        }
-                    } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
-                        synchronized (mFirst) {
-                            if (false) {
-                                Slog.i(TAG, "Device removed: id=0x"
-                                        + Integer.toHexString(ev.deviceId));
-                            }
-                            di = mDevices.get(ev.deviceId);
-                            if (di != null) {
-                                mDevices.delete(ev.deviceId);
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
-                                mIgnoredDevices.remove(ev.deviceId);
-                            } else {
-                                Slog.w(TAG, "Removing bad device id: "
-                                        + Integer.toHexString(ev.deviceId));
-                                continue;
-                            }
-                        }
-                    } else {
-                        di = getInputDevice(ev.deviceId);
-                        if (di == null) {
-                            // This may be some junk from an ignored device.
-                            continue;
-                        }
-                        
-                        // first crack at it
-                        send = preprocessEvent(di, ev);
-
-                        if (ev.type == RawInputEvent.EV_KEY) {
-                            di.mMetaKeysState = makeMetaState(ev.keycode,
-                                    ev.value != 0, di.mMetaKeysState);
-                            mHaveGlobalMetaState = false;
-                        }
-                    }
-
-                    if (configChanged) {
-                        synchronized (mFirst) {
-                            addLocked(di, System.nanoTime(), 0,
-                                    RawInputEvent.CLASS_CONFIGURATION_CHANGED,
-                                    null);
-                        }
-                    }
-                    
-                    if (!send) {
-                        continue;
-                    }
-                    
-                    synchronized (mFirst) {
-                        // NOTE: The event timebase absolutely must be the same
-                        // timebase as SystemClock.uptimeMillis().
-                        //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
-                        final long curTime = SystemClock.uptimeMillis();
-                        final long curTimeNano = System.nanoTime();
-                        //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
-                        
-                        final int classes = di.classes;
-                        final int type = ev.type;
-                        final int scancode = ev.scancode;
-                        send = false;
-                        
-                        // Is it a key event?
-                        if (type == RawInputEvent.EV_KEY &&
-                                (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
-                                (scancode < RawInputEvent.BTN_FIRST ||
-                                        scancode > RawInputEvent.BTN_LAST)) {
-                            boolean down;
-                            if (ev.value != 0) {
-                                down = true;
-                                di.mKeyDownTime = curTime;
-                            } else {
-                                down = false;
-                            }
-                            int keycode = rotateKeyCodeLocked(ev.keycode);
-                            addLocked(di, curTimeNano, ev.flags,
-                                    RawInputEvent.CLASS_KEYBOARD,
-                                    newKeyEvent(di, di.mKeyDownTime, curTime, down,
-                                            keycode, 0, scancode,
-                                            ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
-                                             ? KeyEvent.FLAG_WOKE_HERE : 0));
-                            
-                        } else if (ev.type == RawInputEvent.EV_KEY) {
-                            // Single touch protocol: touch going down or up.
-                            if (ev.scancode == RawInputEvent.BTN_TOUCH &&
-                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mDown[0] = ev.value != 0;
-                            
-                            // Trackball (mouse) protocol: press down or up.
-                            } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
-                                    (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
-                                send = true;
-                            }
-    
-                        // Process position events from multitouch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                        + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_X] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " X:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_Y] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " Y:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-                        
-                        // Process position events from single touch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_X) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_Y) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-    
-                        // Process movement events from trackball (mouse) protocol.
-                        } else if (ev.type == RawInputEvent.EV_REL &&
-                                (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                            // Add this relative movement into our totals.
-                            if (ev.scancode == RawInputEvent.REL_X) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
-                            } else if (ev.scancode == RawInputEvent.REL_Y) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
-                            }
-                        }
-                        
-                        // Handle multitouch protocol sync: tells us that the
-                        // driver has returned all data for -one- of the pointers
-                        // that is currently down.
-                        if (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_MT_REPORT
-                                && di.mAbs != null) {
-                            di.mAbs.changed = true;
-                            if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
-                                // If the value is <= 0, the pointer is not
-                                // down, so keep it in the count.
-                                
-                                if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                                      + MotionEvent.SAMPLE_PRESSURE] != 0) {
-                                    final int num = di.mAbs.mNextNumPointers+1;
-                                    di.mAbs.mNextNumPointers = num;
-                                    if (DEBUG_POINTERS) Slog.v(TAG,
-                                            "MT_REPORT: now have " + num + " pointers");
-                                    final int newOffset = (num <= InputDevice.MAX_POINTERS)
-                                            ? (num * MotionEvent.NUM_SAMPLE_DATA)
-                                            : (InputDevice.MAX_POINTERS *
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                    di.mAbs.mAddingPointerOffset = newOffset;
-                                    di.mAbs.mNextData[newOffset
-                                            + MotionEvent.SAMPLE_PRESSURE] = 0;
-                                } else {
-                                    if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
-                                }
-                            }
-                        
-                        // Handle general event sync: all data for the current
-                        // event update has been delivered.
-                        } else if (send || (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_REPORT)) {
-                            if (mDisplay != null) {
-                                if (!mHaveGlobalMetaState) {
-                                    computeGlobalMetaStateLocked();
-                                }
-                                
-                                MotionEvent me;
-                                
-                                InputDevice.MotionState ms = di.mAbs;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                        ms.mNextNumPointers = 0;
-                                        if (ms.mDown[0]) {
-                                            System.arraycopy(di.curTouchVals, 0,
-                                                    ms.mNextData, 0,
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                            ms.mNextNumPointers++;
-                                        }
-                                    }
-                                    
-                                    if (BAD_TOUCH_HACK) {
-                                        ms.dropBadPoint(di);
-                                    }
-                                    if (JUMPY_TOUCH_HACK) {
-                                        ms.dropJumpyPoint(di);
-                                    }
-                                    
-                                    boolean doMotion = !monitorVirtualKey(di,
-                                            ev, curTime, curTimeNano);
-                                    
-                                    if (doMotion && ms.mNextNumPointers > 0
-                                            && (ms.mLastNumPointers == 0
-                                                    || ms.mSkipLastPointers)) {
-                                        doMotion = !generateVirtualKeyDown(di,
-                                                ev, curTime, curTimeNano);
-                                    }
-                                    
-                                    if (doMotion) {
-                                        // XXX Need to be able to generate
-                                        // multiple events here, for example
-                                        // if two fingers change up/down state
-                                        // at the same time.
-                                        do {
-                                            me = ms.generateAbsMotion(di, curTime,
-                                                    curTimeNano, mDisplay,
-                                                    mOrientation, mGlobalMetaState);
-                                            if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
-                                                    + " y="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
-                                                    + " ev=" + me);
-                                            if (me != null) {
-                                                if (WindowManagerPolicy.WATCH_POINTER) {
-                                                    Slog.i(TAG, "Enqueueing: " + me);
-                                                }
-                                                addLocked(di, curTimeNano, ev.flags,
-                                                        RawInputEvent.CLASS_TOUCHSCREEN, me);
-                                            }
-                                        } while (ms.hasMore());
-                                    } else {
-                                        // We are consuming movement in the
-                                        // virtual key area...  but still
-                                        // propagate this to the previous
-                                        // data for comparisons.
-                                        int num = ms.mNextNumPointers;
-                                        if (num > InputDevice.MAX_POINTERS) {
-                                            num = InputDevice.MAX_POINTERS;
-                                        }
-                                        System.arraycopy(ms.mNextData, 0,
-                                                ms.mLastData, 0,
-                                                num * MotionEvent.NUM_SAMPLE_DATA);
-                                        ms.mLastNumPointers = num;
-                                        ms.mSkipLastPointers = true;
-                                    }
-                                    
-                                    ms.finish();
-                                }
-                                
-                                ms = di.mRel;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    me = ms.generateRelMotion(di, curTime,
-                                            curTimeNano,
-                                            mOrientation, mGlobalMetaState);
-                                    if (false) Slog.v(TAG, "Relative: x="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_X]
-                                            + " y="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
-                                            + " ev=" + me);
-                                    if (me != null) {
-                                        addLocked(di, curTimeNano, ev.flags,
-                                                RawInputEvent.CLASS_TRACKBALL, me);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                
-                } catch (RuntimeException exc) {
-                    Slog.e(TAG, "InputReaderThread uncaught exception", exc);
-                }
-            }
-        }
-    };
-
-    private boolean isInsideDisplay(InputDevice dev) {
-        final InputDevice.AbsoluteInfo absx = dev.absX;
-        final InputDevice.AbsoluteInfo absy = dev.absY;
-        final InputDevice.MotionState absm = dev.mAbs;
-        if (absx == null || absy == null || absm == null) {
-            return true;
-        }
-        
-        if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X]
-                    + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
-                    + ") inside of display");
-            return true;
-        }
-        
-        return false;
-    }
-    
-    private VirtualKey findVirtualKey(InputDevice dev) {
-        final int N = mVirtualKeys.size();
-        if (N <= 0) {
-            return null;
-        }
-        
-        final InputDevice.MotionState absm = dev.mAbs;
-        for (int i=0; i<N; i++) {
-            VirtualKey sb = mVirtualKeys.get(i);
-            sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                    + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
-                    + sb.scancode + " - (" + sb.hitLeft
-                    + "," + sb.hitTop + ")-(" + sb.hitRight + ","
-                    + sb.hitBottom + ")");
-            if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
-                    absm.mNextData[MotionEvent.SAMPLE_Y])) {
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
-                return sb;
-            }
-        }
-        
-        return null;
-    }
-    
-    private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        if (isInsideDisplay(di)) {
-            // Didn't consume event.
-            return false;
-        }
-        
-        
-        VirtualKey vk = findVirtualKey(di);
-        if (vk != null) {
-            final InputDevice.MotionState ms = di.mAbs;
-            mPressedVirtualKey = vk;
-            vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
-            ms.mLastNumPointers = ms.mNextNumPointers;
-            di.mKeyDownTime = curTime;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
-                    "Generate key down for: " + vk.scancode
-                    + " (keycode=" + vk.lastKeycode + ")");
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-        }
-        
-        // We always consume the event, even if we didn't
-        // generate a key event.  There are two reasons for
-        // this: to avoid spurious touches when holding
-        // the edges of the device near the touchscreen,
-        // and to avoid reporting events if there are virtual
-        // keys on the touchscreen outside of the display
-        // area.
-        // Note that for all of this we are only looking at the
-        // first pointer, since what we are handling here is the
-        // first pointer going down, and this is the coordinate
-        // that will be used to dispatch the event.
-        if (false) {
-            final InputDevice.AbsoluteInfo absx = di.absX;
-            final InputDevice.AbsoluteInfo absy = di.absY;
-            final InputDevice.MotionState absm = di.mAbs;
-            Slog.v(TAG, "Rejecting ("
-                + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
-                + absx.minValue + "," + absy.minValue
-                + ")-(" + absx.maxValue + ","
-                + absx.maxValue + ")");
-        }
-        return true;
-    }
-    
-    private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        VirtualKey vk = mPressedVirtualKey;
-        if (vk == null) {
-            return false;
-        }
-        
-        final InputDevice.MotionState ms = di.mAbs;
-        if (ms.mNextNumPointers <= 0) {
-            mPressedVirtualKey = null;
-            ms.mLastNumPointers = 0;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            return true;
-            
-        } else if (isInsideDisplay(di)) {
-            // Whoops the pointer has moved into
-            // the display area!  Cancel the
-            // virtual key and start a pointer
-            // motion.
-            mPressedVirtualKey = null;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            ms.mLastNumPointers = 0;
-            return false;
-        }
-        
-        return true;
-    }
-    
-    /**
-     * Returns a new meta state for the given keys and old state.
-     */
-    private static final int makeMetaState(int keycode, boolean down, int old) {
-        int mask;
-        switch (keycode) {
-        case KeyEvent.KEYCODE_ALT_LEFT:
-            mask = KeyEvent.META_ALT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_ALT_RIGHT:
-            mask = KeyEvent.META_ALT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_LEFT:
-            mask = KeyEvent.META_SHIFT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_RIGHT:
-            mask = KeyEvent.META_SHIFT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SYM:
-            mask = KeyEvent.META_SYM_ON;
-            break;
-        default:
-            return old;
-        }
-        int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
-                    & (down ? (old | mask) : (old & ~mask));
-        if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
-            result |= KeyEvent.META_ALT_ON;
-        }
-        if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
-            result |= KeyEvent.META_SHIFT_ON;
-        }
-        return result;
-    }
-
-    private void computeGlobalMetaStateLocked() {
-        int i = mDevices.size();
-        mGlobalMetaState = 0;
-        while ((--i) >= 0) {
-            mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
-        }
-        mHaveGlobalMetaState = true;
-    }
-    
-    /*
-     * Return true if you want the event to get passed on to the 
-     * rest of the system, and false if you've handled it and want
-     * it dropped.
-     */
-    abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
-
-    InputDevice getInputDevice(int deviceId) {
-        synchronized (mFirst) {
-            return getInputDeviceLocked(deviceId);
-        }
-    }
-    
-    private InputDevice getInputDeviceLocked(int deviceId) {
-        return mDevices.get(deviceId);
-    }
-
-    public void setOrientation(int orientation) {
-        synchronized(mFirst) {
-            mOrientation = orientation;
-            switch (orientation) {
-                case Surface.ROTATION_90:
-                    mKeyRotationMap = KEY_90_MAP;
-                    break;
-                case Surface.ROTATION_180:
-                    mKeyRotationMap = KEY_180_MAP;
-                    break;
-                case Surface.ROTATION_270:
-                    mKeyRotationMap = KEY_270_MAP;
-                    break;
-                default:
-                    mKeyRotationMap = null;
-                    break;
-            }
-        }
-    }
-    
-    public int rotateKeyCode(int keyCode) {
-        synchronized(mFirst) {
-            return rotateKeyCodeLocked(keyCode);
-        }
-    }
-    
-    private int rotateKeyCodeLocked(int keyCode) {
-        int[] map = mKeyRotationMap;
-        if (map != null) {
-            final int N = map.length;
-            for (int i=0; i<N; i+=2) {
-                if (map[i] == keyCode) {
-                    return map[i+1];
-                }
-            }
-        }
-        return keyCode;
-    }
-    
-    boolean hasEvents() {
-        synchronized (mFirst) {
-            return mFirst.next != mLast;
-        }
-    }
-    
-    /*
-     * returns true if we returned an event, and false if we timed out
-     */
-    QueuedEvent getEvent(long timeoutMS) {
-        long begin = SystemClock.uptimeMillis();
-        final long end = begin+timeoutMS;
-        long now = begin;
-        synchronized (mFirst) {
-            while (mFirst.next == mLast && end > now) {
-                try {
-                    mWakeLock.release();
-                    mFirst.wait(end-now);
-                }
-                catch (InterruptedException e) {
-                }
-                now = SystemClock.uptimeMillis();
-                if (begin > now) {
-                    begin = now;
-                }
-            }
-            if (mFirst.next == mLast) {
-                return null;
-            }
-            QueuedEvent p = mFirst.next;
-            mFirst.next = p.next;
-            mFirst.next.prev = mFirst;
-            p.inQueue = false;
-            return p;
-        }
-    }
-
-    /**
-     * Return true if the queue has an up event pending that corresponds
-     * to the same key as the given key event.
-     */
-    boolean hasKeyUpEvent(KeyEvent origEvent) {
-        synchronized (mFirst) {
-            final int keyCode = origEvent.getKeyCode();
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
-                    KeyEvent ke = (KeyEvent)cur.event;
-                    if (ke.getAction() == KeyEvent.ACTION_UP
-                            && ke.getKeyCode() == keyCode) {
-                        return true;
-                    }
-                }
-                cur = cur.prev;
-            }
-        }
-        
-        return false;
-    }
-    
-    void recycleEvent(QueuedEvent ev) {
-        synchronized (mFirst) {
-            //Slog.i(TAG, "Recycle event: " + ev);
-            if (ev.event == ev.inputDevice.mAbs.currentMove) {
-                ev.inputDevice.mAbs.currentMove = null;
-            }
-            if (ev.event == ev.inputDevice.mRel.currentMove) {
-                if (false) Slog.i(TAG, "Detach rel " + ev.event);
-                ev.inputDevice.mRel.currentMove = null;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
-            }
-            recycleLocked(ev);
-        }
-    }
-    
-    void filterQueue(FilterCallback cb) {
-        synchronized (mFirst) {
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                switch (cb.filterEvent(cur)) {
-                    case FILTER_REMOVE:
-                        cur.prev.next = cur.next;
-                        cur.next.prev = cur.prev;
-                        break;
-                    case FILTER_ABORT:
-                        return;
-                }
-                cur = cur.prev;
-            }
-        }
-    }
-    
-    private QueuedEvent obtainLocked(InputDevice device, long whenNano,
-            int flags, int classType, Object event) {
-        QueuedEvent ev;
-        if (mCacheCount == 0) {
-            ev = new QueuedEvent();
-        } else {
-            ev = mCache;
-            ev.inQueue = false;
-            mCache = ev.next;
-            mCacheCount--;
-        }
-        ev.inputDevice = device;
-        ev.whenNano = whenNano;
-        ev.flags = flags;
-        ev.classType = classType;
-        ev.event = event;
-        return ev;
-    }
-
-    private void recycleLocked(QueuedEvent ev) {
-        if (ev.inQueue) {
-            throw new RuntimeException("Event already in queue!");
-        }
-        if (mCacheCount < 10) {
-            mCacheCount++;
-            ev.next = mCache;
-            mCache = ev;
-            ev.inQueue = true;
-        }
-    }
-
-    private void addLocked(InputDevice device, long whenNano, int flags,
-            int classType, Object event) {
-        boolean poke = mFirst.next == mLast;
-
-        QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
-        QueuedEvent p = mLast.prev;
-        while (p != mFirst && ev.whenNano < p.whenNano) {
-            p = p.prev;
-        }
-
-        ev.next = p.next;
-        ev.prev = p;
-        p.next = ev;
-        ev.next.prev = ev;
-        ev.inQueue = true;
-
-        if (poke) {
-            long time;
-            if (MEASURE_LATENCY) {
-                time = System.nanoTime();
-            }
-            mFirst.notify();
-            mWakeLock.acquire();
-            if (MEASURE_LATENCY) {
-                lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
-            }
-        }
-    }
-
-    private InputDevice newInputDevice(int deviceId) {
-        int classes = getDeviceClasses(deviceId);
-        String name = getDeviceName(deviceId);
-        InputDevice.AbsoluteInfo absX = null;
-        InputDevice.AbsoluteInfo absY = null;
-        InputDevice.AbsoluteInfo absPressure = null;
-        InputDevice.AbsoluteInfo absSize = null;
-        if (classes != 0) {
-            Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
-                    + ", name=" + name
-                    + ", classes=" + Integer.toHexString(classes));
-            if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
-            } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_PRESSURE, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_TOOL_WIDTH, "Size");
-            }
-        }
-        
-        return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
-    }
-    
-    private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
-            String name) {
-        InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
-        if (getAbsoluteInfo(id, channel, info)
-                && info.minValue != info.maxValue) {
-            Slog.i(TAG, "  " + name + ": min=" + info.minValue
-                    + " max=" + info.maxValue
-                    + " flat=" + info.flat
-                    + " fuzz=" + info.fuzz);
-            info.range = info.maxValue-info.minValue;
-            return info;
-        }
-        Slog.i(TAG, "  " + name + ": unknown values");
-        return null;
-    }
-    private static native boolean readEvent(RawInputEvent outEvent);
-    
-    void dump(PrintWriter pw, String prefix) {
-        synchronized (mFirst) {
-            for (int i=0; i<mDevices.size(); i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                pw.print(prefix); pw.print("Device #");
-                        pw.print(mDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println("):");
-                pw.print(prefix); pw.print("  mKeyDownTime=");
-                        pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
-                        pw.println(dev.mMetaKeysState);
-                if (dev.absX != null) {
-                    pw.print(prefix); pw.print("  absX: "); dev.absX.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absY != null) {
-                    pw.print(prefix); pw.print("  absY: "); dev.absY.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absPressure != null) {
-                    pw.print(prefix); pw.print("  absPressure: ");
-                            dev.absPressure.dump(pw); pw.println("");
-                }
-                if (dev.absSize != null) {
-                    pw.print(prefix); pw.print("  absSize: ");
-                            dev.absSize.dump(pw); pw.println("");
-                }
-                if (dev.mAbs.everChanged) {
-                    pw.print(prefix); pw.println("  mAbs:");
-                    dev.mAbs.dump(pw, prefix + "    ");
-                }
-                if (dev.mRel.everChanged) {
-                    pw.print(prefix); pw.println("  mRel:");
-                    dev.mRel.dump(pw, prefix + "    ");
-                }
-            }
-            pw.println(" ");
-            for (int i=0; i<mIgnoredDevices.size(); i++) {
-                InputDevice dev = mIgnoredDevices.valueAt(i);
-                pw.print(prefix); pw.print("Ignored Device #");
-                        pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println(")");
-            }
-            pw.println(" ");
-            for (int i=0; i<mVirtualKeys.size(); i++) {
-                VirtualKey vk = mVirtualKeys.get(i);
-                pw.print(prefix); pw.print("Virtual Key #");
-                        pw.print(i); pw.println(":");
-                pw.print(prefix); pw.print("  scancode="); pw.println(vk.scancode);
-                pw.print(prefix); pw.print("  centerx="); pw.print(vk.centerx);
-                        pw.print(" centery="); pw.print(vk.centery);
-                        pw.print(" width="); pw.print(vk.width);
-                        pw.print(" height="); pw.println(vk.height);
-                pw.print(prefix); pw.print("  hitLeft="); pw.print(vk.hitLeft);
-                        pw.print(" hitTop="); pw.print(vk.hitTop);
-                        pw.print(" hitRight="); pw.print(vk.hitRight);
-                        pw.print(" hitBottom="); pw.println(vk.hitBottom);
-                if (vk.lastDevice != null) {
-                    pw.print(prefix); pw.print("  lastDevice=#");
-                            pw.println(vk.lastDevice.id);
-                }
-                if (vk.lastKeycode != 0) {
-                    pw.print(prefix); pw.print("  lastKeycode=");
-                            pw.println(vk.lastKeycode);
-                }
-            }
-            pw.println(" ");
-            pw.print(prefix); pw.print("  Default keyboard: ");
-                    pw.println(SystemProperties.get("hw.keyboards.0.devname"));
-            pw.print(prefix); pw.print("  mGlobalMetaState=");
-                    pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
-                    pw.println(mHaveGlobalMetaState);
-            pw.print(prefix); pw.print("  mDisplayWidth=");
-                    pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
-                    pw.println(mDisplayHeight);
-            pw.print(prefix); pw.print("  mOrientation=");
-                    pw.println(mOrientation);
-            if (mPressedVirtualKey != null) {
-                pw.print(prefix); pw.print("  mPressedVirtualKey.scancode=");
-                        pw.println(mPressedVirtualKey.scancode);
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 493a348..e9d5efc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -247,6 +247,9 @@
     private static final boolean mSpew = false;
     private static final boolean mDebugProximitySensor = (true || mSpew);
     private static final boolean mDebugLightSensor = (false || mSpew);
+    
+    private native void nativeInit();
+    private native void nativeSetPowerState(boolean screenOn, boolean screenBright);
 
     /*
     static PrintStream mLog;
@@ -481,6 +484,11 @@
                 }
             }
         }
+        
+        nativeInit();
+        synchronized (mLocks) {
+            updateNativePowerStateLocked();
+        }
     }
 
     void initInThread() {
@@ -1557,8 +1565,16 @@
                     }
                 }
             }
+            
+            updateNativePowerStateLocked();
         }
     }
+    
+    private void updateNativePowerStateLocked() {
+        nativeSetPowerState(
+                (mPowerState & SCREEN_ON_BIT) != 0,
+                (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+    }
 
     private int screenOffFinishedAnimatingLocked(int reason) {
         // I don't think we need to check the current state here because all of these
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 483f9eb..38f1e1f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -48,7 +48,6 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.KeyInputQueue.QueuedEvent;
 import com.android.server.am.BatteryStatsService;
 
 import android.Manifest;
@@ -95,6 +94,7 @@
 import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -105,7 +105,6 @@
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.View;
@@ -137,7 +136,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
+        implements Watchdog.Monitor {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_FOCUS = false;
@@ -159,17 +158,12 @@
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
-    static final boolean ENABLE_NATIVE_INPUT_DISPATCH =
-        WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH;
     static private LatencyTimer lt;
 
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean BLUR = true;
     static final boolean localLOGV = DEBUG;
 
-    /** How long to wait for subsequent key repeats, in milliseconds */
-    static final int KEY_REPEAT_DELAY = 50;
-
     /** How much to multiply the policy's type layer, to reserve room
      * for multiple windows of the same type and Z-ordering adjustment
      * with TYPE_LAYER_OFFSET. */
@@ -210,34 +204,11 @@
     // Default input dispatching timeout in nanoseconds.
     private static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
-    static final int INJECT_FAILED = 0;
-    static final int INJECT_SUCCEEDED = 1;
-    static final int INJECT_NO_PERMISSION = -1;
-
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
     static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
 
-    /** The minimum time between dispatching touch events. */
-    int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
-
-    // Last touch event time
-    long mLastTouchEventTime = 0;
-
-    // Last touch event type
-    int mLastTouchEventType = OTHER_EVENT;
-
-    // Time to wait before calling useractivity again. This saves CPU usage
-    // when we get a flood of touch events.
-    static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
-
-    // Last time we call user activity
-    long mLastUserActivityCallTime = 0;
-
-    // Last time we updated battery stats
-    long mLastBatteryStatsCallTime = 0;
-
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
@@ -486,7 +457,6 @@
     float mLastWallpaperY = -1;
     float mLastWallpaperXStep = -1;
     float mLastWallpaperYStep = -1;
-    boolean mSendingPointersToWallpaper = false;
     // This is set when we are waiting for a wallpaper to tell us it is done
     // changing its scroll position.
     WindowState mWaitingOnWallpaper;
@@ -504,10 +474,7 @@
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
 
-    final KeyWaiter mKeyWaiter = new KeyWaiter();
-    final KeyQ mQueue;
     final InputManager mInputManager;
-    final InputDispatcherThread mInputThread;
 
     // Who is holding the screen on.
     Session mHoldingScreenOn;
@@ -523,8 +490,6 @@
 
     private ViewServer mViewServer;
 
-    final Rect mTempRect = new Rect();
-
     final Configuration mTempConfiguration = new Configuration();
     int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
 
@@ -652,28 +617,11 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        int max_events_per_sec = 35;
-        try {
-            max_events_per_sec = Integer.parseInt(SystemProperties
-                    .get("windowsmgr.max_events_per_sec"));
-            if (max_events_per_sec < 1) {
-                max_events_per_sec = 35;
-            }
-        } catch (NumberFormatException e) {
-        }
-        mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-
         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "KEEP_SCREEN_ON_FLAG");
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager = new InputManager(context, this, mPolicy, pmc, mPowerManager);
-        } else {
-            mInputManager = null;
-        }
-        mQueue = new KeyQ();
-        mInputThread = new InputDispatcherThread();
+        mInputManager = new InputManager(context, this, pmc, mPowerManager);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -687,11 +635,7 @@
             }
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.start();
-        } else {
-            mInputThread.start();
-        }
+        mInputManager.start();
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -1817,70 +1761,6 @@
             }
         }
     }
-
-    void sendPointerToWallpaperLocked(WindowState srcWin,
-            MotionEvent pointer, long eventTime) {
-        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;
-                }
-                try {
-                    MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
-                    if (srcWin != null) {
-                        ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
-                                srcWin.mFrame.top-wallpaper.mFrame.top);
-                    } else {
-                        ev.offsetLocation(-wallpaper.mFrame.left, -wallpaper.mFrame.top);
-                    }
-                    switch (pointer.getAction()) {
-                        case MotionEvent.ACTION_DOWN:
-                            mSendingPointersToWallpaper = true;
-                            break;
-                        case MotionEvent.ACTION_UP:
-                            mSendingPointersToWallpaper = false;
-                            break;
-                    }
-                    wallpaper.mClient.dispatchPointer(ev, eventTime, false);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure sending pointer to wallpaper", e);
-                }
-            }
-        }
-    }
-
-    void dispatchPointerElsewhereLocked(WindowState srcWin, WindowState relWin,
-            MotionEvent pointer, long eventTime, boolean skipped) {
-        if (relWin != null) {
-            mPolicy.dispatchedPointerEventLw(pointer, relWin.mFrame.left, relWin.mFrame.top);
-        } else {
-            mPolicy.dispatchedPointerEventLw(pointer, 0, 0);
-        }
-        
-        // If we sent an initial down to the wallpaper, then continue
-        // sending events until the final up.
-        if (mSendingPointersToWallpaper) {
-            if (skipped) {
-                Slog.i(TAG, "Sending skipped pointer to wallpaper!");
-            }
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-            
-        // If we are on top of the wallpaper, then the wallpaper also
-        // gets to see this movement.
-        } else if (srcWin != null
-                && pointer.getAction() == MotionEvent.ACTION_DOWN
-                && mWallpaperTarget == srcWin
-                && srcWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-        }
-    }
     
     public int addWindow(Session session, IWindow client,
             WindowManager.LayoutParams attrs, int viewVisibility,
@@ -1903,12 +1783,7 @@
                 mDisplay = wm.getDefaultDisplay();
                 mInitialDisplayWidth = mDisplay.getWidth();
                 mInitialDisplayHeight = mDisplay.getHeight();
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputManager.setDisplaySize(0,
-                            mInitialDisplayWidth, mInitialDisplayHeight);
-                } else {
-                    mQueue.setDisplay(mDisplay);
-                }
+                mInputManager.setDisplaySize(0, mInitialDisplayWidth, mInitialDisplayHeight);
                 reportNewConfig = true;
             }
 
@@ -2002,15 +1877,13 @@
                 return res;
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (outInputChannel != null) {
-                    String name = win.makeInputChannelName();
-                    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
-                    win.mInputChannel = inputChannels[0];
-                    inputChannels[1].transferToBinderOutParameter(outInputChannel);
-                    
-                    mInputManager.registerInputChannel(win.mInputChannel);
-                }
+            if (outInputChannel != null) {
+                String name = win.makeInputChannelName();
+                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
+                win.mInputChannel = inputChannels[0];
+                inputChannels[1].transferToBinderOutParameter(outInputChannel);
+                
+                mInputManager.registerInputChannel(win.mInputChannel);
             }
 
             // From now on, no exceptions or errors allowed!
@@ -2186,14 +2059,7 @@
     }
 
     private void removeWindowInnerLocked(Session session, WindowState win) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.windowIsBeingRemovedLw(win);
-        } else {
-            mKeyWaiter.finishedKey(session, win.mClient, true,
-                    KeyWaiter.RETURN_NOTHING);
-            mKeyWaiter.releasePendingPointerLocked(win.mSession);
-            mKeyWaiter.releasePendingTrackballLocked(win.mSession);
-        }
+        mInputMonitor.windowIsBeingRemovedLw(win);
 
         win.mRemoved = true;
 
@@ -2561,12 +2427,7 @@
                               applyAnimationLocked(win, transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(session, client, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(win);
                         } else if (win.isAnimating()) {
                             // Currently in a hide animation... turn this into
                             // an exit.
@@ -3027,12 +2888,7 @@
                         if (win.isVisibleNow()) {
                             applyAnimationLocked(win,
                                     WindowManagerPolicy.TRANSIT_EXIT, false);
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBeingRemovedLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBeingRemovedLw(win);
                             changed = true;
                         }
                     }
@@ -3349,12 +3205,8 @@
                 if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
                 changed = mFocusedApp != null;
                 mFocusedApp = null;
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 AppWindowToken newFocus = findAppWindowToken(token);
@@ -3365,12 +3217,8 @@
                 changed = mFocusedApp != newFocus;
                 mFocusedApp = newFocus;
                 if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp);
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(newFocus);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(newFocus);
                 }
             }
 
@@ -3682,12 +3530,7 @@
                         applyAnimationLocked(win,
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
                     }
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(win);
-                    } else {
-                        mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                KeyWaiter.RETURN_NOTHING);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(win);
                     changed = true;
                 }
             }
@@ -3972,11 +3815,7 @@
                     if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
                     mFocusedApp = null;
                     updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    } else {
-                        mKeyWaiter.tickle();
-                    }
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
@@ -4441,11 +4280,7 @@
                 "getSwitchState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(sw);
-        } else {
-            return KeyInputQueue.getSwitchState(sw);
-        }
+        return mInputManager.getSwitchState(sw);
     }
 
     public int getSwitchStateForDevice(int devid, int sw) {
@@ -4453,11 +4288,7 @@
                 "getSwitchStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(devid, sw);
-        } else {
-            return KeyInputQueue.getSwitchState(devid, sw);
-        }
+        return mInputManager.getSwitchState(devid, sw);
     }
 
     public int getScancodeState(int sw) {
@@ -4465,11 +4296,7 @@
                 "getScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(sw);
-        } else {
-            return mQueue.getScancodeState(sw);
-        }
+        return mInputManager.getScancodeState(sw);
     }
 
     public int getScancodeStateForDevice(int devid, int sw) {
@@ -4477,11 +4304,7 @@
                 "getScancodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(devid, sw);
-        } else {
-            return mQueue.getScancodeState(devid, sw);
-        }
+        return mInputManager.getScancodeState(devid, sw);
     }
 
     public int getTrackballScancodeState(int sw) {
@@ -4489,11 +4312,7 @@
                 "getTrackballScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballScancodeState(sw);
-        } else {
-            return mQueue.getTrackballScancodeState(sw);
-        }
+        return mInputManager.getTrackballScancodeState(sw);
     }
 
     public int getDPadScancodeState(int sw) {
@@ -4501,11 +4320,7 @@
                 "getDPadScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadScancodeState(sw);
-        } else {
-            return mQueue.getDPadScancodeState(sw);
-        }
+        return mInputManager.getDPadScancodeState(sw);
     }
 
     public int getKeycodeState(int sw) {
@@ -4513,11 +4328,7 @@
                 "getKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(sw);
-        } else {
-            return mQueue.getKeycodeState(sw);
-        }
+        return mInputManager.getKeycodeState(sw);
     }
 
     public int getKeycodeStateForDevice(int devid, int sw) {
@@ -4525,11 +4336,7 @@
                 "getKeycodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(devid, sw);
-        } else {
-            return mQueue.getKeycodeState(devid, sw);
-        }
+        return mInputManager.getKeycodeState(devid, sw);
     }
 
     public int getTrackballKeycodeState(int sw) {
@@ -4537,11 +4344,7 @@
                 "getTrackballKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballKeycodeState(sw);
-        } else {
-            return mQueue.getTrackballKeycodeState(sw);
-        }
+        return mInputManager.getTrackballKeycodeState(sw);
     }
 
     public int getDPadKeycodeState(int sw) {
@@ -4549,19 +4352,11 @@
                 "getDPadKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadKeycodeState(sw);
-        } else {
-            return mQueue.getDPadKeycodeState(sw);
-        }
+        return mInputManager.getDPadKeycodeState(sw);
     }
 
     public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.hasKeys(keycodes, keyExists);
-        } else {
-            return KeyInputQueue.hasKeys(keycodes, keyExists);
-        }
+        return mInputManager.hasKeys(keycodes, keyExists);
     }
 
     public void enableScreenAfterBoot() {
@@ -4706,11 +4501,7 @@
             mLayoutNeeded = true;
             startFreezingDisplayLocked();
             Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputManager.setDisplayOrientation(0, rotation);
-            } else {
-                mQueue.setOrientation(rotation);
-            }
+            mInputManager.setDisplayOrientation(0, rotation);
             if (mDisplayEnabled) {
                 Surface.setOrientation(0, rotation, animFlags);
             }
@@ -5041,11 +4832,8 @@
         if (mDisplay == null) {
             return false;
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.getInputConfiguration(config);
-        } else {
-            mQueue.getInputConfiguration(config);
-        }
+        
+        mInputManager.getInputConfiguration(config);
 
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == Surface.ROTATION_90
@@ -5326,6 +5114,13 @@
             mTempInputWindows.clear();
         }
         
+        /* Provides feedback for a virtual key down. */
+        public void virtualKeyDownFeedback() {
+            synchronized (mWindowMap) {
+                mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+            }
+        }
+        
         /* Notifies that an app switch key (BACK / HOME) has just been pressed.
          * This essentially starts a .5 second timeout for the application to process
          * subsequent input events while waiting for the app switch to occur.  If it takes longer
@@ -5334,30 +5129,28 @@
         public void notifyAppSwitchComing() {
             // TODO Not implemented yet.  Should go in the native side.
         }
-
+        
+        /* Notifies that the lid switch changed state. */
+        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+            mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+        }
+        
         /* Provides an opportunity for the window manager policy to intercept early key
          * processing as soon as the key has been read from the device. */
-        public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            RawInputEvent event = new RawInputEvent();
-            event.deviceId = deviceId;
-            event.type = type;
-            event.scancode = scanCode;
-            event.keycode = keyCode;
-            event.flags = policyFlags;
-            event.value = value;
-            event.when = whenNanos / 1000000;
-            
-            return mPolicy.interceptKeyTq(event, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
+                    keyCode, down, policyFlags, isScreenOn);
         }
         
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus,
+                int action, int flags, int keyCode, int metaState, int repeatCount,
+                int policyFlags) {
             WindowState windowState = getWindowStateForInputChannel(focus);
-            return mPolicy.interceptKeyTi(windowState, keyCode, metaState, down, repeatCount,
-                    policyFlags);
+            return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
+                    keyCode, metaState, repeatCount, policyFlags);
         }
         
         /* Called when the current input focus changes.
@@ -5496,450 +5289,6 @@
         }
     }
 
-    private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
-        long curTime = SystemClock.uptimeMillis();
-
-        if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
-            if (mLastTouchEventType == eventType &&
-                    (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
-                return;
-            }
-            mLastUserActivityCallTime = curTime;
-            mLastTouchEventType = eventType;
-        }
-
-        if (targetWin == null
-                || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            mPowerManager.userActivity(curTime, false, eventType, false);
-        }
-    }
-
-    // tells if it's a cheek event or not -- this function is stateful
-    private static final int EVENT_NONE = 0;
-    private static final int EVENT_UNKNOWN = 0;
-    private static final int EVENT_CHEEK = 0;
-    private static final int EVENT_IGNORE_DURATION = 300; // ms
-    private static final float CHEEK_THRESHOLD = 0.6f;
-    private int mEventState = EVENT_NONE;
-    private float mEventSize;
-
-    private int eventType(MotionEvent ev) {
-        float size = ev.getSize();
-        switch (ev.getAction()) {
-        case MotionEvent.ACTION_DOWN:
-            mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
-        case MotionEvent.ACTION_UP:
-            if (size > mEventSize) mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
-        case MotionEvent.ACTION_MOVE:
-            final int N = ev.getHistorySize();
-            if (size > mEventSize) mEventSize = size;
-            if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            for (int i=0; i<N; i++) {
-                size = ev.getHistoricalSize(i);
-                if (size > mEventSize) mEventSize = size;
-                if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            }
-            if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
-                return TOUCH_EVENT;
-            } else {
-                return LONG_TOUCH_EVENT;
-            }
-        default:
-            // not good
-            return OTHER_EVENT;
-        }
-    }
-    
-    private boolean mFatTouch; // remove me together with dispatchPointer
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Slog.v(TAG,
-                "dispatchPointer " + ev);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
-        }
-
-        Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, true, false, pid, uid);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
-        }
-
-        int action = ev.getAction();
-
-        if (action == MotionEvent.ACTION_UP) {
-            // let go of our target
-            mKeyWaiter.mMotionTarget = null;
-            mPowerManager.logPointerUpEvent();
-        } else if (action == MotionEvent.ACTION_DOWN) {
-            mPowerManager.logPointerDownEvent();
-        }
-
-        if (targetObj == 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 " + ev.getAction());
-            }
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState target = (WindowState)targetObj;
-
-        final long eventTime = ev.getEventTime();
-        final long eventTimeNano = ev.getEventTimeNano();
-
-        //Slog.i(TAG, "Sending " + ev + " to " + target);
-
-        if (uid != 0 && uid != target.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting pointer event from pid "
-                        + pid + " uid " + uid + " to window " + target
-                        + " owned by uid " + target.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("4 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        if ((target.mAttrs.flags &
-                        WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
-            //target wants to ignore fat touch events
-            boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
-            //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
-                        ev.setAction(MotionEvent.ACTION_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
-                        ev.setAction(MotionEvent.ACTION_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) {
-                //recycle que, ev
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_FAILED;
-            }
-        } //end if target
-
-        // Enable this for testing the "right" value
-        if (false && action == MotionEvent.ACTION_DOWN) {
-            int max_events_per_sec = 35;
-            try {
-                max_events_per_sec = Integer.parseInt(SystemProperties
-                        .get("windowsmgr.max_events_per_sec"));
-                if (max_events_per_sec < 1) {
-                    max_events_per_sec = 35;
-                }
-            } catch (NumberFormatException e) {
-            }
-            mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-        }
-
-        /*
-         * Throttle events to minimize CPU usage when there's a flood of events
-         * e.g. constant contact with the screen
-         */
-        if (action == MotionEvent.ACTION_MOVE) {
-            long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
-            long now = SystemClock.uptimeMillis();
-            if (now < nextEventTime) {
-                try {
-                    Thread.sleep(nextEventTime - now);
-                } catch (InterruptedException e) {
-                }
-                mLastTouchEventTime = nextEventTime;
-            } else {
-                mLastTouchEventTime = now;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("5 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        synchronized(mWindowMap) {
-            if (!target.isVisibleLw()) {
-                // During this motion dispatch, the target window has become
-                // invisible.
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), false);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_SUCCEEDED;
-            }
-
-            if (qev != null && action == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(target,
-                        KeyWaiter.RETURN_PENDING_POINTER, qev);
-                ev = null;
-            } else {
-                if (action == MotionEvent.ACTION_DOWN) {
-                    WindowState out = mKeyWaiter.mOutsideTouchTargets;
-                    if (out != null) {
-                        MotionEvent oev = MotionEvent.obtain(ev);
-                        oev.setAction(MotionEvent.ACTION_OUTSIDE);
-                        do {
-                            final Rect frame = out.mFrame;
-                            oev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                            try {
-                                out.mClient.dispatchPointer(oev, eventTime, false);
-                            } catch (android.os.RemoteException e) {
-                                Slog.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
-                            }
-                            oev.offsetLocation((float)frame.left, (float)frame.top);
-                            out = out.mNextOutsideTouch;
-                        } while (out != null);
-                        mKeyWaiter.mOutsideTouchTargets = null;
-                    }
-                }
-
-                dispatchPointerElsewhereLocked(target, null, ev, ev.getEventTime(), false);
-
-                final Rect frame = target.mFrame;
-                ev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                mKeyWaiter.bindTargetWindowLocked(target);
-            }
-        }
-
-        // finally offset the event to the target's coordinate system and
-        // dispatch the event.
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
-                Slog.v(TAG, "Delivering pointer " + qev + " to " + target);
-            }
-
-            if (MEASURE_LATENCY) {
-                lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-
-            target.mClient.dispatchPointer(ev, eventTime, true);
-
-            if (MEASURE_LATENCY) {
-                lt.sample("7 after  svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during motion dispatch: " + target);
-            mKeyWaiter.mMotionTarget = null;
-            try {
-                removeWindow(target.mSession, target.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(
-                TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping trackball: " + ev);
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        final long eventTime = ev.getEventTime();
-
-        synchronized(mWindowMap) {
-            if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(focus,
-                        KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
-                // We don't deliver movement events to the client, we hold
-                // them and wait for them to call back.
-                ev = null;
-            } else {
-                mKeyWaiter.bindTargetWindowLocked(focus);
-            }
-        }
-
-        try {
-            focus.mClient.dispatchTrackball(ev, eventTime, true);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchKey(KeyEvent event, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
-                null, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping: " + event);
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            return INJECT_SUCCEEDED;
-        }
-
-        // Okay we have finished waiting for the last event to be processed.
-        // First off, if this is a repeat event, check to see if there is
-        // a corresponding up event in the queue.  If there is, we will
-        // just drop the repeat, because it makes no sense to repeat after
-        // the user has released a key.  (This is especially important for
-        // long presses.)
-        if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (DEBUG_INPUT) Slog.v(
-            TAG, "Dispatching to " + focus + ": " + event);
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        synchronized(mWindowMap) {
-            mKeyWaiter.bindTargetWindowLocked(focus);
-        }
-
-        // NOSHIP extra state logging
-        mKeyWaiter.recordDispatchState(event, focus);
-        // END NOSHIP
-
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS) {
-                Slog.v(TAG, "Delivering key " + event.getKeyCode()
-                        + " to " + focus);
-            }
-            focus.mClient.dispatchKey(event);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
     public void pauseKeyDispatching(IBinder _token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "pauseKeyDispatching()")) {
@@ -5949,11 +5298,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.pauseDispatchingLw(token);
-                } else {
-                    mKeyWaiter.pauseDispatchingLocked(token);
-                }
+                mInputMonitor.pauseDispatchingLw(token);
             }
         }
     }
@@ -5967,11 +5312,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.resumeDispatchingLw(token);
-                } else {
-                    mKeyWaiter.resumeDispatchingLocked(token);
-                }
+                mInputMonitor.resumeDispatchingLw(token);
             }
         }
     }
@@ -5983,11 +5324,7 @@
         }
 
         synchronized (mWindowMap) {
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputMonitor.setEventDispatchingLw(enabled);
-            } else {
-                mKeyWaiter.setEventDispatchingLocked(enabled);
-            }
+            mInputMonitor.setEventDispatchingLw(enabled);
         }
     }
 
@@ -6020,16 +5357,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectKeyEvent(newEvent, InputQueue.INPUT_EVENT_NATURE_KEY,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchKey(newEvent, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectKeyEvent(newEvent,
+                InputQueue.INPUT_EVENT_NATURE_KEY, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6049,16 +5378,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TOUCH,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchPointer(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TOUCH, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6078,48 +5399,29 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TRACKBALL,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchTrackball(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TRACKBALL, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         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;
+        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;
         }
     }
 
@@ -6133,867 +5435,6 @@
         return mCurrentFocus;
     }
 
-    /**
-     * This class holds the state for dispatching key events.  This state
-     * is protected by the KeyWaiter instance, NOT by the window lock.  You
-     * can be holding the main window lock while acquire the KeyWaiter lock,
-     * but not the other way around.
-     */
-    final class KeyWaiter {
-        // NOSHIP debugging
-        public class DispatchState {
-            private KeyEvent event;
-            private WindowState focus;
-            private long time;
-            private WindowState lastWin;
-            private IBinder lastBinder;
-            private boolean finished;
-            private boolean gotFirstWindow;
-            private boolean eventDispatching;
-            private long timeToSwitch;
-            private boolean wasFrozen;
-            private boolean focusPaused;
-            private WindowState curFocus;
-
-            DispatchState(KeyEvent theEvent, WindowState theFocus) {
-                focus = theFocus;
-                event = theEvent;
-                time = System.currentTimeMillis();
-                // snapshot KeyWaiter state
-                lastWin = mLastWin;
-                lastBinder = mLastBinder;
-                finished = mFinished;
-                gotFirstWindow = mGotFirstWindow;
-                eventDispatching = mEventDispatching;
-                timeToSwitch = mTimeToSwitch;
-                wasFrozen = mWasFrozen;
-                curFocus = mCurrentFocus;
-                // cache the paused state at ctor time as well
-                if (theFocus == null || theFocus.mToken == null) {
-                    focusPaused = false;
-                } else {
-                    focusPaused = theFocus.mToken.paused;
-                }
-            }
-
-            public String toString() {
-                return "{{" + event + " to " + focus + " @ " + time
-                        + " lw=" + lastWin + " lb=" + lastBinder
-                        + " fin=" + finished + " gfw=" + gotFirstWindow
-                        + " ed=" + eventDispatching + " tts=" + timeToSwitch
-                        + " wf=" + wasFrozen + " fp=" + focusPaused
-                        + " mcf=" + curFocus + "}}";
-            }
-        };
-        private DispatchState mDispatchState = null;
-        public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
-            mDispatchState = new DispatchState(theEvent, theFocus);
-        }
-        // END NOSHIP
-
-        public static final int RETURN_NOTHING = 0;
-        public static final int RETURN_PENDING_POINTER = 1;
-        public static final int RETURN_PENDING_TRACKBALL = 2;
-
-        final Object SKIP_TARGET_TOKEN = new Object();
-        final Object CONSUMED_EVENT_TOKEN = new Object();
-
-        private WindowState mLastWin = null;
-        private IBinder mLastBinder = null;
-        private boolean mFinished = true;
-        private boolean mGotFirstWindow = false;
-        private boolean mEventDispatching = true;
-        private long mTimeToSwitch = 0;
-        /* package */ boolean mWasFrozen = false;
-
-        // Target of Motion events
-        WindowState mMotionTarget;
-
-        // Windows above the target who would like to receive an "outside"
-        // touch event for any down events outside of them.
-        WindowState mOutsideTouchTargets;
-
-        /**
-         * Wait for the last event dispatch to complete, then find the next
-         * target that should receive the given event and wait for that one
-         * to be ready to receive it.
-         */
-        Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                boolean failIfTimeout, int callingPid, int callingUid) {
-            long startTime = SystemClock.uptimeMillis();
-            long keyDispatchingTimeout = 5 * 1000;
-            long waitedFor = 0;
-
-            while (true) {
-                // Figure out which window we care about.  It is either the
-                // last window we are waiting to have process the event or,
-                // if none, then the next window we think the event should go
-                // to.  Note: we retrieve mLastWin outside of the lock, so
-                // it may change before we lock.  Thus we must check it again.
-                WindowState targetWin = mLastWin;
-                boolean targetIsNew = targetWin == null;
-                if (DEBUG_INPUT) Slog.v(
-                        TAG, "waitForLastKey: mFinished=" + mFinished +
-                        ", mLastWin=" + mLastWin);
-                if (targetIsNew) {
-                    Object target = findTargetWindow(nextKey, qev, nextMotion,
-                            isPointerEvent, callingPid, callingUid);
-                    if (target == SKIP_TARGET_TOKEN) {
-                        // The user has pressed a special key, and we are
-                        // dropping all pending events before it.
-                        if (DEBUG_INPUT) Slog.v(TAG, "Skipping: " + nextKey
-                                + " " + nextMotion);
-                        return null;
-                    }
-                    if (target == CONSUMED_EVENT_TOKEN) {
-                        if (DEBUG_INPUT) Slog.v(TAG, "Consumed: " + nextKey
-                                + " " + nextMotion);
-                        return target;
-                    }
-                    targetWin = (WindowState)target;
-                }
-
-                AppWindowToken targetApp = null;
-
-                // Now: is it okay to send the next event to this window?
-                synchronized (this) {
-                    // First: did we come here based on the last window not
-                    // being null, but it changed by the time we got here?
-                    // If so, try again.
-                    if (!targetIsNew && mLastWin == null) {
-                        continue;
-                    }
-
-                    // We never dispatch events if not finished with the
-                    // last one, or the display is frozen.
-                    if (mFinished && !mDisplayFrozen) {
-                        // If event dispatching is disabled, then we
-                        // just consume the events.
-                        if (!mEventDispatching) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; dispatching disabled: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                        if (targetWin != null) {
-                            // If this is a new target, and that target is not
-                            // paused or unresponsive, then all looks good to
-                            // handle the event.
-                            if (targetIsNew && !targetWin.mToken.paused) {
-                                return targetWin;
-                            }
-
-                        // If we didn't find a target window, and there is no
-                        // focused app window, then just eat the events.
-                        } else if (mFocusedApp == null) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; no focused app: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                    }
-
-                    if (DEBUG_INPUT) Slog.v(
-                            TAG, "Waiting for last key in " + mLastBinder
-                            + " target=" + targetWin
-                            + " mFinished=" + mFinished
-                            + " mDisplayFrozen=" + mDisplayFrozen
-                            + " targetIsNew=" + targetIsNew
-                            + " paused="
-                            + (targetWin != null ? targetWin.mToken.paused : false)
-                            + " mFocusedApp=" + mFocusedApp
-                            + " mCurrentFocus=" + mCurrentFocus);
-
-                    targetApp = targetWin != null
-                            ? targetWin.mAppToken : mFocusedApp;
-
-                    long curTimeout = keyDispatchingTimeout;
-                    if (mTimeToSwitch != 0) {
-                        long now = SystemClock.uptimeMillis();
-                        if (mTimeToSwitch <= now) {
-                            // If an app switch key has been pressed, and we have
-                            // waited too long for the current app to finish
-                            // processing keys, then wait no more!
-                            doFinishedKeyLocked(false);
-                            continue;
-                        }
-                        long switchTimeout = mTimeToSwitch - now;
-                        if (curTimeout > switchTimeout) {
-                            curTimeout = switchTimeout;
-                        }
-                    }
-
-                    try {
-                        // after that continue
-                        // processing keys, so we don't get stuck.
-                        if (DEBUG_INPUT) Slog.v(
-                                TAG, "Waiting for key dispatch: " + curTimeout);
-                        wait(curTimeout);
-                        if (DEBUG_INPUT) Slog.v(TAG, "Finished waiting @"
-                                + SystemClock.uptimeMillis() + " startTime="
-                                + startTime + " switchTime=" + mTimeToSwitch
-                                + " target=" + targetWin + " mLW=" + mLastWin
-                                + " mLB=" + mLastBinder + " fin=" + mFinished
-                                + " mCurrentFocus=" + mCurrentFocus);
-                    } catch (InterruptedException e) {
-                    }
-                }
-
-                // If we were frozen during configuration change, restart the
-                // timeout checks from now; otherwise look at whether we timed
-                // out before awakening.
-                if (mWasFrozen) {
-                    waitedFor = 0;
-                    mWasFrozen = false;
-                } else {
-                    waitedFor = SystemClock.uptimeMillis() - startTime;
-                }
-
-                if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
-                    IApplicationToken at = null;
-                    synchronized (this) {
-                        Slog.w(TAG, "Key dispatching timed out sending to " +
-                              (targetWin != null ? targetWin.mAttrs.getTitle()
-                              : "<null>: no window ready for key dispatch"));
-                        // NOSHIP debugging
-                        Slog.w(TAG, "Previous dispatch state: " + mDispatchState);
-                        Slog.w(TAG, "Current dispatch state: " +
-                                new DispatchState(nextKey, targetWin));
-                        // END NOSHIP
-                        //dump();
-                        if (targetWin != null) {
-                            at = targetWin.getAppToken();
-                        } else if (targetApp != null) {
-                            at = targetApp.appToken;
-                        }
-                    }
-
-                    boolean abort = true;
-                    if (at != null) {
-                        try {
-                            long timeout = at.getKeyDispatchingTimeout();
-                            if (timeout > waitedFor) {
-                                // we did not wait the proper amount of time for this application.
-                                // set the timeout to be the real timeout and wait again.
-                                keyDispatchingTimeout = timeout - waitedFor;
-                                continue;
-                            } else {
-                                abort = at.keyDispatchingTimedOut();
-                            }
-                        } catch (RemoteException ex) {
-                        }
-                    }
-
-                    synchronized (this) {
-                        if (abort && (mLastWin == targetWin || targetWin == null)) {
-                            mFinished = true;
-                            if (mLastWin != null) {
-                                if (DEBUG_INPUT) Slog.v(TAG,
-                                        "Window " + mLastWin +
-                                        " timed out on key input");
-                                if (mLastWin.mToken.paused) {
-                                    Slog.w(TAG, "Un-pausing dispatching to this window");
-                                    mLastWin.mToken.paused = false;
-                                }
-                            }
-                            if (mMotionTarget == targetWin) {
-                                mMotionTarget = null;
-                            }
-                            mLastWin = null;
-                            mLastBinder = null;
-                            if (failIfTimeout || targetWin == null) {
-                                return null;
-                            }
-                        } else {
-                            Slog.w(TAG, "Continuing to wait for key to be dispatched");
-                            startTime = SystemClock.uptimeMillis();
-                        }
-                    }
-                }
-            }
-        }
-
-        Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                int callingPid, int callingUid) {
-            mOutsideTouchTargets = null;
-
-            if (nextKey != null) {
-                // Find the target window for a normal key event.
-                final int keycode = nextKey.getKeyCode();
-                final int repeatCount = nextKey.getRepeatCount();
-                final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
-
-                if (!dispatch) {
-                    if (callingUid == 0 ||
-                            mContext.checkPermission(
-                                    android.Manifest.permission.INJECT_EVENTS,
-                                    callingPid, callingUid)
-                                    == PackageManager.PERMISSION_GRANTED) {
-                        mPolicy.interceptKeyTi(null, keycode,
-                                nextKey.getMetaState(), down, repeatCount,
-                                nextKey.getFlags());
-                    }
-                    Slog.w(TAG, "Event timeout during app switch: dropping "
-                            + nextKey);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-
-                if (callingUid == 0 ||
-                        (focus != null && callingUid == focus.mSession.mUid) ||
-                        mContext.checkPermission(
-                                android.Manifest.permission.INJECT_EVENTS,
-                                callingPid, callingUid)
-                                == PackageManager.PERMISSION_GRANTED) {
-                    if (mPolicy.interceptKeyTi(focus,
-                            keycode, nextKey.getMetaState(), down, repeatCount,
-                            nextKey.getFlags())) {
-                        return CONSUMED_EVENT_TOKEN;
-                    }
-                }
-
-                return focus;
-
-            } else if (!isPointerEvent) {
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
-                if (!dispatch) {
-                    Slog.w(TAG, "Event timeout during app switch: dropping trackball "
-                            + nextMotion);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-                return focus;
-            }
-
-            if (nextMotion == null) {
-                return SKIP_TARGET_TOKEN;
-            }
-
-            boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
-                    KeyEvent.KEYCODE_UNKNOWN);
-            if (!dispatch) {
-                Slog.w(TAG, "Event timeout during app switch: dropping pointer "
-                        + nextMotion);
-                return SKIP_TARGET_TOKEN;
-            }
-
-            // Find the target window for a pointer event.
-            int action = nextMotion.getAction();
-            final float xf = nextMotion.getX();
-            final float yf = nextMotion.getY();
-            final long eventTime = nextMotion.getEventTime();
-
-            final boolean screenWasOff = qev != null
-                    && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
-
-            WindowState target = null;
-
-            synchronized(mWindowMap) {
-                synchronized (this) {
-                    if (action == MotionEvent.ACTION_DOWN) {
-                        if (mMotionTarget != 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: "
-                                    + mMotionTarget);
-                            mMotionTarget = null;
-                        }
-
-                        // ACTION_DOWN is special, because we need to lock next events to
-                        // the window we'll land onto.
-                        final int x = (int)xf;
-                        final int y = (int)yf;
-
-                        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;
-                            }
-                            tmpRect.set(child.mFrame);
-                            if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the content part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenContentInsets.left;
-                                tmpRect.top += child.mGivenContentInsets.top;
-                                tmpRect.right -= child.mGivenContentInsets.right;
-                                tmpRect.bottom -= child.mGivenContentInsets.bottom;
-                            } else if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the visible part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenVisibleInsets.left;
-                                tmpRect.top += child.mGivenVisibleInsets.top;
-                                tmpRect.right -= child.mGivenVisibleInsets.right;
-                                tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
-                            }
-                            final int touchFlags = flags &
-                                (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-                            if (tmpRect.contains(x, y) || touchFlags == 0) {
-                                //Slog.i(TAG, "Using this target!");
-                                if (!screenWasOff || (flags &
-                                        WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
-                                    mMotionTarget = child;
-                                } else {
-                                    //Slog.i(TAG, "Waking, skip!");
-                                    mMotionTarget = null;
-                                }
-                                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 && mMotionTarget != topErrWindow) {
-                            mMotionTarget = null;
-                        }
-                    }
-
-                    target = mMotionTarget;
-                }
-            }
-
-            wakeupIfNeeded(target, eventType(nextMotion));
-
-            // Pointer events are a little different -- if there isn't a
-            // target found for any event, then just drop it.
-            return target != null ? target : SKIP_TARGET_TOKEN;
-        }
-
-        boolean checkShouldDispatchKey(int keycode) {
-            synchronized (this) {
-                if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
-                    mTimeToSwitch = 0;
-                    return true;
-                }
-                if (mTimeToSwitch != 0
-                        && mTimeToSwitch < SystemClock.uptimeMillis()) {
-                    return false;
-                }
-                return true;
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
-            }
-        }
-
-        void bindTargetWindowLockedLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            mLastWin = win;
-            mLastBinder = win.mClient.asBinder();
-            mFinished = false;
-            if (pendingMotion != null) {
-                final Session s = win.mSession;
-                if (pendingWhat == RETURN_PENDING_POINTER) {
-                    releasePendingPointerLocked(s);
-                    s.mPendingPointerMove = pendingMotion;
-                    s.mPendingPointerWindow = win;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "bindTargetToWindow " + s.mPendingPointerMove);
-                } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
-                    releasePendingTrackballLocked(s);
-                    s.mPendingTrackballMove = pendingMotion;
-                    s.mPendingTrackballWindow = win;
-                }
-            }
-        }
-
-        void releasePendingPointerLocked(Session s) {
-            if (DEBUG_INPUT) Slog.v(TAG,
-                    "releasePendingPointer " + s.mPendingPointerMove);
-            if (s.mPendingPointerMove != null) {
-                mQueue.recycleEvent(s.mPendingPointerMove);
-                s.mPendingPointerMove = null;
-            }
-        }
-
-        void releasePendingTrackballLocked(Session s) {
-            if (s.mPendingTrackballMove != null) {
-                mQueue.recycleEvent(s.mPendingTrackballMove);
-                s.mPendingTrackballMove = null;
-            }
-        }
-
-        MotionEvent finishedKey(Session session, IWindow client, boolean force,
-                int returnWhat) {
-            if (DEBUG_INPUT) Slog.v(
-                TAG, "finishedKey: client=" + client + ", force=" + force);
-
-            if (client == null) {
-                return null;
-            }
-
-            MotionEvent res = null;
-            QueuedEvent qev = null;
-            WindowState win = null;
-
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "finishedKey: client=" + client.asBinder()
-                    + ", force=" + force + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
-
-                if (returnWhat == RETURN_PENDING_POINTER) {
-                    qev = session.mPendingPointerMove;
-                    win = session.mPendingPointerWindow;
-                    session.mPendingPointerMove = null;
-                    session.mPendingPointerWindow = null;
-                } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
-                    qev = session.mPendingTrackballMove;
-                    win = session.mPendingTrackballWindow;
-                    session.mPendingTrackballMove = null;
-                    session.mPendingTrackballWindow = null;
-                }
-
-                if (mLastBinder == client.asBinder()) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "finishedKey: last paused="
-                        + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
-                    if (mLastWin != null && (!mLastWin.mToken.paused || force
-                            || !mEventDispatching)) {
-                        doFinishedKeyLocked(true);
-                    } else {
-                        // Make sure to wake up anyone currently waiting to
-                        // dispatch a key, so they can re-evaluate their
-                        // current situation.
-                        mFinished = true;
-                        notifyAll();
-                    }
-                }
-
-                if (qev != null) {
-                    res = (MotionEvent)qev.event;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "Returning pending motion: " + res);
-                    mQueue.recycleEvent(qev);
-                    if (win != null && returnWhat == RETURN_PENDING_POINTER) {
-                        res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
-                    }
-                }
-            }
-
-            if (res != null && returnWhat == RETURN_PENDING_POINTER) {
-                synchronized (mWindowMap) {
-                    dispatchPointerElsewhereLocked(win, win, res, res.getEventTime(), false);
-                }
-            }
-
-            return res;
-        }
-
-        void tickle() {
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-        void handleNewWindowLocked(WindowState newWindow) {
-            if (!newWindow.canReceiveKeys()) {
-                return;
-            }
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "New key dispatch window: win="
-                    + newWindow.mClient.asBinder()
-                    + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                    + "), finished=" + mFinished + ", paused="
-                    + newWindow.mToken.paused);
-
-                // Displaying a window implicitly causes dispatching to
-                // be unpaused.  (This is to protect against bugs if someone
-                // pauses dispatching but forgets to resume.)
-                newWindow.mToken.paused = false;
-
-                mGotFirstWindow = true;
-
-                if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "New SYSTEM_ERROR window; resetting state");
-                    mLastWin = null;
-                    mLastBinder = null;
-                    mMotionTarget = null;
-                    mFinished = true;
-                } else if (mLastWin != null) {
-                    // If the new window is above the window we are
-                    // waiting on, then stop waiting and let key dispatching
-                    // start on the new guy.
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Last win layer=" + mLastWin.mLayer
-                        + ", new win layer=" + newWindow.mLayer);
-                    if (newWindow.mLayer >= mLastWin.mLayer) {
-                        // The new window is above the old; finish pending input to the last
-                        // window and start directing it to the new one.
-                        mLastWin.mToken.paused = false;
-                        doFinishedKeyLocked(false);  // does a notifyAll()
-                        return;
-                    }
-                }
-
-                // Now that we've put a new window state in place, make the event waiter
-                // take notice and retarget its attentions.
-                notifyAll();
-            }
-        }
-
-        void pauseDispatchingLocked(WindowToken token) {
-            synchronized (this)
-            {
-                if (DEBUG_INPUT) Slog.v(TAG, "Pausing WindowToken " + token);
-                token.paused = true;
-
-                /*
-                if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
-                    mPaused = true;
-                } else {
-                    if (mLastWin == null) {
-                        Slog.i(TAG, "Key dispatching not paused: no last window.");
-                    } else if (mFinished) {
-                        Slog.i(TAG, "Key dispatching not paused: finished last key.");
-                    } else {
-                        Slog.i(TAG, "Key dispatching not paused: window in higher layer.");
-                    }
-                }
-                */
-            }
-        }
-
-        void resumeDispatchingLocked(WindowToken token) {
-            synchronized (this) {
-                if (token.paused) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Resuming WindowToken " + token
-                        + ", last=" + mLastBinder
-                        + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                        + "), finished=" + mFinished + ", paused="
-                        + token.paused);
-                    token.paused = false;
-                    if (mLastWin != null && mLastWin.mToken == token && mFinished) {
-                        doFinishedKeyLocked(false);
-                    } else {
-                        notifyAll();
-                    }
-                }
-            }
-        }
-
-        void setEventDispatchingLocked(boolean enabled) {
-            synchronized (this) {
-                mEventDispatching = enabled;
-                notifyAll();
-            }
-        }
-
-        void appSwitchComing() {
-            synchronized (this) {
-                // Don't wait for more than .5 seconds for app to finish
-                // processing the pending events.
-                long now = SystemClock.uptimeMillis() + 500;
-                if (DEBUG_INPUT) Slog.v(TAG, "appSwitchComing: " + now);
-                if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
-                    mTimeToSwitch = now;
-                }
-                notifyAll();
-            }
-        }
-
-        private final void doFinishedKeyLocked(boolean force) {
-            if (mLastWin != null) {
-                releasePendingPointerLocked(mLastWin.mSession);
-                releasePendingTrackballLocked(mLastWin.mSession);
-            }
-
-            if (force || mLastWin == null || !mLastWin.mToken.paused
-                    || !mLastWin.isVisibleLw()) {
-                // If the current window has been paused, we aren't -really-
-                // finished...  so let the waiters still wait.
-                mLastWin = null;
-                mLastBinder = null;
-            }
-            mFinished = true;
-            notifyAll();
-        }
-    }
-
-    private class KeyQ extends KeyInputQueue
-            implements KeyInputQueue.FilterCallback {
-        KeyQ() {
-            super(mContext, WindowManagerService.this);
-        }
-
-        @Override
-        boolean preprocessEvent(InputDevice device, RawInputEvent event) {
-            if (mPolicy.preprocessInputEventTq(event)) {
-                return true;
-            }
-
-            switch (event.type) {
-                case RawInputEvent.EV_KEY: {
-                    // XXX begin hack
-                    if (DEBUG) {
-                        if (event.keycode == KeyEvent.KEYCODE_G) {
-                            if (event.value != 0) {
-                                // G down
-                                mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-                            }
-                            return false;
-                        }
-                        if (event.keycode == KeyEvent.KEYCODE_D) {
-                            if (event.value != 0) {
-                                //dump();
-                            }
-                            return false;
-                        }
-                    }
-                    // XXX end hack
-
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
-
-                    if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
-                        mPowerManager.goToSleep(event.when);
-                    }
-
-                    if (screenIsOff) {
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
-                        mPowerManager.userActivity(event.when, false,
-                                LocalPowerManager.BUTTON_EVENT, false);
-                    }
-
-                    if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
-                        if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
-                            filterQueue(this);
-                            mKeyWaiter.appSwitchComing();
-                        }
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-
-                case RawInputEvent.EV_REL: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeRelMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                case RawInputEvent.EV_ABS: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                default:
-                    return true;
-            }
-        }
-
-        public int filterEvent(QueuedEvent ev) {
-            switch (ev.classType) {
-                case RawInputEvent.CLASS_KEYBOARD:
-                    KeyEvent ke = (KeyEvent)ev.event;
-                    if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
-                        Slog.w(TAG, "Dropping movement key during app switch: "
-                                + ke.getKeyCode() + ", action=" + ke.getAction());
-                        return FILTER_REMOVE;
-                    }
-                    return FILTER_ABORT;
-                default:
-                    return FILTER_KEEP;
-            }
-        }
-    }
-
     public boolean detectSafeMode() {
         mSafeMode = mPolicy.detectSafeMode();
         return mSafeMode;
@@ -7003,219 +5444,6 @@
         mPolicy.systemReady();
     }
 
-    private final class InputDispatcherThread extends Thread {
-        // Time to wait when there is nothing to do: 9999 seconds.
-        static final int LONG_WAIT=9999*1000;
-
-        public InputDispatcherThread() {
-            super("InputDispatcher");
-        }
-
-        @Override
-        public void run() {
-            while (true) {
-                try {
-                    process();
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception in input dispatcher", e);
-                }
-            }
-        }
-
-        private void process() {
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
-            // The last key event we saw
-            KeyEvent lastKey = null;
-
-            // Last keydown time for auto-repeating keys
-            long lastKeyTime = SystemClock.uptimeMillis();
-            long nextKeyTime = lastKeyTime+LONG_WAIT;
-            long downTime = 0;
-
-            // How many successive repeats we generated
-            int keyRepeatCount = 0;
-
-            // Need to report that configuration has changed?
-            boolean configChanged = false;
-
-            while (true) {
-                long curTime = SystemClock.uptimeMillis();
-
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "Waiting for next key: now=" + curTime
-                    + ", repeat @ " + nextKeyTime);
-
-                // Retrieve next event, waiting only as long as the next
-                // repeat timeout.  If the configuration has changed, then
-                // don't wait at all -- we'll report the change as soon as
-                // we have processed all events.
-                QueuedEvent ev = mQueue.getEvent(
-                    (int)((!configChanged && curTime < nextKeyTime)
-                            ? (nextKeyTime-curTime) : 0));
-
-                if (DEBUG_INPUT && ev != null) Slog.v(
-                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);
-
-                if (MEASURE_LATENCY) {
-                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);
-                }
-
-                if (lastKey != null && !mPolicy.allowKeyRepeat()) {
-                    // cancel key repeat at the request of the policy.
-                    lastKey = null;
-                    downTime = 0;
-                    lastKeyTime = curTime;
-                    nextKeyTime = curTime + LONG_WAIT;
-                }
-                try {
-                    if (ev != null) {
-                        curTime = SystemClock.uptimeMillis();
-                        int eventType;
-                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
-                            eventType = eventType((MotionEvent)ev.event);
-                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
-                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {
-                            eventType = LocalPowerManager.BUTTON_EVENT;
-                        } else {
-                            eventType = LocalPowerManager.OTHER_EVENT;
-                        }
-                        try {
-                            if ((curTime - mLastBatteryStatsCallTime)
-                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                                mLastBatteryStatsCallTime = curTime;
-                                mBatteryStats.noteInputEvent();
-                            }
-                        } catch (RemoteException e) {
-                            // Ignore
-                        }
-
-                        if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
-                            // do not wake screen in this case
-                        } else if (eventType != TOUCH_EVENT
-                                && eventType != LONG_TOUCH_EVENT
-                                && eventType != CHEEK_EVENT) {
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        } else if (mLastTouchEventType != eventType
-                                || (curTime - mLastUserActivityCallTime)
-                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                            mLastUserActivityCallTime = curTime;
-                            mLastTouchEventType = eventType;
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        }
-
-                        switch (ev.classType) {
-                            case RawInputEvent.CLASS_KEYBOARD:
-                                KeyEvent ke = (KeyEvent)ev.event;
-                                if (ke.isDown()) {
-                                    lastKeyTime = curTime;
-                                    if (lastKey != null &&
-                                            ke.getKeyCode() == lastKey.getKeyCode()) {
-                                        keyRepeatCount++;
-                                        // Arbitrary long timeout to block
-                                        // repeating here since we know that
-                                        // the device driver takes care of it.
-                                        nextKeyTime = lastKeyTime + LONG_WAIT;
-                                        if (DEBUG_INPUT) Slog.v(
-                                                TAG, "Received repeated key down");
-                                    } else {
-                                        downTime = curTime;
-                                        keyRepeatCount = 0;
-                                        nextKeyTime = lastKeyTime
-                                                + ViewConfiguration.getLongPressTimeout();
-                                        if (DEBUG_INPUT) Slog.v(
-                                            TAG, "Received key down: first repeat @ "
-                                            + nextKeyTime);
-                                    }
-                                    lastKey = ke;
-                                } else {
-                                    lastKey = null;
-                                    downTime = 0;
-                                    keyRepeatCount = 0;
-                                    // Arbitrary long timeout.
-                                    lastKeyTime = curTime;
-                                    nextKeyTime = curTime + LONG_WAIT;
-                                    if (DEBUG_INPUT) Slog.v(
-                                        TAG, "Received key up: ignore repeat @ "
-                                        + nextKeyTime);
-                                }
-                                if (keyRepeatCount > 0) {
-                                    dispatchKey(KeyEvent.changeTimeRepeat(ke,
-                                            ke.getEventTime(), keyRepeatCount), 0, 0);
-                                } else {
-                                    dispatchKey(ke, 0, 0);
-                                }
-                                mQueue.recycleEvent(ev);
-                                break;
-                            case RawInputEvent.CLASS_TOUCHSCREEN:
-                                //Slog.i(TAG, "Read next event " + ev);
-                                dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_TRACKBALL:
-                                dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
-                                configChanged = true;
-                                break;
-                            default:
-                                mQueue.recycleEvent(ev);
-                            break;
-                        }
-
-                    } else if (configChanged) {
-                        configChanged = false;
-                        sendNewConfiguration();
-
-                    } else if (lastKey != null) {
-                        curTime = SystemClock.uptimeMillis();
-
-                        // Timeout occurred while key was down.  If it is at or
-                        // past the key repeat time, dispatch the repeat.
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key timeout: repeat=" + nextKeyTime
-                            + ", now=" + curTime);
-                        if (curTime < nextKeyTime) {
-                            continue;
-                        }
-
-                        lastKeyTime = nextKeyTime;
-                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
-                        keyRepeatCount++;
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key repeat: count=" + keyRepeatCount
-                            + ", next @ " + nextKeyTime);
-                        KeyEvent newEvent;
-                        if (downTime != 0 && (downTime
-                                + ViewConfiguration.getLongPressTimeout())
-                                <= curTime) {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount,
-                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
-                            downTime = 0;
-                        } else {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount);
-                        }
-                        dispatchKey(newEvent, 0, 0);
-
-                    } else {
-                        curTime = SystemClock.uptimeMillis();
-
-                        lastKeyTime = curTime;
-                        nextKeyTime = curTime + LONG_WAIT;
-                    }
-
-                } catch (Exception e) {
-                    Slog.e(TAG,
-                        "Input thread received uncaught exception: " + e, e);
-                }
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Client Session State
     // -------------------------------------------------------------
@@ -7231,20 +5459,6 @@
         int mNumWindow = 0;
         boolean mClientDead = false;
 
-        /**
-         * Current pointer move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingPointerMove;
-        WindowState mPendingPointerWindow;
-
-        /**
-         * Current trackball move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingTrackballMove;
-        WindowState mPendingTrackballWindow;
-
         public Session(IInputMethodClient client, IInputContext inputContext) {
             mClient = client;
             mInputContext = inputContext;
@@ -7363,36 +5577,6 @@
             finishDrawingWindow(this, window);
         }
 
-        public void finishKey(IWindow window) {
-            if (localLOGV) Slog.v(
-                TAG, "IWindow finishKey called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_NOTHING);
-        }
-
-        public MotionEvent getPendingPointerMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_POINTER);
-        }
-
-        public MotionEvent getPendingTrackballMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_TRACKBALL);
-        }
-
         public void setInTouchMode(boolean mode) {
             synchronized(mWindowMap) {
                 mInTouchMode = mode;
@@ -7496,16 +5680,6 @@
             pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
                     pw.print(" mClientDead="); pw.print(mClientDead);
                     pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
-            if (mPendingPointerWindow != null || mPendingPointerMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
-                        pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
-            }
-            if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
-                        pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
-            }
         }
 
         @Override
@@ -7556,8 +5730,6 @@
         boolean mObscured;
         boolean mTurnOnScreen;
 
-        WindowState mNextOutsideTouch;
-
         int mLayoutSeq = -1;
         
         Configuration mConfiguration = null;
@@ -8074,16 +6246,6 @@
         }
 
         void destroySurfaceLocked() {
-            // Window is no longer on-screen, so can no longer receive
-            // key events...  if we were waiting for it to finish
-            // handling a key event, the wait is over!
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                mKeyWaiter.finishedKey(mSession, mClient, true,
-                        KeyWaiter.RETURN_NOTHING);
-                mKeyWaiter.releasePendingPointerLocked(mSession);
-                mKeyWaiter.releasePendingTrackballLocked(mSession);
-            }
-
             if (mAppToken != null && this == mAppToken.startingWindow) {
                 mAppToken.startingDisplayed = false;
             }
@@ -8099,9 +6261,7 @@
                     WindowState c = (WindowState)mChildWindows.get(i);
                     c.mAttachedHidden = true;
                     
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(c);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(c);
                 }
 
                 if (mReportDestroySurface) {
@@ -8410,12 +6570,8 @@
                 }
                 mLastHidden = true;
                 
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    for (int i=0; i<N; i++) {
-                        mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
-                    }
-                } else {
-                    mKeyWaiter.releasePendingPointerLocked(mSession);
+                for (int i=0; i<N; i++) {
+                    mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
                 }
             }
             mExiting = false;
@@ -8752,13 +6908,11 @@
                 // we are doing this as part of processing a death note.)
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (mInputChannel != null) {
-                    mInputManager.unregisterInputChannel(mInputChannel);
-                    
-                    mInputChannel.dispose();
-                    mInputChannel = null;
-                }
+            if (mInputChannel != null) {
+                mInputManager.unregisterInputChannel(mInputChannel);
+                
+                mInputChannel.dispose();
+                mInputChannel = null;
             }
         }
 
@@ -10174,9 +8328,7 @@
         }
         
         // Window frames may have changed.  Tell the input dispatcher about it.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.updateInputWindowsLw();
-        }
+        mInputMonitor.updateInputWindowsLw();
 
         return mPolicy.finishLayoutLw();
     }
@@ -10977,11 +9129,7 @@
                                     Slog.w(TAG, "Exception hiding surface in " + w);
                                 }
                             }
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(w);
-                            } else {
-                                mKeyWaiter.releasePendingPointerLocked(w.mSession);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(w);
                         }
                         // If we are waiting for this window to handle an
                         // orientation change, well, it is hidden, so
@@ -11583,13 +9731,7 @@
     }
     
     private void finishUpdateFocusedWindowAfterAssignLayersLocked() {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.setInputFocusLw(mCurrentFocus);
-        } else {
-            if (mCurrentFocus != null) {
-                mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
-            }
-        }
+        mInputMonitor.setInputFocusLw(mCurrentFocus);
     }
 
     private WindowState computeFocusedWindowLocked() {
@@ -11663,17 +9805,6 @@
 
     private void startFreezingDisplayLocked() {
         if (mDisplayFrozen) {
-            // Freezing the display also suspends key event delivery, to
-            // keep events from going astray while the display is reconfigured.
-            // If someone has changed orientation again while the screen is
-            // still frozen, the events will continue to be blocked while the
-            // successive orientation change is processed.  To prevent spurious
-            // ANRs, we reset the event dispatch timeout in this case.
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                synchronized (mKeyWaiter) {
-                    mKeyWaiter.mWasFrozen = true;
-                }
-            }
             return;
         }
 
@@ -11696,9 +9827,7 @@
         
         mDisplayFrozen = true;
         
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.freezeInputDispatchingLw();
-        }
+        mInputMonitor.freezeInputDispatchingLw();
         
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11731,16 +9860,7 @@
         }
         Surface.unfreezeDisplay(0);
 
-        // Reset the key delivery timeout on unfreeze, too.  We force a wakeup here
-        // too because regular key delivery processing should resume immediately.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.thawInputDispatchingLw();
-        } else {
-            synchronized (mKeyWaiter) {
-                mKeyWaiter.mWasFrozen = true;
-                mKeyWaiter.notifyAll();
-            }
-        }
+        mInputMonitor.thawInputDispatchingLw();
 
         // While the display is frozen we don't re-compute the orientation
         // to avoid inconsistent states.  However, something interesting
@@ -11772,13 +9892,8 @@
             return;
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            pw.println("Input Dispatcher State:");
-            mInputManager.dump(pw);
-        } else {
-            pw.println("Input State:");
-            mQueue.dump(pw, "  ");
-        }
+        pw.println("Input Dispatcher State:");
+        mInputManager.dump(pw);
         pw.println(" ");
         
         synchronized(mWindowMap) {
@@ -11995,16 +10110,6 @@
             }
             pw.print("  DisplayWidth="); pw.print(mDisplay.getWidth());
                     pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
-
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                pw.println("  KeyWaiter state:");
-                pw.print("    mLastWin="); pw.print(mKeyWaiter.mLastWin);
-                        pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
-                pw.print("    mFinished="); pw.print(mKeyWaiter.mFinished);
-                        pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
-                        pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
-                        pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
-            }
         }
     }
 
@@ -12012,12 +10117,6 @@
     public void monitor() {
         synchronized (mWindowMap) { }
         synchronized (mKeyguardTokenWatcher) { }
-        synchronized (mKeyWaiter) { }
-        synchronized (mInputMonitor) { }
-    }
-
-    public void virtualKeyFeedback(KeyEvent event) {
-        mPolicy.keyFeedbackFromInput(event);
     }
 
     /**
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 499ca86..0cf36b3 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,9 +4,9 @@
 LOCAL_SRC_FILES:= \
     com_android_server_AlarmManagerService.cpp \
     com_android_server_BatteryService.cpp \
-    com_android_server_KeyInputQueue.cpp \
     com_android_server_InputManager.cpp \
     com_android_server_LightsService.cpp \
+    com_android_server_PowerManagerService.cpp \
     com_android_server_SensorService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_VibratorService.cpp \
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index d0f856b..fc901f4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -40,6 +40,7 @@
 #include "../../core/jni/android_view_KeyEvent.h"
 #include "../../core/jni/android_view_MotionEvent.h"
 #include "../../core/jni/android_view_InputChannel.h"
+#include "com_android_server_PowerManagerService.h"
 
 namespace android {
 
@@ -107,16 +108,6 @@
     LAST_SYSTEM_WINDOW      = 2999,
 };
 
-enum {
-    POWER_MANAGER_OTHER_EVENT = 0,
-    POWER_MANAGER_CHEEK_EVENT = 1,
-    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
-                                   // up events or LONG_TOUCH events.
-    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
-    POWER_MANAGER_TOUCH_UP_EVENT = 4,
-    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
-};
-
 // Delay between reporting long touch events to the power manager.
 const nsecs_t EVENT_IGNORE_DURATION = 300 * 1000000LL; // 300 ms
 
@@ -133,20 +124,16 @@
 static struct {
     jclass clazz;
 
-    jmethodID isScreenOn;
-    jmethodID isScreenBright;
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
     jmethodID notifyInputChannelANR;
     jmethodID notifyInputChannelRecoveredFromANR;
     jmethodID notifyANR;
-    jmethodID virtualKeyFeedback;
+    jmethodID virtualKeyDownFeedback;
     jmethodID interceptKeyBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID checkInjectEventsPermission;
-    jmethodID goToSleep;
-    jmethodID pokeUserActivity;
     jmethodID notifyAppSwitchComing;
     jmethodID filterTouchEvents;
     jmethodID filterJumpyTouchEvents;
@@ -228,9 +215,7 @@
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime);
+    virtual void virtualKeyDownFeedback();
     virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
             bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
     virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
@@ -321,7 +306,7 @@
     int32_t mDisplayWidth, mDisplayHeight;
     int32_t mDisplayOrientation;
 
-    // Callbacks.
+    // Power manager interactions.
     bool isScreenOn();
     bool isScreenBright();
 
@@ -369,9 +354,9 @@
 
     void releaseTouchedWindowLd();
 
-    int32_t identifyTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
-    int32_t identifyTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
 
     bool interceptKeyBeforeDispatching(const InputTarget& target,
@@ -391,6 +376,7 @@
     }
 
     static bool isAppSwitchKey(int32_t keyCode);
+    static bool isPolicyKey(int32_t keyCode, bool isScreenOn);
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 };
 
@@ -422,6 +408,36 @@
     return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
 }
 
+bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
+    // Special keys that the WindowManagerPolicy might care about.
+    switch (keyCode) {
+    case KEYCODE_VOLUME_UP:
+    case KEYCODE_VOLUME_DOWN:
+    case KEYCODE_ENDCALL:
+    case KEYCODE_POWER:
+    case KEYCODE_CALL:
+    case KEYCODE_HOME:
+    case KEYCODE_MENU:
+    case KEYCODE_SEARCH:
+        // media keys
+    case KEYCODE_HEADSETHOOK:
+    case KEYCODE_MEDIA_PLAY_PAUSE:
+    case KEYCODE_MEDIA_STOP:
+    case KEYCODE_MEDIA_NEXT:
+    case KEYCODE_MEDIA_PREVIOUS:
+    case KEYCODE_MEDIA_REWIND:
+    case KEYCODE_MEDIA_FAST_FORWARD:
+        return true;
+    default:
+        // We need to pass all keys to the policy in the following cases:
+        // - screen is off
+        // - keyguard is visible
+        // - policy is performing key chording
+        //return ! isScreenOn || keyguardVisible || chording;
+        return true; // XXX stubbed out for now
+    }
+}
+
 bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     if (env->ExceptionCheck()) {
         LOGE("An exception was thrown by callback '%s'.", methodName);
@@ -546,39 +562,22 @@
 }
 
 bool NativeInputManager::isScreenOn() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "isScreenOn")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenOn();
 }
 
 bool NativeInputManager::isScreenBright() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenBright);
-    if (checkAndClearExceptionFromCallback(env, "isScreenBright")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenBright();
 }
 
-void NativeInputManager::virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-        int32_t action, int32_t flags, int32_t keyCode,
-        int32_t scanCode, int32_t metaState, nsecs_t downTime) {
+void NativeInputManager::virtualKeyDownFeedback() {
 #if DEBUG_INPUT_READER_POLICY
-    LOGD("virtualKeyFeedback - when=%lld, deviceId=%d, action=%d, flags=%d, keyCode=%d, "
-            "scanCode=%d, metaState=%d, downTime=%lld",
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
+    LOGD("virtualKeyDownFeedback");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyFeedback,
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
-    checkAndClearExceptionFromCallback(env, "virtualKeyFeedback");
+    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
+    checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
 }
 
 int32_t NativeInputManager::interceptKey(nsecs_t when,
@@ -593,16 +592,21 @@
     const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
     const int32_t WM_ACTION_GO_TO_SLEEP = 4;
 
-    JNIEnv* env = jniEnv();
-
     bool isScreenOn = this->isScreenOn();
     bool isScreenBright = this->isScreenBright();
 
-    jint wmActions = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.interceptKeyBeforeQueueing,
-            deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
-        wmActions = 0;
+    jint wmActions = 0;
+    if (isPolicyKey(keyCode, isScreenOn)) {
+        JNIEnv* env = jniEnv();
+
+        wmActions = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.interceptKeyBeforeQueueing,
+                when, keyCode, down, policyFlags, isScreenOn);
+        if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+            wmActions = 0;
+        }
+    } else {
+        wmActions = WM_ACTION_PASS_TO_USER;
     }
 
     int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
@@ -617,8 +621,7 @@
     }
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.goToSleep, when);
-        checkAndClearExceptionFromCallback(env, "goToSleep");
+        android_server_PowerManagerService_goToSleep(when);
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
@@ -629,6 +632,8 @@
         actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
 
         if (down && isAppSwitchKey(keyCode)) {
+            JNIEnv* env = jniEnv();
+
             env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
             checkAndClearExceptionFromCallback(env, "notifyAppSwitchComing");
 
@@ -1531,11 +1536,13 @@
         windowType = focusedWindow->layoutParamsType;
     } // release lock
 
-    const InputTarget& target = outTargets.top();
-    bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
-    if (consumed) {
-        outTargets.clear();
-        return INPUT_EVENT_INJECTION_SUCCEEDED;
+    if (isPolicyKey(keyEvent->getKeyCode(), isScreenOn())) {
+        const InputTarget& target = outTargets.top();
+        bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
+        if (consumed) {
+            outTargets.clear();
+            return INPUT_EVENT_INJECTION_SUCCEEDED;
+        }
     }
 
     pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT);
@@ -1552,11 +1559,11 @@
 
     switch (motionEvent->getNature()) {
     case INPUT_EVENT_NATURE_TRACKBALL:
-        return identifyTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     case INPUT_EVENT_NATURE_TOUCH:
-        return identifyTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     default:
@@ -1565,11 +1572,11 @@
     }
 }
 
-int32_t NativeInputManager::identifyTrackballEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTrackballEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1591,11 +1598,11 @@
     return INPUT_EVENT_INJECTION_SUCCEEDED;
 }
 
-int32_t NativeInputManager::identifyTouchEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTouchEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1642,8 +1649,8 @@
     if (inputChannelObj) {
         jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                inputChannelObj, keyEvent->getKeyCode(), keyEvent->getMetaState(),
-                keyEvent->getAction() == KEY_EVENT_ACTION_DOWN,
+                inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
+                keyEvent->getKeyCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), policyFlags);
         bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
@@ -1665,10 +1672,7 @@
 }
 
 void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
-    JNIEnv* env = jniEnv();
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.pokeUserActivity,
-            eventTime, eventType);
-    checkAndClearExceptionFromCallback(env, "pokeUserActivity");
+    android_server_PowerManagerService_userActivity(eventTime, eventType);
 }
 
 void NativeInputManager::dumpDispatchStateLd() {
@@ -2082,12 +2086,6 @@
 
     FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks");
 
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz,
-            "isScreenOn", "()Z");
-
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz,
-            "isScreenBright", "()Z");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
             "notifyConfigurationChanged", "(JIII)V");
 
@@ -2106,24 +2104,18 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
             "notifyANR", "(Ljava/lang/Object;)J");
 
-    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
-            "virtualKeyFeedback", "(JIIIIIIJ)V");
+    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
+            "virtualKeyDownFeedback", "()V");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeQueueing", "(IIIIIIJZ)I");
+            "interceptKeyBeforeQueueing", "(JIZIZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIZII)Z");
+            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz,
-            "goToSleep", "(J)V");
-
-    GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivity, gCallbacksClassInfo.clazz,
-            "pokeUserActivity", "(JI)V");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz,
             "notifyAppSwitchComing", "()V");
 
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
deleted file mode 100644
index f9e3585..0000000
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Input"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <ui/EventHub.h>
-#include <utils/threads.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct input_offsets_t
-{
-    jfieldID mMinValue;
-    jfieldID mMaxValue;
-    jfieldID mFlat;
-    jfieldID mFuzz;
-    
-    jfieldID mDeviceId;
-    jfieldID mType;
-    jfieldID mScancode;
-    jfieldID mKeycode;
-    jfieldID mFlags;
-    jfieldID mValue;
-    jfieldID mWhen;
-} gInputOffsets;
-
-// ----------------------------------------------------------------------------
-
-static Mutex gLock;
-static sp<EventHub> gHub;
-
-static jboolean
-android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
-                                          jobject event)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    int32_t deviceId;
-    int32_t type;
-    int32_t scancode, keycode;
-    uint32_t flags;
-    int32_t value;
-    nsecs_t when;
-    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
-            &flags, &value, &when);
-
-    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
-    env->SetIntField(event, gInputOffsets.mType, (jint)type);
-    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
-    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
-    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
-    env->SetIntField(event, gInputOffsets.mValue, value);
-    env->SetLongField(event, gInputOffsets.mWhen,
-                        (jlong)(nanoseconds_to_milliseconds(when)));
-
-    return res;
-}
-
-static jint
-android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    jint classes = 0;
-    gLock.lock();
-    if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId);
-    gLock.unlock();
-    return classes;
-}
-
-static jstring
-android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    String8 name;
-    gLock.lock();
-    if (gHub != NULL) name = gHub->getDeviceName(deviceId);
-    gLock.unlock();
-    
-    if (name.size() > 0) {
-        return env->NewStringUTF(name.string());
-    }
-    return NULL;
-}
-
-static void
-android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz,
-                                              jstring deviceName)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    const char* nameStr = env->GetStringUTFChars(deviceName, NULL);
-    gHub->addExcludedDevice(nameStr);
-    env->ReleaseStringUTFChars(deviceName, nameStr);
-}
-
-static jboolean
-android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
-                                             jint deviceId, jint axis,
-                                             jobject info)
-{
-    int32_t minValue, maxValue, flat, fuzz;
-    int res = -1;
-    gLock.lock();
-    if (gHub != NULL) {
-        res = gHub->getAbsoluteInfo(deviceId, axis,
-                &minValue, &maxValue, &flat, &fuzz);
-    }
-    gLock.unlock();
-    
-    if (res < 0) return JNI_FALSE;
-    
-    env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue);
-    env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue);
-    env->SetIntField(info, gInputOffsets.mFlat, (jint)flat);
-    env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz);
-    return JNI_TRUE;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(-1, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(deviceId,-1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint scancode)
-{
-    jint res = 0;
-    gLock.lock();
-    if (gHub != NULL) {
-        int32_t keycode;
-        uint32_t flags;
-        gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
-        res = keycode;
-    }
-    gLock.unlock();
-    
-    return res;
-}
-
-static jboolean
-android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
-                                     jintArray keyCodes, jbooleanArray outFlags)
-{
-    jboolean ret = JNI_FALSE;
-
-    int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
-    uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
-    jsize numCodes = env->GetArrayLength(keyCodes);
-    if (numCodes == env->GetArrayLength(outFlags)) {
-        gLock.lock();
-        if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags);
-        gLock.unlock();
-    }
-
-    env->ReleaseBooleanArrayElements(outFlags, flags, 0);
-    env->ReleaseIntArrayElements(keyCodes, codes, 0);
-    return ret;
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gInputMethods[] = {
-    /* name, signature, funcPtr */
-    { "readEvent",       "(Landroid/view/RawInputEvent;)Z",
-            (void*) android_server_KeyInputQueue_readEvent },
-    { "getDeviceClasses", "(I)I",
-        (void*) android_server_KeyInputQueue_getDeviceClasses },
-    { "getDeviceName", "(I)Ljava/lang/String;",
-        (void*) android_server_KeyInputQueue_getDeviceName },
-    { "addExcludedDevice", "(Ljava/lang/String;)V",
-        (void*) android_server_KeyInputQueue_addExcludedDevice },
-    { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
-        (void*) android_server_KeyInputQueue_getAbsoluteInfo },
-    { "getSwitchState", "(I)I",
-        (void*) android_server_KeyInputQueue_getSwitchState },
-    { "getSwitchState", "(II)I",
-        (void*) android_server_KeyInputQueue_getSwitchStateDevice },
-    { "nativeGetScancodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getScancodeState },
-    { "nativeGetScancodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getScancodeStateDevice },
-    { "nativeGetKeycodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getKeycodeState },
-    { "nativeGetKeycodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
-    { "hasKeys", "([I[Z)Z",
-        (void*) android_server_KeyInputQueue_hasKeys },
-    { "scancodeToKeycode", "(II)I",
-        (void*) android_server_KeyInputQueue_scancodeToKeycode },
-};
-
-int register_android_server_KeyInputQueue(JNIEnv* env)
-{
-    jclass input = env->FindClass("com/android/server/KeyInputQueue");
-    LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue");
-    int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue",
-                                        gInputMethods, NELEM(gInputMethods));
-
-    jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo");
-    LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo");
-    
-    gInputOffsets.mMinValue
-        = env->GetFieldID(absoluteInfo, "minValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue");
-    
-    gInputOffsets.mMaxValue
-        = env->GetFieldID(absoluteInfo, "maxValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue");
-    
-    gInputOffsets.mFlat
-        = env->GetFieldID(absoluteInfo, "flat", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat");
-    
-    gInputOffsets.mFuzz
-        = env->GetFieldID(absoluteInfo, "fuzz", "I");
-    LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz");
-    
-    jclass inputEvent = env->FindClass("android/view/RawInputEvent");
-    LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent");
-
-    gInputOffsets.mDeviceId
-        = env->GetFieldID(inputEvent, "deviceId", "I");
-    LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId");
-    
-    gInputOffsets.mType
-        = env->GetFieldID(inputEvent, "type", "I");
-    LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type");
-    
-    gInputOffsets.mScancode
-        = env->GetFieldID(inputEvent, "scancode", "I");
-    LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode");
-
-    gInputOffsets.mKeycode
-        = env->GetFieldID(inputEvent, "keycode", "I");
-    LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode");
-
-    gInputOffsets.mFlags
-        = env->GetFieldID(inputEvent, "flags", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags");
-
-    gInputOffsets.mValue
-        = env->GetFieldID(inputEvent, "value", "I");
-    LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value");
-    
-    gInputOffsets.mWhen
-        = env->GetFieldID(inputEvent, "when", "J");
-    LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when");
-
-    return res;
-}
-
-}; // namespace android
-
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
new file mode 100644
index 0000000..b80dbc5
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerManagerService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <limits.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "com_android_server_PowerManagerService.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+
+    jmethodID goToSleep;
+    jmethodID userActivity;
+} gPowerManagerServiceClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static jobject gPowerManagerServiceObj;
+
+static Mutex gPowerManagerLock;
+static bool gScreenOn;
+static bool gScreenBright;
+
+// ----------------------------------------------------------------------------
+
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+        return true;
+    }
+    return false;
+}
+
+bool android_server_PowerManagerService_isScreenOn() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenOn;
+}
+
+bool android_server_PowerManagerService_isScreenBright() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenBright;
+}
+
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity,
+                nanoseconds_to_milliseconds(eventTime), false, eventType, false);
+        checkAndClearExceptionFromCallback(env, "userActivity");
+    }
+}
+
+void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
+                nanoseconds_to_milliseconds(eventTime));
+        checkAndClearExceptionFromCallback(env, "goToSleep");
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+static void android_server_PowerManagerService_nativeInit(JNIEnv* env, jobject obj) {
+    gPowerManagerServiceObj = env->NewGlobalRef(obj);
+}
+
+static void android_server_PowerManagerService_nativeSetPowerState(JNIEnv* env,
+        jobject serviceObj, jboolean screenOn, jboolean screenBright) {
+    AutoMutex _l(gPowerManagerLock);
+    gScreenOn = screenOn;
+    gScreenBright = screenBright;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gPowerManagerServiceMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "()V",
+            (void*) android_server_PowerManagerService_nativeInit },
+    { "nativeSetPowerState", "(ZZ)V",
+            (void*) android_server_PowerManagerService_nativeSetPowerState },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_PowerManagerService(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/PowerManagerService",
+            gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    // Callbacks
+
+    FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz,
+            "goToSleep", "(J)V");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz,
+            "userActivity", "(JZIZ)V");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h
new file mode 100644
index 0000000..9b05f38
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+#define _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+enum {
+    POWER_MANAGER_OTHER_EVENT = 0,
+    POWER_MANAGER_CHEEK_EVENT = 1,
+    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
+                                   // up events or LONG_TOUCH events.
+    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
+    POWER_MANAGER_TOUCH_UP_EVENT = 4,
+    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
+};
+
+extern bool android_server_PowerManagerService_isScreenOn();
+extern bool android_server_PowerManagerService_isScreenBright();
+extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index a1a6838..1a2d8b6 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -6,9 +6,9 @@
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_KeyInputQueue(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
+int register_android_server_PowerManagerService(JNIEnv* env);
 int register_android_server_SensorService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
@@ -28,7 +28,7 @@
     }
     LOG_ASSERT(env, "Could not retrieve the env!");
 
-    register_android_server_KeyInputQueue(env);
+    register_android_server_PowerManagerService(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
diff --git a/tests/StatusBar/res/drawable-hdpi/stat_sys_phone.png b/tests/StatusBar/res/drawable-hdpi/stat_sys_phone.png
new file mode 100644
index 0000000..9815553
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/stat_sys_phone.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-mdpi/stat_sys_phone.png b/tests/StatusBar/res/drawable-mdpi/stat_sys_phone.png
new file mode 100644
index 0000000..402abc7
--- /dev/null
+++ b/tests/StatusBar/res/drawable-mdpi/stat_sys_phone.png
Binary files differ
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index c6a4134..b665d2f 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -89,11 +89,12 @@
         new Test("Priority notification") {
             public void run() {
                 Notification not = new Notification(StatusBarTest.this,
-                                R.drawable.ic_statusbar_missedcall,
-                                "tick tick tick",
+                                R.drawable.stat_sys_phone,
+                                "Incoming call from: Imperious Leader",
                                 System.currentTimeMillis()-(1000*60*60*24),
-                                "(453) 123-2328",
-                                "", null
+                                "Imperious Leader",
+                                "(888) 555-5038",
+                                null
                                 );
                 not.flags |= Notification.FLAG_HIGH_PRIORITY;
                 Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class);