Merge "DO NOT MERGE Doc Change: Javadoc for test case classes" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 5d71cad..e66b2e7 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4717,6 +4717,17 @@
  visibility="public"
 >
 </field>
+<field name="immersive"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inAnimation"
  type="int"
  transient="false"
@@ -5916,17 +5927,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad64"
- type="int"
- transient="false"
- volatile="false"
- value="16843457"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -13625,7 +13625,7 @@
  value="17301636"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13636,7 +13636,7 @@
  value="17301637"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13647,7 +13647,7 @@
  value="17301638"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13691,7 +13691,7 @@
  value="17301671"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13702,7 +13702,7 @@
  value="17301672"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -154519,6 +154519,21 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="setPackageObbPath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fc9bcf7..63bbf9c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2657,6 +2657,15 @@
             return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         }
 
+        @Override
+        public void setPackageObbPath(String packageName, String path) {
+            try {
+                mPM.setPackageObbPath(packageName, path);
+            } catch (RemoteException e) {
+                // Should never happen!
+            }
+        }
+
         private final ContextImpl mContext;
         private final IPackageManager mPM;
 
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 161161c..d72dda7 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -6,7 +6,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.PixelFormat;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.view.InputChannel;
@@ -33,7 +35,8 @@
     
     private boolean mDestroyed;
     
-    private native int loadNativeCode(String path, MessageQueue queue);
+    private native int loadNativeCode(String path, MessageQueue queue,
+            String internalDataPath, String externalDataPath, int sdkVersion);
     private native void unloadNativeCode(int handle);
     
     private native void onStartNative(int handle);
@@ -90,7 +93,11 @@
             throw new IllegalArgumentException("Unable to find native library: " + libname);
         }
         
-        mNativeHandle = loadNativeCode(path, Looper.myQueue());
+        mNativeHandle = loadNativeCode(path, Looper.myQueue(),
+                 getFilesDir().toString(),
+                 Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
+                 Build.VERSION.SDK_INT);
+        
         if (mNativeHandle == 0) {
             throw new IllegalArgumentException("Unable to load native library: " + path);
         }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9939478..160a481 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -319,4 +319,6 @@
 
     boolean setInstallLocation(int loc);
     int getInstallLocation();
+
+    void setPackageObbPath(String packageName, String path);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a5b419..15a446b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2193,4 +2193,17 @@
      */
     public abstract void movePackage(
             String packageName, IPackageMoveObserver observer, int flags);
+
+    /**
+     * Sets the Opaque Binary Blob (OBB) file location.
+     * <p>
+     * NOTE: The existence or format of this file is not currently checked, but
+     * it may be in the future.
+     * 
+     * @param packageName Name of the package with which to associate the .obb
+     *            file
+     * @param path Path on the filesystem to the .obb file
+     * @hide
+     */
+    public abstract void setPackageObbPath(String packageName, String path);
 }
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..fb45971 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -452,6 +452,7 @@
                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                     if (mSurfaceHolderCallback != null) {
                         mSurfaceHolder = new TakenSurfaceHolder();
+                        mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                     }
                 }
                 Resources resources = mView.getContext().getResources();
@@ -556,18 +557,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);
@@ -756,7 +755,7 @@
             // object is not initialized to its backing store, but soon it
             // will be (assuming the window is visible).
             attachInfo.mSurface = mSurface;
-            attachInfo.mTranslucentWindow = lp.format != PixelFormat.OPAQUE;
+            attachInfo.mTranslucentWindow = PixelFormat.formatHasAlpha(lp.format);
             attachInfo.mHasWindowFocus = false;
             attachInfo.mWindowVisibility = viewVisibility;
             attachInfo.mRecomputeGlobalAttributes = false;
@@ -928,8 +927,6 @@
             if (mSurfaceHolder != null) {
                 mSurfaceHolder.mSurfaceLock.lock();
                 mDrawingAllowed = true;
-                lp.format = mSurfaceHolder.getRequestedFormat();
-                lp.type = mSurfaceHolder.getRequestedType();
             }
             
             boolean initialized = false;
@@ -1745,16 +1742,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 +1756,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 +1860,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 +2009,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 +2136,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 +2239,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 +2765,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 +2805,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 +2947,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 +2963,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/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
index 7b9b7bd..3fadf4c 100644
--- a/core/java/android/widget/CursorTreeAdapter.java
+++ b/core/java/android/widget/CursorTreeAdapter.java
@@ -134,14 +134,16 @@
     /**
      * Sets the group Cursor.
      * 
-     * @param cursor The Cursor to set for the group.
+     * @param cursor The Cursor to set for the group. If there is an existing cursor 
+     * it will be closed.
      */
     public void setGroupCursor(Cursor cursor) {
         mGroupCursorHelper.changeCursor(cursor, false);
     }
     
     /**
-     * Sets the children Cursor for a particular group.
+     * Sets the children Cursor for a particular group. If there is an existing cursor
+     * it will be closed.
      * <p>
      * This is useful when asynchronously querying to prevent blocking the UI.
      * 
@@ -476,7 +478,7 @@
             
             mCursor.unregisterContentObserver(mContentObserver);
             mCursor.unregisterDataSetObserver(mDataSetObserver);
-            mCursor.deactivate();
+            mCursor.close();
             mCursor = null;
         }
         
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index a1c65f0..a033542 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -38,6 +38,10 @@
  * binding can be found, an {@link IllegalStateException} is thrown.
  */
 public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
+    
+    /** The name of the columns that contain the data to display for a group. */
+    private String[] mGroupFromNames;
+    
     /** The indices of columns that contain data to display for a group. */
     private int[] mGroupFrom;
     /**
@@ -46,6 +50,9 @@
      */
     private int[] mGroupTo;
 
+    /** The name of the columns that contain the data to display for a child. */
+    private String[] mChildFromNames;
+    
     /** The indices of columns that contain data to display for a child. */
     private int[] mChildFrom;
     /**
@@ -171,38 +178,12 @@
 
     private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames,
             int[] childTo) {
+        
+        mGroupFromNames = groupFromNames;
         mGroupTo = groupTo;
         
+        mChildFromNames = childFromNames;
         mChildTo = childTo;
-        
-        // Get the group cursor column indices, the child cursor column indices will come
-        // when needed
-        initGroupFromColumns(groupFromNames);
-        
-        // Get a temporary child cursor to init the column indices
-        if (getGroupCount() > 0) {
-            MyCursorHelper tmpCursorHelper = getChildrenCursorHelper(0, true);
-            if (tmpCursorHelper != null) {
-                initChildrenFromColumns(childFromNames, tmpCursorHelper.getCursor());
-                deactivateChildrenCursorHelper(0);
-            }
-        }
-    }
-    
-    private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
-        for (int i = fromColumnNames.length - 1; i >= 0; i--) {
-            fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
-        }
-    }
-    
-    private void initGroupFromColumns(String[] groupFromNames) {
-        mGroupFrom = new int[groupFromNames.length];
-        initFromColumns(mGroupCursorHelper.getCursor(), groupFromNames, mGroupFrom);
-    }
-
-    private void initChildrenFromColumns(String[] childFromNames, Cursor childCursor) {
-        mChildFrom = new int[childFromNames.length];
-        initFromColumns(childCursor, childFromNames, mChildFrom);
     }
     
     /**
@@ -257,13 +238,29 @@
         }
     }
     
+    private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
+        for (int i = fromColumnNames.length - 1; i >= 0; i--) {
+            fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
+        }
+    }
+    
     @Override
     protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
+        if (mChildFrom == null) {
+            mChildFrom = new int[mChildFromNames.length];
+            initFromColumns(cursor, mChildFromNames, mChildFrom);
+        }
+        
         bindView(view, context, cursor, mChildFrom, mChildTo);
     }
 
     @Override
     protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
+        if (mGroupFrom == null) {
+            mGroupFrom = new int[mGroupFromNames.length];
+            initFromColumns(cursor, mGroupFromNames, mGroupFrom);
+        }
+        
         bindView(view, context, cursor, mGroupFrom, mGroupTo);
     }
 
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/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index dab1dba..54a9c2a 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -21,7 +21,8 @@
 #include <dlfcn.h>
 
 #include <android_runtime/AndroidRuntime.h>
-#include <android/native_activity.h>
+#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_app_NativeActivity.h>
 #include <surfaceflinger/Surface.h>
 #include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
@@ -31,7 +32,6 @@
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
-#include "android_view_Surface.h"
 
 namespace android
 {
@@ -46,6 +46,48 @@
 
 // ------------------------------------------------------------------------
 
+struct ActivityWork {
+    int32_t cmd;
+    int32_t arg1;
+    int32_t arg2;
+};
+
+enum {
+    CMD_DEF_KEY = 1,
+    CMD_SET_WINDOW_FORMAT,
+    CMD_SET_WINDOW_FLAGS,
+};
+
+static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
+    ActivityWork work;
+    work.cmd = cmd;
+    work.arg1 = arg1;
+    work.arg2 = arg2;
+    
+restart:
+    int res = write(fd, &work, sizeof(work));
+    if (res < 0 && errno == EINTR) {
+        goto restart;
+    }
+    
+    if (res == sizeof(work)) return;
+    
+    if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno));
+    else LOGW("Truncated writing to work fd: %d", res);
+}
+
+static bool read_work(int fd, ActivityWork* outWork) {
+    int res = read(fd, outWork, sizeof(ActivityWork));
+    // no need to worry about EINTR, poll loop will just come back again.
+    if (res == sizeof(ActivityWork)) return true;
+    
+    if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno));
+    else LOGW("Truncated reading work fd: %d", res);
+    return false;
+}
+
+// ------------------------------------------------------------------------
+
 /*
  * Specialized input queue that allows unhandled key events to be dispatched
  * back to the native activity's Java framework code.
@@ -59,8 +101,7 @@
         mLock.lock();
         LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
         if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
-            int8_t cmd = 1;
-            write(mWorkWrite, &cmd, sizeof(cmd));
+            write_work(mWorkWrite, CMD_DEF_KEY);
         }
         mPendingKeys.add(keyEvent);
         mLock.unlock();
@@ -90,9 +131,9 @@
 /*
  * Native state for interacting with the NativeActivity class.
  */
-struct NativeCode {
+struct NativeCode : public ANativeActivity {
     NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
-        memset(&activity, sizeof(activity), 0);
+        memset((ANativeActivity*)this, sizeof(ANativeActivity), 0);
         memset(&callbacks, sizeof(callbacks), 0);
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
@@ -103,8 +144,11 @@
     }
     
     ~NativeCode() {
-        if (activity.env != NULL && activity.clazz != NULL) {
-            activity.env->DeleteGlobalRef(activity.clazz);
+        if (callbacks.onDestroy != NULL) {
+            callbacks.onDestroy(this);
+        }
+        if (env != NULL && clazz != NULL) {
+            env->DeleteGlobalRef(clazz);
         }
         if (pollLoop != NULL && mainWorkRead >= 0) {
             pollLoop->removeCallback(mainWorkRead);
@@ -114,9 +158,6 @@
         }
         setSurface(NULL);
         setInputChannel(NULL);
-        if (callbacks.onDestroy != NULL) {
-            callbacks.onDestroy(&activity);
-        }
         if (mainWorkRead >= 0) close(mainWorkRead);
         if (mainWorkWrite >= 0) close(mainWorkWrite);
         if (dlhandle != NULL) {
@@ -129,7 +170,7 @@
     
     void setSurface(jobject _surface) {
         if (_surface != NULL) {
-            nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
+            nativeWindow = android_Surface_getNativeWindow(env, _surface);
         } else {
             nativeWindow = NULL;
         }
@@ -138,14 +179,14 @@
     status_t setInputChannel(jobject _channel) {
         if (inputChannel != NULL) {
             delete nativeInputQueue;
-            activity.env->DeleteGlobalRef(inputChannel);
+            env->DeleteGlobalRef(inputChannel);
         }
         inputChannel = NULL;
         nativeInputQueue = NULL;
         if (_channel != NULL) {
-            inputChannel = activity.env->NewGlobalRef(_channel);
+            inputChannel = env->NewGlobalRef(_channel);
             sp<InputChannel> ic =
-                    android_view_InputChannel_getInputChannel(activity.env, _channel);
+                    android_view_InputChannel_getInputChannel(env, _channel);
             if (ic != NULL) {
                 nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
                 if (nativeInputQueue->getConsumer().initialize() != android::OK) {
@@ -160,12 +201,14 @@
         return OK;
     }
     
-    ANativeActivity activity;
     ANativeActivityCallbacks callbacks;
     
     void* dlhandle;
     ANativeActivity_createFunc* createActivityFunc;
     
+    String8 internalDataPath;
+    String8 externalDataPath;
+    
     sp<ANativeWindow> nativeWindow;
     jobject inputChannel;
     struct MyInputQueue* nativeInputQueue;
@@ -176,6 +219,18 @@
     sp<PollLoop> pollLoop;
 };
 
+void android_NativeActivity_setWindowFormat(
+        ANativeActivity* activity, int32_t format) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
+}
+
+void android_NativeActivity_setWindowFlags(
+        ANativeActivity* activity, int32_t values, int32_t mask) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
+}
+
 // ------------------------------------------------------------------------
 
 /*
@@ -183,19 +238,40 @@
  */
 static bool mainWorkCallback(int fd, int events, void* data) {
     NativeCode* code = (NativeCode*)data;
-    if ((events & POLLIN) != 0) {
-        KeyEvent* keyEvent;
-        while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
-            jobject inputEventObj = android_view_KeyEvent_fromNative(
-                    code->activity.env, keyEvent);
-            code->activity.env->CallVoidMethod(code->activity.clazz,
-                    gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
-            int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
-            if (res != OK) {
-                LOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                        code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+    if ((events & POLLIN) == 0) {
+        return true;
+    }
+    
+    ActivityWork work;
+    if (!read_work(code->mainWorkRead, &work)) {
+        return true;
+    }
+    switch (work.cmd) {
+        case CMD_DEF_KEY: {
+            KeyEvent* keyEvent;
+            while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
+                jobject inputEventObj = android_view_KeyEvent_fromNative(
+                        code->env, keyEvent);
+                code->env->CallVoidMethod(code->clazz,
+                        gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+                int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
+                if (res != OK) {
+                    LOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                            code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+                }
             }
-        }
+        } break;
+        case CMD_SET_WINDOW_FORMAT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.setWindowFormat, work.arg1);
+        } break;
+        case CMD_SET_WINDOW_FLAGS: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
+        } break;
+        default:
+            LOGW("Unknown work command: %d", work.cmd);
+            break;
     }
     
     return true;
@@ -204,7 +280,8 @@
 // ------------------------------------------------------------------------
 
 static jint
-loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue)
+loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
+        jstring internalDataDir, jstring externalDataDir, int sdkVersion)
 {
     const char* pathStr = env->GetStringUTFChars(path, NULL);
     NativeCode* code = NULL;
@@ -239,15 +316,28 @@
         code->mainWorkWrite = msgpipe[1];
         code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
         
-        code->activity.callbacks = &code->callbacks;
-        if (env->GetJavaVM(&code->activity.vm) < 0) {
+        code->ANativeActivity::callbacks = &code->callbacks;
+        if (env->GetJavaVM(&code->vm) < 0) {
             LOGW("NativeActivity GetJavaVM failed");
             delete code;
             return 0;
         }
-        code->activity.env = env;
-        code->activity.clazz = env->NewGlobalRef(clazz);
-        code->createActivityFunc(&code->activity, NULL, 0);
+        code->env = env;
+        code->clazz = env->NewGlobalRef(clazz);
+        
+        const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
+        code->internalDataPath = dirStr;
+        code->internalDataPath = code->internalDataPath.string();
+        env->ReleaseStringUTFChars(path, dirStr);
+    
+        dirStr = env->GetStringUTFChars(externalDataDir, NULL);
+        code->externalDataPath = dirStr;
+        code->externalDataPath = code->externalDataPath.string();
+        env->ReleaseStringUTFChars(path, dirStr);
+    
+        code->sdkVersion = sdkVersion;
+        
+        code->createActivityFunc(code, NULL, 0);
     }
     
     return (jint)code;
@@ -268,7 +358,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStart != NULL) {
-            code->callbacks.onStart(&code->activity);
+            code->callbacks.onStart(code);
         }
     }
 }
@@ -279,7 +369,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onResume != NULL) {
-            code->callbacks.onResume(&code->activity);
+            code->callbacks.onResume(code);
         }
     }
 }
@@ -291,7 +381,7 @@
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onSaveInstanceState != NULL) {
             size_t len = 0;
-            code->callbacks.onSaveInstanceState(&code->activity, &len);
+            code->callbacks.onSaveInstanceState(code, &len);
         }
     }
 }
@@ -302,7 +392,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onPause != NULL) {
-            code->callbacks.onPause(&code->activity);
+            code->callbacks.onPause(code);
         }
     }
 }
@@ -313,7 +403,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStop != NULL) {
-            code->callbacks.onStop(&code->activity);
+            code->callbacks.onStop(code);
         }
     }
 }
@@ -324,7 +414,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onLowMemory != NULL) {
-            code->callbacks.onLowMemory(&code->activity);
+            code->callbacks.onLowMemory(code);
         }
     }
 }
@@ -335,7 +425,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onWindowFocusChanged != NULL) {
-            code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
+            code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
         }
     }
 }
@@ -347,7 +437,7 @@
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
-            code->callbacks.onNativeWindowCreated(&code->activity,
+            code->callbacks.onNativeWindowCreated(code,
                     code->nativeWindow.get());
         }
     }
@@ -363,11 +453,11 @@
         code->setSurface(surface);
         if (oldNativeWindow != code->nativeWindow) {
             if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
-                code->callbacks.onNativeWindowDestroyed(&code->activity,
+                code->callbacks.onNativeWindowDestroyed(code,
                         oldNativeWindow.get());
             }
             if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
-                code->callbacks.onNativeWindowCreated(&code->activity,
+                code->callbacks.onNativeWindowCreated(code,
                         code->nativeWindow.get());
             }
         }
@@ -380,7 +470,7 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
-            code->callbacks.onNativeWindowDestroyed(&code->activity,
+            code->callbacks.onNativeWindowDestroyed(code,
                     code->nativeWindow.get());
         }
         code->setSurface(NULL);
@@ -399,7 +489,7 @@
             return;
         }
         if (code->callbacks.onInputQueueCreated != NULL) {
-            code->callbacks.onInputQueueCreated(&code->activity,
+            code->callbacks.onInputQueueCreated(code,
                     code->nativeInputQueue);
         }
     }
@@ -412,7 +502,7 @@
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeInputQueue != NULL
                 && code->callbacks.onInputQueueDestroyed != NULL) {
-            code->callbacks.onInputQueueDestroyed(&code->activity,
+            code->callbacks.onInputQueueDestroyed(code,
                     code->nativeInputQueue);
         }
         code->setInputChannel(NULL);
@@ -420,7 +510,8 @@
 }
 
 static const JNINativeMethod g_methods[] = {
-    { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;)I", (void*)loadNativeCode_native },
+    { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;I)I",
+            (void*)loadNativeCode_native },
     { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
     { "onStartNative", "(I)V", (void*)onStart_native },
     { "onResumeNative", "(I)V", (void*)onResume_native },
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 030d6c7..847b5a5 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -51,14 +51,18 @@
 // ----------------------------------------------------------------------------
 
 NativeMessageQueue::NativeMessageQueue() {
-    mPollLoop = new PollLoop();
+    mPollLoop = PollLoop::getForThread();
+    if (mPollLoop == NULL) {
+        mPollLoop = new PollLoop(false);
+        PollLoop::setForThread(mPollLoop);
+    }
 }
 
 NativeMessageQueue::~NativeMessageQueue() {
 }
 
 bool NativeMessageQueue::pollOnce(int timeoutMillis) {
-    return mPollLoop->pollOnce(timeoutMillis);
+    return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
 }
 
 void NativeMessageQueue::wake() {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index a82abc93..7305032 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,7 +33,7 @@
 
 #include "jni.h"
 #include <android_runtime/AndroidRuntime.h>
-#include "android_view_Surface.h"
+#include <android_runtime/android_view_Surface.h>
 #include <utils/misc.h>
 
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 866c038..941ed63 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -16,6 +16,7 @@
 */
 
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
 #include <utils/misc.h>
 
 #include <EGL/egl.h>
@@ -25,8 +26,6 @@
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
-#include "android_view_Surface.h"
-
 namespace android {
 
 static jclass gDisplay_class;
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index 950713b..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index c44d062..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 27cb763..bd65fee 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -869,8 +869,11 @@
   <public type="drawable" name="stat_sys_download" id="0x01080081" />
   <public type="drawable" name="stat_sys_download_done" id="0x01080082" />
   <public type="drawable" name="stat_sys_headset" id="0x01080083" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call" id="0x01080084" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call_forward" id="0x01080085" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call_on_hold" id="0x01080086" />
   <public type="drawable" name="stat_sys_speakerphone" id="0x01080087" />
   <public type="drawable" name="stat_sys_upload" id="0x01080088" />
@@ -1132,7 +1135,9 @@
   <public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" />
   <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
 
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" />
 
   <public type="anim" name="anticipate_interpolator" id="0x010a0007" />
@@ -1246,6 +1251,7 @@
   <public type="attr" name="logo" id="0x010102be" />
   <public type="attr" name="xlargeScreens" id="0x010102bf" />
   <public type="attr" name="heavyWeight" id="0x010102c0" />
+  <public type="attr" name="immersive" id="0x010102c1" />
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
   
   <public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
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/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd
index 1d6e0ad..0c16b60 100644
--- a/docs/html/sdk/android-1.5.jd
+++ b/docs/html/sdk/android-1.5.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.5, Revision 3</a> <em>(July 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-1.6.jd b/docs/html/sdk/android-1.6.jd
index c2651b6..c4e08ff 100644
--- a/docs/html/sdk/android-1.6.jd
+++ b/docs/html/sdk/android-1.6.jd
@@ -138,7 +138,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.6, Revision 2</a> <em>(December 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.1.jd b/docs/html/sdk/android-2.1.jd
index 7490bae..cd48a72 100644
--- a/docs/html/sdk/android-2.1.jd
+++ b/docs/html/sdk/android-2.1.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 2.1, Revision 1</a> <em>(January 2010)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.2.jd b/docs/html/sdk/android-2.2.jd
index f82edf9..495fd80 100644
--- a/docs/html/sdk/android-2.2.jd
+++ b/docs/html/sdk/android-2.2.jd
@@ -2,7 +2,6 @@
 sdk.platform.version=2.2
 sdk.platform.apiLevel=8
 sdk.platform.majorMinor=minor
-sdk.platform.deployableDate=May 2010
 
 @jd:body
 
@@ -118,6 +117,30 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        Android {@sdkPlatformVersion}, Revision 2</a> <em>(July 2010)</em></a>
+  <div class="toggleme">
+<dl>
+<dt>Dependencies:</dt>
+<dd>
+<p>Requires SDK Tools r6 or higher.</p>
+</dd>
+
+<dt>System Image:</dt>
+<dd>
+<ul>
+<li>Adds default Search Widget.</li>
+<li>Includes proper provisioning for the platform's Backup Manager. For more information about how to use the Backup Manager, see <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a>.</li>
+<li>Updates the Android 2.2 system image to FRF91.</li>
+</ul>
+</dd>
+
+</dl>
+ </div>
+</div>
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android {@sdkPlatformVersion}, Revision 1</a> <em>(May 2010)</em></a>
   <div class="toggleme">
 <dl>
@@ -135,7 +158,6 @@
  </div>
 </div>
 
-
 <h2 id="api-level">API Level</h2>
 
 <p>The Android {@sdkPlatformVersion} platform delivers an updated version of
@@ -444,4 +466,4 @@
 <p>For more information about how to develop an application that displays
 and functions properly on all Android-powered devices, see <a
 href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-Screens</a>.</p>
\ No newline at end of file
+Screens</a>.</p>
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
new file mode 100644
index 0000000..81b4ff6
--- /dev/null
+++ b/docs/html/sdk/download.jd
@@ -0,0 +1,4 @@
+sdk.redirect=true
+
+@jd:body
+
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f5558ab..bd7eeed 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -48,6 +48,9 @@
 how to update ADT to the latest version or how to uninstall it, if necessary.
 </p>
 
+<p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin running with
+Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+
 <h2 id="notes">Revisions</h2>
 
 <p>The sections below provide notes about successive releases of
@@ -295,7 +298,7 @@
 
 <p>Additionally, before you can configure or use ADT, you must install the
 Android SDK starter package, as described in <a
-href="installing.html#Installing">Downloading the SDK Starter Pacskage</a>.
+href="installing.html#Installing">Downloading the SDK Starter Package</a>.
 Specifically, you need to install a compatible version of the Android SDK Tools
 and at least one development platform. To simplify ADT setup, we recommend
 installing the Android SDK prior to installing ADT. </p>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 69cc73d..9e88d94 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
 ndk=true
 
-ndk.win_download=android-ndk-r4-windows.zip
-ndk.win_bytes=45778965
-ndk.win_checksum=1eded98a7f5cd5e71f8ac74565f73f11
+ndk.win_download=android-ndk-r4b-windows.zip
+ndk.win_bytes=45792835
+ndk.win_checksum=e397145e155a639be53ee4b6db8ad511
 
-ndk.mac_download=android-ndk-r4-darwin-x86.zip
-ndk.mac_bytes=50572163
-ndk.mac_checksum=b7d5f149fecf951c05a79b045f00419f
+ndk.mac_download=android-ndk-r4b-darwin-x86.zip
+ndk.mac_bytes=50586041
+ndk.mac_checksum=41dbd54335fb828ee408eab17103a1b0
 
-ndk.linux_download=android-ndk-r4-linux-x86.zip
-ndk.linux_bytes=49450682
-ndk.linux_checksum=0892b0637d45d145e045cc68e163dee3
+ndk.linux_download=android-ndk-r4b-linux-x86.zip
+ndk.linux_bytes=49464776
+ndk.linux_checksum=2deabcb125c219b34140975b710f00ec
 
 page.title=Android NDK
 @jd:body
@@ -62,8 +62,15 @@
 <div class="toggleable open">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
-Android NDK, Revision 4</a> <em>(May 2010)</em>
+Android NDK, Revision 4b</a> <em>(June 2010)</em>
   <div class="toggleme">
+<dl>
+<dt>NDK r4b notes:</dt>
+<dd><p>Includes fixes for several issues in the NDK build and debugging scripts
+&mdash; if you are using NDK r4, we recommend downloading the NDK r4b build. For
+detailed information the changes in this release, read the CHANGES.TXT document
+included in the downloaded NDK package.</p></dd>
+</dl>
 
 <dl>
 <dt>General notes:</dt>
@@ -114,7 +121,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
 Android NDK, Revision 3</a> <em>(March 2010)</em>
   <div class="toggleme">
 
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index cb9cdf3..d710b8e 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -23,6 +23,9 @@
 <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
     <ul>
       <li>Eclipse 3.4 (Ganymede) or 3.5 (Galileo)
+         <p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin
+running with Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+      </li>
       <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
 in most Eclipse IDE packages) </li>
       <li>If you need to install or update Eclipse, you can download it from <a
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index a80981ce..404e938 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -75,7 +75,8 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a> <span class="new">new!</span></li>
+      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a>
+      </li>
       <li><a href="<?cs var:toroot ?>sdk/win-usb.html">USB Driver for
       Windows, r3</a>
       </li>
@@ -101,7 +102,6 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span></a>
-        <span class="new">new!</span>
       </li>
     </ul>
   </li>
@@ -116,7 +116,7 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4b</a>
       <span class="new">new!</span></li>
     </ul>
   </li>
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
new file mode 100644
index 0000000..f808328
--- /dev/null
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -0,0 +1,35 @@
+/*
+ * 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_APP_NATIVEACTIVITY_H
+#define _ANDROID_APP_NATIVEACTIVITY_H
+
+#include <android/native_activity.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern void android_NativeActivity_setWindowFormat(
+        ANativeActivity* activity, int32_t format);
+
+extern void android_NativeActivity_setWindowFlags(
+        ANativeActivity* activity, int32_t values, int32_t mask);
+
+
+} // namespace android
+
+#endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/core/jni/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
similarity index 100%
rename from core/jni/android_view_Surface.h
rename to include/android_runtime/android_view_Surface.h
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/EffectBassBoostApi.h b/include/media/EffectBassBoostApi.h
new file mode 100644
index 0000000..b24a5f4
--- /dev/null
+++ b/include/media/EffectBassBoostApi.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_EFFECTBASSBOOSTAPI_H_
+#define ANDROID_EFFECTBASSBOOSTAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
+
+/* enumerated parameter settings for BassBoost effect */
+typedef enum
+{
+    BASSBOOST_PARAM_STRENGTH_SUPPORTED,
+    BASSBOOST_PARAM_STRENGTH
+} t_bassboost_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTBASSBOOSTAPI_H_*/
diff --git a/include/media/EffectReverbApi.h b/include/media/EffectEnvironmentalReverbApi.h
similarity index 79%
rename from include/media/EffectReverbApi.h
rename to include/media/EffectEnvironmentalReverbApi.h
index 6371adb..d490f71 100644
--- a/include/media/EffectReverbApi.h
+++ b/include/media/EffectEnvironmentalReverbApi.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EFFECTREVERBAPI_H_
-#define ANDROID_EFFECTREVERBAPI_H_
+#ifndef ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
+#define ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
 
 #include <media/EffectApi.h>
 
@@ -27,14 +27,9 @@
 static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
 const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
 
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
-
-/* enumerated parameter settings for Reverb effect */
+/* enumerated parameter settings for environmental reverb effect */
 typedef enum
 {
-    REVERB_PARAM_BYPASS,
-    REVERB_PARAM_PRESET,
     // Parameters below are as defined in OpenSL ES specification for environmental reverb interface
     REVERB_PARAM_ROOM_LEVEL,            // in millibels,    range -6000 to 0
     REVERB_PARAM_ROOM_HF_LEVEL,         // in millibels,    range -4000 to 0
@@ -46,17 +41,9 @@
     REVERB_PARAM_REVERB_DELAY,          // in milliseconds, range 0 to 65
     REVERB_PARAM_DIFFUSION,             // in permilles,    range 0 to 1000
     REVERB_PARAM_DENSITY,               // in permilles,    range 0 to 1000
-    REVERB_PARAM_PROPERTIES
-} t_reverb_params;
-
-
-typedef enum
-{
-    REVERB_PRESET_LARGE_HALL,
-    REVERB_PRESET_HALL,
-    REVERB_PRESET_CHAMBER,
-    REVERB_PRESET_ROOM,
-} t_reverb_presets;
+    REVERB_PARAM_PROPERTIES,
+    REVERB_PARAM_BYPASS
+} t_env_reverb_params;
 
 //t_reverb_properties is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
 typedef struct s_reverb_properties {
@@ -79,4 +66,4 @@
 #endif
 
 
-#endif /*ANDROID_EFFECTREVERBAPI_H_*/
+#endif /*ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_*/
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
new file mode 100644
index 0000000..34ffffe
--- /dev/null
+++ b/include/media/EffectPresetReverbApi.h
@@ -0,0 +1,54 @@
+/*
+ * 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_EFFECTPRESETREVERBAPI_H_
+#define ANDROID_EFFECTPRESETREVERBAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
+
+/* enumerated parameter settings for preset reverb effect */
+typedef enum
+{
+    REVERB_PARAM_PRESET
+} t_preset_reverb_params;
+
+
+typedef enum
+{
+    REVERB_PRESET_NONE,
+    REVERB_PRESET_SMALLROOM,
+    REVERB_PRESET_MEDIUMROOM,
+    REVERB_PRESET_LARGEROOM,
+    REVERB_PRESET_MEDIUMHALL,
+    REVERB_PRESET_LARGEHALL,
+    REVERB_PRESET_PLATE
+} t_reverb_presets;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTPRESETREVERBAPI_H_*/
diff --git a/include/media/EffectVirtualizerApi.h b/include/media/EffectVirtualizerApi.h
new file mode 100644
index 0000000..601c384
--- /dev/null
+++ b/include/media/EffectVirtualizerApi.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_EFFECTVIRTUALIZERAPI_H_
+#define ANDROID_EFFECTVIRTUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
+
+/* enumerated parameter settings for virtualizer effect */
+typedef enum
+{
+    VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
+    VIRTUALIZER_PARAM_STRENGTH
+} t_virtualizer_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVIRTUALIZERAPI_H_*/
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/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 497965c..5e9e368 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -48,6 +48,7 @@
     virtual status_t close() = 0;
     virtual status_t reset() = 0;
     virtual status_t getMaxAmplitude(int *max) = 0;
+    virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
 
 private:
     MediaRecorderBase(const MediaRecorderBase &);
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index c04105e..f75d80d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -52,6 +52,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     status_t doStop();
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/media/stagefright/foundation/AHandler.h b/include/media/stagefright/foundation/AHandler.h
index 9fccead..b008b54 100644
--- a/include/media/stagefright/foundation/AHandler.h
+++ b/include/media/stagefright/foundation/AHandler.h
@@ -34,6 +34,8 @@
         return mID;
     }
 
+    sp<ALooper> looper();
+
 protected:
     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
 
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 1c6869c..c1bd4ed 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -34,10 +34,12 @@
     void postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
     void deliverMessage(const sp<AMessage> &msg);
 
+    sp<ALooper> findLooper(ALooper::handler_id handlerID);
+
 private:
     struct HandlerInfo {
-        sp<ALooper> mLooper;
-        sp<AHandler> mHandler;
+        wp<ALooper> mLooper;
+        wp<AHandler> mHandler;
     };
 
     Mutex mLock;
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/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 2dfe2a8..11714d5 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -33,6 +33,7 @@
 #include <semaphore.h>
 #include <ui/Input.h>
 #include <utils/Errors.h>
+#include <utils/PollLoop.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
@@ -345,11 +346,15 @@
     
     android::status_t consume(android::InputEvent** event);
     
+    void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
+    const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
+    
     virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
     
 private:
     android::InputConsumer mConsumer;
     android::PreallocatedInputEventFactory mInputEventFactory;
+    android::sp<android::PollLoop> mPollLoop;
 };
 
 #endif // _UI_INPUT_TRANSPORT_H
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index a213c09..4e65a2d 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -20,31 +20,28 @@
 #include <utils/TypeHelpers.h>
 #include <ui/Point.h>
 
+#include <android/rect.h>
+
 namespace android {
 
-class Rect
+class Rect : public ARect
 {
 public:
-    int left;
-    int top;
-    int right;
-    int bottom;
-
-    typedef int value_type;
+    typedef int32_t value_type;
 
     // we don't provide copy-ctor and operator= on purpose
     // because we want the compiler generated versions
 
     inline Rect() {
     }
-    inline Rect(int w, int h)
-        : left(0), top(0), right(w), bottom(h) {
+    inline Rect(int32_t w, int32_t h) {
+        left = top = 0; right = w; bottom = h;
     }
-    inline Rect(int l, int t, int r, int b)
-        : left(l), top(t), right(r), bottom(b) {
+    inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) {
+        left = l; top = t; right = r; bottom = b;
     }
-    inline Rect(const Point& lt, const Point& rb) 
-        : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {
+    inline Rect(const Point& lt, const Point& rb) {
+        left = lt.x; top = lt.y; right = rb.x; bottom = rb.y;
     }
 
     void makeInvalid();
@@ -68,12 +65,12 @@
     }
 
     // rectangle's width
-    inline int width() const {
+    inline int32_t width() const {
         return right-left;
     }
     
     // rectangle's height
-    inline int height() const {
+    inline int32_t height() const {
         return bottom-top;
     }
 
@@ -136,12 +133,12 @@
     const Rect operator + (const Point& rhs) const;
     const Rect operator - (const Point& rhs) const;
 
-    void translate(int dx, int dy) { // legacy, don't use.
+    void translate(int32_t dx, int32_t dy) { // legacy, don't use.
         offsetBy(dx, dy);
     }
  
-    Rect&   offsetTo(int x, int y);
-    Rect&   offsetBy(int x, int y);
+    Rect&   offsetTo(int32_t x, int32_t y);
+    Rect&   offsetBy(int32_t x, int32_t y);
     bool    intersect(const Rect& with, Rect* result) const;
 };
 
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
new file mode 100644
index 0000000..075927c
--- /dev/null
+++ b/include/utils/ObbFile.h
@@ -0,0 +1,87 @@
+/*
+ * 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 OBBFILE_H_
+#define OBBFILE_H_
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class ObbFile : public RefBase {
+protected:
+    virtual ~ObbFile();
+
+public:
+    ObbFile();
+
+    bool readFrom(const char* filename);
+    bool readFrom(int fd);
+    bool writeTo(const char* filename);
+    bool writeTo(int fd);
+
+    const char* getFileName() const {
+        return mFileName;
+    }
+
+    const String8 getPackageName() const {
+        return mPackageName;
+    }
+
+    int32_t getVersion() const {
+        return mVersion;
+    }
+
+    void setPackageName(String8 packageName) {
+        mPackageName = packageName;
+    }
+
+    void setVersion(int32_t version) {
+        mVersion = version;
+    }
+
+    static inline uint32_t get4LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+
+    static inline void put4LE(unsigned char* buf, uint32_t val) {
+        buf[0] = val & 0xFF;
+        buf[1] = (val >> 8) & 0xFF;
+        buf[2] = (val >> 16) & 0xFF;
+        buf[3] = (val >> 24) & 0xFF;
+    }
+
+private:
+    /* Package name this ObbFile is associated with */
+    String8 mPackageName;
+
+    /* Package version this ObbFile is associated with */
+    int32_t mVersion;
+
+    const char* mFileName;
+
+    size_t mFileSize;
+
+    unsigned char* mReadBuf;
+
+    bool parseObbFile(int fd);
+};
+
+}
+#endif /* OBBFILE_H_ */
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index a95fb17..81230e8 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -22,17 +22,27 @@
 
 #include <sys/poll.h>
 
+#include <android/looper.h>
+
+struct ALooper : public android::RefBase {
+protected:
+    virtual ~ALooper() { }
+
+public:
+    ALooper() { }
+};
+
 namespace android {
 
 /**
  * A basic file descriptor polling loop based on poll() with callbacks.
  */
-class PollLoop : public RefBase {
+class PollLoop : public ALooper {
 protected:
     virtual ~PollLoop();
 
 public:
-    PollLoop();
+    PollLoop(bool allowNonCallbacks);
 
     /**
      * A callback that it to be invoked when an event occurs on a file descriptor.
@@ -44,6 +54,12 @@
      */
     typedef bool (*Callback)(int fd, int events, void* data);
 
+    enum {
+        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
+        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
+        POLL_ERROR = ALOOPER_POLL_ERROR,
+    };
+    
     /**
      * Performs a single call to poll() with optional timeout in milliseconds.
      * Invokes callbacks for all file descriptors on which an event occurred.
@@ -51,16 +67,25 @@
      * If the timeout is zero, returns immediately without blocking.
      * If the timeout is negative, waits indefinitely until awoken.
      *
-     * Returns true if a callback was invoked or if the loop was awoken by wake().
-     * Returns false if a timeout or error occurred.
+     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
      *
-     * This method must only be called on the main thread.
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing a file descriptor if it has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outEvents and outData will contain the poll
+     * events and data associated with the fd.
+     *
+     * This method must only be called on the thread owning the PollLoop.
      * This method blocks until either a file descriptor is signalled, a timeout occurs,
      * or wake() is called.
      * This method does not return until it has finished invoking the appropriate callbacks
      * for all file descriptors that were signalled.
      */
-    bool pollOnce(int timeoutMillis);
+    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
 
     /**
      * Wakes the loop asynchronously.
@@ -71,6 +96,12 @@
     void wake();
 
     /**
+     * Control whether this PollLoop instance allows using IDs instead
+     * of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+    
+    /**
      * Sets the callback for a file descriptor, replacing the existing one, if any.
      * It is an error to call this method with events == 0 or callback == NULL.
      *
@@ -83,6 +114,12 @@
     void setCallback(int fd, int events, Callback callback, void* data = NULL);
 
     /**
+     * Like setCallback(), but for the NDK callback function.
+     */
+    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+            void* data);
+    
+    /**
      * Removes the callback for a file descriptor, if one exists.
      *
      * When this method returns, it is safe to close the file descriptor since the poll loop
@@ -100,9 +137,22 @@
      */
     bool removeCallback(int fd);
 
+    /**
+     * Set the given PollLoop to be associated with the
+     * calling thread.  There must be a 1:1 relationship between
+     * PollLoop and thread.
+     */
+    static void setForThread(const sp<PollLoop>& pollLoop);
+    
+    /**
+     * Return the PollLoop associated with the calling thread.
+     */
+    static sp<PollLoop> getForThread();
+    
 private:
     struct RequestedCallback {
         Callback callback;
+        ALooper_callbackFunc* looperCallback;
         void* data;
     };
 
@@ -110,9 +160,12 @@
         int fd;
         int events;
         Callback callback;
+        ALooper_callbackFunc* looperCallback;
         void* data;
     };
-
+    
+    const bool mAllowNonCallbacks;
+    
     Mutex mLock;
     bool mPolling;
     uint32_t mWaiters;
@@ -126,12 +179,17 @@
     Vector<RequestedCallback> mRequestedCallbacks;
 
     Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce
-
+    Vector<PendingCallback> mPendingFds;       // used privately by pollOnce
+    size_t mPendingFdsPos;
+    
     void openWakePipe();
     void closeWakePipe();
 
+    void setCallbackCommon(int fd, int events, Callback callback,
+            ALooper_callbackFunc* looperCallback, void* data);
     ssize_t getRequestIndexLocked(int fd);
     void wakeAndLock();
+    static void threadDestructor(void *st);
 };
 
 } // namespace android
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..f809cba 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -54,7 +54,7 @@
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy) {
-    mPollLoop = new PollLoop();
+    mPollLoop = new PollLoop(false);
 
     mInboundQueue.head.refCount = -1;
     mInboundQueue.head.type = EventEntry::TYPE_SENTINEL;
@@ -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/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 66b9576..5694e00 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -18,11 +18,11 @@
 
 namespace android {
 
-static inline int min(int a, int b) {
+static inline int32_t min(int32_t a, int32_t b) {
     return (a<b) ? a : b;
 }
 
-static inline int max(int a, int b) {
+static inline int32_t max(int32_t a, int32_t b) {
     return (a>b) ? a : b;
 }
 
@@ -53,7 +53,7 @@
     return false;
 }
 
-Rect& Rect::offsetTo(int x, int y)
+Rect& Rect::offsetTo(int32_t x, int32_t y)
 {
     right -= left - x;
     bottom -= top - y;
@@ -62,7 +62,7 @@
     return *this;
 }
 
-Rect& Rect::offsetBy(int x, int y)
+Rect& Rect::offsetBy(int32_t x, int32_t y)
 {
     left += x;
     top  += y;
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 7d4524a..2bb42ab 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -26,6 +26,7 @@
 	Debug.cpp \
 	FileMap.cpp \
 	Flattenable.cpp \
+	ObbFile.cpp \
 	Pool.cpp \
 	RefBase.cpp \
 	ResourceTypes.cpp \
@@ -65,6 +66,11 @@
 endif
 endif
 
+ifeq ($(HOST_OS),darwin)
+# MacOS doesn't have lseek64. However, off_t is 64-bit anyway.
+LOCAL_CFLAGS += -DOFF_T_IS_64_BIT
+endif
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
new file mode 100644
index 0000000..fe49300
--- /dev/null
+++ b/libs/utils/ObbFile.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "ObbFile"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+
+//#define DEBUG 1
+
+#define kFooterTagSize 8  /* last two 32-bit integers */
+
+#define kFooterMinSize 21 /* 32-bit signature version
+                           * 32-bit package version
+                           * 32-bit package name size
+                           * 1-character package name
+                           * 32-bit footer size
+                           * 32-bit footer marker
+                           */
+
+#define kMaxBufSize    32768 /* Maximum file read buffer */
+
+#define kSignature     0x01059983U /* ObbFile signature */
+
+#define kSigVersion    1 /* We only know about signature version 1 */
+
+/* offsets in version 1 of the header */
+#define kPackageVersionOffset 4
+#define kPackageNameLenOffset 8
+#define kPackageNameOffset    12
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+/*
+ * Work around situations where off_t is 64-bit and use off64_t in
+ * situations where it's 32-bit.
+ */
+#ifdef OFF_T_IS_64_BIT
+#define my_lseek64 lseek
+typedef off_t my_off64_t;
+#else
+#define my_lseek64 lseek64
+typedef off64_t my_off64_t;
+#endif
+
+namespace android {
+
+ObbFile::ObbFile() :
+        mVersion(-1) {
+}
+
+ObbFile::~ObbFile() {
+}
+
+bool ObbFile::readFrom(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_RDONLY);
+    if (fd < 0) {
+        LOGW("couldn't open file %s: %s", filename, strerror(errno));
+        goto out;
+    }
+    success = readFrom(fd);
+    close(fd);
+
+    if (!success) {
+        LOGW("failed to read from %s (fd=%d)\n", filename, fd);
+    }
+
+out:
+    return success;
+}
+
+bool ObbFile::readFrom(int fd)
+{
+    if (fd < 0) {
+        LOGW("attempt to read from invalid fd\n");
+        return false;
+    }
+
+    return parseObbFile(fd);
+}
+
+bool ObbFile::parseObbFile(int fd)
+{
+    my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
+
+    if (fileLength < kFooterMinSize) {
+        if (fileLength < 0) {
+            LOGW("error seeking in ObbFile: %s\n", strerror(errno));
+        } else {
+            LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
+        }
+        return false;
+    }
+
+    ssize_t actual;
+    size_t footerSize;
+
+    {
+        my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
+
+        char *footer = new char[kFooterTagSize];
+        actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
+        if (actual != kFooterTagSize) {
+            LOGW("couldn't read footer signature: %s\n", strerror(errno));
+            return false;
+        }
+
+        unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
+        if (fileSig != kSignature) {
+            LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
+                    kSignature, fileSig);
+            return false;
+        }
+
+        footerSize = get4LE((unsigned char*)footer);
+        if (footerSize > (size_t)fileLength - kFooterTagSize
+                || footerSize > kMaxBufSize) {
+            LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
+                    footerSize, fileLength);
+            return false;
+        }
+
+        if (footerSize < kFooterMinSize) {
+            LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n",
+                    footerSize, kFooterMinSize);
+            return false;
+        }
+    }
+
+    my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
+    if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
+        LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
+        return false;
+    }
+
+    char* scanBuf = (char*)malloc(footerSize);
+    if (scanBuf == NULL) {
+        LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
+        return false;
+    }
+
+    actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
+    // readAmount is guaranteed to be less than kMaxBufSize
+    if (actual != (ssize_t)footerSize) {
+        LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+#ifdef DEBUG
+    for (int i = 0; i < footerSize; ++i) {
+        LOGI("char: 0x%02x", scanBuf[i]);
+    }
+#endif
+
+    uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
+    if (sigVersion != kSigVersion) {
+        LOGW("Unsupported ObbFile version %d\n", sigVersion);
+        free(scanBuf);
+        return false;
+    }
+
+    mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
+
+    uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
+    if (packageNameLen <= 0
+            || packageNameLen > (footerSize - kPackageNameOffset)) {
+        LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
+                packageNameLen, footerSize - kPackageNameOffset);
+        free(scanBuf);
+        return false;
+    }
+
+    char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
+    mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
+
+    free(scanBuf);
+
+#ifdef DEBUG
+    LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
+#endif
+
+    return true;
+}
+
+bool ObbFile::writeTo(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_WRONLY);
+    if (fd < 0) {
+        goto out;
+    }
+    success = writeTo(fd);
+    close(fd);
+
+out:
+    if (!success) {
+        LOGW("failed to write to %s: %s\n", filename, strerror(errno));
+    }
+    return success;
+}
+
+bool ObbFile::writeTo(int fd)
+{
+    if (fd < 0) {
+        return false;
+    }
+
+    my_lseek64(fd, 0, SEEK_END);
+
+    if (mPackageName.size() == 0 || mVersion == -1) {
+        LOGW("tried to write uninitialized ObbFile data");
+        return false;
+    }
+
+    unsigned char intBuf[sizeof(uint32_t)+1];
+    memset(&intBuf, 0, sizeof(intBuf));
+
+    put4LE(intBuf, kSigVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write signature version: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, mVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package version");
+        return false;
+    }
+
+    size_t packageNameLen = mPackageName.size();
+    put4LE(intBuf, packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package name length: %s", strerror(errno));
+        return false;
+    }
+
+    if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
+        LOGW("couldn't write package name: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer size: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, kSignature);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer magic signature: %s", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+}
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 20a4d13..f740fa0 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -21,8 +21,13 @@
 
 namespace android {
 
-PollLoop::PollLoop() :
-        mPolling(false), mWaiters(0) {
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+PollLoop::PollLoop(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
+        mWaiters(0), mPendingFdsPos(0) {
     openWakePipe();
 }
 
@@ -30,6 +35,41 @@
     closeWakePipe();
 }
 
+void PollLoop::threadDestructor(void *st) {
+    PollLoop* const self = static_cast<PollLoop*>(st);
+    if (self != NULL) {
+        self->decStrong((void*)threadDestructor);
+    }
+}
+
+void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
+    sp<PollLoop> old = getForThread();
+    
+    if (pollLoop != NULL) {
+        pollLoop->incStrong((void*)threadDestructor);
+    }
+    
+    pthread_setspecific(gTLS, pollLoop.get());
+    
+    if (old != NULL) {
+        old->decStrong((void*)threadDestructor);
+    }
+}
+    
+sp<PollLoop> PollLoop::getForThread() {
+    if (!gHaveTLS) {
+        pthread_mutex_lock(&gTLSMutex);
+        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            return NULL;
+        }
+        gHaveTLS = true;
+        pthread_mutex_unlock(&gTLSMutex);
+    }
+    
+    return (PollLoop*)pthread_getspecific(gTLS);
+}
+
 void PollLoop::openWakePipe() {
     int wakeFds[2];
     int result = pipe(wakeFds);
@@ -54,6 +94,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = NULL;
+    requestedCallback.looperCallback = NULL;
     requestedCallback.data = NULL;
     mRequestedCallbacks.insertAt(requestedCallback, 0);
 }
@@ -66,7 +107,18 @@
     //       method is currently only called by the destructor.
 }
 
-bool PollLoop::pollOnce(int timeoutMillis) {
+int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+    // If there are still pending fds from the last call, dispatch those
+    // first, to avoid an earlier fd from starving later ones.
+    const size_t pendingFdsCount = mPendingFds.size();
+    if (mPendingFdsPos < pendingFdsCount) {
+        const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
+        mPendingFdsPos++;
+        if (outEvents != NULL) *outEvents = pending.events;
+        if (outData != NULL) *outData = pending.data;
+        return pending.fd;
+    }
+    
     mLock.lock();
     while (mWaiters != 0) {
         mResume.wait(mLock);
@@ -74,7 +126,7 @@
     mPolling = true;
     mLock.unlock();
 
-    bool result;
+    int32_t result;
     size_t requestedCount = mRequestedFds.size();
 
 #if DEBUG_POLL_AND_WAKE
@@ -91,7 +143,7 @@
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - timeout", this);
 #endif
-        result = false;
+        result = POLL_TIMEOUT;
         goto Done;
     }
 
@@ -103,7 +155,7 @@
         if (errno != EINTR) {
             LOGW("Poll failed with an unexpected error, errno=%d", errno);
         }
-        result = false;
+        result = POLL_ERROR;
         goto Done;
     }
 
@@ -116,36 +168,44 @@
 #endif
 
     mPendingCallbacks.clear();
+    mPendingFds.clear();
+    mPendingFdsPos = 0;
+    if (outEvents != NULL) *outEvents = 0;
+    if (outData != NULL) *outData = NULL;
+    
+    result = POLL_CALLBACK;
     for (size_t i = 0; i < requestedCount; i++) {
         const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
 
         short revents = requestedFd.revents;
         if (revents) {
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
-            Callback callback = requestedCallback.callback;
+            PendingCallback pending;
+            pending.fd = requestedFd.fd;
+            pending.events = revents;
+            pending.callback = requestedCallback.callback;
+            pending.looperCallback = requestedCallback.looperCallback;
+            pending.data = requestedCallback.data;
 
-            if (callback) {
-                PendingCallback pendingCallback;
-                pendingCallback.fd = requestedFd.fd;
-                pendingCallback.events = requestedFd.revents;
-                pendingCallback.callback = callback;
-                pendingCallback.data = requestedCallback.data;
-                mPendingCallbacks.push(pendingCallback);
-            } else {
-                if (requestedFd.fd == mWakeReadPipeFd) {
-#if DEBUG_POLL_AND_WAKE
-                    LOGD("%p ~ pollOnce - awoken", this);
-#endif
-                    char buffer[16];
-                    ssize_t nRead;
-                    do {
-                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                    } while (nRead == sizeof(buffer));
+            if (pending.callback || pending.looperCallback) {
+                mPendingCallbacks.push(pending);
+            } else if (pending.fd != mWakeReadPipeFd) {
+                if (result == POLL_CALLBACK) {
+                    result = pending.fd;
+                    if (outEvents != NULL) *outEvents = pending.events;
+                    if (outData != NULL) *outData = pending.data;
                 } else {
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-                    LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
-#endif
+                    mPendingFds.push(pending);
                 }
+            } else {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - awoken", this);
+#endif
+                char buffer[16];
+                ssize_t nRead;
+                do {
+                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+                } while (nRead == sizeof(buffer));
             }
 
             respondedCount -= 1;
@@ -154,7 +214,6 @@
             }
         }
     }
-    result = true;
 
 Done:
     mLock.lock();
@@ -164,7 +223,7 @@
     }
     mLock.unlock();
 
-    if (result) {
+    if (result == POLL_CALLBACK || result >= 0) {
         size_t pendingCount = mPendingCallbacks.size();
         for (size_t i = 0; i < pendingCount; i++) {
             const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
@@ -172,8 +231,14 @@
             LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
 #endif
 
-            bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
-                    pendingCallback.data);
+            bool keep = true;
+            if (pendingCallback.callback != NULL) {
+                keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
+                        pendingCallback.data);
+            } else {
+                keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
+                        pendingCallback.data) != 0;
+            }
             if (! keep) {
                 removeCallback(pendingCallback.fd);
             }
@@ -199,17 +264,38 @@
     }
 }
 
+bool PollLoop::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
 void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
+    setCallbackCommon(fd, events, callback, NULL, data);
+}
+
+void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+        void* data) {
+    setCallbackCommon(fd, events, NULL, callback, data);
+}
+
+void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
+        ALooper_callbackFunc* looperCallback, void* data) {
+
 #if DEBUG_CALLBACKS
     LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
 #endif
 
-    if (! events || ! callback) {
-        LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
+    if (! events) {
+        LOGE("Invalid attempt to set a callback with no selected poll events.");
         removeCallback(fd);
         return;
     }
 
+    if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
+        LOGE("Invalid attempt to set NULL callback but not allowed.");
+        removeCallback(fd);
+        return;
+    }
+    
     wakeAndLock();
 
     struct pollfd requestedFd;
@@ -218,6 +304,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = callback;
+    requestedCallback.looperCallback = looperCallback;
     requestedCallback.data = data;
 
     ssize_t index = getRequestIndexLocked(fd);
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 92ebfd7c..f1b8cd5 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -3,6 +3,7 @@
 include $(CLEAR_VARS)
 
 test_src_files := \
+	ObbFile_test.cpp \
 	PollLoop_test.cpp
 
 shared_libraries := \
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
new file mode 100644
index 0000000..29bb70a
--- /dev/null
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "ObbFile_test"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.obb"
+
+class ObbFileTest : public testing::Test {
+protected:
+    sp<ObbFile> mObbFile;
+    char* mExternalStorage;
+    char* mFileName;
+
+    virtual void SetUp() {
+        mObbFile = new ObbFile();
+        mExternalStorage = getenv("EXTERNAL_STORAGE");
+
+        const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1;
+        mFileName = new char[totalLen];
+        snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME);
+
+        int fd = ::open(mFileName, O_CREAT | O_TRUNC);
+        if (fd < 0) {
+            FAIL() << "Couldn't create " << mFileName << " for tests";
+        }
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ObbFileTest, ReadFailure) {
+    EXPECT_FALSE(mObbFile->readFrom(-1))
+            << "No failure on invalid file descriptor";
+}
+
+TEST_F(ObbFileTest, WriteThenRead) {
+    const char* packageName = "com.example.obbfile";
+    const int32_t versionNum = 1;
+
+    mObbFile->setPackageName(String8(packageName));
+    mObbFile->setVersion(versionNum);
+
+    EXPECT_TRUE(mObbFile->writeTo(mFileName))
+            << "couldn't write to fake .obb file";
+
+    mObbFile = new ObbFile();
+
+    EXPECT_TRUE(mObbFile->readFrom(mFileName))
+            << "couldn't read from fake .obb file";
+
+    EXPECT_EQ(versionNum, mObbFile->getVersion())
+            << "version didn't come out the same as it went in";
+    const char* currentPackageName = mObbFile->getPackageName().string();
+    EXPECT_STREQ(packageName, currentPackageName)
+            << "package name didn't come out the same as it went in";
+}
+
+}
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
index 4848c0f..02f1808 100644
--- a/libs/utils/tests/PollLoop_test.cpp
+++ b/libs/utils/tests/PollLoop_test.cpp
@@ -87,7 +87,7 @@
     sp<PollLoop> mPollLoop;
 
     virtual void SetUp() {
-        mPollLoop = new PollLoop();
+        mPollLoop = new PollLoop(false);
     }
 
     virtual void TearDown() {
@@ -98,26 +98,26 @@
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
     mPollLoop->wake();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because wake() was called before waiting";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
@@ -125,24 +125,24 @@
     delayedWake->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal wake delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
@@ -152,13 +152,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -171,13 +171,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -193,13 +193,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -212,15 +212,15 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -238,15 +238,15 @@
     delayedWriteSignal->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal signal delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -264,15 +264,15 @@
     mPollLoop->removeCallback(pipe.receiveFd);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout because FD was no longer registered";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not be invoked";
 }
@@ -287,15 +287,15 @@
     pipe.writeSignal();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked";
 
@@ -310,8 +310,8 @@
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because timeout was zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should not be invoked this time";
 }
@@ -351,15 +351,15 @@
     pipe.writeSignal(); // would cause FD to be considered signalled
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(0, handler1.callbackCount)
             << "original handler callback should not be invoked because it was replaced";
     EXPECT_EQ(1, handler2.callbackCount)
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index b1b7fed0..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/BassBoost.java b/media/java/android/media/BassBoost.java
new file mode 100644
index 0000000..ef4ce05
--- /dev/null
+++ b/media/java/android/media/BassBoost.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to an simple equalizer but limited to one band amplification in the low frequency range.
+ * <p>An application creates a BassBoost object to instantiate and control a bass boost engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLBassBoostItf interface. Please refer to this specification for more details.
+ * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. If the audio session ID 0
+ * is specified, the BassBoost applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class BassBoost extends AudioEffect {
+
+    private final static String TAG = "BassBoost";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectBassBoostApi.h
+    /**
+     * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Bass boost effect strength. Parameter ID for
+     * {@link android.media.BassBoost.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the bass boost engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the BassBoost
+     * engine. As the same 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 BassBoost will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the BassBoost will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public BassBoost(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the bass boost effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the BassBoost when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * BassBoost engine.
+         * @param effect the BassBoost on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(BassBoost effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(BassBoost.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/EnvironmentalReverb.java b/media/java/android/media/EnvironmentalReverb.java
new file mode 100644
index 0000000..88230fc
--- /dev/null
+++ b/media/java/android/media/EnvironmentalReverb.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The EnvironmentalReverb class allows an application to control each reverb engine property in a
+ * global reverb environment and is more suitable for games. For basic control, more suitable for
+ * music applications, it is recommended to use the
+ // TODO when PresetReverb is unhidden
+ // {_at_link android.media.PresetReverb} class.
+ * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLEnvironmentalReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The EnvironmentalReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling
+ * audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class EnvironmentalReverb extends AudioEffect {
+
+    private final static String TAG = "EnvironmentalReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEnvironmentalReverbApi.h
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.EnvironmentalReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_ROOM_LEVEL = 0;
+    /**
+     * Room HF level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_ROOM_HF_LEVEL = 1;
+    /**
+     * Decay time. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_TIME = 2;
+    /**
+     * Decay HF ratio. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_HF_RATIO = 3;
+    /**
+     * Early reflections level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_LEVEL = 4;
+    /**
+     * Early reflections delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_DELAY = 5;
+    /**
+     * Reverb level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_LEVEL = 6;
+    /**
+     * Reverb delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_DELAY = 7;
+    /**
+     * Diffusion. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DIFFUSION = 8;
+    /**
+     * Density. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DENSITY = 9;
+
+    /**
+     * Registered listener for parameter changes
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super
+     * class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * EnvironmentalReverb engine. As the same 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 EnvironmentalReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the EnvironmentalReverb will apply to the output mix.
+     *  As the EnvironmentalReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public EnvironmentalReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_ENV_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     * Sets the master volume level of the environmental reverb effect.
+     * @param room Room level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomLevel(short room)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(room);
+        checkStatus(setParameter(PARAM_ROOM_LEVEL, param));
+    }
+
+    /**
+     * Gets the master volume level of the environmental reverb effect.
+     * @return the room level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level at 5 kHz relative to the volume level at low frequencies of the
+     * overall reverb effect.
+     * <p>This controls a low-pass filter that will reduce the level of the high-frequency.
+     * @param roomHF High frequency attenuation level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomHFLevel(short roomHF)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(roomHF);
+        checkStatus(setParameter(PARAM_ROOM_HF_LEVEL, param));
+    }
+
+    /**
+     * Gets the room HF level.
+     * @return the room HF level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomHFLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_HF_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time taken for the level of reverberation to decay by 60 dB.
+     * @param decayTime Decay time in milliseconds. The valid range is [100, 20000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayTime(int decayTime)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(decayTime);
+        checkStatus(setParameter(PARAM_DECAY_TIME, param));
+    }
+
+    /**
+     * Gets the decay time.
+     * @return the decay time in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getDecayTime()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_DECAY_TIME, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the ratio of high frequency decay time (at 5 kHz) relative to the decay time at low
+     * frequencies.
+     * @param decayHFRatio High frequency decay ratio using a permille scale. The valid range is
+     * [100, 2000]. A ratio of 1000 indicates that all frequencies decay at the same rate.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayHFRatio(short decayHFRatio)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(decayHFRatio);
+        checkStatus(setParameter(PARAM_DECAY_HF_RATIO, param));
+    }
+
+    /**
+     * Gets the ratio of high frequency decay time (at 5 kHz) relative to low frequencies.
+     * @return the decay HF ration. See {@link #setDecayHFRatio(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDecayHFRatio()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DECAY_HF_RATIO, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level of the early reflections.
+     * <p>This level is combined with the overall room level
+     * (set using {@link #setRoomLevel(short)}).
+     * @param reflectionsLevel Reflection level in millibels. The valid range is [-9000, 1000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsLevel(short reflectionsLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reflectionsLevel);
+        checkStatus(setParameter(PARAM_REFLECTIONS_LEVEL, param));
+    }
+
+    /**
+     * Gets the volume level of the early reflections.
+     * @return the early reflections level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReflectionsLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REFLECTIONS_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the delay time for the early reflections.
+     * <p>This method sets the time between when the direct path is heard and when the first
+     * reflection is heard.
+     * @param reflectionsDelay Reflections delay in milliseconds. The valid range is [0, 300].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsDelay(int reflectionsDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reflectionsDelay);
+        checkStatus(setParameter(PARAM_REFLECTIONS_DELAY, param));
+    }
+
+    /**
+     * Gets the reflections delay.
+     * @return the early reflections delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReflectionsDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REFLECTIONS_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the volume level of the late reverberation.
+     * <p>This level is combined with the overall room level (set using {@link #setRoomLevel(short)}).
+     * @param reverbLevel Reverb level in millibels. The valid range is [-9000, 2000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbLevel(short reverbLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reverbLevel);
+        checkStatus(setParameter(PARAM_REVERB_LEVEL, param));
+    }
+
+    /**
+     * Gets the reverb level.
+     * @return the reverb level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReverbLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REVERB_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time between the first reflection and the reverberation.
+     * @param reverbDelay Reverb delay in milliseconds. The valid range is [0, 100].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbDelay(int reverbDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reverbDelay);
+        checkStatus(setParameter(PARAM_REVERB_DELAY, param));
+    }
+
+    /**
+     * Gets the reverb delay.
+     * @return the reverb delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReverbDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REVERB_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the echo density in the late reverberation decay.
+     * <p>The scale should approximately map linearly to the perceived change in reverberation.
+     * @param diffusion Diffusion specified using a permille scale. The diffusion valid range is
+     * [0, 1000]. A value of 1000 o/oo indicates a smooth reverberation decay.
+     * Values below this level give a more <i>grainy</i> character.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDiffusion(short diffusion)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(diffusion);
+        checkStatus(setParameter(PARAM_DIFFUSION, param));
+    }
+
+    /**
+     * Gets diffusion level.
+     * @return the diffusion level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDiffusion()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DIFFUSION, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * Controls the modal density of the late reverberation decay.
+     * <p> The scale should approximately map linearly to the perceived change in reverberation.
+     * A lower density creates a hollow sound that is useful for simulating small reverberation
+     * spaces such as bathrooms.
+     * @param density Density specified using a permille scale. The valid range is [0, 1000].
+     * A value of 1000 o/oo indicates a natural sounding reverberation. Values below this level
+     * produce a more colored effect.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDensity(short density)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(density);
+        checkStatus(setParameter(PARAM_DENSITY, param));
+    }
+
+    /**
+     * Gets the density level.
+     * @return the density level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDensity()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DENSITY, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the EnvironmentalReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * EnvironmentalReverb engine.
+         * @param effect the EnvironmentalReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(EnvironmentalReverb effect, int status, int param, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                int v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(EnvironmentalReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/Equalizer.java
new file mode 100644
index 0000000..082f694
--- /dev/null
+++ b/media/java/android/media/Equalizer.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An Equalizer is used to alter the frequency response of a particular music source or of the main
+ * output mix.
+ * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine
+ * in the audio framework. The application can either simply use predefined presets or have a more
+ * precise control of the gain in each frequency band controlled by the equalizer.
+ * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLEqualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. If the audio session ID 0
+ * is specified, the Equalizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Equalizer extends AudioEffect {
+
+    private final static String TAG = "Equalizer";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEqualizerApi.h
+    /**
+     * Number of bands. Parameter ID for {@link android.media.Equalizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_NUM_BANDS = 0;
+    /**
+     * Band level range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_LEVEL_RANGE = 1;
+    /**
+     * Band level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_LEVEL = 2;
+    /**
+     * Band center frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CENTER_FREQ = 3;
+    /**
+     * Band frequency range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_FREQ_RANGE = 4;
+    /**
+     * Band for a given frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_BAND = 5;
+    /**
+     * Current preset. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CURRENT_PRESET = 6;
+    /**
+     * Request number of presets. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_NUM_OF_PRESETS = 7;
+    /**
+     * Request preset name. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_PRESET_NAME = 8;
+    /**
+     * maximum size for perset name
+     */
+    public static final int PARAM_STRING_SIZE_MAX = 32;
+
+    /**
+     * Number of presets implemented by Equalizer engine
+     */
+    private int mNumPresets;
+    /**
+     * Names of presets implemented by Equalizer engine
+     */
+    private String[] mPresetNames;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Equalizer
+     * engine. As the same 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 Equalizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Equalizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Equalizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        mNumPresets = (int)getNumberOfPresets();
+
+        if (mNumPresets != 0) {
+            mPresetNames = new String[mNumPresets];
+            byte[] value = new byte[PARAM_STRING_SIZE_MAX];
+            int[] param = new int[2];
+            param[0] = PARAM_GET_PRESET_NAME;
+            for (int i = 0; i < mNumPresets; i++) {
+                param[1] = i;
+                checkStatus(getParameter(param, value));
+                int length = 0;
+                while (value[length] != 0) length++;
+                try {
+                    mPresetNames[i] = new String(value, 0, length, "ISO-8859-1");
+                    Log.e(TAG, "preset #: "+i+" name: "+mPresetNames[i]+" length: "+length);
+                } catch (java.io.UnsupportedEncodingException e) {
+                    Log.e(TAG, "preset name decode error");
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the number of frequency bands supported by the Equalizer engine.
+     * @return the number of bands
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfBands()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_NUM_BANDS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the level range for use by {@link #setBandLevel(int,short)}. The level is expressed in
+     * milliBel.
+     * @return the band level range in an array of short integers. The first element is the lower
+     * limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short[] getBandLevelRange()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        int[] value = new int[2];
+        param[0] = PARAM_LEVEL_RANGE;
+        checkStatus(getParameter(param, value));
+
+        short[] result = new short[2];
+
+        result[0] = (short)value[0];
+        result[1] = (short)value[1];
+
+        return result;
+    }
+
+    /**
+     * Sets the given equalizer band to the given gain value.
+     * @param band Frequency band that will have the new gain. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1). See @see #getNumberOfBands().
+     * @param level New gain in millibels that will be set to the given band. getBandLevelRange()
+     * will define the maximum and minimum values.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setBandLevel(int band, short level)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] value = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        value[0] = (int)level;
+        checkStatus(setParameter(param, value));
+    }
+
+    /**
+     * Gets the gain set for the given equalizer band.
+     * @param band Frequency band whose gain is requested. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1).
+     * @return Gain in millibels of the given band.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getBandLevel(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return (short)result[0];
+    }
+
+
+    /**
+     * Gets the center frequency of the given band.
+     * @param band Frequency band whose center frequency is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The center frequency in milliHertz
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getCenterFreq(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_CENTER_FREQ;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets the frequency range of the given frequency band.
+     * @param band Frequency band whose frequency range is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The frequency range in millHertz in an array of integers. The first element is the
+     * lower limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int[] getBandFreqRange(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[2];
+        param[0] = PARAM_BAND_FREQ_RANGE;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result;
+    }
+
+    /**
+     * Gets the band that has the most effect on the given frequency.
+     * @param frequency Frequency in milliHertz which is to be equalized via the returned band.
+     * @return Frequency band that has most effect on the given frequency.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getBand(int frequency)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_GET_BAND;
+        param[1] = frequency;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets current preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getCurrentPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_CURRENT_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Sets the equalizer according to the given preset.
+     * @param preset New preset that will be taken into use. The valid range is [0,
+     * number of presets-1]. See {@see #getNumberOfPresets()}.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void usePreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_CURRENT_PRESET, preset));
+    }
+
+    /**
+     * Gets the total number of presets the equalizer supports. The presets will have indices
+     * [0, number of presets-1].
+     * @return The number of presets the equalizer supports.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfPresets()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_GET_NUM_OF_PRESETS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the preset name based on the index.
+     * @param preset Index of the preset. The valid range is [0, number of presets-1].
+     * @return A string containing the name of the given preset.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public String getPresetName(short preset)
+    {
+        if (preset >= 0 && preset < mNumPresets) {
+            return mPresetNames[preset];
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Equalizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Equalizer engine.
+         * @param effect the Equalizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ...
+         * @param param2 additional parameter qualifier (e.g the band for band level parameter).
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Equalizer effect, int status, int param1, int param2, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p1 = -1;
+                int p2 = -1;
+                int v = -1;
+
+                if (param.length >= 4) {
+                    p1 = byteArrayToInt(param, 0);
+                    if (param.length >= 8) {
+                        p2 = byteArrayToInt(param, 4);
+                    }
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);;
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+
+                if (p1 != -1 && v != -1) {
+                    l.onParameterChange(Equalizer.this, status, p1, p2, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/PresetReverb.java b/media/java/android/media/PresetReverb.java
new file mode 100644
index 0000000..83a01a4
--- /dev/null
+++ b/media/java/android/media/PresetReverb.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The PresetReverb class allows an application to configure the global reverb using a reverb preset.
+ * This is primarily used for adding some reverb in a music playback context. Applications
+ * requiring control over a more advanced environmental reverb are advised to use the
+ // TODO when EnvironmentalReverb is unhidden
+ // {_at_link android.media.EnvironmentalReverb} class.
+ * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the
+ * audio framework.
+ * <p>The methods, parameter types and units exposed by the PresetReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLPresetReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The PresetReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class PresetReverb extends AudioEffect {
+
+    private final static String TAG = "PresetReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectPresetReverbApi.h
+
+    /**
+     * Preset. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_PRESET = 0;
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PRESET_NONE        = 0;
+    public static final int PRESET_SMALLROOM   = 1;
+    public static final int PRESET_MEDIUMROOM  = 2;
+    public static final int PRESET_LARGEROOM   = 3;
+    public static final int PRESET_MEDIUMHALL  = 4;
+    public static final int PRESET_LARGEHALL   = 5;
+    public static final int PRESET_PLATE       = 6;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * PresetReverb engine. As the same 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 PresetReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the PresetReverb will apply to the output mix.
+     *  As the PresetReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public PresetReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     *  Enables a preset on the reverb.
+     *  <p>The reverb PRESET_NONE disables any reverb from the current output but does not free the
+     *  resources associated with the reverb. For an application to signal to the implementation
+     *  to free the resources, it must call the release() method.
+     * @param preset This must be one of the the preset constants defined in this class.
+     * e.g. {@link #PRESET_SMALLROOM}
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setPreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_PRESET, preset));
+    }
+
+    /**
+     * Gets current reverb preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the PresetReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * PresetReverb engine.
+         * @param effect the PresetReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(PresetReverb effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(PresetReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/Virtualizer.java
new file mode 100644
index 0000000..9f71297
--- /dev/null
+++ b/media/java/android/media/Virtualizer.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact
+ * behavior of this effect is dependent on the number of audio input channels and the types and
+ * number of audio output channels of the device. For example, in the case of a stereo input and
+ * stereo headphone output, a stereo widening effect is used when this effect is turned on.
+ * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLVirtualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. If the audio session ID 0
+ * is specified, the Virtualizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Virtualizer extends AudioEffect {
+
+    private final static String TAG = "Virtualizer";
+
+    // These constants must be synchronized with those in frameworks/base/include/media/EffectVirtualizerApi.h
+    /**
+     * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Virtualizer effect strength. Parameter ID for
+     * {@link android.media.Virtualizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the virtualizer engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Virtualizer
+     * engine. As the same 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 Virtualizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Virtualizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Virtualizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the virtualizer effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Virtualizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Virtualizer engine.
+         * @param effect the Virtualizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Virtualizer effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(Virtualizer.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
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..beb3dfc5f 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -323,8 +323,8 @@
                                     priority,
                                     effectCallback,
                                     &lpJniStorage->mCallbackData,
-                                    0,
-                                    sessionId);
+                                    sessionId,
+                                    0);
     if (lpAudioEffect == NULL) {
         LOGE("Error creating AudioEffect");
         goto setup_failure;
@@ -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/EffectReverb.c b/media/libeffects/EffectReverb.c
index ada252c..5c87f23 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -57,7 +57,7 @@
 
 // Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
 static const effect_descriptor_t gAuxPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_AUXILIARY,
@@ -69,7 +69,7 @@
 
 // Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
 static const effect_descriptor_t gInsertPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
@@ -196,7 +196,7 @@
     pReverb = (reverb_object_t*) &pRvbModule->context;
 
     //if bypassed or the preset forces the signal to be completely dry
-    if (pReverb->m_bBypass) {
+    if (pReverb->m_bBypass != 0) {
         if (inBuffer->raw != outBuffer->raw) {
             int16_t smp;
             pSrc = inBuffer->s16;
@@ -520,7 +520,7 @@
         pReverb->m_bUseNoise = true;
 
         // for debugging purposes, allow bypass
-        pReverb->m_bBypass = false;
+        pReverb->m_bBypass = 0;
 
         pReverb->m_nNextRoom = 1;
 
@@ -662,248 +662,254 @@
     int32_t temp2;
     size_t size;
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) {
+            return -EINVAL;
+        }
         size = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        size = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        size = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (*pSize < size) {
-        return -EINVAL;
-    }
-    *pSize = size;
-    pValue32 = (int32_t *) pValue;
-    pValue16 = (int16_t *) pValue;
-    pProperties = (t_reverb_properties *) pValue;
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        *(int32_t *) pValue = (int32_t) pReverb->m_bBypass;
-        break;
-    case REVERB_PARAM_PRESET:
-        *(int32_t *) pValue = (int8_t) pReverb->m_nCurrentRoom;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        pValue16 = &pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert m_nRoomLpfFwd to millibels
-        temp = (pReverb->m_nRoomLpfFwd << 15)
-                / (32767 - pReverb->m_nRoomLpfFbk);
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        if (param == REVERB_PARAM_ROOM_LEVEL) {
-            break;
-        }
-        pValue16 = &pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-        // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
-        // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-
-        temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
-        temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
-                << 1;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
-        temp = 32767 + temp - temp2;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
-        temp = Effects_Sqrt(temp) * 181;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
-        temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
-
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-        // Calculate reverb feedback path gain
-        temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-        temp = Effects_Linear16ToMillibels(temp);
-
-        // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        temp = (-6000 * pReverb->m_nLateDelay) / temp;
-
-        // Convert samples to ms
-        *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
-
-        if (param == REVERB_PARAM_DECAY_TIME) {
-            break;
-        }
-        pValue16 = &pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-        // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
-        //       DT_5000Hz = DT_0Hz * r
-        //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
-        // r = G_0Hz/G_5000Hz in millibels
-        // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
-        // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-        if (pReverb->m_nRvbLpfFbk == 0) {
-            *pValue16 = 1000;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+        pValue16 = (int16_t *)pValue;
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (pReverb->m_bBypass != 0) {
+            *pValue16 = (int16_t)REVERB_PRESET_NONE;
         } else {
-            temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
-            temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+            *pValue16 = (int16_t)(pReverb->m_nNextRoom + 1);
+        }
+        LOGV("get REVERB_PARAM_PRESET, preset %d", *pValue16);
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            size = sizeof(int16_t);
+            break;
+
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            size = sizeof(int32_t);
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            size = sizeof(t_reverb_properties);
+            break;
+
+        default:
+            return -EINVAL;
+        }
+
+        if (*pSize < size) {
+            return -EINVAL;
+        }
+
+        pValue32 = (int32_t *) pValue;
+        pValue16 = (int16_t *) pValue;
+        pProperties = (t_reverb_properties *) pValue;
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            *pValue32 = (int32_t) pReverb->m_bBypass;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            pValue16 = &pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert m_nRoomLpfFwd to millibels
+            temp = (pReverb->m_nRoomLpfFwd << 15)
+                    / (32767 - pReverb->m_nRoomLpfFbk);
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            if (param == REVERB_PARAM_ROOM_LEVEL) {
+                break;
+            }
+            pValue16 = &pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+            // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
+            // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+
+            temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
+            temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
                     << 1;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
             temp = 32767 + temp - temp2;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
             temp = Effects_Sqrt(temp) * 181;
-            temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
-            // The linear gain at 0Hz is b0 / (a1 + 1)
-            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
-                    - pReverb->m_nRvbLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
+            temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
 
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+            // Calculate reverb feedback path gain
+            temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
             temp = Effects_Linear16ToMillibels(temp);
-            temp2 = Effects_Linear16ToMillibels(temp2);
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
 
-            if (temp == 0)
-                temp = 1;
-            temp = (int16_t) ((1000 * temp2) / temp);
+            // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            temp = (-6000 * pReverb->m_nLateDelay) / temp;
+
+            // Convert samples to ms
+            *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
+
+            if (param == REVERB_PARAM_DECAY_TIME) {
+                break;
+            }
+            pValue16 = &pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+            // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
+            //       DT_5000Hz = DT_0Hz * r
+            //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
+            // r = G_0Hz/G_5000Hz in millibels
+            // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
+            // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+            if (pReverb->m_nRvbLpfFbk == 0) {
+                *pValue16 = 1000;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+            } else {
+                temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
+                temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+                        << 1;
+                temp = 32767 + temp - temp2;
+                temp = Effects_Sqrt(temp) * 181;
+                temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
+                // The linear gain at 0Hz is b0 / (a1 + 1)
+                temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
+                        - pReverb->m_nRvbLpfFbk);
+
+                temp = Effects_Linear16ToMillibels(temp);
+                temp2 = Effects_Linear16ToMillibels(temp2);
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
+
+                if (temp == 0)
+                    temp = 1;
+                temp = (int16_t) ((1000 * temp2) / temp);
+                if (temp > 1000)
+                    temp = 1000;
+
+                *pValue16 = temp;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
+            }
+
+            if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+                break;
+            }
+            pValue16 = &pProperties->reflectionsLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // Convert linear gain to millibels
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
+
+            LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REVERB_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
+                    / AP0_GAIN_RANGE);
+
+            if (temp < 0)
+                temp = 0;
             if (temp > 1000)
                 temp = 1000;
 
             *pValue16 = temp;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
-        }
+            LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
 
-        if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+            if (param == REVERB_PARAM_DIFFUSION) {
+                break;
+            }
+            pValue16 = &pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            // Calculate AP delay in time units
+            temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
+                    / pReverb->m_nSamplingRate;
+
+            temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
+
+            if (temp < 0)
+                temp = 0;
+            if (temp > 1000)
+                temp = 1000;
+
+            *pValue16 = temp;
+
+            LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
+            break;
+
+        default:
             break;
         }
-        pValue16 = &pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // Convert linear gain to millibels
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
-
-        LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REVERB_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
-                / AP0_GAIN_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-        LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION) {
-            break;
-        }
-        pValue16 = &pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        // Calculate AP delay in time units
-        temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
-                / pReverb->m_nSamplingRate;
-
-        temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-
-        LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
-        break;
-
-    default:
-        break;
     }
 
+    *pSize = size;
+
     LOGV("Reverb_getParameter, context %p, param %d, value %d",
             pReverb, param, *(int *)pValue);
 
@@ -945,382 +951,386 @@
     LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
             pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
-        paramSize = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        paramSize = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        paramSize = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (size != paramSize) {
-        return -EINVAL;
-    }
-
-    if (paramSize == sizeof(int16_t)) {
-        value16 = *(int16_t *) pValue;
-    } else if (paramSize == sizeof(int32_t)) {
-        value32 = *(int32_t *) pValue;
-    } else {
-        pProperties = (t_reverb_properties *) pValue;
-    }
-
-    pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nCurrentRoom];
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        pReverb->m_bBypass = (uint16_t)value32;
-        break;
-    case REVERB_PARAM_PRESET:
-        if (value32 != REVERB_PRESET_LARGE_HALL && value32
-                != REVERB_PRESET_HALL && value32 != REVERB_PRESET_CHAMBER
-                && value32 != REVERB_PRESET_ROOM)
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || size != sizeof(int16_t)) {
             return -EINVAL;
-        pReverb->m_nNextRoom = (int16_t) value32;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        value16 = pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
-        if (value16 > 0)
-            return -EINVAL;
-
-        temp = Effects_MillibelsToLinear16(value16);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
-
-        LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-        if (param == REVERB_PARAM_ROOM_LEVEL)
-            break;
-        value16 = pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-
-        // Limit to 0 , -40dB range because of low pass implementation
-        if (value16 > 0 || value16 < -4000)
-            return -EINVAL;
-        // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
-        // m_nRoomLpfFbk is -a1 where a1 is the solution of:
-        // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
-        // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
-        // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
-                - pReverb->m_nRoomLpfFbk);
-        if (value16 == 0) {
-            pReverb->m_nRoomLpfFbk = 0;
-        } else {
-            int32_t dG2, b, delta;
-
-            // dG^2
-            temp = Effects_MillibelsToLinear16(value16);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
-            temp = (1 << 30) / temp;
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
-
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
-
-            LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
-
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
         }
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
-                temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL)
-            break;
-        value32 = pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-
-        // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
-        // convert ms to samples
-        value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
-
-        // calculate valid decay time range as a function of current reverb delay and
-        // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
-        // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
-        // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
-        averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
-                + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
-
-        temp = (-6000 * averageDelay) / value32;
-        LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
-        if (temp < -4000 || temp > -100)
+        value16 = *(int16_t *)pValue;
+        LOGV("set REVERB_PARAM_PRESET, preset %d", value16);
+        if (value16 < REVERB_PRESET_NONE || value16 > REVERB_PRESET_PLATE) {
             return -EINVAL;
-
-        // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
-        // xfade and sum gain (max +9dB)
-        temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
-        temp = Effects_MillibelsToLinear16(temp);
-
-        // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
-
-        LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
-
-        if (param == REVERB_PARAM_DECAY_TIME)
-            break;
-        value16 = pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-
-        // We limit max value to 1000 because reverb filter is lowpass only
-        if (value16 < 100 || value16 > 1000)
-            return -EINVAL;
-        // Convert per mille to => m_nLpfFwd, m_nLpfFbk
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-
-        if (value16 == 1000) {
-            pReverb->m_nRvbLpfFbk = 0;
+        }
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (value16 == REVERB_PRESET_NONE) {
+            pReverb->m_bBypass = 1;
         } else {
-            int32_t dG2, b, delta;
+            pReverb->m_bBypass = 0;
+            pReverb->m_nNextRoom = value16 - 1;
+        }
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            paramSize = sizeof(int16_t);
+            break;
 
-            temp = Effects_Linear16ToMillibels(temp2);
-            // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            paramSize = sizeof(int32_t);
+            break;
 
-            value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+        case REVERB_PARAM_PROPERTIES:
+            paramSize = sizeof(t_reverb_properties);
+            break;
 
-            temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+        default:
+            return -EINVAL;
+        }
 
-            if (temp < -4000) {
-                LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
-                temp = -4000;
+        if (size != paramSize) {
+            return -EINVAL;
+        }
+
+        if (paramSize == sizeof(int16_t)) {
+            value16 = *(int16_t *) pValue;
+        } else if (paramSize == sizeof(int32_t)) {
+            value32 = *(int32_t *) pValue;
+        } else {
+            pProperties = (t_reverb_properties *) pValue;
+        }
+
+        pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            pReverb->m_bBypass = (uint16_t)value32;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            value16 = pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
+            if (value16 > 0)
+                return -EINVAL;
+
+            temp = Effects_MillibelsToLinear16(value16);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
+
+            LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+            if (param == REVERB_PARAM_ROOM_LEVEL)
+                break;
+            value16 = pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+
+            // Limit to 0 , -40dB range because of low pass implementation
+            if (value16 > 0 || value16 < -4000)
+                return -EINVAL;
+            // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
+            // m_nRoomLpfFbk is -a1 where a1 is the solution of:
+            // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
+            // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
+            // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
+                    - pReverb->m_nRoomLpfFbk);
+            if (value16 == 0) {
+                pReverb->m_nRoomLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                // dG^2
+                temp = Effects_MillibelsToLinear16(value16);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
+                temp = (1 << 30) / temp;
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
+
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+            }
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
+                    temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL)
+                break;
+            value32 = pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+
+            // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
+            // convert ms to samples
+            value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
+            // calculate valid decay time range as a function of current reverb delay and
+            // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
+            // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
+            // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
+            averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
+                    + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
+
+            temp = (-6000 * averageDelay) / value32;
+            LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
+            if (temp < -4000 || temp > -100)
+                return -EINVAL;
+
+            // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
+            // xfade and sum gain (max +9dB)
+            temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
+            temp = Effects_MillibelsToLinear16(temp);
+
+            // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
+
+            LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
+
+            if (param == REVERB_PARAM_DECAY_TIME)
+                break;
+            value16 = pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+
+            // We limit max value to 1000 because reverb filter is lowpass only
+            if (value16 < 100 || value16 > 1000)
+                return -EINVAL;
+            // Convert per mille to => m_nLpfFwd, m_nLpfFbk
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+
+            if (value16 == 1000) {
+                pReverb->m_nRvbLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                temp = Effects_Linear16ToMillibels(temp2);
+                // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+
+                value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+
+                temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+
+                if (temp < -4000) {
+                    LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
+                    temp = -4000;
+                }
+
+                temp = Effects_MillibelsToLinear16(temp);
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
+                // dG^2
+                temp = (temp2 << 15) / temp;
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+
             }
 
-            temp = Effects_MillibelsToLinear16(temp);
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
-            // dG^2
-            temp = (temp2 << 15) / temp;
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+            LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
 
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
 
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
+            if (param == REVERB_PARAM_DECAY_HF_RATIO)
+                break;
+            value16 = pProperties->reflectionsLevel;
+            /* FALL THROUGH */
 
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
 
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+            // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
+            value16 = Effects_MillibelsToLinear16(value16);
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                pReverb->m_sEarlyL.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
+                pReverb->m_sEarlyR.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
+            }
+            pReverb->m_nEarlyGain = value16;
+            LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
 
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
+                break;
+            value32 = pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // We limit max value MAX_EARLY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_EARLY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
+            }
+            pReverb->m_nEarlyDelay = temp;
+
+            LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nEarlyDelay
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY)
+                break;
+            value16 = pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
+            // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
+            pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+
+            LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL)
+                break;
+            value32 = pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // We limit max value to MAX_DELAY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_DELAY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+                temp = maxSamples - pReverb->m_nMaxExcursion;
+            }
+            if (temp < pReverb->m_nMaxExcursion) {
+                temp = pReverb->m_nMaxExcursion;
+            }
+
+            temp -= pReverb->m_nLateDelay;
+            pReverb->m_nDelay0Out += temp;
+            pReverb->m_nDelay1Out += temp;
+            pReverb->m_nLateDelay += temp;
+
+            LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
+            if (param == REVERB_PARAM_REVERB_DELAY)
+                break;
+
+            value16 = pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
+            pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
+                    * AP0_GAIN_RANGE) / 1000;
+            pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
+                    * AP1_GAIN_RANGE) / 1000;
+
+            LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
+
+            if (param == REVERB_PARAM_DIFFUSION)
+                break;
+
+            value16 = pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
+            maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+
+            temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+
+            LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
+
+            temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+
+            LOGV("Ap1 delay smps %d", temp);
+
+            break;
+
+        default:
+            break;
         }
-
-        LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
-
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
-
-        if (param == REVERB_PARAM_DECAY_HF_RATIO)
-            break;
-        value16 = pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-
-        // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
-        value16 = Effects_MillibelsToLinear16(value16);
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            pReverb->m_sEarlyL.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
-            pReverb->m_sEarlyR.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
-        }
-        pReverb->m_nEarlyGain = value16;
-        LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
-
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
-            break;
-        value32 = pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // We limit max value MAX_EARLY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_EARLY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
-        }
-        pReverb->m_nEarlyDelay = temp;
-
-        LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nEarlyDelay
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY)
-            break;
-        value16 = pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-        // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
-        pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
-
-        LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL)
-            break;
-        value32 = pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // We limit max value to MAX_DELAY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_DELAY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
-            temp = maxSamples - pReverb->m_nMaxExcursion;
-        }
-        if (temp < pReverb->m_nMaxExcursion) {
-            temp = pReverb->m_nMaxExcursion;
-        }
-
-        temp -= pReverb->m_nLateDelay;
-        pReverb->m_nDelay0Out += temp;
-        pReverb->m_nDelay1Out += temp;
-        pReverb->m_nLateDelay += temp;
-
-        LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
-        if (param == REVERB_PARAM_REVERB_DELAY)
-            break;
-
-        value16 = pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
-        pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
-                * AP0_GAIN_RANGE) / 1000;
-        pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
-                * AP1_GAIN_RANGE) / 1000;
-
-        LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION)
-            break;
-
-        value16 = pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
-        maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
-
-        temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
-
-        LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
-
-        temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
-
-        LOGV("Ap1 delay smps %d", temp);
-
-        break;
-
-    default:
-        break;
     }
+
     return 0;
 } /* end Reverb_setParameter */
 
@@ -1905,139 +1915,15 @@
  */
 static int ReverbReadInPresets(reverb_object_t *pReverb) {
 
-    int preset = 0;
-    int defaultPreset = 0;
+    int preset;
 
-    //now init any remaining presets to defaults
-    for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) {
-        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[defaultPreset];
-        if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE - 1) {
-            pPreset->m_nRvbLpfFbk = 8307;
-            pPreset->m_nRvbLpfFwd = 14768;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6388;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 711;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1029;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 1) {
-            pPreset->m_nRvbLpfFbk = 6461;
-            pPreset->m_nRvbLpfFwd = 14307;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6391;
-            pPreset->m_nAp0_ApGain = 15230;
-            pPreset->m_nAp0_ApOut = 708;
-            pPreset->m_nAp1_ApGain = 15547;
-            pPreset->m_nAp1_ApOut = 1023;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 2) {
-            pPreset->m_nRvbLpfFbk = 5077;
-            pPreset->m_nRvbLpfFwd = 12922;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 21703;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6449;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 774;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1155;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 3) {
+    // this is for test only. OpenSL ES presets are mapped to 4 presets.
+    // REVERB_PRESET_NONE is mapped to bypass
+    for (preset = 0; preset < REVERB_NUM_PRESETS; preset++) {
+        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[preset];
+        switch (preset + 1) {
+        case REVERB_PRESET_PLATE:
+        case REVERB_PRESET_SMALLROOM:
             pPreset->m_nRvbLpfFbk = 5077;
             pPreset->m_nRvbLpfFwd = 11076;
             pPreset->m_nEarlyGain = 27690;
@@ -2079,6 +1965,137 @@
             pPreset->m_rfu8 = 0;
             pPreset->m_rfu9 = 0;
             pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMROOM:
+        case REVERB_PRESET_LARGEROOM:
+            pPreset->m_nRvbLpfFbk = 5077;
+            pPreset->m_nRvbLpfFwd = 12922;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 21703;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6449;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 774;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1155;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMHALL:
+            pPreset->m_nRvbLpfFbk = 6461;
+            pPreset->m_nRvbLpfFwd = 14307;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6391;
+            pPreset->m_nAp0_ApGain = 15230;
+            pPreset->m_nAp0_ApOut = 708;
+            pPreset->m_nAp1_ApGain = 15547;
+            pPreset->m_nAp1_ApOut = 1023;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_LARGEHALL:
+            pPreset->m_nRvbLpfFbk = 8307;
+            pPreset->m_nRvbLpfFwd = 14768;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6388;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 711;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1029;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
         }
     }
 
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index f5aadfa..5af316d 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -17,7 +17,8 @@
 #ifndef ANDROID_EFFECTREVERB_H_
 #define ANDROID_EFFECTREVERB_H_
 
-#include <media/EffectReverbApi.h>
+#include <media/EffectEnvironmentalReverbApi.h>
+#include <media/EffectPresetReverbApi.h>
 
 
 /*------------------------------------
@@ -43,7 +44,7 @@
 
 #define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX   16384
 
-#define REVERB_MAX_ROOM_TYPE            4   // any room numbers larger than this are invalid
+#define REVERB_NUM_PRESETS  REVERB_PRESET_PLATE   // REVERB_PRESET_NONE is not included
 #define REVERB_MAX_NUM_REFLECTIONS      5   // max num reflections per channel
 
 
@@ -171,7 +172,7 @@
 
 typedef struct
 {
-    reverb_preset_t     m_sPreset[REVERB_MAX_ROOM_TYPE];    //array of presets
+    reverb_preset_t     m_sPreset[REVERB_NUM_PRESETS]; // array of presets(does not include REVERB_PRESET_NONE)
 
 } reverb_preset_bank_t;
 
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..df0f73b 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -52,7 +52,7 @@
                 )
     : mStatus(NO_INIT)
 {
-    mStatus = set(type, uuid, priority, cbf, user, output, sessionId);
+    mStatus = set(type, uuid, priority, cbf, user, sessionId, output);
 }
 
 AudioEffect::AudioEffect(const char *typeStr,
@@ -84,7 +84,7 @@
         }
     }
 
-    mStatus = set(pType, pUuid, priority, cbf, user, output, sessionId);
+    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);
 }
 
 status_t AudioEffect::set(const effect_uuid_t *type,
@@ -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..5401ec0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -511,11 +511,17 @@
             sp<Client> c = mClients[i].promote();
             if (c != 0) c->dump(fd, args);
         }
-        for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
-            result.append(" MediaRecorderClient\n");
-            sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
-            snprintf(buffer, 255, "  pid(%d)\n\n", c->mPid);
-            result.append(buffer);
+        if (mMediaRecorderClients.size() == 0) {
+                result.append(" No media recorder client\n\n");
+        } else {
+            for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
+                sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
+                snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+                result.append(buffer);
+                write(fd, result.string(), result.size());
+                result = "\n";
+                c->dump(fd, args);
+            }
         }
 
         result.append(" Files opened and/or mapped:\n");
@@ -1265,98 +1271,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 +1285,6 @@
     mRightVolume = 1.0;
     mLatency = 0;
     mMsecsPerFrame = 0;
-    mNumFramesWritten = 0;
     setMinBufferCount();
 }
 
@@ -1516,30 +1429,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 +1440,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 +1450,6 @@
 {
     LOGV("stop");
     if (mTrack) mTrack->stop();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::flush()
@@ -1573,7 +1462,6 @@
 {
     LOGV("pause");
     if (mTrack) mTrack->pause();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::close()
@@ -1609,9 +1497,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/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 80b1cfd..fef3e6e 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -329,5 +329,12 @@
     return mRecorder->setListener(listener);
 }
 
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
+    if (mRecorder != NULL) {
+        return mRecorder->dump(fd, args);
+    }
+    return OK;
+}
+
 }; // namespace android
 
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index b53d950..d12e558 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -28,7 +28,7 @@
 class MediaRecorderClient : public BnMediaRecorder
 {
 public:
-    virtual	    status_t		setCamera(const sp<ICamera>& camera);
+    virtual     status_t        setCamera(const sp<ICamera>& camera);
     virtual     status_t        setPreviewSurface(const sp<ISurface>& surface);
     virtual     status_t        setVideoSource(int vs);
     virtual     status_t        setAudioSource(int as);
@@ -45,21 +45,22 @@
     virtual     status_t        getMaxAmplitude(int* max);
     virtual     status_t        start();
     virtual     status_t        stop();
-    virtual	    status_t        reset();
+    virtual     status_t        reset();
     virtual     status_t        init();
     virtual     status_t        close();
     virtual     status_t        release();
 
+    virtual     status_t        dump(int fd, const Vector<String16>& args) const;
 private:
-    friend class                 MediaPlayerService;  // for accessing private constructor
+    friend class                MediaPlayerService;  // for accessing private constructor
 
-                                 MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
-    virtual 		         ~MediaRecorderClient();
+                                MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
+    virtual                     ~MediaRecorderClient();
 
-    pid_t			 mPid;
-    Mutex			 mLock;
-    MediaRecorderBase            *mRecorder;
-    sp<MediaPlayerService>       mMediaPlayerService;
+    pid_t                       mPid;
+    Mutex                       mLock;
+    MediaRecorderBase           *mRecorder;
+    sp<MediaPlayerService>      mMediaPlayerService;
 };
 
 }; // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 91c5b92..72061ad 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();
@@ -1019,4 +1057,64 @@
     return OK;
 }
 
+status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "   Recorder: %p", this);
+    snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file size (bytes): %lld\n", mMaxFileSizeBytes);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file duration (us): %lld\n", mMaxFileDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Interleave duration (us): %d\n", mInterleaveDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %d frames\n", mTrackEveryNumberOfFrames);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Audio\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mAudioSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mAudioEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mAudioBitRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Sampling rate (hz): %d\n", mSampleRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Number of channels: %d\n", mAudioChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Video\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mVideoSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera flags: %d\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder profile: %d\n", mVideoEncoderProfile);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder level: %d\n", mVideoEncoderLevel);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     I frames interval (s): %d\n", mIFramesInterval);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame rate (fps): %d\n", mFrameRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mVideoBitRate);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index cb05571..704523f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -54,6 +54,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     enum CameraFlags {
@@ -82,6 +83,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 +111,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..efaab5b 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: %d, level %d",
+            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/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 2bc4448..f3b281f 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "AACDecoder.h"
+#define LOG_TAG "AACDecoder"
 
 #include "../../include/ESDS.h"
 
@@ -36,26 +37,33 @@
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mInputBuffer(NULL) {
-}
 
-AACDecoder::~AACDecoder() {
-    if (mStarted) {
-        stop();
+    sp<MetaData> srcFormat = mSource->getFormat();
+
+    int32_t sampleRate;
+    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+    // We'll always output stereo, regardless of how many channels are
+    // present in the input due to decoder limitations.
+    mMeta->setInt32(kKeyChannelCount, 2);
+    mMeta->setInt32(kKeySampleRate, sampleRate);
+
+    int64_t durationUs;
+    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+        mMeta->setInt64(kKeyDuration, durationUs);
     }
+    mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
 
-    delete mConfig;
-    mConfig = NULL;
+    mInitCheck = initCheck();
 }
 
-status_t AACDecoder::start(MetaData *params) {
-    CHECK(!mStarted);
-
-    mBufferGroup = new MediaBufferGroup;
-    mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
-
+status_t AACDecoder::initCheck() {
+    memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
     mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
-    mConfig->aacPlusUpsamplingFactor = 0;
-    mConfig->aacPlusEnabled = false;
+    mConfig->aacPlusEnabled = 1;
 
     // The software decoder doesn't properly support mono output on
     // AACplus files. Always output stereo.
@@ -64,8 +72,11 @@
     UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
     mDecoderBuf = malloc(memRequirements);
 
-    CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf),
-             MP4AUDEC_SUCCESS);
+    status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+    if (err != MP4AUDEC_SUCCESS) {
+        LOGE("Failed to initialize MP4 audio decoder");
+        return UNKNOWN_ERROR;
+    }
 
     uint32_t type;
     const void *data;
@@ -83,18 +94,38 @@
         mConfig->pInputBuffer = (UChar *)codec_specific_data;
         mConfig->inputBufferCurrentLength = codec_specific_data_size;
         mConfig->inputBufferMaxLength = 0;
-        mConfig->inputBufferUsedLength = 0;
-        mConfig->remainderBits = 0;
-
-        mConfig->pOutputBuffer = NULL;
-        mConfig->pOutputBuffer_plus = NULL;
-        mConfig->repositionFlag = false;
 
         if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
                 != MP4AUDEC_SUCCESS) {
             return ERROR_UNSUPPORTED;
         }
+
+        // Check on the sampling rate to see whether it is changed.
+        int32_t sampleRate;
+        CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+        if (mConfig->samplingRate != sampleRate) {
+            mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+            LOGW("Sample rate was %d, but now is %d",
+                    sampleRate, mConfig->samplingRate);
+        }
     }
+    return OK;
+}
+
+AACDecoder::~AACDecoder() {
+    if (mStarted) {
+        stop();
+    }
+
+    delete mConfig;
+    mConfig = NULL;
+}
+
+status_t AACDecoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mBufferGroup = new MediaBufferGroup;
+    mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
 
     mSource->start();
 
@@ -127,28 +158,7 @@
 }
 
 sp<MetaData> AACDecoder::getFormat() {
-    sp<MetaData> srcFormat = mSource->getFormat();
-
-    int32_t sampleRate;
-    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
-    // We'll always output stereo, regardless of how many channels are
-    // present in the input due to decoder limitations.
-    meta->setInt32(kKeyChannelCount, 2);
-
-    meta->setInt32(kKeySampleRate, sampleRate);
-
-    int64_t durationUs;
-    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
-        meta->setInt64(kKeyDuration, durationUs);
-    }
-
-    meta->setCString(kKeyDecoderComponent, "AACDecoder");
-
-    return meta;
+    return mMeta;
 }
 
 status_t AACDecoder::read(
@@ -200,13 +210,19 @@
     mConfig->remainderBits = 0;
 
     mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
-    mConfig->pOutputBuffer_plus = NULL;
+    mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
     mConfig->repositionFlag = false;
 
     Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
 
     size_t numOutBytes =
         mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+    if (mConfig->aacPlusUpsamplingFactor == 2) {
+        if (mConfig->desiredChannels == 1) {
+            memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
+        }
+        numOutBytes *= 2;
+    }
 
     if (decoderErr != MP4AUDEC_SUCCESS) {
         LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
diff --git a/media/libstagefright/foundation/AHandler.cpp b/media/libstagefright/foundation/AHandler.cpp
new file mode 100644
index 0000000..bd5f7e94
--- /dev/null
+++ b/media/libstagefright/foundation/AHandler.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "AHandler"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+
+#include <media/stagefright/foundation/ALooperRoster.h>
+
+namespace android {
+
+sp<ALooper> AHandler::looper() {
+    extern ALooperRoster gLooperRoster;
+
+    return gLooperRoster.findLooper(id());
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 5bb1cf9..65f7593 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -54,10 +54,15 @@
     Mutex::Autolock autoLock(mLock);
 
     ssize_t index = mHandlers.indexOfKey(handlerID);
-    CHECK(index >= 0);
+    CHECK_GE(index, 0);
 
     const HandlerInfo &info = mHandlers.valueAt(index);
-    info.mHandler->setID(0);
+
+    sp<AHandler> handler = info.mHandler.promote();
+
+    if (handler != NULL) {
+        handler->setID(0);
+    }
 
     mHandlers.removeItemsAt(index);
 }
@@ -74,7 +79,18 @@
     }
 
     const HandlerInfo &info = mHandlers.valueAt(index);
-    info.mLooper->post(msg, delayUs);
+
+    sp<ALooper> looper = info.mLooper.promote();
+
+    if (looper == NULL) {
+        LOG(WARNING) << "failed to post message. "
+                        "Target handler still registered, but object gone.";
+
+        mHandlers.removeItemsAt(index);
+        return;
+    }
+
+    looper->post(msg, delayUs);
 }
 
 void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
@@ -86,15 +102,43 @@
         ssize_t index = mHandlers.indexOfKey(msg->target());
 
         if (index < 0) {
-            LOG(WARNING) << "failed to deliver message. Target handler not registered.";
+            LOG(WARNING) << "failed to deliver message. "
+                         << "Target handler not registered.";
             return;
         }
 
         const HandlerInfo &info = mHandlers.valueAt(index);
-        handler = info.mHandler;
+        handler = info.mHandler.promote();
+
+        if (handler == NULL) {
+            LOG(WARNING) << "failed to deliver message. "
+                            "Target handler registered, but object gone.";
+
+            mHandlers.removeItemsAt(index);
+            return;
+        }
     }
 
     handler->onMessageReceived(msg);
 }
 
+sp<ALooper> ALooperRoster::findLooper(ALooper::handler_id handlerID) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t index = mHandlers.indexOfKey(handlerID);
+
+    if (index < 0) {
+        return NULL;
+    }
+
+    sp<ALooper> looper = mHandlers.valueAt(index).mLooper.promote();
+
+    if (looper == NULL) {
+        mHandlers.removeItemsAt(index);
+        return NULL;
+    }
+
+    return looper;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 73047e7..35eea7e 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -5,6 +5,7 @@
     AAtomizer.cpp               \
     ABuffer.cpp                 \
     ADebug.cpp                  \
+    AHandler.cpp                \
     ALooper.cpp                 \
     ALooperRoster.cpp           \
     AMessage.cpp                \
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index f09addd..200f93c 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -25,6 +25,7 @@
 namespace android {
 
 struct MediaBufferGroup;
+struct MetaData;
 
 struct AACDecoder : public MediaSource {
     AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@
     virtual ~AACDecoder();
 
 private:
+    sp<MetaData>    mMeta;
     sp<MediaSource> mSource;
     bool mStarted;
 
@@ -50,9 +52,11 @@
     void *mDecoderBuf;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
+    status_t mInitCheck;
 
     MediaBuffer *mInputBuffer;
 
+    status_t initCheck();
     AACDecoder(const AACDecoder &);
     AACDecoder &operator=(const AACDecoder &);
 };
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/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ad5b0f9..6de761f 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -164,6 +164,10 @@
         instance = mLiveNodes.editValueAt(index);
         mLiveNodes.removeItemsAt(index);
 
+        index = mDispatchers.indexOfKey(instance->nodeID());
+        CHECK(index >= 0);
+        mDispatchers.removeItemsAt(index);
+
         invalidateNodeID_l(instance->nodeID());
     }
 
@@ -240,6 +244,11 @@
     ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
     CHECK(index >= 0);
     mLiveNodes.removeItemsAt(index);
+
+    index = mDispatchers.indexOfKey(node);
+    CHECK(index >= 0);
+    mDispatchers.removeItemsAt(index);
+
     instance->observer()->asBinder()->unlinkToDeath(this);
 
     return instance->freeNode(mMaster);
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/native/android/Android.mk b/native/android/Android.mk
index fe8ed00..509a379 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -6,16 +6,18 @@
 # our source files
 #
 LOCAL_SRC_FILES:= \
-    activity.cpp \
     input.cpp \
+    looper.cpp \
+    native_activity.cpp \
     native_window.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
     libcutils \
     libutils \
     libbinder \
-    libui
+    libui \
+    libsurfaceflinger_client \
+    libandroid_runtime
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
diff --git a/native/android/activity.cpp b/native/android/activity.cpp
deleted file mode 100644
index e69de29..0000000
--- a/native/android/activity.cpp
+++ /dev/null
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 8498840..89d53e2 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -20,6 +20,7 @@
 #include <android/input.h>
 #include <ui/Input.h>
 #include <ui/InputTransport.h>
+#include <utils/PollLoop.h>
 
 #include <poll.h>
 
@@ -184,8 +185,16 @@
             pointer_index, history_index);
 }
 
-int AInputQueue_getFd(AInputQueue* queue) {
-    return queue->getConsumer().getChannel()->getReceivePipeFd();
+void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
+        ALooper_callbackFunc* callback, void* data) {
+    queue->setPollLoop(static_cast<android::PollLoop*>(looper));
+    ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
+            POLLIN, callback, data);
+}
+
+void AInputQueue_detachLooper(AInputQueue* queue) {
+    queue->getPollLoop()->removeCallback(
+            queue->getConsumer().getChannel()->getReceivePipeFd());
 }
 
 int AInputQueue_hasEvents(AInputQueue* queue) {
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
new file mode 100644
index 0000000..1564c47
--- /dev/null
+++ b/native/android/looper.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "ALooper"
+#include <utils/Log.h>
+
+#include <android/looper.h>
+#include <utils/PollLoop.h>
+
+using android::PollLoop;
+using android::sp;
+
+ALooper* ALooper_forThread() {
+    return PollLoop::getForThread().get();
+}
+
+ALooper* ALooper_prepare(int32_t opts) {
+    bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        loop = new PollLoop(allowFds);
+        PollLoop::setForThread(loop);
+    }
+    if (loop->getAllowNonCallbacks() != allowFds) {
+        LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
+    }
+    return loop.get();
+}
+
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        LOGW("ALooper_pollOnce: No looper for this thread!");
+        return -1;
+    }
+    return loop->pollOnce(timeoutMillis, outEvents, outData);
+}
+
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        LOGW("ALooper_pollOnce: No looper for this thread!");
+        return -1;
+    }
+    
+    int32_t result;
+    while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
+        ;
+    }
+    
+    return result;
+}
+
+void ALooper_acquire(ALooper* looper) {
+    static_cast<PollLoop*>(looper)->incStrong((void*)ALooper_acquire);
+}
+
+void ALooper_release(ALooper* looper) {
+    static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
+}
+
+void ALooper_addFd(ALooper* looper, int fd, int events,
+        ALooper_callbackFunc* callback, void* data) {
+    static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
+}
+
+int32_t ALooper_removeFd(ALooper* looper, int fd) {
+    return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
+}
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
new file mode 100644
index 0000000..509cc33
--- /dev/null
+++ b/native/android/native_activity.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 "native_activity"
+#include <utils/Log.h>
+
+#include <android_runtime/android_app_NativeActivity.h>
+
+using namespace android;
+
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format) {
+	android_NativeActivity_setWindowFormat(activity, format);
+}
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+		uint32_t addFlags, uint32_t removeFlags) {
+	android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags);
+}
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 448cbfc..bada078 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -17,10 +17,27 @@
 #define LOG_TAG "Surface"
 #include <utils/Log.h>
 
-#include <android/native_window.h>
+#include <android/native_window_jni.h>
 #include <surfaceflinger/Surface.h>
+#include <android_runtime/android_view_Surface.h>
 
-using android::Surface;
+using namespace android;
+
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) {
+    sp<ANativeWindow> win = android_Surface_getNativeWindow(env, surface);
+    if (win != NULL) {
+        win->incStrong((void*)ANativeWindow_acquire);
+    }
+    return win.get();
+}
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+    window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+    window->decStrong((void*)ANativeWindow_acquire);
+}
 
 static int32_t getWindowProp(ANativeWindow* window, int what) {
     int value;
@@ -41,7 +58,40 @@
 }
 
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format) {
-    native_window_set_buffers_geometry(window, width, height, format);
+        int32_t height) {
+    native_window_set_buffers_geometry(window, width, height, 0);
     return 0;
 }
+
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+        ARect* inOutDirtyBounds) {
+    Region dirtyRegion;
+    Region* dirtyParam = NULL;
+    if (inOutDirtyBounds != NULL) {
+        dirtyRegion.set(*(Rect*)inOutDirtyBounds);
+        dirtyParam = &dirtyRegion;
+    }
+    
+    Surface::SurfaceInfo info;
+    status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
+    if (res != OK) {
+        return -1;
+    }
+    
+    outBuffer->width = (int32_t)info.w;
+    outBuffer->height = (int32_t)info.h;
+    outBuffer->stride = (int32_t)info.s;
+    outBuffer->format = (int32_t)info.format;
+    outBuffer->bits = info.bits;
+    
+    if (inOutDirtyBounds != NULL) {
+        *inOutDirtyBounds = dirtyRegion.getBounds();
+    }
+    
+    return 0;
+}
+
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
+    status_t res = static_cast<Surface*>(window)->unlockAndPost();
+    return res == android::OK ? 0 : -1;
+}
diff --git a/native/glue/threaded_app/Android.mk b/native/glue/threaded_app/Android.mk
new file mode 100644
index 0000000..cfc9b2a
--- /dev/null
+++ b/native/glue/threaded_app/Android.mk
@@ -0,0 +1,18 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# our source files
+#
+LOCAL_SRC_FILES:= \
+    threaded_app.c
+
+LOCAL_C_INCLUDES += \
+    frameworks/base/native/include \
+    frameworks/base/core/jni/android \
+    dalvik/libnativehelper/include/nativehelper
+
+LOCAL_MODULE:= libthreaded_app
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c
new file mode 100644
index 0000000..2411e93
--- /dev/null
+++ b/native/glue/threaded_app/threaded_app.c
@@ -0,0 +1,279 @@
+/*
+ * 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 <jni.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include <android_glue/threaded_app.h>
+
+#include <android/log.h>
+
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__))
+
+int8_t android_app_read_cmd(struct android_app* android_app) {
+    int8_t cmd;
+    if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+        return cmd;
+    } else {
+        LOGW("No data on command pipe!");
+    }
+    return -1;
+}
+
+int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) {
+    switch (cmd) {
+        case APP_CMD_INPUT_CHANGED:
+            LOGI("APP_CMD_INPUT_CHANGED\n");
+            pthread_mutex_lock(&android_app->mutex);
+            if (android_app->inputQueue != NULL) {
+                AInputQueue_detachLooper(android_app->inputQueue);
+            }
+            android_app->inputQueue = android_app->pendingInputQueue;
+            if (android_app->inputQueue != NULL) {
+                LOGI("Attaching input queue to looper");
+                AInputQueue_attachLooper(android_app->inputQueue,
+                        android_app->looper, NULL, (void*)LOOPER_ID_EVENT);
+            }
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_WINDOW_CHANGED:
+            LOGI("APP_CMD_WINDOW_CHANGED\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->window = android_app->pendingWindow;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_START:
+        case APP_CMD_RESUME:
+        case APP_CMD_PAUSE:
+        case APP_CMD_STOP:
+            LOGI("activityState=%d\n", cmd);
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->activityState = cmd;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+            
+        case APP_CMD_DESTROY:
+            LOGI("APP_CMD_DESTROY\n");
+            android_app->destroyRequested = 1;
+            break;
+    }
+    
+    return android_app->destroyRequested ? 0 : 1;
+}
+
+static void android_app_destroy(struct android_app* android_app) {
+    LOGI("android_app_destroy!");
+    pthread_mutex_lock(&android_app->mutex);
+    if (android_app->inputQueue != NULL) {
+        AInputQueue_detachLooper(android_app->inputQueue);
+    }
+    android_app->destroyed = 1;
+    pthread_cond_broadcast(&android_app->cond);
+    pthread_mutex_unlock(&android_app->mutex);
+    // Can't touch android_app object after this.
+}
+
+static void* android_app_entry(void* param) {
+    struct android_app* android_app = (struct android_app*)param;
+    
+    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+    ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN);
+    android_app->looper = looper;
+    
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->running = 1;
+    pthread_cond_broadcast(&android_app->cond);
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    android_main(android_app);
+    
+    android_app_destroy(android_app);
+    return NULL;
+}
+
+// --------------------------------------------------------------------
+// Native activity interaction (called from main thread)
+// --------------------------------------------------------------------
+
+static struct android_app* android_app_create(ANativeActivity* activity) {
+    struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
+    memset(android_app, 0, sizeof(struct android_app));
+    android_app->activity = activity;
+    
+    pthread_mutex_init(&android_app->mutex, NULL);
+    pthread_cond_init(&android_app->cond, NULL);
+    
+    int msgpipe[2];
+    if (pipe(msgpipe)) {
+        LOGI("could not create pipe: %s", strerror(errno));
+    }
+    android_app->msgread = msgpipe[0];
+    android_app->msgwrite = msgpipe[1];
+    
+    pthread_attr_t attr; 
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
+    
+    // Wait for thread to start.
+    pthread_mutex_lock(&android_app->mutex);
+    while (!android_app->running) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    return android_app;
+}
+
+static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
+    if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+        LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
+    }
+}
+
+static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->pendingInputQueue = inputQueue;
+    android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
+    while (android_app->inputQueue != android_app->pendingInputQueue) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->pendingWindow = window;
+    android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED);
+    while (android_app->window != android_app->pendingWindow) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app_write_cmd(android_app, cmd);
+    while (android_app->activityState != cmd) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_free(struct android_app* android_app) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app_write_cmd(android_app, APP_CMD_DESTROY);
+    while (!android_app->destroyed) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    close(android_app->msgread);
+    close(android_app->msgwrite);
+    pthread_cond_destroy(&android_app->cond);
+    pthread_mutex_destroy(&android_app->mutex);
+    free(android_app);
+}
+
+static void onDestroy(ANativeActivity* activity) {
+    LOGI("Destroy: %p\n", activity);
+    android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+    LOGI("Start: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+    LOGI("Resume: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
+}
+
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+    LOGI("SaveInstanceState: %p\n", activity);
+    return NULL;
+}
+
+static void onPause(ANativeActivity* activity) {
+    LOGI("Pause: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+    LOGI("Stop: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
+}
+
+static void onLowMemory(ANativeActivity* activity) {
+    LOGI("LowMemory: %p\n", activity);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+    LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
+    android_app_write_cmd((struct android_app*)activity->instance,
+            focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
+}
+
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
+    android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+    android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+    LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
+    android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+    LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
+    android_app_set_input((struct android_app*)activity->instance, NULL);
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity,
+        void* savedState, size_t savedStateSize) {
+    LOGI("Creating: %p\n", activity);
+    activity->callbacks->onDestroy = onDestroy;
+    activity->callbacks->onStart = onStart;
+    activity->callbacks->onResume = onResume;
+    activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+    activity->callbacks->onPause = onPause;
+    activity->callbacks->onStop = onStop;
+    activity->callbacks->onLowMemory = onLowMemory;
+    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+    
+    activity->instance = android_app_create(activity);
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 7617662..014b6a3 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -42,6 +42,7 @@
 
 #include <sys/types.h>
 #include <android/keycodes.h>
+#include <android/looper.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -533,12 +534,16 @@
 typedef struct AInputQueue AInputQueue;
 
 /*
- * Return a file descriptor for the queue, which you
- * can use to determine if there are events available.  This
- * is typically used with select() or poll() to multiplex
- * with other kinds of events.
+ * Add this input queue to a looper for processing.  See
+ * ALooper_addFd() for information on the callback and data params.
  */
-int AInputQueue_getFd(AInputQueue* queue);
+void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
+        ALooper_callbackFunc* callback, void* data);
+
+/*
+ * Remove the input queue from the looper it is currently attached to.
+ */
+void AInputQueue_detachLooper(AInputQueue* queue);
 
 /*
  * Returns true if there are one or more events available in the
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
new file mode 100644
index 0000000..2917216
--- /dev/null
+++ b/native/include/android/looper.h
@@ -0,0 +1,177 @@
+/*
+ * 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_LOOPER_H
+#define ANDROID_LOOPER_H
+
+#include <poll.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ALooper
+ *
+ * A looper is the state tracking an event loop for a thread.
+ * Loopers do not define event structures or other such things; rather
+ * they are a lower-level facility to attach one or more discrete objects
+ * listening for an event.  An "event" here is simply data available on
+ * a file descriptor: each attached object has an associated file descriptor,
+ * and waiting for "events" means (internally) polling on all of these file
+ * descriptors until one or more of them have data available.
+ *
+ * A thread can have only one ALooper associated with it.
+ */
+struct ALooper;
+typedef struct ALooper ALooper;
+
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called.  It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically POLLIN), and
+ * the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
+typedef int ALooper_callbackFunc(int fd, int events, void* data);
+
+/**
+ * Return the ALooper associated with the calling thread, or NULL if
+ * there is not one.
+ */
+ALooper* ALooper_forThread();
+
+enum {
+    /**
+     * Option for ALooper_prepare: this ALooper will accept calls to
+     * ALooper_addFd() that do not have a callback (that is provide NULL
+     * for the callback).  In this case the caller of ALooper_pollOnce()
+     * or ALooper_pollAll() MUST check the return from these functions to
+     * discover when data is available on such fds and process it.
+     */
+    ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0
+};
+
+/**
+ * Prepare an ALooper associated with the calling thread, and return it.
+ * If the thread already has an ALooper, it is returned.  Otherwise, a new
+ * one is created, associated with the thread, and returned.
+ *
+ * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+ */
+ALooper* ALooper_prepare(int32_t opts);
+
+enum {
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
+     * more callbacks were executed.
+     */
+    ALOOPER_POLL_CALLBACK = -1,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): the
+     * timeout expired.
+     */
+    ALOOPER_POLL_TIMEOUT = -2,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
+     * occurred.
+     */
+    ALOOPER_POLL_ERROR = -3,
+};
+
+/**
+ * Wait for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing a file descriptor if it has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outEvents and outData will contain the poll
+ * events and data associated with the fd.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Acquire a reference on the given ALooper object.  This prevents the object
+ * from being deleted until the reference is removed.  This is only needed
+ * to safely hand an ALooper from one thread to another.
+ */
+void ALooper_acquire(ALooper* looper);
+
+/**
+ * Remove a reference that was previously acquired with ALooper_acquire().
+ */
+void ALooper_release(ALooper* looper);
+
+/**
+ * Add a new file descriptor to be polled by the looper.  If the same file
+ * descriptor was previously added, it is replaced.
+ *
+ * "fd" is the file descriptor to be added.
+ * "events" are the poll events to wake up on.  Typically this is POLLIN.
+ * "callback" is the function to call when there is an event on the file
+ * descriptor.
+ * "id" is an identifier to associated with this file descriptor, or 0.
+ * "data" is a private data pointer to supply to the callback.
+ *
+ * There are two main uses of this function:
+ *
+ * (1) If "callback" is non-NULL, then
+ * this function will be called when there is data on the file descriptor.  It
+ * should execute any events it has pending, appropriately reading from the
+ * file descriptor.
+ *
+ * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
+ * when it has data available, requiring the caller to take care of processing
+ * it.
+ */
+void ALooper_addFd(ALooper* looper, int fd, int events,
+        ALooper_callbackFunc* callback, void* data);
+
+/**
+ * Remove a previously added file descriptor from the looper.
+ */
+int32_t ALooper_removeFd(ALooper* looper, int fd);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index bf5c641..d0ff052 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -64,6 +64,21 @@
     jobject clazz;
 
     /**
+     * Path to this application's internal data directory.
+     */
+    const char* internalDataPath;
+    
+    /**
+     * Path to this application's external (removable/mountable) data directory.
+     */
+    const char* externalDataPath;
+    
+    /**
+     * The platform's SDK version code.
+     */
+    int32_t sdkVersion;
+    
+    /**
      * This is the native instance of the application.  It is not used by
      * the framework, but can be set by the application to its own instance
      * state.
@@ -177,6 +192,11 @@
  */
 extern ANativeActivity_createFunc ANativeActivity_onCreate;
 
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format);
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+        uint32_t addFlags, uint32_t removeFlags);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 678ba3d..7599d7e 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-
 #ifndef ANDROID_NATIVE_WINDOW_H
 #define ANDROID_NATIVE_WINDOW_H
 
+#include <android/rect.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -34,6 +35,27 @@
 struct ANativeWindow;
 typedef struct ANativeWindow ANativeWindow;
 
+typedef struct ANativeWindow_Buffer {
+    int32_t width;
+    int32_t height;
+    int32_t stride;
+    int32_t format;
+    void* bits;
+    
+    uint32_t reserved[6];
+} ANativeWindow_Buffer;
+
+/**
+ * Acquire a reference on the given ANativeWindow object.  This prevents the object
+ * from being deleted until the reference is removed.
+ */
+void ANativeWindow_acquire(ANativeWindow* window);
+
+/**
+ * Remove a reference that was previously acquired with ANativeWindow_acquire().
+ */
+void ANativeWindow_release(ANativeWindow* window);
+
 /*
  * Return the current width in pixels of the window surface.  Returns a
  * negative value on error.
@@ -60,13 +82,22 @@
  * window's physical size, then it buffer will be scaled to match that size
  * when compositing it to the screen.
  *
- * The format may be one of the window format constants above.
- *
- * For all of these parameters, if 0 is supplied than the window's base
+ * For all of these parameters, if 0 is supplied then the window's base
  * value will come back in force.
  */
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height);
+
+/**
+ * Lock the window's next drawing surface for writing.
+ */
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+        ARect* inOutDirtyBounds);
+
+/**
+ * Unlock the window's drawing surface after previously locking it,
+ * posting the new buffer to the display.
+ */
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h
new file mode 100644
index 0000000..b9e72ef
--- /dev/null
+++ b/native/include/android/native_window_jni.h
@@ -0,0 +1,40 @@
+/*
+ * 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_NATIVE_WINDOW_JNI_H
+#define ANDROID_NATIVE_WINDOW_JNI_H
+
+#include <android/native_window.h>
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Return the ANativeWindow associated with a Java Surface object,
+ * for interacting with it through native code.  This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/native/include/android/rect.h b/native/include/android/rect.h
new file mode 100644
index 0000000..3e81f53
--- /dev/null
+++ b/native/include/android/rect.h
@@ -0,0 +1,36 @@
+/*
+ * 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_RECT_H
+#define ANDROID_RECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ARect {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} ARect;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_RECT_H
diff --git a/native/include/android/window.h b/native/include/android/window.h
new file mode 100644
index 0000000..2ab192b
--- /dev/null
+++ b/native/include/android/window.h
@@ -0,0 +1,58 @@
+/*
+ * 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_WINDOW_H
+#define ANDROID_WINDOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Window flags, as per the Java API at android.view.WindowManager.LayoutParams.
+ */
+enum {
+    AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
+    AWINDOW_FLAG_DIM_BEHIND                 = 0x00000002,
+    AWINDOW_FLAG_BLUR_BEHIND                = 0x00000004,
+    AWINDOW_FLAG_NOT_FOCUSABLE              = 0x00000008,
+    AWINDOW_FLAG_NOT_TOUCHABLE              = 0x00000010,
+    AWINDOW_FLAG_NOT_TOUCH_MODAL            = 0x00000020,
+    AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING      = 0x00000040,
+    AWINDOW_FLAG_KEEP_SCREEN_ON             = 0x00000080,
+    AWINDOW_FLAG_LAYOUT_IN_SCREEN           = 0x00000100,
+    AWINDOW_FLAG_LAYOUT_NO_LIMITS           = 0x00000200,
+    AWINDOW_FLAG_FULLSCREEN                 = 0x00000400,
+    AWINDOW_FLAG_FORCE_NOT_FULLSCREEN       = 0x00000800,
+    AWINDOW_FLAG_DITHER                     = 0x00001000,
+    AWINDOW_FLAG_SECURE                     = 0x00002000,
+    AWINDOW_FLAG_SCALED                     = 0x00004000,
+    AWINDOW_FLAG_IGNORE_CHEEK_PRESSES       = 0x00008000,
+    AWINDOW_FLAG_LAYOUT_INSET_DECOR         = 0x00010000,
+    AWINDOW_FLAG_ALT_FOCUSABLE_IM           = 0x00020000,
+    AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH        = 0x00040000,
+    AWINDOW_FLAG_SHOW_WHEN_LOCKED           = 0x00080000,
+    AWINDOW_FLAG_SHOW_WALLPAPER             = 0x00100000,
+    AWINDOW_FLAG_TURN_SCREEN_ON             = 0x00200000,
+    AWINDOW_FLAG_DISMISS_KEYGUARD           = 0x00400000,
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_WINDOW_H
diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
new file mode 100644
index 0000000..adfdbea
--- /dev/null
+++ b/native/include/android_glue/threaded_app.h
@@ -0,0 +1,165 @@
+/*
+ * 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 <poll.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <android/native_activity.h>
+#include <android/looper.h>
+
+/**
+ * This is the interface for the standard glue code of a threaded
+ * application.  In this model, the application's code is running
+ * in its own thread separate from the main thread of the process.
+ * It is not required that this thread be associated with the Java
+ * VM, although it will need to be in order to make JNI calls any
+ * Java objects.
+ */
+struct android_app {
+    // The application can place a pointer to its own state object
+    // here if it likes.
+    void* userData;
+
+    // The ANativeActivity object instance that this app is running in.
+    ANativeActivity* activity;
+
+    // The ALooper associated with the app's thread.
+    ALooper* looper;
+
+    // When non-NULL, this is the input queue from which the app will
+    // receive user input events.
+    AInputQueue* inputQueue;
+
+    // When non-NULL, this is the window surface that the app can draw in.
+    ANativeWindow* window;
+
+    // Current state of the app's activity.  May be either APP_CMD_START,
+    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
+    int activityState;
+
+    // -------------------------------------------------
+    // Below are "private" implementation of the glue code.
+
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+
+    int msgread;
+    int msgwrite;
+
+    pthread_t thread;
+
+    // This is non-zero when the application's NativeActivity is being
+    // destroyed and waiting for the app thread to complete.
+    int destroyRequested;
+
+    int running;
+    int destroyed;
+    AInputQueue* pendingInputQueue;
+    ANativeWindow* pendingWindow;
+};
+
+enum {
+    /**
+     * Looper data ID of commands coming from the app's main thread.
+     * These can be retrieved and processed with android_app_read_cmd()
+     * and android_app_exec_cmd().
+     */
+    LOOPER_ID_MAIN = 1,
+
+    /**
+     * Looper data ID of events coming from the AInputQueue of the
+     * application's window.  These can be read via the inputQueue
+     * object of android_app.
+     */
+    LOOPER_ID_EVENT = 2
+};
+
+enum {
+    /**
+     * Command from main thread: the AInputQueue has changed.  Upon processing
+     * this command, android_app->inputQueue will be updated to the new queue
+     * (or NULL).
+     */
+    APP_CMD_INPUT_CHANGED,
+
+    /**
+     * Command from main thread: the ANativeWindow has changed.  Upon processing
+     * this command, android_app->window will be updated to the new window surface
+     * (or NULL).
+     */
+    APP_CMD_WINDOW_CHANGED,
+
+    /**
+     * Command from main thread: the app's activity window has gained
+     * input focus.
+     */
+    APP_CMD_GAINED_FOCUS,
+
+    /**
+     * Command from main thread: the app's activity window has lost
+     * input focus.
+     */
+    APP_CMD_LOST_FOCUS,
+
+    /**
+     * Command from main thread: the app's activity has been started.
+     */
+    APP_CMD_START,
+
+    /**
+     * Command from main thread: the app's activity has been resumed.
+     */
+    APP_CMD_RESUME,
+
+    /**
+     * Command from main thread: the app's activity has been paused.
+     */
+    APP_CMD_PAUSE,
+
+    /**
+     * Command from main thread: the app's activity has been stopped.
+     */
+    APP_CMD_STOP,
+
+    /**
+     * Command from main thread: the app's activity is being destroyed,
+     * and waiting for the app thread to clean up and exit before proceeding.
+     */
+    APP_CMD_DESTROY,
+};
+
+/**
+ * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
+ * app command message.
+ */
+int8_t android_app_read_cmd(struct android_app* android_app);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * default processing of the given command.
+ *
+ * Important: returns 0 if the app should exit.  You must ALWAYS check for
+ * a zero return and, if found, exit your android_main() function.
+ */
+int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * This is the function that application code must implement, representing
+ * the main entry to the app.
+ */
+extern void android_main(struct android_app* app);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cd4f96d..7395233 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -49,6 +49,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -67,11 +68,29 @@
 
     private Context mContext;
 
+    private static final HashSet<String> mValidTables = new HashSet<String>();
+
+    static {
+        mValidTables.add("system");
+        mValidTables.add("secure");
+        mValidTables.add("bluetooth_devices");
+        mValidTables.add("bookmarks");
+
+        // These are old.
+        mValidTables.add("favorites");
+        mValidTables.add("gservices");
+        mValidTables.add("old_favorites");
+    }
+
     public DatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
         mContext = context;
     }
 
+    public static boolean isValidTable(String name) {
+        return mValidTables.contains(name);
+    }
+
     private void createSecureTable(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE secure (" +
                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1019fa8..6a5290e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -83,6 +83,9 @@
         SqlArguments(Uri url, String where, String[] args) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = where;
                 this.args = args;
             } else if (url.getPathSegments().size() != 2) {
@@ -91,6 +94,9 @@
                 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
             } else {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 if ("system".equals(this.table) || "secure".equals(this.table)) {
                     this.where = Settings.NameValueTable.NAME + "=?";
                     this.args = new String[] { url.getPathSegments().get(1) };
@@ -105,6 +111,9 @@
         SqlArguments(Uri url) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = null;
                 this.args = null;
             } else {
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/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index f8abc5a..b9e915a4 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -244,27 +244,12 @@
             intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-            final boolean adbOn = 1 == Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                Settings.Secure.ADB_ENABLED,
-                0);
-
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
             setUsbStorageNotification(
                     com.android.internal.R.string.usb_storage_notification_title,
                     com.android.internal.R.string.usb_storage_notification_message,
                     com.android.internal.R.drawable.stat_sys_data_usb,
                     false, true, pi);
-
-            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
-                // We assume that developers don't want to enable UMS every
-                // time they attach a device to a USB host. The average user,
-                // however, is looking to charge the phone (in which case this
-                // is harmless) or transfer files (in which case this coaches
-                // the user about how to complete that task and saves several
-                // steps).
-                mContext.startActivity(intent);
-            }
         } else {
             setUsbStorageNotification(0, 0, 0, false, false, null);
         }
@@ -313,6 +298,23 @@
             }
 
             mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+            final boolean adbOn = 1 == Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.ADB_ENABLED,
+                0);
+
+            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+                // Pop up a full-screen alert to coach the user through enabling UMS. The average
+                // user has attached the device to USB either to charge the phone (in which case
+                // this is harmless) or transfer files, and in the latter case this alert saves
+                // several steps (as well as subtly indicates that you shouldn't mix UMS with other
+                // activities on the device).
+                //
+                // If ADB is enabled, however, we suppress this dialog (under the assumption that a
+                // developer (a) knows how to enable UMS, and (b) is probably using USB to install
+                // builds or use adb commands.
+                mUsbStorageNotification.fullScreenIntent = pi;
+            }
         }
     
         final int notificationId = mUsbStorageNotification.icon;
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/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b4fc15a..11d0b7a 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4583,6 +4583,8 @@
         }
     };
 
+    private static final boolean DEBUG_OBB = false;
+
     private static final void sendPackageBroadcast(String action, String pkg,
             Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
@@ -4757,6 +4759,29 @@
         mHandler.sendMessage(msg);
     }
 
+    public void setPackageObbPath(String packageName, String path) {
+        if (DEBUG_OBB)
+            Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        final int permission = mContext.checkCallingPermission(
+                android.Manifest.permission.INSTALL_PACKAGES);
+        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+        synchronized (mPackages) {
+            pkgSetting = mSettings.mPackages.get(packageName);
+            if (pkgSetting == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (!allowedByPermission && (uid != pkgSetting.userId)) {
+                throw new SecurityException("Permission denial: attempt to set .obb file from pid="
+                        + Binder.getCallingPid() + ", uid=" + uid + ", package uid="
+                        + pkgSetting.userId);
+            }
+            pkgSetting.obbPathString = path;
+            mSettings.writeLP();
+        }
+    }
+
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
@@ -7118,6 +7143,7 @@
                     pw.print("    pkg="); pw.println(ps.pkg);
                     pw.print("    codePath="); pw.println(ps.codePathString);
                     pw.print("    resourcePath="); pw.println(ps.resourcePathString);
+                    pw.print("    obbPath="); pw.println(ps.obbPathString);
                     if (ps.pkg != null) {
                         pw.print("    dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
                         pw.print("    targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
@@ -7684,6 +7710,7 @@
         String codePathString;
         File resourcePath;
         String resourcePathString;
+        String obbPathString;
         private long timeStamp;
         private String timeStampString = "0";
         int versionCode;
@@ -8684,6 +8711,9 @@
             if (pkg.installerPackageName != null) {
                 serializer.attribute(null, "installer", pkg.installerPackageName);
             }
+            if (pkg.obbPathString != null) {
+                serializer.attribute(null, "obbPath", pkg.obbPathString);
+            }
             pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
             if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                 serializer.startTag(null, "perms");
@@ -9060,6 +9090,7 @@
             String sharedIdStr = null;
             String codePathStr = null;
             String resourcePathStr = null;
+            String obbPathStr = null;
             String systemStr = null;
             String installerPackageName = null;
             String uidError = null;
@@ -9077,6 +9108,7 @@
                 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
                 codePathStr = parser.getAttributeValue(null, "codePath");
                 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+                obbPathStr = parser.getAttributeValue(null, "obbPath");
                 version = parser.getAttributeValue(null, "version");
                 if (version != null) {
                     try {
@@ -9174,6 +9206,7 @@
             if (packageSetting != null) {
                 packageSetting.uidError = "true".equals(uidError);
                 packageSetting.installerPackageName = installerPackageName;
+                packageSetting.obbPathString = obbPathStr;
                 final String enabledStr = parser.getAttributeValue(null, "enabled");
                 if (enabledStr != null) {
                     if (enabledStr.equalsIgnoreCase("true")) {
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/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
index a74c5c2..de59b81 100644
--- a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
@@ -496,9 +496,11 @@
         assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
-        TelephonyManager mTelephonyManager =
+        // This test fails on a device without a sim card
+        /*TelephonyManager mTelephonyManager =
             (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
         String mVoiceMailNumber = mTelephonyManager.getDefault().getVoiceMailNumber();
         assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+        */
     }
 }
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 63d50c7..70d1643 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -496,9 +496,18 @@
         return null;
     }
 
+    /**
+     * Initialize the current thread as a looper.
+     * <p/>
+     * Exposed for unit testing.
+     */
+    void prepareLooper() {
+        Looper.prepare();
+    }
+
     @Override
     public void onStart() {
-        Looper.prepare();
+        prepareLooper();
 
         if (mJustCount) {
             mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -521,6 +530,11 @@
                 long runTime = System.currentTimeMillis() - startTime;
 
                 resultPrinter.print(mTestRunner.getTestResult(), runTime);
+            } catch (Throwable t) {
+                // catch all exceptions so a more verbose error message can be outputted
+                writer.println(String.format("Test run aborted due to unexpected exception: %s",
+                                t.getMessage()));
+                t.printStackTrace(writer);
             } finally {
                 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
                         String.format("\nTest results for %s=%s",
@@ -762,9 +776,11 @@
                             TimedTest.class).includeDetailedStats();
                 }
             } catch (SecurityException e) {
-                throw new IllegalStateException(e);
+                // ignore - the test with given name cannot be accessed. Will be handled during
+                // test execution
             } catch (NoSuchMethodException e) {
-                throw new IllegalStateException(e);
+                // ignore- the test with given name does not exist. Will be handled during test
+                // execution
             }
 
             if (mIsTimedTest && mIncludeDetailedStats) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3e77b9b..e96173b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -483,4 +483,9 @@
     public boolean isSafeMode() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void setPackageObbPath(String packageName, String path) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
index 6db72ad..d98b217 100644
--- a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
@@ -16,6 +16,7 @@
 
 package android.test;
 
+import android.app.Instrumentation;
 import android.content.Context;
 import android.os.Bundle;
 import android.test.mock.MockContext;
@@ -89,6 +90,42 @@
         
     }
 
+    /**
+     * Test that runtime exceptions during runTest are handled gracefully
+     */
+    public void testUnhandledException() throws Exception {
+        StubAndroidTestRunner stubAndroidTestRunner = new StubAndroidTestRunner() {
+            @Override
+            public void runTest() {
+                throw new RuntimeException();
+            }
+        };
+        StubInstrumentationTestRunner instrumentationTestRunner = new StubInstrumentationTestRunner(
+                new StubContext("com.google.foo.tests"),
+                new StubContext(mTargetContextPackageName), stubAndroidTestRunner);
+        instrumentationTestRunner.onCreate(new Bundle());
+        instrumentationTestRunner.onStart();
+        assertTrue("Instrumentation did not finish", instrumentationTestRunner.isFinished());
+        // ensure a meaningful error message placed in results
+        String resultsData = instrumentationTestRunner.mResults.getString(
+                Instrumentation.REPORT_KEY_STREAMRESULT);
+        assertTrue("Instrumentation results is missing RuntimeException",
+                resultsData.contains("RuntimeException"));
+    }
+
+    /**
+     * Test that specifying a method which does not exist is handled gracefully
+     */
+    public void testBadMethodArgument() throws Exception {
+        String testClassName = PlaceHolderTest.class.getName();
+        String invalidMethodName = "testNoExist";
+        String classAndMethod = testClassName + "#" + invalidMethodName;
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+        assertTestRunnerCalledWithExpectedParameters(testClassName,
+                invalidMethodName);
+    }
+
     public void testDelayParameter() throws Exception {
         int delayMsec = 1000;
         Bundle args = new Bundle();
@@ -170,6 +207,7 @@
         private TestSuite mTestSuite;
         private TestSuite mDefaultTestSuite;
         private String mPackageNameForDefaultTests;
+        private Bundle mResults;
 
         public StubInstrumentationTestRunner(Context context, Context targetContext,
                 AndroidTestRunner androidTestRunner) {
@@ -200,6 +238,7 @@
 
         public void finish(int resultCode, Bundle results) {
             mFinished = true;
+            mResults = results;
         }
 
         public boolean isStarted() {
@@ -221,6 +260,11 @@
         public String getPackageNameForDefaultTests() {
             return mPackageNameForDefaultTests;
         }
+
+        @Override
+        void prepareLooper() {
+            // ignore
+        }
     }
 
     private static class StubContext extends MockContext {
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);