Merge "Added Visualizer effect." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 9145462..5d71cad 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -87294,6 +87294,21 @@
 <parameter name="quality" type="int">
 </parameter>
 </method>
+<method name="get"
+ return="android.media.CamcorderProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cameraId" type="int">
+</parameter>
+<parameter name="quality" type="int">
+</parameter>
+</method>
 <field name="QUALITY_HIGH"
  type="int"
  transient="false"
@@ -87466,6 +87481,21 @@
 <parameter name="quality" type="int">
 </parameter>
 </method>
+<method name="getJpegEncodingQualityParameter"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cameraId" type="int">
+</parameter>
+<parameter name="quality" type="int">
+</parameter>
+</method>
 <field name="QUALITY_HIGH"
  type="int"
  transient="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 75948a5..10668a4 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -1031,6 +1031,7 @@
             mHardware->getRawHeap());
 
         mSurface->registerBuffers(buffers);
+        IPCThreadState::self()->flushCommands();
     }
 
     mLock.unlock();
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 33696f4..9a97284 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -7,7 +7,7 @@
 	SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia libutils libbinder
+	libstagefright libmedia libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 877b908..b7a3f99 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -38,6 +38,9 @@
 #include <media/stagefright/OMXCodec.h>
 #include <media/mediametadataretriever.h>
 
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MPEG4Writer.h>
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -45,6 +48,8 @@
 static long gReproduceBug;  // if not -1.
 static bool gPreferSoftwareCodec;
 static bool gPlaybackAudio;
+static bool gWriteMP4;
+static String8 gWriteMP4Filename;
 
 static int64_t getNowUs() {
     struct timeval tv;
@@ -258,6 +263,21 @@
     }
 }
 
+static void writeSourceToMP4(const sp<MediaSource> &source) {
+    sp<MPEG4Writer> writer =
+        new MPEG4Writer(gWriteMP4Filename.string());
+
+    CHECK_EQ(writer->addSource(source), OK);
+
+    sp<MetaData> params = new MetaData;
+    CHECK_EQ(writer->start(), OK);
+
+    while (!writer->reachedEOS()) {
+        usleep(100000);
+    }
+    writer->stop();
+}
+
 static void usage(const char *me) {
     fprintf(stderr, "usage: %s\n", me);
     fprintf(stderr, "       -h(elp)\n");
@@ -270,6 +290,7 @@
     fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
     fprintf(stderr, "       -o playback audio\n");
+    fprintf(stderr, "       -w(rite) filename (write to .mp4 file)\n");
 }
 
 int main(int argc, char **argv) {
@@ -284,9 +305,10 @@
     gReproduceBug = -1;
     gPreferSoftwareCodec = false;
     gPlaybackAudio = false;
+    gWriteMP4 = false;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:ptso")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:ptsow:")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -322,6 +344,13 @@
                 break;
             }
 
+            case 'w':
+            {
+                gWriteMP4 = true;
+                gWriteMP4Filename.setTo(optarg);
+                break;
+            }
+
             case 'p':
             {
                 dumpProfiles = true;
@@ -554,7 +583,11 @@
             mediaSource = extractor->getTrack(i);
         }
 
-        playSource(&client, mediaSource);
+        if (gWriteMP4) {
+            writeSourceToMP4(mediaSource);
+        } else {
+            playSource(&client, mediaSource);
+        }
     }
 
     client.disconnect();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9b9ae52..985f591 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -39,7 +39,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e56fee9..1fe85e6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1021,16 +1021,6 @@
             return true;
         }
 
-        case REPORT_PSS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = ApplicationThreadNative.asInterface(b);
-            int pss = data.readInt();
-            reportPss(app, pss);
-            reply.writeNoException();
-            return true;
-        }
-
         case START_RUNNING_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
@@ -2529,14 +2519,6 @@
         reply.recycle();
         return res;
     }
-    public void reportPss(IApplicationThread caller, int pss) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller.asBinder());
-        data.writeInt(pss);
-        mRemote.transact(REPORT_PSS_TRANSACTION, data, null, 0);
-        data.recycle();
-    }
     public void startRunning(String pkg, String cls, String action,
             String indata) throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 03bb858..883366b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -616,14 +616,6 @@
             queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
         }
 
-        public void requestPss() {
-            try {
-                ActivityManagerNative.getDefault().reportPss(this,
-                        (int)Process.getPss(Process.myPid()));
-            } catch (RemoteException e) {
-            }
-        }
-
         public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
             ProfilerControlData pcd = new ProfilerControlData();
             pcd.path = path;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 360959d..1c20062 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -341,13 +341,6 @@
             return true;
         }
         
-        case REQUEST_PSS_TRANSACTION:
-        {
-            data.enforceInterface(IApplicationThread.descriptor);
-            requestPss();
-            return true;
-        }
-        
         case PROFILER_CONTROL_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -779,14 +772,6 @@
         data.recycle();
     }
     
-    public final void requestPss() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IApplicationThread.descriptor);
-        mRemote.transact(REQUEST_PSS_TRANSACTION, data, null,
-                IBinder.FLAG_ONEWAY);
-        data.recycle();
-    }
-    
     public void profilerControl(boolean start, String path,
             ParcelFileDescriptor fd) throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index bf02d5a..20c9a80 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -247,8 +247,6 @@
     
     public boolean killPids(int[] pids, String reason) throws RemoteException;
     
-    public void reportPss(IApplicationThread caller, int pss) throws RemoteException;
-    
     // Special low-level communication with activity manager.
     public void startRunning(String pkg, String cls, String action,
             String data) throws RemoteException;
@@ -502,7 +500,7 @@
     int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
     int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
-    int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
+
     int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
     int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83;
     int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ffb8651..c8ef17f 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -95,7 +95,6 @@
             throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
-    void requestPss() throws RemoteException;
     void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
@@ -132,7 +131,7 @@
     int SCHEDULE_LOW_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+23;
     int SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24;
     int SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
-    int REQUEST_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
+
     int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
     int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
     int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 429d164..d72dda7 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -5,10 +5,18 @@
 import android.content.pm.ActivityInfo;
 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;
 import android.view.InputQueue;
+import android.view.KeyEvent;
+import android.view.Surface;
 import android.view.SurfaceHolder;
+import android.view.View;
 
 import java.io.File;
 
@@ -22,7 +30,13 @@
     
     private int mNativeHandle;
     
-    private native int loadNativeCode(String path);
+    private InputQueue mCurInputQueue;
+    private SurfaceHolder mCurSurfaceHolder;
+    
+    private boolean mDestroyed;
+    
+    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);
@@ -32,10 +46,10 @@
     private native void onStopNative(int handle);
     private native void onLowMemoryNative(int handle);
     private native void onWindowFocusChangedNative(int handle, boolean focused);
-    private native void onSurfaceCreatedNative(int handle, SurfaceHolder holder);
-    private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
+    private native void onSurfaceCreatedNative(int handle, Surface surface);
+    private native void onSurfaceChangedNative(int handle, Surface surface,
             int format, int width, int height);
-    private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
+    private native void onSurfaceDestroyedNative(int handle);
     private native void onInputChannelCreatedNative(int handle, InputChannel channel);
     private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
     
@@ -46,6 +60,7 @@
         
         getWindow().takeSurface(this);
         getWindow().takeInputQueue(this);
+        getWindow().setFormat(PixelFormat.RGB_565);
         
         try {
             ai = getPackageManager().getActivityInfo(
@@ -78,7 +93,11 @@
             throw new IllegalArgumentException("Unable to find native library: " + libname);
         }
         
-        mNativeHandle = loadNativeCode(path);
+        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);
         }
@@ -87,6 +106,15 @@
 
     @Override
     protected void onDestroy() {
+        mDestroyed = true;
+        if (mCurSurfaceHolder != null) {
+            onSurfaceDestroyedNative(mNativeHandle);
+            mCurSurfaceHolder = null;
+        }
+        if (mCurInputQueue != null) {
+            onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel());
+            mCurInputQueue = null;
+        }
         unloadNativeCode(mNativeHandle);
         super.onDestroy();
     }
@@ -124,32 +152,66 @@
     @Override
     public void onLowMemory() {
         super.onLowMemory();
-        onLowMemoryNative(mNativeHandle);
+        if (!mDestroyed) {
+            onLowMemoryNative(mNativeHandle);
+        }
     }
 
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
-        onWindowFocusChangedNative(mNativeHandle, hasFocus);
+        if (!mDestroyed) {
+            onWindowFocusChangedNative(mNativeHandle, hasFocus);
+        }
     }
     
     public void surfaceCreated(SurfaceHolder holder) {
-        onSurfaceCreatedNative(mNativeHandle, holder);
+        if (!mDestroyed) {
+            mCurSurfaceHolder = holder;
+            onSurfaceCreatedNative(mNativeHandle, holder.getSurface());
+        }
     }
     
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-        onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
+        if (!mDestroyed) {
+            mCurSurfaceHolder = holder;
+            onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height);
+        }
     }
     
     public void surfaceDestroyed(SurfaceHolder holder) {
-        onSurfaceDestroyedNative(mNativeHandle, holder);
+        mCurSurfaceHolder = null;
+        if (!mDestroyed) {
+            onSurfaceDestroyedNative(mNativeHandle);
+        }
     }
     
     public void onInputQueueCreated(InputQueue queue) {
-        onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
+        if (!mDestroyed) {
+            mCurInputQueue = queue;
+            onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
+        }
     }
     
     public void onInputQueueDestroyed(InputQueue queue) {
-        onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
+        mCurInputQueue = null;
+        if (!mDestroyed) {
+            onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
+        }
+    }
+    
+    void dispatchUnhandledKeyEvent(KeyEvent event) {
+        View decor = getWindow().getDecorView();
+        if (decor != null) {
+            decor.dispatchKeyEvent(event);
+        }
+    }
+    
+    void setWindowFlags(int flags, int mask) {
+        getWindow().setFlags(flags, mask);
+    }
+    
+    void setWindowFormat(int format) {
+        getWindow().setFormat(format);
     }
 }
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/hardware/Usb.java b/core/java/android/hardware/Usb.java
index e9c2cf7..57271d4 100644
--- a/core/java/android/hardware/Usb.java
+++ b/core/java/android/hardware/Usb.java
@@ -39,6 +39,27 @@
     public static final String ACTION_USB_DISCONNECTED =
             "android.hardware.action.USB_DISCONNECTED";
 
+   /**
+     * Broadcast Action:  A sticky broadcast for USB state change events.
+     *
+     * This is a sticky broadcast for clients that are interested in both USB connect and
+     * disconnect events.  If you are only concerned with one or the other, you can use
+     * {@link #ACTION_USB_CONNECTED} or {@link #ACTION_USB_DISCONNECTED} to avoid receiving
+     * unnecessary broadcasts.  The boolean {@link #USB_CONNECTED} extra indicates whether
+     * USB is connected or disconnected.
+     * The extras bundle will also contain name/value pairs with the name of the function
+     * and a value of either {@link #USB_FUNCTION_ENABLED} or {@link #USB_FUNCTION_DISABLED}.
+     * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE},
+     * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}.
+     */
+    public static final String ACTION_USB_STATE =
+            "android.hardware.action.USB_STATE";
+
+    /**
+     * Boolean extra indicating whether USB is connected or disconnected.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+     */
+    public static final String USB_CONNECTED = "connected";
 
     /**
      * Name of the USB mass storage USB function.
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index a8c6f9b..9ad125b 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -35,6 +35,11 @@
 import java.security.cert.X509Certificate;
 
 import javax.net.SocketFactory;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
@@ -48,17 +53,33 @@
 
 /**
  * SSLSocketFactory implementation with several extra features:
+ *
  * <ul>
  * <li>Timeout specification for SSL handshake operations
+ * <li>Hostname verification in most cases (see WARNINGs below)
  * <li>Optional SSL session caching with {@link SSLSessionCache}
  * <li>Optionally bypass all SSL certificate checks
  * </ul>
- * Note that the handshake timeout does not apply to actual connection.
- * If you want a connection timeout as well, use {@link #createSocket()} and
- * {@link Socket#connect(SocketAddress, int)}.
- * <p>
- * On development devices, "setprop socket.relaxsslcheck yes" bypasses all
- * SSL certificate checks, for testing with development servers.
+ *
+ * The handshake timeout does not apply to actual TCP socket connection.
+ * If you want a connection timeout as well, use {@link #createSocket()}
+ * and {@link Socket#connect(SocketAddress, int)}, after which you
+ * must verify the identity of the server you are connected to.
+ *
+ * <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not
+ * verify the server's identity, allowing man-in-the-middle attacks.</b>
+ * This implementation does check the server's certificate hostname, but only
+ * for createSocket variants that specify a hostname.  When using methods that
+ * use {@link InetAddress} or which return an unconnected socket, you MUST
+ * verify the server's identity yourself to ensure a secure connection.</p>
+ *
+ * <p>One way to verify the server's identity is to use
+ * {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a
+ * {@link HostnameVerifier} to verify the certificate hostname.
+ *
+ * <p>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
+ * SSL certificate and hostname checks for testing purposes.  This setting
+ * requires root access.
  */
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
     private static final String TAG = "SSLCertificateSocketFactory";
@@ -71,6 +92,9 @@
         }
     };
 
+    private static final HostnameVerifier HOSTNAME_VERIFIER =
+        HttpsURLConnection.getDefaultHostnameVerifier();
+
     private SSLSocketFactory mInsecureFactory = null;
     private SSLSocketFactory mSecureFactory = null;
 
@@ -95,7 +119,7 @@
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
-     * @return a new SocketFactory with the specified parameters
+     * @return a new SSLSocketFactory with the specified parameters
      */
     public static SocketFactory getDefault(int handshakeTimeoutMillis) {
         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true);
@@ -108,7 +132,7 @@
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
      * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
-     * @return a new SocketFactory with the specified parameters
+     * @return a new SSLSocketFactory with the specified parameters
      */
     public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true);
@@ -117,13 +141,14 @@
     /**
      * Returns a new instance of a socket factory with all SSL security checks
      * disabled, using an optional handshake timeout and SSL session cache.
-     * Sockets created using this factory are vulnerable to man-in-the-middle
-     * attacks!
+     *
+     * <p class="caution"><b>Warning:</b> Sockets created using this factory
+     * are vulnerable to man-in-the-middle attacks!</p>
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
      * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
-     * @return an insecure SocketFactory with the specified parameters
+     * @return an insecure SSLSocketFactory with the specified parameters
      */
     public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false);
@@ -145,6 +170,44 @@
                 new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
     }
 
+    /**
+     * Verify the hostname of the certificate used by the other end of a
+     * connected socket.  You MUST call this if you did not supply a hostname
+     * to {@link #createSocket()}.  It is harmless to call this method
+     * redundantly if the hostname has already been verified.
+     *
+     * <p>Wildcard certificates are allowed to verify any matching hostname,
+     * so "foo.bar.example.com" is verified if the peer has a certificate
+     * for "*.example.com".
+     *
+     * @param socket An SSL socket which has been connected to a server
+     * @param hostname The expected hostname of the remote server
+     * @throws IOException if something goes wrong handshaking with the server
+     * @throws SSLPeerUnverifiedException if the server cannot prove its identity
+     *
+     * @hide
+     */
+    public static void verifyHostname(Socket socket, String hostname) throws IOException {
+        if (!(socket instanceof SSLSocket)) {
+            throw new IllegalArgumentException("Attempt to verify non-SSL socket");
+        }
+
+        if (!isSslCheckRelaxed()) {
+            // The code at the start of OpenSSLSocketImpl.startHandshake()
+            // ensures that the call is idempotent, so we can safely call it.
+            SSLSocket ssl = (SSLSocket) socket;
+            ssl.startHandshake();
+
+            SSLSession session = ssl.getSession();
+            if (session == null) {
+                throw new SSLException("Cannot verify SSL socket without session");
+            }
+            if (!HOSTNAME_VERIFIER.verify(hostname, session)) {
+                throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
+            }
+        }
+    }
+
     private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
         try {
             SSLContextImpl sslContext = new SSLContextImpl();
@@ -156,10 +219,14 @@
         }
     }
 
+    private static boolean isSslCheckRelaxed() {
+        return "1".equals(SystemProperties.get("ro.debuggable")) &&
+            "yes".equals(SystemProperties.get("socket.relaxsslcheck"));
+    }
+
     private synchronized SSLSocketFactory getDelegate() {
         // Relax the SSL check if instructed (for this factory, or systemwide)
-        if (!mSecure || ("1".equals(SystemProperties.get("ro.debuggable")) &&
-            "yes".equals(SystemProperties.get("socket.relaxsslcheck")))) {
+        if (!mSecure || isSslCheckRelaxed()) {
             if (mInsecureFactory == null) {
                 if (mSecure) {
                     Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
@@ -177,13 +244,27 @@
         }
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method verifies the peer's certificate hostname after connecting.
+     */
     @Override
     public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        verifyHostname(s, host);
         return s;
     }
 
+    /**
+     * Creates a new socket which is not connected to any remote host.
+     * You must use {@link Socket#connect} to connect the socket.
+     *
+     * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+     * with this method.  You MUST verify the server's identity after connecting
+     * the socket to avoid man-in-the-middle attacks.</p>
+     */
     @Override
     public Socket createSocket() throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
@@ -191,6 +272,13 @@
         return s;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+     * with this method.  You MUST verify the server's identity after connecting
+     * the socket to avoid man-in-the-middle attacks.</p>
+     */
     @Override
     public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
             throws IOException {
@@ -200,6 +288,13 @@
         return s;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+     * with this method.  You MUST verify the server's identity after connecting
+     * the socket to avoid man-in-the-middle attacks.</p>
+     */
     @Override
     public Socket createSocket(InetAddress addr, int port) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
@@ -207,19 +302,31 @@
         return s;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method verifies the peer's certificate hostname after connecting.
+     */
     @Override
     public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
             throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                 host, port, localAddr, localPort);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        verifyHostname(s, host);
         return s;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method verifies the peer's certificate hostname after connecting.
+     */
     @Override
     public Socket createSocket(String host, int port) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        verifyHostname(s, host);
         return s;
     }
 
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5640a06..f695dbb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -626,6 +626,15 @@
             throws IllegalArgumentException, SecurityException;
 
     /**
+     * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to
+     * throw an exception if passed a background-level thread priority.  This is only
+     * effective if the JNI layer is built with GUARD_THREAD_PRIORITY defined to 1.
+     *
+     * @hide
+     */
+    public static final native void setCanSelfBackground(boolean backgroundOk);
+
+    /**
      * Sets the scheduling group for a thread.
      * @hide
      * @param tid The indentifier of the thread/process to change.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index ae9746e..0bfb6d6 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -676,33 +676,12 @@
      * TODO: should the dpad keys be here?  arguably, because they also shouldn't be menu shortcuts
      */
     public final boolean isSystem() {
-        switch (mKeyCode) {
-        case KEYCODE_MENU:
-        case KEYCODE_SOFT_RIGHT:
-        case KEYCODE_HOME:
-        case KEYCODE_BACK:
-        case KEYCODE_CALL:
-        case KEYCODE_ENDCALL:
-        case KEYCODE_VOLUME_UP:
-        case KEYCODE_VOLUME_DOWN:
-        case KEYCODE_MUTE:
-        case KEYCODE_POWER:
-        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:
-        case KEYCODE_CAMERA:
-        case KEYCODE_FOCUS:
-        case KEYCODE_SEARCH:
-        case KEYCODE_PICTSYMBOLS:
-        case KEYCODE_SWITCH_CHARSET:
-            return true;
-        default:
-            return false;
-        }
+        return native_isSystemKey(mKeyCode);
+    }
+
+    /** @hide */
+    public final boolean hasDefaultAction() {
+        return native_hasDefaultAction(mKeyCode);
     }
 
 
@@ -1226,4 +1205,7 @@
         mDownTime = in.readLong();
         mEventTime = in.readLong();
     }
+    
+    private native boolean native_isSystemKey(int keyCode);
+    private native boolean native_hasDefaultAction(int keyCode);
 }
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 2369d25..127ed68 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -126,6 +126,11 @@
 
     public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 
+    /**
+     * Battery capacity in milliAmpHour (mAh).
+     */
+    public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
+
     static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
 
     private static final String TAG_DEVICE = "device";
@@ -243,6 +248,19 @@
         }
     }
 
+    /**
+     * Returns the battery capacity, if available, in milli Amp Hours. If not available,
+     * it returns zero.
+     * @return the battery capacity in mAh
+     */
+    public double getBatteryCapacity() {
+        return getAveragePower(POWER_BATTERY_CAPACITY);
+    }
+
+    /**
+     * Returns the number of speeds that the CPU can be run at.
+     * @return
+     */
     public int getNumSpeedSteps() {
         Object value = sPowerMap.get(POWER_CPU_SPEEDS);
         if (value != null && value instanceof Double[]) {
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 5e5e47e..af61b80 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -17,47 +17,121 @@
 #define LOG_TAG "NativeActivity"
 #include <utils/Log.h>
 
-#include "JNIHelp.h"
-#include "android_view_InputChannel.h"
+#include <poll.h>
+#include <dlfcn.h>
+
 #include <android_runtime/AndroidRuntime.h>
 #include <android/native_activity.h>
+#include <surfaceflinger/Surface.h>
+#include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
+#include <utils/PollLoop.h>
 
-#include <dlfcn.h>
+#include "JNIHelp.h"
+#include "android_os_MessageQueue.h"
+#include "android_view_InputChannel.h"
+#include "android_view_KeyEvent.h"
+#include "android_view_Surface.h"
 
 namespace android
 {
 
+static struct {
+    jclass clazz;
+
+    jmethodID dispatchUnhandledKeyEvent;
+    jmethodID setWindowFlags;
+    jmethodID setWindowFormat;
+} gNativeActivityClassInfo;
+
+// ------------------------------------------------------------------------
+
+/*
+ * Specialized input queue that allows unhandled key events to be dispatched
+ * back to the native activity's Java framework code.
+ */
+struct MyInputQueue : AInputQueue {
+    explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
+        : AInputQueue(channel), mWorkWrite(workWrite) {
+    }
+    
+    virtual void doDefaultKey(android::KeyEvent* keyEvent) {
+        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));
+        }
+        mPendingKeys.add(keyEvent);
+        mLock.unlock();
+    }
+    
+    KeyEvent* getNextEvent() {
+        KeyEvent* event = NULL;
+        
+        mLock.lock();
+        if (mPendingKeys.size() > 0) {
+            event = mPendingKeys[0];
+            mPendingKeys.removeAt(0);
+        }
+        mLock.unlock();
+        
+        return event;
+    }
+    
+    int mWorkWrite;
+    
+    Mutex mLock;
+    Vector<KeyEvent*> mPendingKeys;
+};
+
+// ------------------------------------------------------------------------
+
+/*
+ * Native state for interacting with the NativeActivity class.
+ */
 struct NativeCode {
-    NativeCode(void* _dlhandle, android_activity_create_t* _createFunc) {
+    NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
         memset(&activity, sizeof(activity), 0);
         memset(&callbacks, sizeof(callbacks), 0);
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
-        surface = NULL;
+        nativeWindow = NULL;
         inputChannel = NULL;
         nativeInputQueue = NULL;
+        mainWorkRead = mainWorkWrite = -1;
     }
     
     ~NativeCode() {
+        if (activity.env != NULL && activity.clazz != NULL) {
+            activity.env->DeleteGlobalRef(activity.clazz);
+        }
+        if (pollLoop != NULL && mainWorkRead >= 0) {
+            pollLoop->removeCallback(mainWorkRead);
+        }
+        if (nativeInputQueue != NULL) {
+            nativeInputQueue->mWorkWrite = -1;
+        }
         setSurface(NULL);
         setInputChannel(NULL);
         if (callbacks.onDestroy != NULL) {
             callbacks.onDestroy(&activity);
         }
+        if (mainWorkRead >= 0) close(mainWorkRead);
+        if (mainWorkWrite >= 0) close(mainWorkWrite);
         if (dlhandle != NULL) {
-            dlclose(dlhandle);
+            // for now don't unload...  we probably should clean this
+            // up and only keep one open dlhandle per proc, since there
+            // is really no benefit to unloading the code.
+            //dlclose(dlhandle);
         }
     }
     
     void setSurface(jobject _surface) {
-        if (surface != NULL) {
-            activity.env->DeleteGlobalRef(surface);
-        }
         if (_surface != NULL) {
-            surface = activity.env->NewGlobalRef(_surface);
+            nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
         } else {
-            surface = NULL;
+            nativeWindow = NULL;
         }
     }
     
@@ -73,7 +147,7 @@
             sp<InputChannel> ic =
                     android_view_InputChannel_getInputChannel(activity.env, _channel);
             if (ic != NULL) {
-                nativeInputQueue = new input_queue_t(ic);
+                nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
                 if (nativeInputQueue->getConsumer().initialize() != android::OK) {
                     delete nativeInputQueue;
                     nativeInputQueue = NULL;
@@ -86,19 +160,55 @@
         return OK;
     }
     
-    android_activity_t activity;
-    android_activity_callbacks_t callbacks;
+    ANativeActivity activity;
+    ANativeActivityCallbacks callbacks;
     
     void* dlhandle;
-    android_activity_create_t* createActivityFunc;
+    ANativeActivity_createFunc* createActivityFunc;
     
-    jobject surface;
+    String8 internalDataPath;
+    String8 externalDataPath;
+    
+    sp<ANativeWindow> nativeWindow;
     jobject inputChannel;
-    struct input_queue_t* nativeInputQueue;
+    struct MyInputQueue* nativeInputQueue;
+    
+    // These are used to wake up the main thread to process work.
+    int mainWorkRead;
+    int mainWorkWrite;
+    sp<PollLoop> pollLoop;
 };
 
+// ------------------------------------------------------------------------
+
+/*
+ * Callback for handling native events on the application's main thread.
+ */
+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);
+            }
+        }
+    }
+    
+    return true;
+}
+
+// ------------------------------------------------------------------------
+
 static jint
-loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
+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;
@@ -108,16 +218,52 @@
     env->ReleaseStringUTFChars(path, pathStr);
     
     if (handle != NULL) {
-        code = new NativeCode(handle, (android_activity_create_t*)
-                dlsym(handle, "android_onCreateActivity"));
+        code = new NativeCode(handle, (ANativeActivity_createFunc*)
+                dlsym(handle, "ANativeActivity_onCreate"));
         if (code->createActivityFunc == NULL) {
-            LOGW("android_onCreateActivity not found");
+            LOGW("ANativeActivity_onCreate not found");
             delete code;
             return 0;
         }
+        
+        code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue);
+        if (code->pollLoop == NULL) {
+            LOGW("Unable to retrieve MessageQueue's PollLoop");
+            delete code;
+            return 0;
+        }
+        
+        int msgpipe[2];
+        if (pipe(msgpipe)) {
+            LOGW("could not create pipe: %s", strerror(errno));
+            delete code;
+            return 0;
+        }
+        code->mainWorkRead = msgpipe[0];
+        code->mainWorkWrite = msgpipe[1];
+        code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
+        
         code->activity.callbacks = &code->callbacks;
+        if (env->GetJavaVM(&code->activity.vm) < 0) {
+            LOGW("NativeActivity GetJavaVM failed");
+            delete code;
+            return 0;
+        }
         code->activity.env = env;
-        code->activity.clazz = clazz;
+        code->activity.clazz = env->NewGlobalRef(clazz);
+        
+        const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
+        code->internalDataPath = dirStr;
+        code->activity.internalDataPath = code->internalDataPath.string();
+        env->ReleaseStringUTFChars(path, dirStr);
+    
+        dirStr = env->GetStringUTFChars(externalDataDir, NULL);
+        code->externalDataPath = dirStr;
+        code->activity.externalDataPath = code->externalDataPath.string();
+        env->ReleaseStringUTFChars(path, dirStr);
+    
+        code->activity.sdkVersion = sdkVersion;
+        
         code->createActivityFunc(&code->activity, NULL, 0);
     }
     
@@ -217,9 +363,9 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
-        if (code->callbacks.onSurfaceCreated != NULL) {
-            code->callbacks.onSurfaceCreated(&code->activity,
-                    (android_surface_t*)code->surface);
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
+            code->callbacks.onNativeWindowCreated(&code->activity,
+                    code->nativeWindow.get());
         }
     }
 }
@@ -230,9 +376,17 @@
 {
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
-        if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) {
-            code->callbacks.onSurfaceChanged(&code->activity,
-                    (android_surface_t*)code->surface, format, width, height);
+        sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
+        code->setSurface(surface);
+        if (oldNativeWindow != code->nativeWindow) {
+            if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
+                code->callbacks.onNativeWindowDestroyed(&code->activity,
+                        oldNativeWindow.get());
+            }
+            if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
+                code->callbacks.onNativeWindowCreated(&code->activity,
+                        code->nativeWindow.get());
+            }
         }
     }
 }
@@ -242,9 +396,9 @@
 {
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
-        if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) {
-            code->callbacks.onSurfaceDestroyed(&code->activity,
-                    (android_surface_t*)code->surface);
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
+            code->callbacks.onNativeWindowDestroyed(&code->activity,
+                    code->nativeWindow.get());
         }
         code->setSurface(NULL);
     }
@@ -283,7 +437,8 @@
 }
 
 static const JNINativeMethod g_methods[] = {
-    { "loadNativeCode", "(Ljava/lang/String;)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 },
@@ -292,23 +447,40 @@
     { "onStopNative", "(I)V", (void*)onStop_native },
     { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
     { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
-    { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
-    { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
-    { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
+    { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
+    { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+    { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
     { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
     { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
 };
 
 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
 
+#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, fieldDescriptor) \
+        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method" methodName);
+        
 int register_android_app_NativeActivity(JNIEnv* env)
 {
     //LOGD("register_android_app_NativeActivity");
 
-    jclass clazz;
+    FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName);
+    
+    GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
+            gNativeActivityClassInfo.clazz,
+            "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V");
 
-    clazz = env->FindClass(kNativeActivityPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity");
+    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
+            gNativeActivityClassInfo.clazz,
+            "setWindowFlags", "(II)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
+            gNativeActivityClassInfo.clazz,
+            "setWindowFormat", "(I)V");
 
     return AndroidRuntime::registerNativeMethods(
         env, kNativeActivityPathName,
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 030d6c7..961f806 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -51,7 +51,11 @@
 // ----------------------------------------------------------------------------
 
 NativeMessageQueue::NativeMessageQueue() {
-    mPollLoop = new PollLoop();
+    mPollLoop = PollLoop::getForThread();
+    if (mPollLoop == NULL) {
+        mPollLoop = new PollLoop();
+        PollLoop::setForThread(mPollLoop);
+    }
 }
 
 NativeMessageQueue::~NativeMessageQueue() {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 68be741..7c99271 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -52,9 +52,15 @@
 #endif
 
 #define POLICY_DEBUG 0
+#define GUARD_THREAD_PRIORITY 0
 
 using namespace android;
 
+#if GUARD_THREAD_PRIORITY
+Mutex gKeyCreateMutex;
+static pthread_key_t gBgKey = -1;
+#endif
+
 static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
 {
     switch (err) {
@@ -264,9 +270,41 @@
     closedir(d);
 }
 
+static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) {
+    // Establishes the calling thread as illegal to put into the background.
+    // Typically used only for the system process's main looper.
+#if GUARD_THREAD_PRIORITY
+    LOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, androidGetTid());
+    {
+        Mutex::Autolock _l(gKeyCreateMutex);
+        if (gBgKey == -1) {
+            pthread_key_create(&gBgKey, NULL);
+        }
+    }
+
+    // inverted:  not-okay, we set a sentinel value
+    pthread_setspecific(gBgKey, (void*)(bgOk ? 0 : 0xbaad));
+#endif
+}
+
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
+#if GUARD_THREAD_PRIORITY
+    // if we're putting the current thread into the background, check the TLS
+    // to make sure this thread isn't guarded.  If it is, raise an exception.
+    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+        if (pid == androidGetTid()) {
+            void* bgOk = pthread_getspecific(gBgKey);
+            if (bgOk == ((void*)0xbaad)) {
+                LOGE("Thread marked fg-only put self in background!");
+                jniThrowException(env, "java/lang/SecurityException", "May not put this thread into background");
+                return;
+            }
+        }
+    }
+#endif
+
     int rc = androidSetThreadPriority(pid, pri);
     if (rc != 0) {
         if (rc == INVALID_OPERATION) {
@@ -852,6 +890,7 @@
     {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
     {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
     {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
+    {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
     {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
     {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index df3b952..8f648f4 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -76,8 +76,23 @@
             milliseconds_to_nanoseconds(eventTime));
 }
 
+static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) {
+    return KeyEvent::isSystemKey(keyCode);
+}
+
+static jboolean native_hasDefaultAction(JNIEnv* env, jobject clazz, jint keyCode) {
+    return KeyEvent::hasDefaultAction(keyCode);
+}
+
 // ----------------------------------------------------------------------------
 
+static const JNINativeMethod g_methods[] = {
+    { "native_isSystemKey", "(I)Z", (void*)native_isSystemKey },
+    { "native_hasDefaultAction", "(I)Z", (void*)native_hasDefaultAction },
+};
+
+static const char* const kKeyEventPathName = "android/view/KeyEvent";
+
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
         LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -92,8 +107,8 @@
         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
 
 int register_android_view_KeyEvent(JNIEnv* env) {
-    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
-
+    FIND_CLASS(gKeyEventClassInfo.clazz, kKeyEventPathName);
+        
     GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz,
             "<init>", "(JJIIIIIII)V");
 
@@ -118,7 +133,9 @@
     GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz,
             "mCharacters", "Ljava/lang/String;");
 
-    return 0;
+    return AndroidRuntime::registerNativeMethods(
+        env, kKeyEventPathName,
+        g_methods, NELEM(g_methods));
 }
 
 } // namespace android
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index cef5c10..a82abc93 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,6 +33,7 @@
 
 #include "jni.h"
 #include <android_runtime/AndroidRuntime.h>
+#include "android_view_Surface.h"
 #include <utils/misc.h>
 
 
@@ -179,7 +180,7 @@
     return result;
 }
 
-EGLNativeWindowType android_Surface_getEGLNativeWindow(
+sp<ANativeWindow> android_Surface_getNativeWindow(
         JNIEnv* env, jobject clazz) {
     return getSurface(env, clazz).get();
 }
diff --git a/core/jni/android_view_Surface.h b/core/jni/android_view_Surface.h
new file mode 100644
index 0000000..c37932e
--- /dev/null
+++ b/core/jni/android_view_Surface.h
@@ -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.
+ */
+
+#ifndef _ANDROID_VIEW_SURFACE_H
+#define _ANDROID_VIEW_SURFACE_H
+
+#include <android/native_window.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern sp<ANativeWindow> android_Surface_getNativeWindow(
+        JNIEnv* env, jobject clazz);
+
+} // namespace android
+
+#endif // _ANDROID_VIEW_SURFACE_H
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index d5cde48..866c038 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -25,10 +25,9 @@
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
-namespace android {
+#include "android_view_Surface.h"
 
-extern EGLNativeWindowType android_Surface_getEGLNativeWindow(
-        JNIEnv* env, jobject clazz);
+namespace android {
 
 static jclass gDisplay_class;
 static jclass gContext_class;
@@ -325,7 +324,7 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext cnf = getConfig(_env, config);
-    EGLNativeWindowType window = 0;
+    sp<ANativeWindow> window;
     if (native_window == NULL) {
 not_valid_surface:
         doThrow(_env, "java/lang/IllegalArgumentException",
@@ -333,12 +332,12 @@
         return 0;
     }
 
-    window = android_Surface_getEGLNativeWindow(_env, native_window);
+    window = android_Surface_getNativeWindow(_env, native_window);
     if (window == NULL)
         goto not_valid_surface;
 
     jint* base = beginNativeAttribList(_env, attrib_list);
-    EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
+    EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
     endNativeAttributeList(_env, attrib_list, base);
     return (jint)sur;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b1f81df..82f822f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -82,6 +82,7 @@
 
     <protected-broadcast android:name="android.hardware.action.USB_CONNECTED" />
     <protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" />
+    <protected-broadcast android:name="android.hardware.action.USB_STATE" />
 
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
diff --git a/core/res/res/anim/priority_alert_enter.xml b/core/res/res/anim/priority_alert_enter.xml
new file mode 100644
index 0000000..c8ce23c
--- /dev/null
+++ b/core/res/res/anim/priority_alert_enter.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        >
+    <scale
+        android:interpolator="@android:anim/overshoot_interpolator"
+        android:fromXScale="0.7" android:toXScale="1.0"
+        android:fromYScale="0.7" android:toYScale="1.0"
+        android:pivotX="50%" android:pivotY="50%"
+        android:duration="@android:integer/config_shortAnimTime" />
+    <alpha 
+        android:interpolator="@android:anim/decelerate_interpolator"
+        android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/priority_alert_exit.xml b/core/res/res/anim/priority_alert_exit.xml
new file mode 100644
index 0000000..b538cb2
--- /dev/null
+++ b/core/res/res/anim/priority_alert_exit.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        >
+    <scale
+        android:interpolator="@android:anim/accelerate_interpolator"
+        android:fromXScale="1.0" android:toXScale="0.7"
+        android:fromYScale="1.0" android:toYScale="0.7"
+        android:pivotX="50%" android:pivotY="50%"
+        android:duration="@android:integer/config_shortAnimTime" />
+    <alpha 
+        android:interpolator="@android:anim/accelerate_interpolator"
+        android:fromAlpha="1.0" android:toAlpha="0.0"
+        android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cffcd1d..d565c68 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -22,7 +22,7 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Component to be used as the status bar service.  Must implement the IStatusBar
          interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.PhoneStatusBarService</string>
+    <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.StatusBarService</string>
 
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8a92757..99c0b3d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -28,6 +28,10 @@
     <dimen name="toast_y_offset">64dip</dimen>
     <!-- Height of the status bar -->
     <dimen name="status_bar_height">25dip</dimen>
+    <!-- Height of the status bar -->
+    <dimen name="status_bar_icon_size">25dip</dimen>
+    <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
+    <dimen name="status_bar_edge_ignore">5dp</dimen>
     <!-- Size of the fastscroll hint letter -->
     <dimen name="fastscroll_overlay_size">104dp</dimen>
     <!-- Width of the fastscroll thumb -->
@@ -38,6 +42,4 @@
     <dimen name="password_keyboard_key_height">56dip</dimen>
     <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
-    <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
-    <dimen name="status_bar_edge_ignore">5dp</dimen>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index af04117..02a601a 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -88,6 +88,13 @@
         <item name="windowExitAnimation">@anim/status_bar_exit</item>
     </style>
 
+    <!-- {@hide} -->
+    <style name="Animation.StatusBar.IntruderAlert"
+        parent="@android:style/Animation.StatusBar">
+        <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
+        <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
+    </style>
+
     <!-- Standard animations for a translucent window or activity.  This
          style is <em>not<em> used by default for the translucent theme
          (since translucent activities are a special case that have no
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index ce623e8..30312b3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -18,6 +18,7 @@
 -->
 
 <device name="Android">
+  <!-- All values are in mAh except as noted -->
   <item name="none">0</item>
   <item name="screen.on">0.1</item>
   <item name="bluetooth.active">0.1</item>
@@ -48,4 +49,6 @@
   <array name="cpu.active">
       <value>0.2</value>
   </array>
+  <!-- This is the battery capacity in mAh -->
+  <item name="battery.capacity">1000</item>
 </device>
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 5480993..d298d40 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -43,6 +43,16 @@
         android:label="Test runner for Connectivity Manager Tests"
     />
 
+    <!--
+     To run the unit tests use the command:
+     "adb shell am instrument -w
+     com.android.connectivitymanagertest/.ConnectivityManagerUnitTestRunner"
+    -->
+    <instrumentation android:name=".ConnectivityManagerUnitTestRunner"
+        android:targetPackage="com.android.connectivitymanagertest"
+        android.label="Test runner for unit tests"
+    />
+
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
new file mode 100644
index 0000000..6adfc74
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -0,0 +1,47 @@
+/*
+ * 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 com.android.connectivitymanagertest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
+
+import junit.framework.TestSuite;
+
+/**
+ * Instrumentation Test Runner for all unit tests
+ *
+ * adb shell am instrument \
+ *     -w com.android.connectivitymanagertest/.ConnectivityManagerUnitTestRunner
+ */
+
+public class ConnectivityManagerUnitTestRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(WifiSoftAPTest.class);
+        return suite;
+    }
+
+
+    @Override
+    public ClassLoader getLoader() {
+        return ConnectivityManagerUnitTestRunner.class.getClassLoader();
+    }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
new file mode 100644
index 0000000..3f43e48
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.android.connectivitymanagertest.unit;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.Context;
+import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Message;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+
+import android.util.Log;
+
+/**
+ * Test Wifi soft AP configuration
+ */
+public class WifiSoftAPTest extends AndroidTestCase {
+
+    private WifiManager mWifiManager;
+    private WifiConfiguration mWifiConfig = null;
+    private final String TAG = "WifiSoftAPTest";
+    private final int DURATION = 10000;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        assertNotNull(mWifiManager);
+        assertTrue(mWifiManager.setWifiApEnabled(null, true));
+        mWifiConfig = mWifiManager.getWifiApConfiguration();
+        if (mWifiConfig != null) {
+            Log.v(TAG, "mWifiConfig is " + mWifiConfig.toString());
+        } else {
+            Log.v(TAG, "mWifiConfig is null.");
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        Log.v(TAG, "turn off wifi tethering");
+        mWifiManager.setWifiApEnabled(null, false);
+        super.tearDown();
+    }
+
+    // Test case 1: Test the soft AP SSID with letters
+    @LargeTest
+    public void testApSsidWithAlphabet() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "abcdefghijklmnopqrstuvwxyz";
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        mWifiConfig = config;
+        assertTrue(mWifiManager.setWifiApEnabled(mWifiConfig, true));
+        try {
+            Thread.sleep(DURATION);
+        } catch (InterruptedException e) {
+            Log.v(TAG, "exception " + e.getStackTrace());
+            assertFalse(true);
+        }
+        assertNotNull(mWifiManager.getWifiApConfiguration());
+        assertEquals("wifi AP state is not enabled", WifiManager.WIFI_AP_STATE_ENABLED,
+                     mWifiManager.getWifiApState());
+    }
+}
diff --git a/docs/html/guide/developing/eclipse-adt.jd b/docs/html/guide/developing/eclipse-adt.jd
index cf2a457..66379a3 100644
--- a/docs/html/guide/developing/eclipse-adt.jd
+++ b/docs/html/guide/developing/eclipse-adt.jd
@@ -527,7 +527,7 @@
 <p>A library project's manifest file must declare all of the shared components
 that it includes, just as would a standard Android application. For more
 information, see the documentation for <a
-href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
 
 <p>For example, the <a
 href="{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a>
@@ -613,7 +613,8 @@
   ...
 &lt;/manifest&gt;</pre>
 
-<p>For more information about the manifest file, see the documentation for <a href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+<p>For more information about the manifest file, see the documentation for <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
 
 
 <h3 id="considerations">Development considerations</h3>
diff --git a/docs/html/guide/developing/other-ide.jd b/docs/html/guide/developing/other-ide.jd
index e8a6fb6..1d67aa9 100644
--- a/docs/html/guide/developing/other-ide.jd
+++ b/docs/html/guide/developing/other-ide.jd
@@ -687,7 +687,7 @@
 <p>A library project's manifest file must declare all of the shared components
 that it includes, just as would a standard Android application. For more
 information, see the documentation for <a
-href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
 
 <p>For example, the <a
 href="{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a>
@@ -799,7 +799,8 @@
   ...
 &lt;/manifest&gt;</pre>
 
-<p>For more information about the manifest file, see the documentation for <a href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+<p>For more information about the manifest file, see the documentation for <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
 
 <h3 id="depAppBuild">Building a dependent application</h3>
 
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index 2f3ac5e..bd9ea52 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -3,99 +3,13 @@
 @jd:body
 
 
-<p>Sometimes, the best way to learn how things are done is to look at some code.
-Here, you can browse the source of some sample Android applications that are included
-in the Android SDK.</p>
+<script type="text/javascript">
+  window.location = toRoot + "resources/samples/index.html";
+</script>
 
-<p>Each version of the Android platform available for the SDK includes a full set of sample
-applications (which may vary between different versions of the platform).
-You can find the samples in your SDK at:</p>
+<p><strong>This document has moved. Please go to <a
+href="http://developer.android.com/resources/samples/index.html">List of Sample
+Apps</a>.</strong></p>
 
-<p style="margin-left:2em">
-<code><em>&lt;sdk&gt;</em>/platforms/android-<em>&lt;version&gt;</em>/samples/</code>
-</p>
-
-<p>You can easily create new Android projects with these samples, modify them
-if you'd like, then run them on an emulator or device. For example, to create
-a project for the API Demos app from Eclipse,
-start a new Android Project, select "Create project from existing source", then select
-{@code ApiDemos} in the {@code samples/} directory. To create the API Demos project
-using the {@code android} tool, execute:</p>
-<pre>
-android update project -s -n API Demos -t <em>&lt;target_ID></em> -p <em>&lt;path-to-platform></em>/samples/ApiDemos/
-</pre>
-
-<p>The pages below provide an overview of each sample application (available with most
-platforms) and allow you to view the source files in your browser. </p>
-
-<div class="special">
-  <p>Some of the samples in this listing are not yet available in the
-  SDK. While we work to update the SDK, you can
-  <a href="{@docRoot}shareables/latest_samples.zip">download the latest samples</a> as a ZIP
-  archive.</p>
-</div>
-
-<dl>
-
- <dt><a href="{@docRoot}resources/samples/ApiDemos/index.html">API Demos</a></dt>
-  <dd>A variety of small applications that demonstrate an extensive collection of
-  framework topics.</dd>
-
- <dt><a href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a></dt>
-  <dd>An simple example that illustrates a few different ways for an application to
-  implement support for the Android data backup and restore mechanism.</dd>
-
- <dt><a href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat</a></dt>
-  <dd>An application for two-way text messaging over Bluetooth.</dd>
-
- <dt><a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a></dt>
-  <dd>An application that demonstrates how to query the system contacts provider 
-  using the <code>ContactsContract</code> API, as
-  well as insert contacts into a specific account.</dd>
-  
- <dt><a href="{@docRoot}resources/samples/Home/index.html">Home</a></dt>
-  <dd>A home screen replacement application.</dd>
-  
- <dt><a href="{@docRoot}resources/samples/JetBoy/index.html">JetBoy</a></dt>
-  <dd>JetBoy is a game that demonstrates the SONiVOX JET interactive music technology,
-  with {@link android.media.JetPlayer}.</dd>
-    
- <dt><a href="{@docRoot}resources/samples/LunarLander/index.html">Lunar Lander</a></dt>
-  <dd>A classic Lunar Lander game.</dd>
-
- <dt><a href="{@docRoot}resources/samples/MultiResolution/index.html">Multiple Resolutions</a></dt>
-  <dd>A sample application that shows how to use resource directory qualifiers to
-  provide different resources for different screen configurations.</dd>
-  
- <dt><a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a></dt>
-  <dd>An application for saving notes. Similar (but not identical) to the 
-    <a href="{@docRoot}resources/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
-  
- <dt><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a></dt>
-  <dd>A sample application that demonstrates Android's search framework, 
-  including how to provide search suggestions for Quick Search Box.</dd>
-  
- <dt><a href="{@docRoot}resources/samples/Snake/index.html">Snake</a></dt>
-  <dd>An implementation of the classic game "Snake."</dd>
-  
- <dt><a href="{@docRoot}resources/samples/SoftKeyboard/index.html">Soft Keyboard</a></dt>
-  <dd>An example of writing an input method for a software keyboard.</dd>
-
- <dt><a href=""{@docRoot}resources/samples/Wiktionary/index.html">Wiktionary</a></dt>
-  <dd>An example of creating interactive widgets for display on the Android
-  home screen.</dd>
-
- <dt><a href="{@docRoot}resources/samples/WiktionarySimple/index.html">Wiktionary (Simplified)</a></dt>
-  <dd>A simple Android home screen widgets example.</dd>
-    
-</dl>
-
-
-<div class="special">
-<p>For more sample applications, check out
-<a href="http://code.google.com/p/apps-for-android/">apps-for-android</a>, a
-collection of open source applications that demonstrate various Android APIs.
-</p>
-</div>
 
 
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 4279d7d..6c02031 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -240,7 +240,7 @@
 <h2 id="BackupAgent">Extending BackupAgent</h2>
 
 <p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
-directly, but should instead <a href="BackupAgentHelper">extend BackupAgentHelper</a> to take
+directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
 advantage of the built-in helper classes that automatically backup and restore your files. However,
 you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
 <ul>
@@ -262,7 +262,7 @@
 <p>If you don't need to perform any of the tasks above and want to back up complete files from
 {@link android.content.SharedPreferences} or <a
 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
-should skip to <a href="BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
+should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
 
 
 
@@ -576,8 +576,8 @@
 
 <h3 id="SharedPreferences">Backing up SharedPreferences</h3>
 
-<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must the
-name of one or more {@link android.content.SharedPreferences} files.</p>
+<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
+include the name of one or more {@link android.content.SharedPreferences} files.</p>
 
 <p>For example, to back up a {@link android.content.SharedPreferences} file named
 "user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index cac85e8..7e2f8a0 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -761,7 +761,7 @@
 cannot use the resources named with the new qualifier. For example, if your <a
 href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
 minSdkVersion}</a> is set to 4, and you qualify all of your drawable resources using <a
-href="NightQualifier">night mode</a> ({@code night} or {@code notnight}, which were added in API
+href="#NightQualifier">night mode</a> ({@code night} or {@code notnight}, which were added in API
 Level 8), then an API Level 4 device cannot access your drawable resources and will crash. In this
 case, you probably want {@code notnight} to be your default resources, so you should exclude that
 qualifier so your drawable resources are in either {@code drawable/} or {@code drawable-night/}.</p>
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index cf3c7de..b4e467c 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -5,198 +5,324 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.view.Menu}</li>
-    <li>{@link android.view.ContextMenu}</li>
-    <li>{@link android.view.SubMenu}</li>
-  </ol>
   <h2>In this document</h2>
   <ol>
-    <li><a href="#options-menu">Options Menu</a></li>
-    <li><a href="#context-menu">Context Menu</a></li>
-    <li><a href="#submenu">Submenu</a></li>
-    <li><a href="#xml">Define Menus in XML</a></li>
-    <li><a href="#features">Menu Features</a>
+    <li><a href="#xml">Defining Menus</a></li>
+    <li><a href="#Inflating">Inflating a Menu Resource</a>
+    <li><a href="#options-menu">Creating an Options Menu</a>
+      <ol>
+        <li><a href="#ChangingTheMenu">Changing the menu when it opens</a></li>
+      </ol>
+    </li>
+    <li><a href="#context-menu">Creating a Context Menu</a></li>
+    <li><a href="#submenu">Creating a Submenu</a></li>
+    <li><a href="#features">Other Menu Features</a>
       <ol>
         <li><a href="#groups">Menu groups</a></li>
         <li><a href="#checkable">Checkable menu items</a></li>
         <li><a href="#shortcuts">Shortcut keys</a></li>
-        <li><a href="#intents">Menu item intents</a></li>
+        <li><a href="#intents">Intents for menu items</a></li>
       </ol>
     </li>
   </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.view.Menu}</li>
+    <li>{@link android.view.MenuItem}</li>
+    <li>{@link android.view.ContextMenu}</li>
+    <li>{@link android.view.SubMenu}</li>
+  </ol>
+
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li>
+  </ol>
 </div>
 </div>
 
-<p>Menus are an important part of any application. They provide familiar interfaces
-that reveal application functions and settings. Android offers an easy programming interface
-for developers to provide standardized application menus for various situations.</p>
+<p>Menus are an important part of an application that provide a familiar interface for the user
+to access application functions and settings. Android offers an easy programming interface
+for you to provide application menus in your application.</p>
 
-<p>Android offers three fundamental types of application menus:</p>
+<p>Android provides three types of application menus:</p>
 <dl>
   <dt><strong>Options Menu</strong></dt>
-    <dd>This is the primary set of menu items for an Activity. It is revealed by pressing 
-    the device MENU key. Within the Options Menu are two groups of menu items:
+    <dd>The primary menu for an Activity, which appears when the user presses
+    the device MENU key. Within the Options Menu are two groups:
       <dl style="margin-top:1em">
         <dt><em>Icon Menu</em></dt>
-          <dd>This is the collection of items initially visible at the bottom of the screen 
+          <dd>The menu items visible at the bottom of the screen
           at the press of the MENU key. It supports a maximum of six menu items.
           These are the only menu items that support icons and the only menu items that <em>do not</em> support
           checkboxes or radio buttons.</dd>
         <dt><em>Expanded Menu</em></dt>
-          <dd>This is a vertical list of items exposed by the "More" menu item from the Icon Menu.
-          It exists only when the Icon Menu becomes over-loaded and is comprised of the sixth 
-          Option Menu item and the rest.</dd>
+          <dd>The vertical list of menu items exposed by the "More" menu item in the Icon Menu.
+          When the Icon Menu is full, the expanded menu is comprised of the sixth
+          menu item and the rest.</dd>
       </dl>
     </dd>
   <dt><strong>Context Menu</strong></dt>
-    <dd>This is a floating list of menu items that may appear when you perform a long-press on a View 
-    (such as a list item). </dd>
+    <dd>A floating list of menu items that appears when the user performs a long-press on a View.
+</dd>
   <dt><strong>Submenu</strong></dt>
-    <dd>This is a floating list of menu items that is revealed by an item in the Options Menu
-    or a Context Menu. A Submenu item cannot support nested Submenus. </dd>
+    <dd>A floating list of menu items that the user opens by pressing a menu item in the Options
+Menu or a context menu. A submenu item cannot support a nested submenu. </dd>
 </dl>
 
 
-<h2 id="options-menu">Options Menu</h2>
-<img align="right" src="{@docRoot}images/options_menu.png" />
-<p>The Options Menu is opened by pressing the device MENU key.
-When opened, the Icon Menu is displayed, which holds the first six menu items.
-If more than six items are added to the Options Menu, then those that can't fit
-in the Icon Menu are revealed in the Expanded Menu, via the "More" menu item. The Expanded Menu
-is automatically added when there are more than six items.</p>
 
-<p>The Options Menu is where you should include basic application functions
-and any necessary navigation items (e.g., to a home screen or application settings).
-You can also add <a href="#submenu">Submenus</a> for organizing topics 
-and including extra menu functionality.</p>
+<h2 id="xml">Defining Menus</h2>
 
-<p>When this menu is opened for the first time, 
-the Android system will call the Activity <code>{@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()}</code> callback method. Override this method in your Activity
-and populate the {@link android.view.Menu} object given to you. You can populate the menu by
-inflating a menu resource that was <a href="#xml">defined in XML</a>, or by calling 
-<code>{@link android.view.Menu#add(CharSequence) add()}</code>
-for each item you'd like in the menu. This method adds a {@link android.view.MenuItem}, and returns the
-newly created object to you. You can use the returned MenuItem to set additional properties like 
-an icon, a keyboard shortcut, an intent, and other settings for the item.</p>
+<p>Instead of instantiating {@link android.view.Menu} objects in your application code, you should
+define a menu and all its items in an XML <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, then inflate the menu
+resource (load it as a programmable object) in your application code. Defining your menus in XML is
+a good practice because it separates your interface design from your application code (the same as
+when you <a href="{@docRoot}guide/topics/ui/declaring-layout.html">define your Activity
+layout</a>).</p>
 
-<p>There are multiple <code>{@link android.view.Menu#add(CharSequence) add()}</code> methods.
-Usually, you'll want to use one that accepts an <var>itemId</var> argument. 
-This is a unique integer that allows you to identify the item during a callback.</p>
+<p>To define a menu, create an XML file inside your project's <code>res/menu/</code>
+directory and build the menu with the following elements:</p>
+<dl>
+  <dt><code>&lt;menu></code></dt>
+    <dd>Creates a {@link android.view.Menu}, which is a container for menu items. It must be
+the root node and holds one or more of the following elements. You can also nest this element
+in an {@code &lt;item&gt;} to create a submenu.</dd>
+  <dt><code>&lt;item></code></dt>
+    <dd>Creates a {@link android.view.MenuItem}, which represents a single item in a menu.</dd>
+  <dt><code>&lt;group></code></dt>
+    <dd>An optional, invisible container for {@code &lt;item&gt;} elements. It allows you to
+categorize menu items so they share properties such as active state and visibility. See <a
+href="#groups">Menu groups</a>.</dd>
+</dl>
 
-<p>When a menu item is selected from the Options Menu, you will receive a callback to the
-<code>{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}</code> 
-method of your Activity. This callback passes you the 
-<code>MenuItem</code> that has been selected. You can identify the item by requesting the 
-<var>itemId</var>, with <code>{@link android.view.MenuItem#getItemId() getItemId()}</code>,
-which returns the integer that was assigned with the <code>add()</code> method. Once you identify
-the menu item, you can take the appropriate action.</p>
+<p>For example, here is a file in <code>res/menu/</code> named <code>game_menu.xml</code>:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/new_game"
+          android:icon="@drawable/ic_new_game"
+          android:title="@string/new_game" /&gt;
+    &lt;item android:id="@+id/quit"
+          android:icon="@drawable/ic_quit"
+          android:title="@string/quit" /&gt;
+&lt;/menu&gt;
+</pre>
 
-<p>Here's an example of this procedure, inside an Activity, wherein we create an 
-Options Menu and handle item selections:</p>
+<p>This example defines a menu with two menu items. Each item includes the attributes:</p>
+<dl>
+  <dt>{@code android:id}</dt>
+    <dd>A resource ID that's unique to the item so that the application can recognize the item when
+the user selects it.</dd>
+  <dt>{@code android:icon}</dt>
+    <dd>A drawable resource that is the icon visible to the user.</dd>
+  <dt>{@code android:title}</dt>
+    <dd>A string resource that is the title visible to the user.</dd>
+</dl>
+
+<p>For more about the XML syntax and attributes for a menu resource, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> reference.</p>
+
+
+<h2 id="Inflating">Inflating a Menu Resource</h2>
+
+<p>You can inflate your menu resource (convert the XML resource into a programmable object) using
+{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}. For
+example, the following code inflates the <code>game_menu.xml</code> file defined above during the
+{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} callback method, to be
+used for the Options Menu:</p>
 
 <pre>
-/* Creates the menu items */
+&#64;Override
 public boolean onCreateOptionsMenu(Menu menu) {
-    menu.add(0, MENU_NEW_GAME, 0, "New Game");
-    menu.add(0, MENU_QUIT, 0, "Quit");
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.game_menu, menu);
     return true;
 }
-
-/* Handles item selections */
-public boolean onOptionsItemSelected(MenuItem item) {
-    switch (item.getItemId()) {
-    case MENU_NEW_GAME:
-        newGame();
-        return true;
-    case MENU_QUIT:
-        quit();
-        return true;
-    }
-    return false;
-}
 </pre>
 
-<p>The <code>add()</code> method used in this sample takes four arguments: 
-<var>groupId</var>, <var>itemId</var>, <var>order</var>, and <var>title</var>.
-The <var>groupId</var> allows you to associate this menu item with a group of other items
-(more about <a href="#groups">Menu groups</a>, below) &mdash; in 
-this example, we ignore it. <var>itemId</var> is a unique integer that we give the 
-MenuItem so that can identify it in the next callback. <var>order</var> allows us to 
-define the display order of the item &mdash; by default, they are displayed by the
-order in which we add them. <var>title</var> is, of course, the name that goes on the 
-menu item (this can also be a 
-<a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">string resource</a>, 
-and we recommend you do it that way for easier localization).</p>
+<p>The {@link android.app.Activity#getMenuInflater()} method returns a {@link
+android.view.MenuInflater} for the Activity. With this object, you can call {@link
+android.view.MenuInflater#inflate(int,Menu) inflate()}, which inflates a menu resource into a
+{@link android.view.Menu} object. In this example, the menu resource defined by
+<code>game_menu.xml</code>
+is inflated into the {@link android.view.Menu} that was passed into {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}. (This callback method for
+creating an option menu is discussed more in the next section.)</p>
 
-<p class="note"><strong>Tip:</strong>
-If you have several menu items that can be grouped together with a title, 
-consider organizing them into a <a href="#submenu">Submenu</a>.</p>
 
-<h3>Adding icons</h3>
-<p>Icons can also be added to items that appears in the Icon Menu with
-<code>{@link android.view.MenuItem#setIcon(Drawable) setIcon()}</code>. For example:</p>
+
+<h2 id="options-menu">Creating an Options Menu</h2>
+
+<div class="figure" style="width:200px">
+  <img src="{@docRoot}images/options_menu.png" height="300" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> Screenshot of an Options Menu.</p>
+</div>
+
+
+<p>The Options Menu is where you should include basic application functions
+and necessary navigation items (for example, a button
+to open application settings). The user
+can open the Options Menu with the device MENU key.
+Figure 1 shows a screenshot of an Options Menu.</p>
+
+<p>When opened, the first visible portion of the Options Menu is called the Icon Menu. It
+holds the first six menu items.
+If you add more than six items to the Options Menu, Android places the sixth item and those after it
+into the Expanded Menu, which the user can open with the "More" menu item.</p>
+
+<p>When the user opens the Options Menu for the first time, Android calls your Activity's
+{@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} method. Override this method in your Activity
+and populate the {@link android.view.Menu} that is passed into the method. Populate the
+{@link android.view.Menu} by inflating a menu resource as described in <a
+href="#Inflating">Inflating a Menu Resource</a>. (You can
+also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int)
+add()} to add menu items.)</p>
+
+<p>When the user selects a menu item from the Options Menu, the system calls your Activity's
+{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}
+method. This method passes the
+{@link android.view.MenuItem} that the user selected. You can identify the menu item by calling
+{@link android.view.MenuItem#getItemId()}, which returns the unique ID for the menu
+item (defined by the {@code android:id} attribute in the menu resource or with an integer passed
+to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match this ID
+against known menu items and perform the appropriate action.</p>
+
+<p>For example:</p>
+
 <pre>
-menu.add(0, MENU_QUIT, 0, "Quit")
-    .setIcon(R.drawable.menu_quit_icon);</pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    // Handle item selection
+    switch (item.getItemId()) {
+    case R.id.new_game:
+        newGame();
+        return true;
+    case R.id.quit:
+        quit();
+        return true;
+    default:
+        return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
 
-<h3>Modifying the menu</h3>
-<p>If you want to sometimes re-write the Options Menu as it is opened, override the 
-<code>{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}</code> method, which is
-called each time the menu is opened. This will pass you the Menu object, just like the 
-<code>onCreateOptionsMenu()</code> callback. This is useful if you'd like to add or remove
-menu options depending on the current state of an application or game.</p>
+<p>In this example, {@link android.view.MenuItem#getItemId()} queries the ID for the selected menu
+item and the switch statement compares the ID against the resource IDs that were assigned to menu
+items in the XML resource. When a switch case successfully handles the item, it
+returns "true" to indicate that the item selection was handled. Otherwise, the default statement
+passes the menu item to the super class in
+case it can handle the item selected. (If you've directly extended the {@link android.app.Activity}
+class, then the super class returns "false", but it's a good practice to
+pass unhandled menu items to the super class instead of directly returning "false".)</p>
+
+<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
+some of them provide the same Options Menu, consider creating
+an Activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} methods. Then extend this class for each Activity that should share the
+same Options Menu. This way, you have to manage only one set of code for handling menu
+actions and each decendent class inherits the menu behaviors.<br/><br/>
+If you want to add menu items to one of your decendent activities,
+override {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} in that Activity. Call {@code super.onCreateOptionsMenu(menu)} so the
+original menu items are created, then add new menu items with {@link
+android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
+behavior for individual menu items.</p>
+
+
+<h3 id="ChangingTheMenu">Changing the menu when it opens</h3>
+
+<p>The {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} method is
+called only the first time the Options Menu is opened. The system keeps and re-uses the {@link
+android.view.Menu} you define in this method until your Activity is destroyed. If you want to change
+the Options Menu each time it opens, you must override the
+{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This passes
+you the {@link android.view.Menu} object as it currently exists. This is useful if you'd like to
+remove, add, disable, or enable menu items depending on the current state of your application.</p>
 
 <p class="note"><strong>Note:</strong> 
-When changing items in the menu, it's bad practice to do so based on the currently selected item.
-Keep in mind that, when in touch mode, there will not be a selected (or focused) item. Instead, you
-should use a <a href="#context-menu">Context Menu</a> for such behaviors, when you want to provide 
-functionality based on a particular item in the UI.</p>
+You should never change items in the Options Menu based on the {@link android.view.View} currently
+in focus. When in touch mode (when the user is not using a trackball or d-pad), Views
+cannot take focus, so you should never use focus as the basis for modifying
+items in the Options Menu. If you want to provide menu items that are context-sensitive to a {@link
+android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
 
 
-<h2 id="context-menu">Context Menu</h2>
-<p>The Android context menu is similar, in concept, to the menu revealed with a "right-click" on a PC. 
-When a view is registered to a context menu, 
-performing a "long-press" (press and hold for about two seconds) on the object
-will reveal a floating menu that provides functions relating to that item. 
-Context menus can be registered to any View object,
-however, they are most often used for items in a 
-{@link android.widget.ListView}, which helpfully indicates the presence of the context menu
-by transforming the background color of the ListView item when pressed.
-(The items in the phone's contact list offer an example of this feature.)
-</p>
 
-<p class="note"><strong>Note:</strong> Context menu items do not support icons or shortcut keys.</p>
+<h2 id="context-menu">Creating a Context Menu</h2>
 
-<p>To create a context menu, you must override the Activity's context menu callback methods:
-<code>{@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) onCreateContextMenu()}</code> and 
-<code>{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}</code>.
-Inside the <code>onCreateContextMenu()</code> callback method, you can add menu items using one of the 
-<code>{@link android.view.Menu#add(CharSequence) add()}</code> methods, or by 
-inflating a menu resource that was <a href="#xml">defined in XML</a>.
-Then, register a {@link android.view.ContextMenu} for the View, with 
-<code>{@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()}</code>.</p>
+<p>A context menu is conceptually similar to the menu displayed when the user performs a
+"right-click" on a PC. You should use a context menu to provide the user access to
+actions that pertain to a specific item in the user interface. On Android, a context menu is
+displayed when the user performs a "long press" (press and hold) on an item.</p>
 
-<p>For example, here is some code that can be used with the 
-<a href="{@docRoot}resources/tutorials/notepad/index.html">Notepad application</a>
-to add a context menu for each note in the list:</p>
+<p>You can create a context menu for any View, though context menus are most often used for items in
+a {@link android.widget.ListView}. When the user performs a long-press on an item in a ListView and
+the list is registered to provide a context menu, the list item signals to the user that a context
+menu is available by animating its background color&mdash;it transitions from
+orange to white before opening the context menu. (The Contacts application demonstrates this
+feature.)</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h3>Register a ListView</h3>
+<p>If your Activity uses a {@link android.widget.ListView} and
+you want all list items to provide a context menu, register all items for a context
+menu by passing the {@link android.widget.ListView} to {@link
+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}. For
+example, if you're using a {@link android.app.ListActivity}, register all list items like this:</p>
+<p><code>registerForContextMenu({@link android.app.ListActivity#getListView()});</code></p>
+</div>
+</div>
+
+<p>In order for a View to provide a context menu, you must "register" the view for a context
+menu. Call {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and
+pass it the {@link android.view.View} you want to give a context menu. When this View then
+receives a long-press, it displays a context menu.</p>
+
+<p>To define the context menu's appearance and behavior, override your Activity's context menu
+callback methods, {@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
+onCreateContextMenu()} and
+{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
+
+<p>For example, here's an {@link
+android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
+onCreateContextMenu()} that uses the {@code context_menu.xml} menu resource:</p>
 <pre>
+&#64;Override
 public void onCreateContextMenu(ContextMenu menu, View v,
                                 ContextMenuInfo menuInfo) {
   super.onCreateContextMenu(menu, v, menuInfo);
-  menu.add(0, EDIT_ID, 0, "Edit");
-  menu.add(0, DELETE_ID, 0,  "Delete");
+  MenuInflater inflater = getMenuInflater();
+  inflater.inflate(R.menu.context_menu, menu);
 }
+</pre>
 
+<p>{@link android.view.MenuInflater} is used to inflate the context menu from a <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. (You can also use
+{@link android.view.Menu#add(int,int,int,int) add()} to add menu items.) The callback method
+parameters include the {@link android.view.View}
+that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
+additional information about the item selected. You might use these parameters to determine
+which context menu should be created, but in this example, all context menus for the Activity are
+the same.</p>
+
+<p>Then when the user selects an item from the context menu, the system calls {@link
+android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}. Here is an example
+of how you can handle selected items:</p>
+
+<pre>
+&#64;Override
 public boolean onContextItemSelected(MenuItem item) {
   AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
   switch (item.getItemId()) {
-  case EDIT_ID:
+  case R.id.edit:
     editNote(info.id);
     return true;
-  case DELETE_ID:
+  case R.id.delete:
     deleteNote(info.id);
     return true;
   default:
@@ -205,285 +331,276 @@
 }
 </pre>
 
-<p>In <code>onCreateContextMenu()</code>, we are given not only the ContextMenu to
-which we will add {@link android.view.MenuItem}s, but also the {@link android.view.View}
-that was selected and a {@link android.view.ContextMenu.ContextMenuInfo ContextMenuInfo} object,
-which provides additional information about the object that was selected. 
-In this example, nothing special is done in <code>onCreateContextMenu()</code> &mdash; just
-a couple items are added as usual. In the <code>onContextItemSelected()</code>
-callback, we request the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo} 
-from the {@code MenuItem}, which provides information about the currently selected item. 
-All we need from
-this is the list ID for the selected item, so whether editing a note or deleting it, 
-we find the ID with the {@code AdapterContextMenuInfo.info} field of the object. This ID
-is passed to the <code>editNote()</code> and <code>deleteNote()</code> methods to perform
-the respective action.</p>
+<p>The structure of this code is similar to the example for <a href="#options-menu">Creating an
+Options Menu</a>, in which {@link android.view.MenuItem#getItemId()} queries the ID for the selected
+menu item and a switch statement matches the item to the IDs that are defined in the menu resource.
+And like the options menu example, the default statement calls the super class in case it
+can handle menu items not handled here, if necessary.</p>
 
-<p>Now, to register this context menu for all the items in a {@link android.widget.ListView},
-we pass the entire {@code ListView} to the 
-<code>{@link android.app.Activity#registerForContextMenu(View)}</code> method:</p>
+<p>In this example, the selected item is an item from a {@link android.widget.ListView}. To
+perform an action on the selected item, the application needs to know the list
+ID for the selected item (it's position in the ListView). To get the ID, the application calls
+{@link android.view.MenuItem#getMenuInfo()}, which returns a {@link
+android.widget.AdapterView.AdapterContextMenuInfo} object that includes the list ID for the
+selected item in the {@link android.widget.AdapterView.AdapterContextMenuInfo#id id} field. The
+local methods <code>editNote()</code> and <code>deleteNote()</code> methods accept this list ID to
+perform an action on the data specified by the list ID.</p>
 
-<pre>registerForContextMenu(getListView());</pre>
-<p>Remember, you can pass any View object to register a context menu. Here,
-<code>{@link android.app.ListActivity#getListView()}</code> returns the ListView
-object used in the Notepad application's {@link android.app.ListActivity}. As such, each item 
-in the list is registered to this context menu.</p>
+<p class="note"><strong>Note:</strong> Items in a context menu do not support icons or shortcut
+keys.</p>
 
 
 
-<h2 id="submenu">Submenus</h2>
-<p>A sub menu can be added within any menu, except another sub menu.
-These are very useful when your application has a lot of functions that may be
-organized in topics, like the items in a PC application's menu bar (File, Edit, View, etc.).</p>
+<h2 id="submenu">Creating Submenus</h2>
 
-<p>A sub menu is created by adding it to an existing {@link android.view.Menu}
-with <code>{@link android.view.Menu#addSubMenu(CharSequence) addSubMenu()}</code>. 
-This returns a {@link android.view.SubMenu} object (an extension of {@link android.view.Menu}). 
-You can then add additional items to this menu, with the normal routine, using
-the <code>{@link android.view.Menu#add(CharSequence) add()}</code> methods. For example:</p>
+<p>A submenu is a menu that the user can open by selecting an item in another menu. You can add a
+submenu to any menu (except a submenu). Submenus are useful when your application has a lot of
+functions that can be organized into topics, like items in a PC application's menu bar (File, Edit,
+View, etc.).</p>
+
+<p>When creating your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu
+resource</a>, you can create a submenu by adding a {@code &lt;menu&gt;} element as the child of an
+{@code &lt;item&gt;}. For example:</p>
 
 <pre>
-public boolean onCreateOptionsMenu(Menu menu) {
-  boolean result = super.onCreateOptionsMenu(menu);
-
-  SubMenu fileMenu = menu.addSubMenu("File");
-  SubMenu editMenu = menu.addSubMenu("Edit");
-  fileMenu.add("new");
-  fileMenu.add("open");
-  fileMenu.add("save");
-  editMenu.add("undo");
-  editMenu.add("redo");
-
-  return result;
-}
-</pre>
-<p>Callbacks for items selected in a sub menu are made to the parent menu's callback method. 
-For the example above, selections in the sub menu will be handled by the 
-<code>onOptionsItemSelected()</code> callback.</p>
-<p>You can also add Submenus when you <a href="#xml">define the parent menu in XML</a>.</p>
-
-
-<h2 id="xml">Define Menus in XML</h2>
-<p>Just like Android UI layouts, you can define application menus in XML, then inflate them 
-in your menu's <code>onCreate...()</code> callback method. This makes your application code cleaner and
-separates more interface design into XML, which is easier to visualize.</p>
-
-<p>To start, create a new folder in your project <code>res/</code> directory called <code>menu</code>.
-This is where you should keep all XML files that define your application menus.</p>
-
-<p>In a menu XML layout, there are
-three valid elements: <code>&lt;menu></code>, <code>&lt;group></code> and <code>&lt;item></code>. The
-<code>item</code> and <code>group</code> elements must be children of a <code>menu</code>, but <code>item</code>
-elements may also be the children of a <code>group</code>, and another <code>menu</code> element may be the child
-of an <code>item</code> (to create a Submenu). Of course, the root node of any file
-must be a <code>menu</code> element.</p>
-
-<p>As an example, we'll define the same menu created in the <a href="#options-menu">Options Menu</a> section, 
-above. We start with an XML file named <code>options_menu.xml</code> inside the <code>res/menu/</code> folder:</p>
-<pre>
-&lt;menu xmlns:android="http://schemas.android.com/apk/res/android">
-    &lt;item android:id="@+id/new_game"
-          android:title="New Game" />
-    &lt;item android:id="@+id/quit"
-          android:title="Quit" />
-&lt;/menu>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/file"
+          android:icon="@drawable/file"
+          android:title="@string/file" &gt;
+        &lt;!-- "file" submenu --&gt;
+        &lt;menu"&gt;
+            &lt;item android:id="@+id/new"
+                  android:title="@string/new" /&gt;
+            &lt;item android:id="@+id/open"
+                  android:title="@string/open" /&gt;
+        &lt;/menu&gt;
+    &lt;/item&gt;
+&lt;/menu&gt;
 </pre>
 
-<p>Then, in the <code>onCreateOptionsMenu()</code> method, we inflate this resource using
-<code>{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}</code>:</p>
-<pre>
-public boolean onCreateOptionsMenu(Menu menu) {
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.options_menu, menu);
-    return true;
-}
-</pre>
+<p>When the user selects an item from a submenu, the parent menu's respective on-item-selected
+callback method receives the event. For instance, if the above menu is applied as an Options Menu,
+then the {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method
+is called when a submenu item is selected.</p>
 
-<p>The <code>{@link android.app.Activity#getMenuInflater()}</code> method returns the {@link android.view.MenuInflater}
-for our activity's context. We then call <code>{@link android.view.MenuInflater#inflate(int,Menu) inflate()}</code>,
-passing it a pointer to our menu resource and the Menu object given by the callback.</code></p>
+<p>You can also use {@link android.view.Menu#addSubMenu(int,int,int,int) addSubMenu()} to
+dynamically add a {@link android.view.SubMenu} to an existing {@link android.view.Menu}. This
+returns the new {@link android.view.SubMenu} object, to which you can add
+submenu items, using {@link android.view.Menu#add(int,int,int,int) add()}</p>
 
-<p>While this small sample may seem like more effort, compared to creating the menu items in the 
-<code>onCreateOptionsMenu()</code> method, this will save a lot of trouble when dealing with more items
-and it keeps your application code clean.</p>
 
-<p>You can define <a href="#groups">menu groups</a> by wrapping <code>item</code> elements in a <code>group</code>
-element, and create Submenus by nesting another <code>menu</code> inside an <code>item</code>.
-Each element also supports all the necessary attributes to control features like shortcut keys,
-checkboxes, icons, and more. To learn about these attributes and more about the XML syntax, see the Menus
-topic in the <a href="{@docRoot}guide/topics/resources/available-resources.html#menus">Available 
-Resource Types</a> document.</p>
 
-<h2 id="features">Menu Features</h2>
-<p>Here are some other features that can be applied to most menu items.</p>
+<h2 id="features">Other Menu Features</h2>
+
+<p>Here are some other features that you can apply to most menu items.</p>
 
 <h3 id="groups">Menu groups</h3>
-<p>When adding new items to a menu, you can optionally include each item in a group.
-A menu group is a collection of menu items that can share certain traits, like
-whether they are visible, enabled, or checkable.</p>
 
-<p>A group is defined by an integer (or a resource id, in XML). A menu item is added to the group when it is
-added to the menu, using one of the <code>add()</code> methods that accepts a <var>groupId</var>
-as an argument, such as <code>{@link android.view.Menu#add(int,int,int,int)}</code>.</p>
+<p>A menu group is a collection of menu items that share certain traits. With a group, you
+can:</p>
+<ul>
+  <li>Show or hide all items with {@link android.view.Menu#setGroupVisible(int,boolean)
+setGroupVisible()}</li>
+  <li>Enable or disable all items with {@link android.view.Menu#setGroupEnabled(int,boolean)
+setGroupEnabled()}</li>
+  <li>Specify whether all items are checkable with {@link
+android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()}</li>
+</ul>
 
-<p>You can show or hide the entire group with 
-<code>{@link android.view.Menu#setGroupVisible(int,boolean) setGroupVisible()}</code>; 
-enable or disable the group with 
-<code>{@link android.view.Menu#setGroupEnabled(int,boolean) setGroupEnabled()}</code>;
-and set whether the items can be checkable with
-<code>{@link android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()}</code>.
-</p>
+<p>You can create a group by nesting {@code &lt;item&gt;} elements inside a {@code &lt;group&gt;}
+element in your menu resource or by specifying a group ID with the the {@link
+android.view.Menu#add(int,int,int,int) add()} method.</p>
+
+<p>Here's an example menu resource that includes a group:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/item1"
+          android:icon="@drawable/item1"
+          android:title="@string/item1" /&gt;
+    &lt;!-- menu group --&gt;
+    &lt;group android:id="@+id/group1"&gt;
+        &lt;item android:id="@+id/groupItem1"
+              android:title="@string/groupItem1" /&gt;
+        &lt;item android:id="@+id/groupItem2"
+              android:title="@string/groupItem2" /&gt;
+    &lt;/group&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>The items that are in the group appear the same as the first item that is not in a
+group&mdash;all three items in the menu are siblings. However, you can modify the traits of the two
+items in the group by referencing the group ID and using the methods listed above.</p>
+
 
 <h3 id="checkable">Checkable menu items</h3>
-<img align="right" src="{@docRoot}images/radio_buttons.png" alt="" />
-<p>Any menu item can be used as an interface for turning options on and off. This can
-be indicated with a checkbox for stand-alone options, or radio buttons for groups of
-mutually exclusive options (see the screenshot, to the right).</p>
 
-<p class="note"><strong>Note:</strong> Menu items in the Icon Menu cannot
+<div class="figure" style="width:200px">
+  <img src="{@docRoot}images/radio_buttons.png" height="300" alt="" />
+  <p class="img-caption"><strong>Figure 2.</strong> Screenshot of checkable menu items</p>
+</div>
+
+<p>A menu can be useful as an interface for turning options on and off, using a checkbox for
+stand-alone options, or radio buttons for groups of
+mutually exclusive options. Figure 2 shows a submenu with items that are checkable with radio
+buttons.</p>
+
+<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the Options Menu) cannot
 display a checkbox or radio button. If you choose to make items in the Icon Menu checkable,
-then you must personally indicate the state by swapping the icon and/or text 
-each time the state changes between on and off.</p>
+you must manually indicate the checked state by swapping the icon and/or text
+each time the state changes.</p>
 
-<p>To make a single item checkable, use the <code>{@link android.view.MenuItem#setCheckable(boolean)
-setCheckable()}</code> method, like so:</p>
+<p>You can define the checkable behavior for individual menu items using the {@code
+android:checkable} attribute in the {@code &lt;item&gt;} element, or for an entire group with
+the {@code android:checkableBehavior} attribute in the {@code &lt;group&gt;} element. For
+example, all items in this menu group are checkable with a radio button:</p>
+
 <pre>
-menu.add(0, VIBRATE_SETTING_ID, 0, "Vibrate")
-    .setCheckable(true);
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;group android:checkableBehavior="single"&gt;
+        &lt;item android:id="@+id/red"
+              android:title="@string/red" /&gt;
+        &lt;item android:id="@+id/blue"
+              android:title="@string/blue" /&gt;
+    &lt;/group&gt;
+&lt;/menu&gt;
 </pre>
-<p>This will display a checkbox with the menu item (unless it's in the Icon Menu). When the item
-is selected, the <code>onOptionsItemSelected()</code> callback is called as usual. It is here that
-you must set the state of the checkbox. You can query the current state of the item with
-<code>{@link android.view.MenuItem#isChecked()}</code> and set the checked state with
-<code>{@link android.view.MenuItem#setChecked(boolean) setChecked()}</code>. 
-Here's what this looks like inside the 
-<code>onOptionsItemSelected()</code> callback:</p>
+
+<p>The {@code android:checkableBehavior} attribute accepts either:
+<dl>
+  <dt>{@code single}</dt>
+    <dd>Only one item from the group can be checked (radio buttons)</dd>
+  <dt>{@code all}</dt>
+    <dd>All items can be checked (checkboxes)</dd>
+  <dt>{@code none}</dt>
+    <dd>No items are checkable</dd>
+</dl>
+
+<p>You can apply a default checked state to an item using the {@code android:checked} attribute in
+the {@code &lt;item&gt;} element and change it in code with the {@link
+android.view.MenuItem#setChecked(boolean) setChecked()} method.</p>
+
+<p>When a checkable item is selected, the system calls your respective item-selected callback method
+(such as {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). It
+is here that you must set the state of the checkbox, because a checkbox or radio button does not
+change its state automatically. You can query the current state of the item (as it was before the
+user selected it) with {@link android.view.MenuItem#isChecked()} and then set the checked state with
+{@link android.view.MenuItem#setChecked(boolean) setChecked()}. For example:</p>
+
 <pre>
-switch (item.getItemId()) {
-case VIBRATE_SETTING_ID:
-  if (item.isChecked()) item.setChecked(false);
-  else item.setChecked(true);
-  return true;
-...
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+  switch (item.getItemId()) {
+  case R.id.vibrate:
+  case R.id.dont_vibrate:
+    if (item.isChecked()) item.setChecked(false);
+    else item.setChecked(true);
+    return true;
+  default:
+    return super.onOptionsItemSelected(item);
+  }
 }
 </pre>
 
-<p>To make a group of mutually exclusive radio button items, simply 
-assign the same group ID to each menu item 
-and call <code>{@link android.view.Menu#setGroupCheckable(int,boolean,boolean) 
-setGroupCheckable()}</code>. In this case, you don't need to call <code>setCheckable()</code>
-on each menu items, because the group as a whole is set checkable. Here's an example of
-two mutually exclusive options in a Submenu:</p>
-<pre>
-SubMenu subMenu = menu.addSubMenu("Color");
-subMenu.add(COLOR_MENU_GROUP, COLOR_RED_ID, 0, "Red");
-subMenu.add(COLOR_MENU_GROUP, COLOR_BLUE_ID, 0, "Blue");
-subMenu.setGroupCheckable(COLOR_MENU_GROUP, true, true);
-</pre>
-<p>In the <code>setGroupCheckable()</code> method, the first argument is the group ID
-that we want to set checkable. The second argument is whether we want the group items
-to be checkable. The last one is whether we want each item to be exclusively checkable 
-(if we set this <em>false</em>, then all the items will be checkboxes instead of radio buttons).
-When the group is set to be exclusive (radio buttons), each time a new item is selected, 
-all other are automatically de-selected.</p>
-<p>
+<p>If you don't set the checked state this way, then the visible state of the item (the checkbox or
+radio button) will not
+change when the user selects it. When you do set the state, the Activity preserves the checked state
+of the item so that when the user opens the menu later, the checked state that you
+set is visible.</p>
 
 <p class="note"><strong>Note:</strong>
-Checkable menu items are intended to be used only on a per-session basis and not saved to the device 
-(e.g., the <em>Map mode</em> setting in the Maps application is not saved &mdash; screenshot above).
-If there are application settings that you would like to save for the user,
-then you should store the data using <a href="#{@docRoot}guide/topics/data/data-storage.html#pref">Preferences</a>,
-and manage them with a {@link android.preference.PreferenceActivity}.</p>
+Checkable menu items are intended to be used only on a per-session basis and not saved after the
+application is destroyed. If you have application settings that you would like to save for the user,
+you should store the data using <a
+href="#{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
 
 
 <h3 id="shortcuts">Shortcut keys</h3>
-<p>Quick access shortcut keys using letters and/or numbers can be added to menu items with
-<code>setAlphabeticShortcut(char)</code> (to set char shortcut), <code>setNumericShortcut(int)</code>
-(to set numeric shortcut),
-or <code>setShortcut(char,int)</code> (to set both)</code>. Case is <em>not</em> sensitive.
 
-For example:</p>
-<pre>
-menu.add(0, MENU_QUIT, 0, "Quit")
-    .setAlphabeticShortcut('q');
-</pre>
-<p>Now, when the menu is open (or while holding the MENU key), pressing the "q" key will 
-select this item.</p>
-<p>This shortcut key will be displayed as a tip in the menu item, below the menu item name
-(except for items in the Icon Menu).</p>
-<p class="note"><strong>Note:</strong> Shortcuts cannot be added to items in a Context Menu.</p>
+<p>You can add quick-access shortcut keys using letters and/or numbers to menu items with the
+{@code android:alphabeticShortcut} and {@code android:numericShortcut} attributes in the {@code
+&lt;item&gt;} element. You can also use the methods {@link
+android.view.MenuItem#setAlphabeticShortcut(char)} and {@link
+android.view.MenuItem#setNumericShortcut(char)}. Shortcut keys are <em>not</em>
+case sensitive.</p>
+
+<p>For example, if you apply the "s" character as an alphabetic shortcut to a "save" menu item, then
+when the menu is open (or while the user holds the MENU key) and the user presses the "s" key,
+the "save" menu item is selected.</p>
+
+<p>This shortcut key is displayed as a tip in the menu item, below the menu item name
+(except for items in the Icon Menu, which are displayed only if the user holds the MENU
+key).</p>
+
+<p class="note"><strong>Note:</strong> Shortcut keys for menu items only work on devices with a
+hardware keyboard. Shortcuts cannot be added to items in a Context Menu.</p>
 
 
-<h3 id="intents">Menu item intents</h3>
-<p>If you've read the <a href="{@docRoot}guide/topics/fundamentals.html">Application
-Fundamentals</a>, then you're at least a little familiar
-with Android Intents. These allow applications to bind with each other, share information,
-and perform user tasks cooperatively. Just like your application might fire an Intent to launch a web browser,
-an email client, or another Activity in your application,
-you can perform such actions from within a menu.
-There are two ways to do this: define an Intent and assign it to a single menu item, or
-define an Intent and allow Android to search the device for activities and dynamically add a 
-menu item for each one that meets the Intent criteria.</p>
+<h3 id="intents">Intents for menu items</h3>
 
-<p>For more information on creating Intents and providing your application's services to other applications, 
-read the <a href="/guide/topics/intents/intents-filters.html">Intents 
-and Intent Filters</a> document.</p>
+<p>Sometimes you'll want a menu item to launch an Activity using an Intent (whether it's an
+Actvitity in your application or another application). When you know the Intent you want to use and
+have a specific menu item that should initiate the Intent, you can execute the Intent with {@link
+android.app.Activity#startActivity(Intent) startActivity()} during the appropriate on-item-selected
+callback method (such as the {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} callback).</p>
 
-<h4>Set an intent for a single menu item</h4>
-<p>If you want to offer a specific menu item that launches a new Activity, then you 
-can specifically define an Intent for the menu item with the
-<code>{@link android.view.MenuItem#setIntent(Intent)
-setIntent()}</code> method.</p>
+<p>However, if you are not certain that the user's device
+contains an application that handles the Intent, then adding a menu item that executes the
+Intent can result in a non-functioning menu item, because the Intent might not resolve to an
+Activity that accepts it. To solve this, Android lets you dynamically add menu items to your menu
+when Android finds activities on the device that handle your Intent.</p>
 
-<p>For example, inside the <code>{@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()}</code> method, you can define a new menu item with an Intent like this:</p>
-<pre>
-MenuItem menuItem = menu.add(0, PHOTO_PICKER_ID, 0, "Select Photo");
-menuItem.setIntent(new Intent(this, PhotoPicker.class));
-</pre>
-<p>Android will automatically launch the Activity when the item is selected.</p>
+<p>If you're not familiar with creating Intents, read the <a
+href="/guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>.</p>
 
-<p class="note"><strong>Note:</strong> This will not return a result to your Activity.
-If you wish to be returned a result, then do not use <code>setIntent()</code>.
-Instead, handle the selection as usual in the <code>onOptionsMenuItemSelected()</code>
-or <code>onContextMenuItemSelected()</code> callback and call
-<code>{@link android.app.Activity#startActivityForResult(Intent,int) startActivityForResult()}</code>.
-</p>
 
-<h4>Dynamically add intents</h4>
+<h4>Dynamically adding Intents</h4>
 
-<p>If there are potentially multiple activities that are relevant to your current
-Activity or selected item, then the application can dynamically add menu items that execute other
-services.</p>
-<p>During menu creation, define an Intent with the category <var>Intent.ALTERNATIVE_CATEGORY</var> and/or
-<var>Intent.SELECTED_ALTERNATIVE</var>, the MIME type currently selected (if any), and any other
-requirements, the same way as you would satisfy an intent filter to open a new
-Activity. Then call  
-<code>{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) 
-addIntentOptions()}</code> to have Android search for any services meeting those requirements
-and add them to the menu for you. If there are no applications installed
-that satisfy the Intent, then no additional menu items are added.</p>
+<p>When you don't know if the user's device has an application that handles a specific Intent,
+you can define the Intent and let Android search the device for activities that accept the Intent.
+When it finds activies that handle the Intent, it adds a menu item for
+each one to your menu and attaches the appropriate Intent to open the Activity when the user
+selects it.</p>
+
+<p>To add menu items based on available activities that accept an Intent:</p>
+<ol>
+  <li>Define an
+Intent with the category {@link android.content.Intent#CATEGORY_ALTERNATIVE} and/or
+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE}, plus any other requirements.</li>
+  <li>Call {@link
+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+Menu.addIntentOptions()}. Android then searches for any applications that can perform the Intent
+and adds them to your menu.</li>
+</ol>
+
+<p>If there are no applications installed
+that satisfy the Intent, then no menu items are added.</p>
 
 <p class="note"><strong>Note:</strong>
-<var>SELECTED_ALTERNATIVE</var> is used to handle the currently selected element on the 
-screen. So, it should only be used when creating a Menu in <code>onCreateContextMenu()</code> or
-<code>onPrepareOptionsMenu()</code>, which is called every time the Options Menu is opened.</p>
+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} is used to handle the currently
+selected element on the screen. So, it should only be used when creating a Menu in {@link
+android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
+onCreateContextMenu()}.</p>
 
-<p>Here's an example demonstrating how an application would search for
-additional services to display on its menu.</p>
+<p>For example:</p>
 
 <pre>
+&#64;Override
 public boolean onCreateOptionsMenu(Menu menu){
     super.onCreateOptionsMenu(menu);
 
     // Create an Intent that describes the requirements to fulfill, to be included
-    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. 
-    Intent intent = new Intent(null, getIntent().getData());
+    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
+    Intent intent = new Intent(null, dataUri);
     intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
-        
-    // Search for, and populate the menu with, acceptable offering applications.
+
+    // Search and populate the menu with acceptable offering applications.
     menu.addIntentOptions(
-         thisClass.INTENT_OPTIONS,  // Menu group 
+         R.id.intent_group,  // Menu group to which new items will be added
          0,      // Unique item ID (none)
          0,      // Order for the items (none)
          this.getComponentName(),   // The current Activity name
@@ -495,17 +612,27 @@
     return true;
 }</pre>
 
-<p>For each Activity found that provides an Intent Filter matching the Intent defined, a menu
-item will be added, using the <var>android:label</var> value of the intent filter as the text
-for the menu item. 
-The <code>{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) addIntentOptions()}</code> method will also return the number of menu items added.</p>
-<p>Also be aware that, when <code>addIntentOptions()</code> is called, it will override any and all
-menu items in the menu group specified in the first argument.</p>
+<p>For each Activity found that provides an Intent filter matching the Intent defined, a menu
+item is added, using the value in the Intent filter's <code>android:label</code> as the
+menu item title and the application icon as the menu item icon. The
+{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()} method returns the number of menu items added.</p>
 
-<p>If you wish to offer the services of your Activity to other application menus, then you 
-only need to define an intent filter as usual. Just be sure to include the <var>ALTERNATIVE</var> and/or
-<var>SELECTED_ALTERNATIVE</var> values in the <var>name</var> attribute of 
-a <code>&lt;category></code> element in the intent filter. For example:</p>
+<p class="note"><strong>Note:</strong> When you call {@link
+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()}, it overrides any and all menu items by the menu group specified in the first
+argument.</p>
+
+
+<h4>Allowing your Activity to be added to menus</h4>
+
+<p>You can also offer the services of your Activity to other applications, so your
+application can be included in the menu of others (reverse the roles described above).</p>
+
+<p>To be included in other application menus, you need to define an Intent
+filter as usual, but be sure to include the {@link android.content.Intent#CATEGORY_ALTERNATIVE}
+and/or {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} values for the Intent filter
+category. For example:</p>
 <pre>
 &lt;intent-filter label="Resize Image">
     ...
@@ -514,9 +641,10 @@
     ...
 &lt;/intent-filter>
 </pre>
-<p>read more about writing intent filters in the 
+
+<p>Read more about writing Intent filters in the
 <a href="/guide/topics/intents/intents-filters.html">Intents and Intent Filters</a> document.</p>
 
 <p>For a sample application using this technique, see the 
-<a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a>
-sample code.</p>
+<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">Note
+Pad</a> sample code.</p>
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/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5e75105..6cb7228 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -43,29 +43,73 @@
 the hands of users. For information about how to target your application to devices based on
 platform version, see <a href="{@docRoot}guide/appendix/api-levels.html">API Levels</a>.</p>
 
-<p class="note"><strong>Note:</strong> This data is based on the number
-of Android devices that have accessed Android Market within a 14-day period
-ending on the data collection date noted below.</p>
+
+<h3 id="Current">Current Distribution</h3>
+
+<p>The following pie chart and table is based on the number of Android devices that have accessed
+Android Market within a 14-day period ending on the data collection date noted below.</p>
 
 <div class="dashboard-panel">
 
-<img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.1,24.6,25.0,0.1,0.3,50.0&chl=
-Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1|Android%202.1&chco=c4df9b,
-6fad0c" />
+<img alt="" height="250" width="460"
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.3,21.3,23.5,53.1,1.8&chl=Other*|
+Android%201.5|Android%201.6|Android%202.1|Android%202.2&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
-  <th>Android Platform</th>
-  <th>Percent of Devices</th>
+  <th>Platform</th>
+  <th>API Level</th>
+  <th>Distribution</th>
 </tr>
-<tr><td>Android 1.1</td><td>0.1%</td></tr> 
-<tr><td>Android 1.5</td><td>24.6%</td></tr> 
-<tr><td>Android 1.6</td><td>25.0%</td></tr> 
-<tr><td>Android 2.0</td><td>0.1%</td></tr> 
-<tr><td>Android 2.0.1</td><td>0.3%</td></tr> 
-<tr><td>Android 2.1</td><td>50.0%</td></tr> 
+<tr><td>Android 1.5</td><td>3</td><td>21.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>23.5%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>53.1%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>1.8%</td></tr>
 </table>
-<p><em>Data collected during two weeks ending on June 16, 2010</em></p>
-</div>
+
+<p><em>Data collected during two weeks ending on July 1, 2010</em></p>
+<p style="font-size:.9em">* <em>Other: 0.3% of devices running obsolete versions</em></p>
+
+</div><!-- end dashboard-panel -->
+
+
+<h3 id="Historical">Historical Distribution</h3>
+
+<p>The following stacked line graph provides a history of the relative number of
+active Android devices running different versions of the Android platform. It also provides a
+valuable perspective of how many devices your application is compatible with, based on the
+platform version.</p>
+
+<p>Notice that the platform versions are stacked on top of each other with the oldest active
+version at the top. This format indicates the total percent of active devices that are compatible
+with a given version of Android. For example, if you develop your application for
+the version that is at the very top of the chart, then your application is
+compatible with 100% of active devices (and all future versions), because all Android APIs are
+forward compatible. Or, if you develop your application for a version lower on the chart,
+then it is currently compatible with the percentage of devices indicated on the y-axis, where the
+line for that version meets the y-axis on the right.</p>
+
+<p>Each dataset in the timeline is based on the number of Android devices that accessed
+Android Market within a 14-day period ending on the date indicated on the x-axis.</p>
+
+<div class="dashboard-panel">
+
+<img alt="" height="265" width="700" style="padding:5px;background:#fff"
+src="http://chart.apis.google.com/chart?&cht=lc&chs=700x265&chxt=x,y,r&chxr=0,0,10%7C1,0,100%7C2,0,
+100&chxl=0%3A%7C2010/02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%
+7C2010/07/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%
+7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10&chxtc=0,5&chd=t:99.0,99.2,99.4,99.5,99.6,99.6,99.6,99.7,100.6
+,101.1,99.9%7C63.4,62.5,61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6%7C22.6,23.2,24.3,25.4,29.4,30.2
+,32.7,35.3,46.2,51.3,55.1%7C0.0,0.0,0.0,0.0,4.0,28.3,32.0,34.9,45.9,51.0,54.9%7C0.0,0.0,0.0,0.0,0.0,
+0.0,0.0,0.0,0.8,1.2,1.8&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5%7Cb,c3df9b,0,1,0%7CtAndroid%201.6,
+638d23,1,0,15,,t::-5%7Cb,b0db6e,1,2,0%7CtAndroid%202.0.1,496c13,2,0,15,,t::-5%7Cb,9ddb3d,2,3,0%
+7CtAndroid%202.1,2f4708,3,5,15,,t::-5%7Cb,89cf19,3,4,0%7CB,6fad0c,4,5,0&chg=9,25&chdl=Android%201.5%
+20(API%20Level%203)%7CAndroid%201.6%20(API%20Level%204)%7CAndroid%202.0.1%20(API%20Level%206)%
+7CAndroid%202.1%20(API%20Level%207)%7CAndroid%202.2%20(API%20Level %208)&chco=add274,
+9ad145,84c323,6ba213,507d08" />
+
+<p><em>Last historical dataset collected during two weeks ending on July 1, 2010</em></p>
+
+
+</div><!-- end dashboard-panel -->
 
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index f8130ea..89fdd2d 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -49,7 +49,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.1,57.8,41.0&chl=Small%20/%20ldpi|
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.4,54.5,44.1&chl=Small%20/%20ldpi|
 Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
 
 <table>
@@ -60,14 +60,14 @@
 <th scope="col">High Density</th>
 </tr>
 <tr><th scope="row">Small</th> 
-<td class='cent hi'>1.1%</td> 
+<td class='cent hi'>1.4%</td> 
 <td></td> 
 <td></td> 
 </tr> 
 <tr><th scope="row">Normal</th> 
 <td></td> 
-<td class='cent hi'>57.8%</td> 
-<td class='cent hi'>41.0%</td> 
+<td class='cent hi'>54.5%</td> 
+<td class='cent hi'>44.1%</td> 
 </tr> 
 <tr><th scope="row">Large</th> 
 <td></td> 
@@ -76,6 +76,6 @@
 </tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on June 16, 2010</em></p>
+<p><em>Data collected during two weeks ending on July 1, 2010</em></p>
 </div>
 
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
index c3ba495..77f7e43 100644
--- a/docs/html/sdk/older_releases.jd
+++ b/docs/html/sdk/older_releases.jd
@@ -47,7 +47,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.6_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip">android-sdk-
 windows-1 .6_r1.zip</a>
     </td>
     <td>260529085 bytes</td>
@@ -57,7 +57,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
 mac_x86-1 .6_r1.zip</a>
     </td>
     <td>247412515 bytes</td>
@@ -67,7 +67,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.6_r1.tgz">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.6_r1.tgz">android-
 sdk- linux_x86-1.6_r1.tgz</a>
     </td>
     <td>238224860 bytes</td>
@@ -92,7 +92,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r3.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r3.zip">android-sdk-
 windows-1 .5_r3.zip</a>
     </td>
     <td>191477853 bytes</td>
@@ -102,7 +102,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
 mac_x86-1 .5_r3.zip</a>
     </td>
     <td>183024673 bytes</td>
@@ -112,7 +112,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r3.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r3.zip">android-
 sdk- linux_x86-1.5_r3.zip</a>
     </td>
     <td>178117561 bytes</td>
@@ -137,7 +137,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.1_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.1_r1.zip">android-sdk-
 windows-1
 .1_r1.zip</a>
     </td>
@@ -148,7 +148,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
 mac_x86-1
 .1_r1.zip</a>
     </td>
@@ -159,7 +159,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.1_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.1_r1.zip">android-
 sdk-
 linux_x86-1.1_r1.zip</a>
     </td>
@@ -185,7 +185,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.0_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r2.zip">android-sdk-
 windows-1
 .0_r2.zip</a>
     </td>
@@ -196,7 +196,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
 mac_x86-1
 .0_r2.zip</a>
     </td>
@@ -207,7 +207,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r2.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r2.zip">android-
 sdk-
 linux_x86-1.0_r2.zip</a>
     </td>
@@ -241,7 +241,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r2.zip">android-sdk-
 windows-1 .5_r2.zip</a>
     </td>
     <td>178346828 bytes</td>
@@ -251,7 +251,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
 mac_x86-1 .5_r2.zip</a>
     </td>
     <td>169945128 bytes</td>
@@ -261,7 +261,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r2.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r2.zip">android-
 sdk- linux_x86-1.5_r2.zip</a>
     </td>
     <td>165035130 bytes</td>
@@ -286,7 +286,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r1.zip">android-sdk-
 windows-1 .5_r1.zip</a>
     </td>
     <td>176263368 bytes</td>
@@ -296,7 +296,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
 mac_x86-1 .5_r1.zip</a>
     </td>
     <td>167848675 bytes</td>
@@ -306,7 +306,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r1.zip">android-
 sdk- linux_x86-1.5_r1.zip</a>
     </td>
     <td>162938845 bytes</td>
@@ -331,7 +331,7 @@
     <td>Windows</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.0_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r1.zip">android-sdk-
 windows-1 .0_r1.zip</a>
     </td>
     <td>89.7 MB bytes</td>
@@ -341,7 +341,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
 mac_x86-1 .0_r1.zip</a>
     </td>
     <td>87.5 MB bytes</td>
@@ -351,7 +351,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r1.zip">android-
 sdk- linux_x86-1.0_r1.zip</a>
     </td>
     <td>87.8 MB bytes</td>
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index a4eea2a..c3cd361 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -48,8 +48,8 @@
     static MediaProfiles* getInstance();
 
     /**
-     * Returns the value for the given param name at the given quality level,
-     * or -1 if error.
+     * Returns the value for the given param name for the given camera at
+     * the given quality level, or -1 if error.
      *
      * Supported param name are:
      * duration - the recording duration.
@@ -64,7 +64,8 @@
      * aud.hz - audio sample rate
      * aud.ch - number of audio channels
      */
-    int getCamcorderProfileParamByName(const char *name, camcorder_quality quality) const;
+    int getCamcorderProfileParamByName(const char *name, int cameraId,
+                                       camcorder_quality quality) const;
 
     /**
      * Returns the output file formats supported.
@@ -124,12 +125,7 @@
     /**
      * Returns the number of image encoding quality levels supported.
      */
-    Vector<int> getImageEncodingQualityLevels() const;
-
-    /**
-     * Returns the maximum amount of memory in bytes we can use for decoding a JPEG file.
-     */
-    int getImageDecodingMaxMemory() const;
+    Vector<int> getImageEncodingQualityLevels(int cameraId) const;
 
 private:
     MediaProfiles& operator=(const MediaProfiles&);  // Don't call me
@@ -171,7 +167,8 @@
 
     struct CamcorderProfile {
         CamcorderProfile()
-            : mFileFormat(OUTPUT_FORMAT_THREE_GPP),
+            : mCameraId(0),
+              mFileFormat(OUTPUT_FORMAT_THREE_GPP),
               mQuality(CAMCORDER_QUALITY_HIGH),
               mDuration(0),
               mVideoCodec(0),
@@ -182,6 +179,7 @@
             delete mAudioCodec;
         }
 
+        int mCameraId;
         output_format mFileFormat;
         camcorder_quality mQuality;
         int mDuration;
@@ -249,6 +247,11 @@
         int tag;
     };
 
+    struct ImageEncodingQualityLevels {
+        int mCameraId;
+        Vector<int> mLevels;
+    };
+
     // Debug
     static void logVideoCodec(const VideoCodec& codec);
     static void logAudioCodec(const AudioCodec& codec);
@@ -267,9 +270,11 @@
     static VideoDecoderCap* createVideoDecoderCap(const char **atts);
     static VideoEncoderCap* createVideoEncoderCap(const char **atts);
     static AudioEncoderCap* createAudioEncoderCap(const char **atts);
-    static CamcorderProfile* createCamcorderProfile(const char **atts);
-    static int getImageEncodingQualityLevel(const char **atts);
-    static int getImageDecodingMaxMemory(const char **atts);
+    static CamcorderProfile* createCamcorderProfile(int cameraId, const char **atts);
+    static int getCameraId(const char **atts);
+
+    ImageEncodingQualityLevels* findImageEncodingQualityLevels(int cameraId) const;
+    void addImageEncodingQualityLevel(int cameraId, const char** atts);
 
     // Customized element tag handler for parsing the xml configuration file.
     static void startElementHandler(void *userData, const char *name, const char **atts);
@@ -303,6 +308,7 @@
     static bool sIsInitialized;
     static MediaProfiles *sInstance;
     static Mutex sLock;
+    int mCurrentCameraId;
 
     Vector<CamcorderProfile*> mCamcorderProfiles;
     Vector<AudioEncoderCap*>  mAudioEncoders;
@@ -310,8 +316,7 @@
     Vector<AudioDecoderCap*>  mAudioDecoders;
     Vector<VideoDecoderCap*>  mVideoDecoders;
     Vector<output_format>     mEncoderOutputFileFormats;
-    Vector<int>               mImageEncodingQualityLevels;
-    int                       mImageDecodingMaxMemory;
+    Vector<ImageEncodingQualityLevels *>  mImageEncodingQualityLevels;
 };
 
 }; // namespace android
diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h
index 1e341b9..bc3f464 100644
--- a/include/media/stagefright/ColorConverter.h
+++ b/include/media/stagefright/ColorConverter.h
@@ -58,6 +58,11 @@
             const void *srcBits, size_t srcSkip,
             void *dstBits, size_t dstSkip);
 
+    void convertYUV420SemiPlanar(
+            size_t width, size_t height,
+            const void *srcBits, size_t srcSkip,
+            void *dstBits, size_t dstSkip);
+
     ColorConverter(const ColorConverter &);
     ColorConverter &operator=(const ColorConverter &);
 };
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index e91d066..8d3a9df 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -27,7 +27,10 @@
 struct MetaData;
 
 struct MediaWriter : public RefBase {
-    MediaWriter() {}
+    MediaWriter()
+        : mMaxFileSizeLimitBytes(0),
+          mMaxFileDurationLimitUs(0) {
+    }
 
     virtual status_t addSource(const sp<MediaSource> &source) = 0;
     virtual bool reachedEOS() = 0;
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 c95fc02..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 {
@@ -172,9 +173,18 @@
     void setVideoInputFormat(
             const char *mime, const sp<MetaData>& meta);
 
+    status_t setupBitRate(int32_t bitRate);
+    status_t setupErrorCorrectionParameters();
+    status_t setupH263EncoderParameters(const sp<MetaData>& meta);
     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/ALooper.h b/include/media/stagefright/foundation/ALooper.h
index 69ad837..194f1fc 100644
--- a/include/media/stagefright/foundation/ALooper.h
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -39,7 +39,10 @@
     handler_id registerHandler(const sp<AHandler> &handler);
     void unregisterHandler(handler_id handlerID);
 
-    status_t start(bool runOnCallingThread = false);
+    status_t start(
+            bool runOnCallingThread = false,
+            bool canCallJava = false);
+
     status_t stop();
 
     static int64_t GetNowUs();
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/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 139c620..c674cbaf 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -60,6 +60,8 @@
 
     sp<AMessage> dup() const;
 
+    AString debugString(int32_t indent = 0) const;
+
 protected:
     virtual ~AMessage();
 
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index f333911..4fd0681 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -131,7 +131,7 @@
 // ---------------------------------------------------------------------------
 
 class Surface 
-    : public EGLNativeBase<android_native_window_t, Surface, RefBase>
+    : public EGLNativeBase<ANativeWindow, Surface, RefBase>
 {
 public:
     struct SurfaceInfo {
@@ -195,14 +195,14 @@
 
 
     /*
-     *  android_native_window_t hooks
+     *  ANativeWindow hooks
      */
-    static int setSwapInterval(android_native_window_t* window, int interval);
-    static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
-    static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
-    static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
-    static int query(android_native_window_t* window, int what, int* value);
-    static int perform(android_native_window_t* window, int operation, ...);
+    static int setSwapInterval(ANativeWindow* window, int interval);
+    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
+    static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int query(ANativeWindow* window, int what, int* value);
+    static int perform(ANativeWindow* window, int operation, ...);
 
     int dequeueBuffer(android_native_buffer_t** buffer);
     int lockBuffer(android_native_buffer_t* buffer);
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 8ea3ab9..0f4594f 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -43,7 +43,7 @@
 
 class FramebufferNativeWindow 
     : public EGLNativeBase<
-        android_native_window_t, 
+        ANativeWindow, 
         FramebufferNativeWindow, 
         LightRefBase<FramebufferNativeWindow> >
 {
@@ -59,12 +59,12 @@
 private:
     friend class LightRefBase<FramebufferNativeWindow>;    
     ~FramebufferNativeWindow(); // this class cannot be overloaded
-    static int setSwapInterval(android_native_window_t* window, int interval);
-    static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
-    static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
-    static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
-    static int query(android_native_window_t* window, int what, int* value);
-    static int perform(android_native_window_t* window, int operation, ...);
+    static int setSwapInterval(ANativeWindow* window, int interval);
+    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
+    static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int query(ANativeWindow* window, int what, int* value);
+    static int perform(ANativeWindow* window, int operation, ...);
     
     framebuffer_device_t* fbDev;
     alloc_device_t* grDev;
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 57b292b..a2e0ba06 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -43,7 +43,7 @@
 /*
  * Declare a concrete type for the NDK's input event forward declaration.
  */
-struct input_event_t { };
+struct AInputEvent { };
 
 namespace android {
 
@@ -87,9 +87,6 @@
     // Indicates that the screen was dim when the event was received and the event
     // should brighten the device.
     POLICY_FLAG_BRIGHT_HERE = 0x20000000,
-
-    // Indicates that the dispatcher should call back into the policy before dispatching. */
-    POLICY_FLAG_INTERCEPT_DISPATCH = 0x40000000,
 };
 
 /*
@@ -136,7 +133,7 @@
 /*
  * Input events.
  */
-class InputEvent : public input_event_t {
+class InputEvent : public AInputEvent {
 public:
     virtual ~InputEvent() { }
 
@@ -145,7 +142,7 @@
     inline int32_t getDeviceId() const { return mDeviceId; }
 
     inline int32_t getNature() const { return mNature; }
-
+    
 protected:
     void initialize(int32_t deviceId, int32_t nature);
 
@@ -179,6 +176,14 @@
 
     inline nsecs_t getEventTime() const { return mEventTime; }
 
+    // Return true if this event may have a default action implementation.
+    static bool hasDefaultAction(int32_t keyCode);
+    bool hasDefaultAction() const;
+
+    // Return true if this event represents a system key.
+    static bool isSystemKey(int32_t keyCode);
+    bool isSystemKey() const;
+    
     void initialize(
             int32_t deviceId,
             int32_t nature,
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 2093560..781da35 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -53,6 +53,8 @@
  */
 struct InputDevice {
     struct AbsoluteAxisInfo {
+        bool valid;        // set to true if axis parameters are known, false otherwise
+
         int32_t minValue;  // minimum value
         int32_t maxValue;  // maximum value
         int32_t range;     // range of values, equal to maxValue - minValue
@@ -272,9 +274,16 @@
         } jumpyTouchFilter;
 
         struct Precalculated {
+            int32_t xOrigin;
             float xScale;
+
+            int32_t yOrigin;
             float yScale;
+
+            int32_t pressureOrigin;
             float pressureScale;
+
+            int32_t sizeOrigin;
             float sizeScale;
         } precalculated;
 
@@ -362,10 +371,6 @@
         // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
         // passes through the dispatch pipeline.
         ACTION_BRIGHT_HERE = 0x00000008,
-
-        // The input dispatcher should add POLICY_FLAG_INTERCEPT_DISPATCH to the policy flags
-        // it passed through the dispatch pipeline.
-        ACTION_INTERCEPT_DISPATCH = 0x00000010
     };
 
     /* Describes a virtual key. */
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index d6bded6..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>
@@ -333,21 +334,27 @@
 /*
  * NDK input queue API.
  */
-struct input_queue_t {
+struct AInputQueue {
 public:
     /* Creates a consumer associated with an input channel. */
-    explicit input_queue_t(const android::sp<android::InputChannel>& channel);
+    explicit AInputQueue(const android::sp<android::InputChannel>& channel);
 
     /* Destroys the consumer and releases its input channel. */
-    ~input_queue_t();
+    virtual ~AInputQueue();
 
     inline android::InputConsumer& getConsumer() { return mConsumer; }
     
     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/egl/android_natives.h b/include/ui/egl/android_natives.h
index 171f3df..ca89b06 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -22,6 +22,8 @@
 
 #include <hardware/gralloc.h>
 
+#include <android/native_window.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -90,19 +92,19 @@
     NATIVE_WINDOW_API_EGL = 1
 };
 
-typedef struct android_native_window_t 
+struct ANativeWindow 
 {
 #ifdef __cplusplus
-    android_native_window_t()
+    ANativeWindow()
         : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
     {
         common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
-        common.version = sizeof(android_native_window_t);
+        common.version = sizeof(ANativeWindow);
         memset(common.reserved, 0, sizeof(common.reserved));
     }
 
-    // Implement the methods that sp<android_native_window_t> expects so that it
-    // can be used to automatically refcount android_native_window_t's.
+    // Implement the methods that sp<ANativeWindow> expects so that it
+    // can be used to automatically refcount ANativeWindow's.
     void incStrong(const void* id) const {
         common.incRef(const_cast<android_native_base_t*>(&common));
     }
@@ -135,7 +137,7 @@
      * 
      * Returns 0 on success or -errno on error.
      */
-    int     (*setSwapInterval)(struct android_native_window_t* window,
+    int     (*setSwapInterval)(struct ANativeWindow* window,
                 int interval);
     
     /*
@@ -145,7 +147,7 @@
      * 
      * Returns 0 on success or -errno on error.
      */
-    int     (*dequeueBuffer)(struct android_native_window_t* window,
+    int     (*dequeueBuffer)(struct ANativeWindow* window,
                 struct android_native_buffer_t** buffer);
 
     /*
@@ -155,7 +157,7 @@
      * 
      * Returns 0 on success or -errno on error.
      */
-    int     (*lockBuffer)(struct android_native_window_t* window,
+    int     (*lockBuffer)(struct ANativeWindow* window,
                 struct android_native_buffer_t* buffer);
    /*
     * hook called by EGL when modifications to the render buffer are done. 
@@ -165,7 +167,7 @@
     * 
     * Returns 0 on success or -errno on error.
     */
-    int     (*queueBuffer)(struct android_native_window_t* window,
+    int     (*queueBuffer)(struct ANativeWindow* window,
                 struct android_native_buffer_t* buffer);
 
     /*
@@ -173,13 +175,13 @@
      * 
      * Returns 0 on success or -errno on error.
      */
-    int     (*query)(struct android_native_window_t* window,
+    int     (*query)(struct ANativeWindow* window,
                 int what, int* value);
     
     /*
      * hook used to perform various operations on the surface.
      * (*perform)() is a generic mechanism to add functionality to
-     * android_native_window_t while keeping backward binary compatibility.
+     * ANativeWindow while keeping backward binary compatibility.
      * 
      * This hook should not be called directly, instead use the helper functions
      * defined below.
@@ -197,12 +199,14 @@
      *  
      */
     
-    int     (*perform)(struct android_native_window_t* window,
+    int     (*perform)(struct ANativeWindow* window,
                 int operation, ... );
     
     void* reserved_proc[3];
-} android_native_window_t;
+};
 
+// Backwards compatibility...  please switch to ANativeWindow.
+typedef struct ANativeWindow android_native_window_t;
 
 /*
  *  native_window_set_usage(..., usage)
@@ -216,7 +220,7 @@
  */
 
 static inline int native_window_set_usage(
-        android_native_window_t* window, int usage)
+        ANativeWindow* window, int usage)
 {
     return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
 }
@@ -228,7 +232,7 @@
  * can happen if it's connected to some other API.
  */
 static inline int native_window_connect(
-        android_native_window_t* window, int api)
+        ANativeWindow* window, int api)
 {
     return window->perform(window, NATIVE_WINDOW_CONNECT, api);
 }
@@ -240,7 +244,7 @@
  * first place.
  */
 static inline int native_window_disconnect(
-        android_native_window_t* window, int api)
+        ANativeWindow* window, int api)
 {
     return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
 }
@@ -258,7 +262,7 @@
  * out of the buffer's bound or if the window is invalid.
  */
 static inline int native_window_set_crop(
-        android_native_window_t* window,
+        ANativeWindow* window,
         android_native_rect_t const * crop)
 {
     return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
@@ -269,7 +273,7 @@
  * Sets the number of buffers associated with this native window.
  */
 static inline int native_window_set_buffer_count(
-        android_native_window_t* window,
+        ANativeWindow* window,
         size_t bufferCount)
 {
     return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
@@ -287,7 +291,7 @@
  *
  */
 static inline int native_window_set_buffers_geometry(
-        android_native_window_t* window,
+        ANativeWindow* window,
         int w, int h, int format)
 {
     return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index a95fb17..b3651ca 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -22,12 +22,22 @@
 
 #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();
 
@@ -83,6 +93,11 @@
     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 +115,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,6 +138,7 @@
         int fd;
         int events;
         Callback callback;
+        ALooper_callbackFunc* looperCallback;
         void* data;
     };
 
@@ -130,8 +159,11 @@
     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/rs/rs.spec b/libs/rs/rs.spec
index cb9937c..5ae8d01 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -29,7 +29,7 @@
 ContextSetSurface {
 	param uint32_t width
 	param uint32_t height
-	param android_native_window_t *sur
+	param ANativeWindow *sur
 	}
 
 ContextDump {
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index d8a9a99..596f533 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -473,7 +473,7 @@
     objDestroyOOBDestroy();
 }
 
-void Context::setSurface(uint32_t w, uint32_t h, android_native_window_t *sur)
+void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur)
 {
     rsAssert(mIsGraphicsContext);
 
@@ -888,7 +888,7 @@
     rsc->resume();
 }
 
-void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, android_native_window_t *sur)
+void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur)
 {
     rsc->setSurface(w, h, sur);
 }
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 82c3687..709730e 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -98,7 +98,7 @@
 
     void pause();
     void resume();
-    void setSurface(uint32_t w, uint32_t h, android_native_window_t *sur);
+    void setSurface(uint32_t w, uint32_t h, ANativeWindow *sur);
     void setPriority(int32_t p);
 
     void assignName(ObjectBase *obj, const char *name, uint32_t len);
@@ -246,7 +246,7 @@
 
     static void * threadProc(void *);
 
-    android_native_window_t *mWndSurface;
+    ANativeWindow *mWndSurface;
 
     Vector<ObjectBase *> mNames;
 
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 0879a66..a14bfb5 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -6,6 +6,7 @@
     DisplayHardware/DisplayHardware.cpp \
     DisplayHardware/DisplayHardwareBase.cpp \
     BlurFilter.cpp.arm \
+    GLExtensions.cpp \
     Layer.cpp \
     LayerBase.cpp \
     LayerBuffer.cpp \
@@ -19,8 +20,8 @@
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
-ifeq ($(TARGET_BOARD_PLATFORM), msm7k)
-	LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+ifeq ($(TARGET_BOARD_PLATFORM), omap3)
+	LOCAL_CFLAGS += -DNO_RGBX_8888
 endif
 
 # need "-lrt" on Linux simulator to pick up clock_gettime
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 51de1da..2eac0a8 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,8 @@
 #include <hardware/overlay.h>
 #include <hardware/gralloc.h>
 
+#include "GLExtensions.h"
+
 using namespace android;
 
 
@@ -73,7 +75,8 @@
 DisplayHardware::DisplayHardware(
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
-    : DisplayHardwareBase(flinger, dpy), mFlags(0)
+    : DisplayHardwareBase(flinger, dpy),
+      mFlags(0)
 {
     init(dpy);
 }
@@ -97,6 +100,9 @@
 {
     mNativeWindow = new FramebufferNativeWindow();
     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+    mDpiX = mNativeWindow->xdpi;
+    mDpiY = mNativeWindow->ydpi;
+    mRefreshRate = fbDev->fps;
 
     mOverlayEngine = NULL;
     hw_module_t const* module;
@@ -104,6 +110,11 @@
         overlay_control_open(module, &mOverlayEngine);
     }
 
+    EGLint w, h, dummy;
+    EGLint numConfigs=0;
+    EGLSurface surface;
+    EGLContext context;
+
     // initialize EGL
     EGLint attribs[] = {
             EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
@@ -121,11 +132,6 @@
         }
     }
 
-    EGLint w, h, dummy;
-    EGLint numConfigs=0;
-    EGLSurface surface;
-    EGLContext context;
-
     // TODO: all the extensions below should be queried through
     // eglGetProcAddress().
 
@@ -144,22 +150,6 @@
     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
 
-    /*
-     * Gather EGL extensions
-     */
-
-    const char* const egl_extensions = eglQueryString(
-            display, EGL_EXTENSIONS);
-    
-    LOGI("EGL informations:");
-    LOGI("# of configs : %d", numConfigs);
-    LOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
-    LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
-    LOGI("extensions: %s", egl_extensions);
-    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
-    
-
     if (mNativeWindow->isUpdateOnDemand()) {
         mFlags |= PARTIAL_UPDATES;
     }
@@ -174,6 +164,8 @@
      */
 
     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
+    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
 
     if (mFlags & PARTIAL_UPDATES) {
         // if we have partial updates, we definitely don't need to
@@ -187,31 +179,6 @@
             mFlags |= BUFFER_PRESERVED;
         }
     }
-
-    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
-    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
-
-#ifdef EGL_ANDROID_swap_rectangle    
-    if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
-        if (eglSetSwapRectangleANDROID(display, surface,
-                0, 0, mWidth, mHeight) == EGL_TRUE) {
-            // This could fail if this extension is not supported by this
-            // specific surface (of config)
-            mFlags |= SWAP_RECTANGLE;
-        }
-    }
-    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
-    // choose PARTIAL_UPDATES, which should be more efficient
-    if (mFlags & PARTIAL_UPDATES)
-        mFlags &= ~SWAP_RECTANGLE;
-#endif
-    
-
-    LOGI("flags     : %08x", mFlags);
-    
-    mDpiX = mNativeWindow->xdpi;
-    mDpiY = mNativeWindow->ydpi;
-    mRefreshRate = fbDev->fps; 
     
     /* Read density from build-specific ro.sf.lcd_density property
      * except if it is overridden by qemu.sf.lcd_density.
@@ -234,49 +201,67 @@
     
     context = eglCreateContext(display, config, NULL, NULL);
     
-    /*
-     * Gather OpenGL ES extensions
-     */
-
-    eglMakeCurrent(display, surface, surface, context);
-    const char* const  gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
-    const char* const  gl_renderer = (const char*)glGetString(GL_RENDERER);
-    LOGI("OpenGL informations:");
-    LOGI("vendor    : %s", glGetString(GL_VENDOR));
-    LOGI("renderer  : %s", gl_renderer);
-    LOGI("version   : %s", glGetString(GL_VERSION));
-    LOGI("extensions: %s", gl_extensions);
-
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
-    LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
-    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
-
-
-    if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
-        mFlags |= NPOT_EXTENSION;
-    }
-#ifdef EGL_ANDROID_image_native_buffer
-    if (strstr( gl_extensions, "GL_OES_EGL_image") &&
-        (strstr(egl_extensions, "EGL_KHR_image_base") || 
-                strstr(egl_extensions, "EGL_KHR_image")) &&
-        strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
-        mFlags |= DIRECT_TEXTURE;
-    }
-#else
-#warning "EGL_ANDROID_image_native_buffer not supported"
-#endif
-
-
-    // Unbind the context from this thread
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
     mDisplay = display;
     mConfig  = config;
     mSurface = surface;
     mContext = context;
     mFormat  = fbDev->format;
     mPageFlipCount = 0;
+
+    /*
+     * Gather OpenGL ES extensions
+     */
+
+    eglMakeCurrent(display, surface, surface, context);
+
+    GLExtensions& extensions(GLExtensions::getInstance());
+    extensions.initWithGLStrings(
+            glGetString(GL_VENDOR),
+            glGetString(GL_RENDERER),
+            glGetString(GL_VERSION),
+            glGetString(GL_EXTENSIONS),
+            eglQueryString(display, EGL_VENDOR),
+            eglQueryString(display, EGL_VERSION),
+            eglQueryString(display, EGL_EXTENSIONS));
+
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+
+
+#ifdef EGL_ANDROID_swap_rectangle
+    if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
+        if (eglSetSwapRectangleANDROID(display, surface,
+                0, 0, mWidth, mHeight) == EGL_TRUE) {
+            // This could fail if this extension is not supported by this
+            // specific surface (of config)
+            mFlags |= SWAP_RECTANGLE;
+        }
+    }
+    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
+    // choose PARTIAL_UPDATES, which should be more efficient
+    if (mFlags & PARTIAL_UPDATES)
+        mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+    LOGI("EGL informations:");
+    LOGI("# of configs : %d", numConfigs);
+    LOGI("vendor    : %s", extensions.getEglVendor());
+    LOGI("version   : %s", extensions.getEglVersion());
+    LOGI("extensions: %s", extensions.getEglExtension());
+    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+
+    LOGI("OpenGL informations:");
+    LOGI("vendor    : %s", extensions.getVendor());
+    LOGI("renderer  : %s", extensions.getRenderer());
+    LOGI("version   : %s", extensions.getVersion());
+    LOGI("extensions: %s", extensions.getExtension());
+    LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
+    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+    LOGI("flags = %08x", mFlags);
+
+    // Unbind the context from this thread
+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 }
 
 /*
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index ebd7c42..66bf521 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -29,6 +29,8 @@
 
 #include <pixelflinger/pixelflinger.h>
 
+#include "GLExtensions.h"
+
 #include "DisplayHardware/DisplayHardwareBase.h"
 
 struct overlay_control_device_t;
@@ -43,13 +45,11 @@
 {
 public:
     enum {
-        DIRECT_TEXTURE          = 0x00000002,
-        COPY_BITS_EXTENSION     = 0x00000008,
-        NPOT_EXTENSION          = 0x00000100,
-        BUFFER_PRESERVED        = 0x00010000,
-        PARTIAL_UPDATES         = 0x00020000,   // video driver feature
-        SLOW_CONFIG             = 0x00040000,   // software
-        SWAP_RECTANGLE          = 0x00080000,
+        COPY_BITS_EXTENSION         = 0x00000008,
+        BUFFER_PRESERVED            = 0x00010000,
+        PARTIAL_UPDATES             = 0x00020000,   // video driver feature
+        SLOW_CONFIG                 = 0x00040000,   // software
+        SWAP_RECTANGLE              = 0x00080000,
     };
 
     DisplayHardware(
diff --git a/libs/surfaceflinger/GLExtensions.cpp b/libs/surfaceflinger/GLExtensions.cpp
new file mode 100644
index 0000000..7f4f9fc
--- /dev/null
+++ b/libs/surfaceflinger/GLExtensions.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "GLExtensions.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
+
+GLExtensions::GLExtensions()
+    : mHaveTextureExternal(false),
+      mHaveNpot(false),
+      mHaveDirectTexture(false)
+{
+}
+
+void GLExtensions::initWithGLStrings(
+        GLubyte const* vendor,
+        GLubyte const* renderer,
+        GLubyte const* version,
+        GLubyte const* extensions,
+        char const* egl_vendor,
+        char const* egl_version,
+        char const* egl_extensions)
+{
+    mVendor     = (char const*)vendor;
+    mRenderer   = (char const*)renderer;
+    mVersion    = (char const*)version;
+    mExtensions = (char const*)extensions;
+    mEglVendor     = egl_vendor;
+    mEglVersion    = egl_version;
+    mEglExtensions = egl_extensions;
+
+    char const* curr = (char const*)extensions;
+    char const* head = curr;
+    do {
+        head = strchr(curr, ' ');
+        String8 s(curr, head ? head-curr : strlen(curr));
+        if (s.length()) {
+            mExtensionList.add(s);
+        }
+        curr = head+1;
+    } while (head);
+
+    curr = egl_extensions;
+    head = curr;
+    do {
+        head = strchr(curr, ' ');
+        String8 s(curr, head ? head-curr : strlen(curr));
+        if (s.length()) {
+            mExtensionList.add(s);
+        }
+        curr = head+1;
+    } while (head);
+
+#ifdef EGL_ANDROID_image_native_buffer
+    if (hasExtension("GL_OES_EGL_image") &&
+        (hasExtension("EGL_KHR_image_base") || hasExtension("EGL_KHR_image")) &&
+        hasExtension("EGL_ANDROID_image_native_buffer"))
+    {
+        mHaveDirectTexture = true;
+    }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
+
+    if (hasExtension("GL_ARB_texture_non_power_of_two")) {
+        mHaveNpot = true;
+    }
+
+    if (hasExtension("GL_OES_texture_external")) {
+        mHaveTextureExternal = true;
+    } else if (strstr(mRenderer.string(), "Adreno")) {
+        // hack for Adreno 200
+        mHaveTextureExternal = true;
+    }
+}
+
+bool GLExtensions::hasExtension(char const* extension) const
+{
+    const String8 s(extension);
+    return mExtensionList.indexOf(s) >= 0;
+}
+
+char const* GLExtensions::getVendor() const {
+    return mVendor.string();
+}
+
+char const* GLExtensions::getRenderer() const {
+    return mRenderer.string();
+}
+
+char const* GLExtensions::getVersion() const {
+    return mVersion.string();
+}
+
+char const* GLExtensions::getExtension() const {
+    return mExtensions.string();
+}
+
+char const* GLExtensions::getEglVendor() const {
+    return mEglVendor.string();
+}
+
+char const* GLExtensions::getEglVersion() const {
+    return mEglVersion.string();
+}
+
+char const* GLExtensions::getEglExtension() const {
+    return mEglExtensions.string();
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/GLExtensions.h b/libs/surfaceflinger/GLExtensions.h
new file mode 100644
index 0000000..bbb284e
--- /dev/null
+++ b/libs/surfaceflinger/GLExtensions.h
@@ -0,0 +1,94 @@
+/*
+ * 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_SF_GLEXTENSION_H
+#define ANDROID_SF_GLEXTENSION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/Singleton.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class GLExtensions : public Singleton<GLExtensions>
+{
+    friend class Singleton<GLExtensions>;
+
+    bool mHaveTextureExternal   : 1;
+    bool mHaveNpot              : 1;
+    bool mHaveDirectTexture     : 1;
+
+    String8 mVendor;
+    String8 mRenderer;
+    String8 mVersion;
+    String8 mExtensions;
+    String8 mEglVendor;
+    String8 mEglVersion;
+    String8 mEglExtensions;
+    SortedVector<String8> mExtensionList;
+
+    GLExtensions(const GLExtensions&);
+    GLExtensions& operator = (const GLExtensions&);
+
+protected:
+    GLExtensions();
+
+public:
+    inline bool haveTextureExternal() const {
+        return mHaveTextureExternal;
+    }
+    inline bool haveNpot() const {
+        return mHaveNpot;
+    }
+    inline bool haveDirectTexture() const {
+        return mHaveDirectTexture;
+    }
+
+    void initWithGLStrings(
+            GLubyte const* vendor,
+            GLubyte const* renderer,
+            GLubyte const* version,
+            GLubyte const* extensions,
+            char const* egl_vendor,
+            char const* egl_version,
+            char const* egl_extensions);
+
+    char const* getVendor() const;
+    char const* getRenderer() const;
+    char const* getVersion() const;
+    char const* getExtension() const;
+
+    char const* getEglVendor() const;
+    char const* getEglVersion() const;
+    char const* getEglExtension() const;
+
+    bool hasExtension(char const* extension) const;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index e606f71..758da4e 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -31,6 +31,7 @@
 #include <surfaceflinger/Surface.h>
 
 #include "clz.h"
+#include "GLExtensions.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
@@ -50,10 +51,11 @@
 Layer::Layer(SurfaceFlinger* flinger,
         DisplayID display, const sp<Client>& client)
     :   LayerBaseClient(flinger, display, client),
+        mGLExtensions(GLExtensions::getInstance()),
         mNeedsBlending(true),
         mNeedsDithering(false),
         mSecure(false),
-        mTextureManager(mFlags),
+        mTextureManager(),
         mBufferManager(mTextureManager),
         mWidth(0), mHeight(0), mFixedSize(false)
 {
@@ -185,17 +187,13 @@
         return;
     }
 
-#ifdef EGL_ANDROID_image_native_buffer
-    if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
+    if (mGLExtensions.haveDirectTexture()) {
         EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
         if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
             // not sure what we can do here...
-            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
             goto slowpath;
         }
-    } else
-#endif
-    {
+    } else {
 slowpath:
         GGLSurface t;
         status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
@@ -786,19 +784,24 @@
     status_t err = NO_INIT;
     ssize_t index = mActiveBuffer;
     if (index >= 0) {
-        Image& texture(mBufferData[index].texture);
-        err = mTextureManager.initEglImage(&texture, dpy, buffer);
-        // if EGLImage fails, we switch to regular texture mode, and we
-        // free all resources associated with using EGLImages.
-        if (err == NO_ERROR) {
-            mFailover = false;
-            destroyTexture(&mFailoverTexture, dpy);
-        } else {
-            mFailover = true;
-            const size_t num = mNumBuffers;
-            for (size_t i=0 ; i<num ; i++) {
-                destroyTexture(&mBufferData[i].texture, dpy);
+        if (!mFailover) {
+            Image& texture(mBufferData[index].texture);
+            err = mTextureManager.initEglImage(&texture, dpy, buffer);
+            // if EGLImage fails, we switch to regular texture mode, and we
+            // free all resources associated with using EGLImages.
+            if (err == NO_ERROR) {
+                mFailover = false;
+                destroyTexture(&mFailoverTexture, dpy);
+            } else {
+                mFailover = true;
+                const size_t num = mNumBuffers;
+                for (size_t i=0 ; i<num ; i++) {
+                    destroyTexture(&mBufferData[i].texture, dpy);
+                }
             }
+        } else {
+            // we failed once, don't try again
+            err = BAD_VALUE;
         }
     }
     return err;
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index dcb27a0..e1d283b 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -37,9 +37,10 @@
 
 // ---------------------------------------------------------------------------
 
-class Client;
-class UserClient;
 class FreezeLock;
+class Client;
+class GLExtensions;
+class UserClient;
 
 // ---------------------------------------------------------------------------
 
@@ -206,6 +207,7 @@
     // constants
     sp<Surface> mSurface;
     PixelFormat mFormat;
+    const GLExtensions& mGLExtensions;
     bool mNeedsBlending;
     bool mNeedsDithering;
 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index c1c440b..64a43c7 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -147,7 +147,9 @@
     Region::const_iterator const end = clip.end();
     if (it != end) {
 #if defined(GL_OES_texture_external)
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
+        }
 #endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
@@ -181,7 +183,7 @@
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
 
-            if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
+            if (GLExtensions::getInstance().haveNpot()) {
                 glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
                         mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / w;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 732a4ec..5f836366 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -315,8 +315,7 @@
 
 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
         const ISurface::BufferHeap& buffers)
-    : Source(layer), mStatus(NO_ERROR), mBufferSize(0),
-      mTextureManager(layer.mFlags)
+    : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
 {
     if (buffers.heap == NULL) {
         // this is allowed, but in this case, it is illegal to receive
@@ -374,11 +373,11 @@
 
     if (mTexture.name != -1U) {
         // GL textures can only be destroyed from the GL thread
-        mLayer.mFlinger->mEventQueue.postMessage(
-                new MessageDestroyTexture(mLayer.mFlinger.get(), mTexture.name) );
+        getFlinger()->mEventQueue.postMessage(
+                new MessageDestroyTexture(getFlinger(), mTexture.name) );
     }
     if (mTexture.image != EGL_NO_IMAGE_KHR) {
-        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
         eglDestroyImageKHR(dpy, mTexture.image);
     }
 }
@@ -444,7 +443,7 @@
     const Rect transformedBounds(mLayer.getTransformedBounds());
 
 #if defined(EGL_ANDROID_image_native_buffer)
-    if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
+    if (GLExtensions::getInstance().haveDirectTexture()) {
         err = INVALID_OPERATION;
         if (ourBuffer->supportsCopybit()) {
             copybit_device_t* copybit = mLayer.mBlitEngine;
@@ -549,7 +548,7 @@
         dst.crop.r = w;
         dst.crop.b = h;
 
-        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
         err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
     }
 
@@ -559,7 +558,7 @@
 void LayerBuffer::BufferSource::clearTempBufferImage() const
 {
     // delete the image
-    EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+    EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
     eglDestroyImageKHR(dpy, mTexture.image);
 
     // and the associated texture (recreate a name)
@@ -576,7 +575,7 @@
     : Source(layer), mVisibilityChanged(false),
     mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
 {
-    overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
+    overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine();
     if (overlay_dev == NULL) {
         // overlays not supported
         return;
@@ -607,7 +606,7 @@
 
     *overlayRef = new OverlayRef(mOverlayHandle, channel,
             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
-    mLayer.mFlinger->signalEvent();
+    getFlinger()->signalEvent();
 }
 
 LayerBuffer::OverlaySource::~OverlaySource()
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 413b8a4..1c0bf83 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -47,6 +47,7 @@
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual void destroy() { }
+        SurfaceFlinger* getFlinger() const { return mLayer.mFlinger.get(); }
     protected:
         LayerBuffer& mLayer;
     };
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 906a583..a1f339e 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -51,54 +51,6 @@
     sWidth = w;
     sHeight = h;
     sUseTexture = false;
-    
-#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
-
-#warning "using a texture to implement LayerDim"
-    
-    /* On some h/w like msm7K, it is faster to use a texture because the
-     * software renderer will defer to copybit, for this to work we need to
-     * use an EGLImage texture so copybit can actually make use of it.
-     * This burns a full-screen worth of graphic memory.
-     */
-
-    const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
-    uint32_t flags = hw.getFlags();
-
-    if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
-        sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
-                 GraphicBuffer::USAGE_SW_WRITE_OFTEN |
-                 GraphicBuffer::USAGE_HW_TEXTURE);
-        
-        android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-        glGenTextures(1, &sTexId);
-        glBindTexture(GL_TEXTURE_2D, sTexId);
-
-        EGLDisplay dpy = eglGetCurrentDisplay();
-        sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 
-                EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
-        if (sImage == EGL_NO_IMAGE_KHR) {
-            LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
-            return;
-        }
-
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
-        GLint error = glGetError();
-        if (error != GL_NO_ERROR) {
-            eglDestroyImageKHR(dpy, sImage);
-            LOGE("glEGLImageTargetTexture2DOES() failed. err=0x%4x", error);
-            return;
-        }
-
-        // initialize the texture with zeros
-        GGLSurface t;
-        buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
-        memset(t.data, 0, t.stride * t.height * 2);
-        buffer->unlock();
-        sUseTexture = true;
-    }
-#endif
 }
 
 LayerDim::~LayerDim()
@@ -112,36 +64,19 @@
     Region::const_iterator const end = clip.end();
     if (s.alpha>0 && (it != end)) {
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        const GGLfixed alpha = (s.alpha << 16)/255;
+        const GLfloat alpha = s.alpha/255.0f;
         const uint32_t fbHeight = hw.getHeight();
         glDisable(GL_DITHER);
         glEnable(GL_BLEND);
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-        glColor4x(0, 0, 0, alpha);
-        
+        glColor4f(0, 0, 0, alpha);
+
 #if defined(GL_OES_texture_external)
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
-#endif
-#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
-        if (sUseTexture) {
-            glBindTexture(GL_TEXTURE_2D, sTexId);
-            glEnable(GL_TEXTURE_2D);
-            glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-            const GLshort texCoords[4][2] = {
-                    { 0,  0 },
-                    { 0,  1 },
-                    { 1,  1 },
-                    { 1,  0 }
-            };
-            glMatrixMode(GL_TEXTURE);
-            glLoadIdentity();
-            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-            glTexCoordPointer(2, GL_SHORT, 0, texCoords);
-        } else
-#endif
-        {
-            glDisable(GL_TEXTURE_2D);
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
+#endif
+        glDisable(GL_TEXTURE_2D);
 
         GLshort w = sWidth;
         GLshort h = sHeight;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 96a5411..68e8f19 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -44,6 +44,7 @@
 #include <GLES/gl.h>
 
 #include "clz.h"
+#include "GLExtensions.h"
 #include "Layer.h"
 #include "LayerBlur.h"
 #include "LayerBuffer.h"
@@ -993,7 +994,9 @@
         glTexCoordPointer(2, GL_SHORT, 0, tcoords);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 #if defined(GL_OES_texture_external)
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
+        }
 #endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
@@ -1260,10 +1263,19 @@
         format = PIXEL_FORMAT_RGBA_8888;
         break;
     case PIXEL_FORMAT_OPAQUE:
+#ifdef NO_RGBX_8888
+        format = PIXEL_FORMAT_RGB_565;
+#else
         format = PIXEL_FORMAT_RGBX_8888;
+#endif
         break;
     }
 
+#ifdef NO_RGBX_8888
+    if (format == PIXEL_FORMAT_RGBX_8888)
+        format = PIXEL_FORMAT_RGBA_8888;
+#endif
+
     sp<Layer> layer = new Layer(this, display, client);
     status_t err = layer->setBuffers(w, h, format, flags);
     if (LIKELY(err != NO_ERROR)) {
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index d9bdc6a..6526032 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -30,14 +30,15 @@
 
 #include "clz.h"
 #include "DisplayHardware/DisplayHardware.h"
+#include "GLExtensions.h"
 #include "TextureManager.h"
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-TextureManager::TextureManager(uint32_t flags)
-    : mFlags(flags)
+TextureManager::TextureManager()
+    : mGLExtensions(GLExtensions::getInstance())
 {
 }
 
@@ -85,9 +86,11 @@
 
     GLenum target = GL_TEXTURE_2D;
 #if defined(GL_OES_texture_external)
-    if (format && isSupportedYuvFormat(format)) {
-        target = GL_TEXTURE_EXTERNAL_OES;
-        pImage->target = Texture::TEXTURE_EXTERNAL;
+    if (GLExtensions::getInstance().haveTextureExternal()) {
+        if (format && isYuvFormat(format)) {
+            target = GL_TEXTURE_EXTERNAL_OES;
+            pImage->target = Texture::TEXTURE_EXTERNAL;
+        }
     }
 #endif
 
@@ -102,23 +105,32 @@
 
 bool TextureManager::isSupportedYuvFormat(int format)
 {
-    return isYuvFormat(format);
+    switch (format) {
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_YV16:
+        return true;
+    }
+    return false;
 }
 
 bool TextureManager::isYuvFormat(int format)
 {
     switch (format) {
-    case HAL_PIXEL_FORMAT_NV16:
-    case HAL_PIXEL_FORMAT_NV21:
-    case HAL_PIXEL_FORMAT_IYUV:
-    case HAL_PIXEL_FORMAT_YUV9:
-    case HAL_PIXEL_FORMAT_YUY2:
-    case HAL_PIXEL_FORMAT_UYVY:
-    case HAL_PIXEL_FORMAT_NV12:
-    case HAL_PIXEL_FORMAT_NV61:
-    case HAL_PIXEL_FORMAT_NV12_ADRENO_TILED:
+    // supported YUV formats
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_YV16:
+    // Legacy/deprecated YUV formats
+    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+    case HAL_PIXEL_FORMAT_YCbCr_422_I:
+    case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
         return true;
     }
+
+    // Any OEM format needs to be considered
+    if (format>=0x100 && format<=0x1FF)
+        return true;
+
     return false;
 }
 
@@ -208,7 +220,7 @@
     /*
      * round to POT if needed
      */
-    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+    if (!mGLExtensions.haveNpot()) {
         texture->NPOTAdjust = true;
     }
 
@@ -252,7 +264,7 @@
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA, texture->potWidth, texture->potHeight, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, data);
-        } else if (isYuvFormat(t.format)) {
+        } else if (isSupportedYuvFormat(t.format)) {
             // just show the Y plane of YUV buffers
             glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
@@ -280,7 +292,7 @@
                     0, bounds.top, t.width, bounds.height(),
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     t.data + bounds.top*t.stride*4);
-        } else if (isYuvFormat(t.format)) {
+        } else if (isSupportedYuvFormat(t.format)) {
             // just show the Y plane of YUV buffers
             glTexSubImage2D(GL_TEXTURE_2D, 0,
                     0, bounds.top, t.width, bounds.height(),
@@ -294,17 +306,19 @@
 void TextureManager::activateTexture(const Texture& texture, bool filter)
 {
     const GLenum target = getTextureTarget(&texture);
-
-    glBindTexture(target, texture.name);
-    glEnable(target);
-
+    if (target == GL_TEXTURE_2D) {
+        glBindTexture(GL_TEXTURE_2D, texture.name);
+        glEnable(GL_TEXTURE_2D);
 #if defined(GL_OES_texture_external)
-    if (texture.target == Texture::TEXTURE_2D) {
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
+        }
     } else {
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name);
+        glEnable(GL_TEXTURE_EXTERNAL_OES);
         glDisable(GL_TEXTURE_2D);
-    }
 #endif
+    }
 
     if (filter) {
         glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -319,7 +333,9 @@
 {
     glDisable(GL_TEXTURE_2D);
 #if defined(GL_OES_texture_external)
-    glDisable(GL_TEXTURE_EXTERNAL_OES);
+    if (GLExtensions::getInstance().haveTextureExternal()) {
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+    }
 #endif
 }
 
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
index 1f7fe3f..c7c14e7 100644
--- a/libs/surfaceflinger/TextureManager.h
+++ b/libs/surfaceflinger/TextureManager.h
@@ -32,6 +32,7 @@
 
 // ---------------------------------------------------------------------------
 
+class GLExtensions;
 class GraphicBuffer;
 
 // ---------------------------------------------------------------------------
@@ -61,7 +62,7 @@
 // ---------------------------------------------------------------------------
 
 class TextureManager {
-    uint32_t mFlags;
+    const GLExtensions& mGLExtensions;
     static status_t initTexture(Image* texture, int32_t format);
     static status_t initTexture(Texture* texture);
     static bool isSupportedYuvFormat(int format);
@@ -69,7 +70,7 @@
     static GLenum getTextureTarget(const Image* pImage);
 public:
 
-    TextureManager(uint32_t flags);
+    TextureManager();
 
     // load bitmap data into the active buffer
     status_t loadTexture(Texture* texture,
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 8617d94a..dc6332c 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -387,21 +387,21 @@
 
 void Surface::init()
 {
-    android_native_window_t::setSwapInterval  = setSwapInterval;
-    android_native_window_t::dequeueBuffer    = dequeueBuffer;
-    android_native_window_t::lockBuffer       = lockBuffer;
-    android_native_window_t::queueBuffer      = queueBuffer;
-    android_native_window_t::query            = query;
-    android_native_window_t::perform          = perform;
+    ANativeWindow::setSwapInterval  = setSwapInterval;
+    ANativeWindow::dequeueBuffer    = dequeueBuffer;
+    ANativeWindow::lockBuffer       = lockBuffer;
+    ANativeWindow::queueBuffer      = queueBuffer;
+    ANativeWindow::query            = query;
+    ANativeWindow::perform          = perform;
 
     DisplayInfo dinfo;
     SurfaceComposerClient::getDisplayInfo(0, &dinfo);
-    const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
-    const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+    const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
+    const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
     // FIXME: set real values here
-    const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
-    const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
-    const_cast<uint32_t&>(android_native_window_t::flags) = 0;
+    const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
+    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+    const_cast<uint32_t&>(ANativeWindow::flags) = 0;
 
     mConnected = 0;
     mSwapRectangle.makeInvalid();
@@ -485,35 +485,35 @@
 
 // ----------------------------------------------------------------------------
 
-int Surface::setSwapInterval(android_native_window_t* window, int interval) {
+int Surface::setSwapInterval(ANativeWindow* window, int interval) {
     return 0;
 }
 
-int Surface::dequeueBuffer(android_native_window_t* window, 
+int Surface::dequeueBuffer(ANativeWindow* window, 
         android_native_buffer_t** buffer) {
     Surface* self = getSelf(window);
     return self->dequeueBuffer(buffer);
 }
 
-int Surface::lockBuffer(android_native_window_t* window, 
+int Surface::lockBuffer(ANativeWindow* window, 
         android_native_buffer_t* buffer) {
     Surface* self = getSelf(window);
     return self->lockBuffer(buffer);
 }
 
-int Surface::queueBuffer(android_native_window_t* window, 
+int Surface::queueBuffer(ANativeWindow* window, 
         android_native_buffer_t* buffer) {
     Surface* self = getSelf(window);
     return self->queueBuffer(buffer);
 }
 
-int Surface::query(android_native_window_t* window, 
+int Surface::query(ANativeWindow* window, 
         int what, int* value) {
     Surface* self = getSelf(window);
     return self->query(what, value);
 }
 
-int Surface::perform(android_native_window_t* window, 
+int Surface::perform(ANativeWindow* window, 
         int operation, ...) {
     va_list args;
     va_start(args, operation);
@@ -803,7 +803,7 @@
 {
     if (getConnectedApi()) {
         LOGE("Surface::lock(%p) failed. Already connected to another API",
-                (android_native_window_t*)this);
+                (ANativeWindow*)this);
         CallStack stack;
         stack.update();
         stack.dump("");
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 52380a0..6f8948d 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -67,7 +67,7 @@
  * This implements the (main) framebuffer management. This class is used
  * mostly by SurfaceFlinger, but also by command line GL application.
  * 
- * In fact this is an implementation of android_native_window_t on top of
+ * In fact this is an implementation of ANativeWindow on top of
  * the framebuffer.
  * 
  * Currently it is pretty simple, it manages only two buffers (the front and 
@@ -117,23 +117,23 @@
         LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
                 fbDev->width, fbDev->height, strerror(-err));
 
-        const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags; 
-        const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
-        const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
-        const_cast<int&>(android_native_window_t::minSwapInterval) = 
+        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 
+        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
+        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
+        const_cast<int&>(ANativeWindow::minSwapInterval) = 
             fbDev->minSwapInterval;
-        const_cast<int&>(android_native_window_t::maxSwapInterval) = 
+        const_cast<int&>(ANativeWindow::maxSwapInterval) = 
             fbDev->maxSwapInterval;
     } else {
         LOGE("Couldn't get gralloc module");
     }
 
-    android_native_window_t::setSwapInterval = setSwapInterval;
-    android_native_window_t::dequeueBuffer = dequeueBuffer;
-    android_native_window_t::lockBuffer = lockBuffer;
-    android_native_window_t::queueBuffer = queueBuffer;
-    android_native_window_t::query = query;
-    android_native_window_t::perform = perform;
+    ANativeWindow::setSwapInterval = setSwapInterval;
+    ANativeWindow::dequeueBuffer = dequeueBuffer;
+    ANativeWindow::lockBuffer = lockBuffer;
+    ANativeWindow::queueBuffer = queueBuffer;
+    ANativeWindow::query = query;
+    ANativeWindow::perform = perform;
 }
 
 FramebufferNativeWindow::~FramebufferNativeWindow() 
@@ -168,13 +168,13 @@
 }
 
 int FramebufferNativeWindow::setSwapInterval(
-        android_native_window_t* window, int interval) 
+        ANativeWindow* window, int interval) 
 {
     framebuffer_device_t* fb = getSelf(window)->fbDev;
     return fb->setSwapInterval(fb, interval);
 }
 
-int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window, 
+int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 
         android_native_buffer_t** buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
@@ -196,7 +196,7 @@
     return 0;
 }
 
-int FramebufferNativeWindow::lockBuffer(android_native_window_t* window, 
+int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, 
         android_native_buffer_t* buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
@@ -210,7 +210,7 @@
     return NO_ERROR;
 }
 
-int FramebufferNativeWindow::queueBuffer(android_native_window_t* window, 
+int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, 
         android_native_buffer_t* buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
@@ -224,7 +224,7 @@
     return res;
 }
 
-int FramebufferNativeWindow::query(android_native_window_t* window,
+int FramebufferNativeWindow::query(ANativeWindow* window,
         int what, int* value) 
 {
     FramebufferNativeWindow* self = getSelf(window);
@@ -245,7 +245,7 @@
     return BAD_VALUE;
 }
 
-int FramebufferNativeWindow::perform(android_native_window_t* window,
+int FramebufferNativeWindow::perform(ANativeWindow* window,
         int operation, ...)
 {
     switch (operation) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 4b5f025..519c277 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -127,18 +127,6 @@
 {
     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
     status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
-
-    if (err<0 && format == PIXEL_FORMAT_RGBX_8888) {
-        /*
-         * There is currently a bug with some gralloc implementations
-         * not supporting RGBX_8888. In this case, we revert to using RGBA_8888
-         * which is not exactly the same, as GL_REPLACE will yield a different
-         * result.
-         */
-        format = PIXEL_FORMAT_RGBA_8888;
-        err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
-    }
-
     if (err == NO_ERROR) {
         this->width  = w;
         this->height = h;
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 4121b5a..a64251f 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -20,6 +20,70 @@
 
 // class KeyEvent
 
+bool KeyEvent::hasDefaultAction(int32_t keyCode) {
+    switch (keyCode) {
+        case KEYCODE_HOME:
+        case KEYCODE_BACK:
+        case KEYCODE_CALL:
+        case KEYCODE_ENDCALL:
+        case KEYCODE_VOLUME_UP:
+        case KEYCODE_VOLUME_DOWN:
+        case KEYCODE_POWER:
+        case KEYCODE_CAMERA:
+        case KEYCODE_HEADSETHOOK:
+        case KEYCODE_MENU:
+        case KEYCODE_NOTIFICATION:
+        case KEYCODE_FOCUS:
+        case KEYCODE_SEARCH:
+        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:
+        case KEYCODE_MUTE:
+            return true;
+    }
+    
+    return false;
+}
+
+bool KeyEvent::hasDefaultAction() const {
+    return hasDefaultAction(getKeyCode());
+}
+
+bool KeyEvent::isSystemKey(int32_t keyCode) {
+    switch (keyCode) {
+        case KEYCODE_MENU:
+        case KEYCODE_SOFT_RIGHT:
+        case KEYCODE_HOME:
+        case KEYCODE_BACK:
+        case KEYCODE_CALL:
+        case KEYCODE_ENDCALL:
+        case KEYCODE_VOLUME_UP:
+        case KEYCODE_VOLUME_DOWN:
+        case KEYCODE_MUTE:
+        case KEYCODE_POWER:
+        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:
+        case KEYCODE_CAMERA:
+        case KEYCODE_FOCUS:
+        case KEYCODE_SEARCH:
+            return true;
+    }
+    
+    return false;
+}
+
+bool KeyEvent::isSystemKey() const {
+    return isSystemKey(getKeyCode());
+}
+
 void KeyEvent::initialize(
         int32_t deviceId,
         int32_t nature,
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 0fc29b2..8f6d1fe 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -232,6 +232,9 @@
     LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime);
 #endif
 
+    // Reset key repeating in case a keyboard device was added or removed or something.
+    resetKeyRepeatLocked();
+
     mLock.unlock();
 
     mPolicy->notifyConfigurationChanged(entry->eventTime);
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 8087f84..899027c 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -387,6 +387,11 @@
  * points has moved more than a screen height from the last position,
  * then drop it. */
 bool InputDevice::TouchScreenState::applyBadTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
     uint32_t pointerCount = currentTouch.pointerCount;
 
     // Nothing to do if there are no points.
@@ -466,6 +471,11 @@
  * the coordinate value for one axis has jumped to the other pointer's location.
  */
 bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
     uint32_t pointerCount = currentTouch.pointerCount;
     if (lastTouch.pointerCount != pointerCount) {
 #if DEBUG_HACKS
@@ -724,6 +734,12 @@
 }
 
 bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
+    if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
+        // Assume all points on a touch screen without valid axis parameters are
+        // inside the display.
+        return true;
+    }
+
     return x >= parameters.xAxis.minValue
         && x <= parameters.xAxis.maxValue
         && y >= parameters.yAxis.minValue
@@ -1435,6 +1451,9 @@
     int32_t pointerIds[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
 
+    const InputDevice::TouchScreenState::Precalculated& precalculated =
+            device->touchScreen.precalculated;
+
     // Walk through the the active pointers and map touch screen coordinates (TouchData) into
     // display coordinates (PointerCoords) and adjust for display orientation.
     while (! idBits.isEmpty()) {
@@ -1442,18 +1461,14 @@
         idBits.clearBit(id);
         uint32_t index = touch->idToIndex[id];
 
-        float x = (float(touch->pointers[index].x)
-                        - device->touchScreen.parameters.xAxis.minValue)
-                * device->touchScreen.precalculated.xScale;
-        float y = (float(touch->pointers[index].y)
-                        - device->touchScreen.parameters.yAxis.minValue)
-                * device->touchScreen.precalculated.yScale;
-        float pressure = (float(touch->pointers[index].pressure)
-                        - device->touchScreen.parameters.pressureAxis.minValue)
-                * device->touchScreen.precalculated.pressureScale;
-        float size = (float(touch->pointers[index].size)
-                        - device->touchScreen.parameters.sizeAxis.minValue)
-                * device->touchScreen.precalculated.sizeScale;
+        float x = float(touch->pointers[index].x
+                - precalculated.xOrigin) * precalculated.xScale;
+        float y = float(touch->pointers[index].y
+                - precalculated.yOrigin) * precalculated.yScale;
+        float pressure = float(touch->pointers[index].pressure
+                - precalculated.pressureOrigin) * precalculated.pressureScale;
+        float size = float(touch->pointers[index].size
+                - precalculated.sizeOrigin) * precalculated.sizeScale;
 
         switch (mDisplayOrientation) {
         case InputReaderPolicyInterface::ROTATION_90: {
@@ -1624,10 +1639,6 @@
         *policyFlags |= POLICY_FLAG_BRIGHT_HERE;
     }
 
-    if (policyActions & InputReaderPolicyInterface::ACTION_INTERCEPT_DISPATCH) {
-        *policyFlags |= POLICY_FLAG_INTERCEPT_DISPATCH;
-    }
-
     return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
 }
 
@@ -1651,7 +1662,11 @@
             }
         }
 
-        mDisplayOrientation = newOrientation;
+        if (newOrientation != mDisplayOrientation) {
+            LOGD("Display orientation changed to %d", mDisplayOrientation);
+
+            mDisplayOrientation = newOrientation;
+        }
         return true;
     } else {
         resetDisplayProperties();
@@ -1740,10 +1755,25 @@
         device->touchScreen.parameters.useJumpyTouchFilter =
                 mPolicy->filterJumpyTouchEvents();
 
-        device->touchScreen.precalculated.pressureScale =
-                1.0f / device->touchScreen.parameters.pressureAxis.range;
-        device->touchScreen.precalculated.sizeScale =
-                1.0f / device->touchScreen.parameters.sizeAxis.range;
+        if (device->touchScreen.parameters.pressureAxis.valid) {
+            device->touchScreen.precalculated.pressureOrigin =
+                    device->touchScreen.parameters.pressureAxis.minValue;
+            device->touchScreen.precalculated.pressureScale =
+                    1.0f / device->touchScreen.parameters.pressureAxis.range;
+        } else {
+            device->touchScreen.precalculated.pressureOrigin = 0;
+            device->touchScreen.precalculated.pressureScale = 1.0f;
+        }
+
+        if (device->touchScreen.parameters.sizeAxis.valid) {
+            device->touchScreen.precalculated.sizeOrigin =
+                    device->touchScreen.parameters.sizeAxis.minValue;
+            device->touchScreen.precalculated.sizeScale =
+                    1.0f / device->touchScreen.parameters.sizeAxis.range;
+        } else {
+            device->touchScreen.precalculated.sizeOrigin = 0;
+            device->touchScreen.precalculated.sizeScale = 1.0f;
+        }
     }
 
     if (device->isTrackball()) {
@@ -1758,22 +1788,42 @@
 
 void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) {
     if (device->isTouchScreen()) {
-        if (mDisplayWidth < 0) {
-            LOGD("Skipping part of touch screen configuration since display size is unknown.");
-        } else {
-            LOGI("Device configured: id=0x%x, name=%s (display size was changed)", device->id,
-                    device->name.string());
-            configureVirtualKeys(device);
+        if (device->touchScreen.parameters.xAxis.valid
+                && device->touchScreen.parameters.yAxis.valid) {
+            device->touchScreen.precalculated.xOrigin =
+                    device->touchScreen.parameters.xAxis.minValue;
+            device->touchScreen.precalculated.yOrigin =
+                    device->touchScreen.parameters.yAxis.minValue;
 
-            device->touchScreen.precalculated.xScale =
-                    float(mDisplayWidth) / device->touchScreen.parameters.xAxis.range;
-            device->touchScreen.precalculated.yScale =
-                    float(mDisplayHeight) / device->touchScreen.parameters.yAxis.range;
+            if (mDisplayWidth < 0) {
+                LOGD("Skipping part of touch screen configuration since display size is unknown.");
+
+                device->touchScreen.precalculated.xScale = 1.0f;
+                device->touchScreen.precalculated.yScale = 1.0f;
+            } else {
+                LOGI("Device configured: id=0x%x, name=%s (display size was changed)", device->id,
+                        device->name.string());
+
+                device->touchScreen.precalculated.xScale =
+                        float(mDisplayWidth) / device->touchScreen.parameters.xAxis.range;
+                device->touchScreen.precalculated.yScale =
+                        float(mDisplayHeight) / device->touchScreen.parameters.yAxis.range;
+
+                configureVirtualKeys(device);
+            }
+        } else {
+            device->touchScreen.precalculated.xOrigin = 0;
+            device->touchScreen.precalculated.xScale = 1.0f;
+            device->touchScreen.precalculated.yOrigin = 0;
+            device->touchScreen.precalculated.yScale = 1.0f;
         }
     }
 }
 
 void InputReader::configureVirtualKeys(InputDevice* device) {
+    assert(device->touchScreen.parameters.xAxis.valid
+            && device->touchScreen.parameters.yAxis.valid);
+
     device->touchScreen.virtualKeys.clear();
 
     Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
@@ -1837,16 +1887,18 @@
         if (out->range != 0) {
             LOGI("  %s: min=%d max=%d flat=%d fuzz=%d",
                     name, out->minValue, out->maxValue, out->flat, out->fuzz);
+            out->valid = true;
             return;
         }
     }
 
+    out->valid = false;
     out->minValue = 0;
     out->maxValue = 0;
     out->flat = 0;
     out->fuzz = 0;
     out->range = 0;
-    LOGI("  %s: unknown axis values, setting to zero", name);
+    LOGI("  %s: unknown axis values, marking as invalid", name);
 }
 
 void InputReader::configureExcludedDevices() {
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index f56537a..25def3c 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -691,7 +691,7 @@
 
 } // namespace android
 
-// --- input_queue_t ---
+// --- AInputQueue ---
 
 using android::InputEvent;
 using android::InputChannel;
@@ -699,13 +699,13 @@
 using android::sp;
 using android::status_t;
 
-input_queue_t::input_queue_t(const sp<InputChannel>& channel) :
+AInputQueue::AInputQueue(const sp<InputChannel>& channel) :
         mConsumer(channel) {
 }
 
-input_queue_t::~input_queue_t() {
+AInputQueue::~AInputQueue() {
 }
 
-status_t input_queue_t::consume(InputEvent** event) {
+status_t AInputQueue::consume(InputEvent** event) {
     return mConsumer.consume(&mInputEventFactory, event);
 }
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index c9a5950..b205418 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -59,16 +59,13 @@
     // YUV format from the HAL are handled here
     switch (format) {
     case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-    case HAL_PIXEL_FORMAT_YCrCb_422_SP:
-    case HAL_PIXEL_FORMAT_YCbCr_422_P:
     case HAL_PIXEL_FORMAT_YCbCr_422_I:
-    case HAL_PIXEL_FORMAT_CbYCrY_422_I:
+    case HAL_PIXEL_FORMAT_YV16:
         info->bitsPerPixel = 16;
         goto done;
-    case HAL_PIXEL_FORMAT_YCbCr_420_SP:
     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
     case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
-    case HAL_PIXEL_FORMAT_YCbCr_420_P:
+    case HAL_PIXEL_FORMAT_YV12:
         info->bitsPerPixel = 12;
      done:
         info->format = format;
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 20a4d13..58fe141 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -21,6 +21,10 @@
 
 namespace android {
 
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
 PollLoop::PollLoop() :
         mPolling(false), mWaiters(0) {
     openWakePipe();
@@ -30,6 +34,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 +93,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = NULL;
+    requestedCallback.looperCallback = NULL;
     requestedCallback.data = NULL;
     mRequestedCallbacks.insertAt(requestedCallback, 0);
 }
@@ -123,12 +163,14 @@
         if (revents) {
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
             Callback callback = requestedCallback.callback;
+            ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
 
-            if (callback) {
+            if (callback || looperCallback) {
                 PendingCallback pendingCallback;
                 pendingCallback.fd = requestedFd.fd;
                 pendingCallback.events = requestedFd.revents;
                 pendingCallback.callback = callback;
+                pendingCallback.looperCallback = looperCallback;
                 pendingCallback.data = requestedCallback.data;
                 mPendingCallbacks.push(pendingCallback);
             } else {
@@ -172,8 +214,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);
             }
@@ -200,11 +248,22 @@
 }
 
 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) {
+    if (! events || (! callback && ! looperCallback)) {
         LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
         removeCallback(fd);
         return;
@@ -218,6 +277,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = callback;
+    requestedCallback.looperCallback = looperCallback;
     requestedCallback.data = data;
 
     ssize_t index = getRequestIndexLocked(fd);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 50f0674..9212708 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import java.util.NoSuchElementException;
 import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -1016,7 +1017,11 @@
                 } else {
                     mStartcount--;
                     if (mStartcount == 0) {
-                        mCb.unlinkToDeath(this, 0);
+                        try {
+                            mCb.unlinkToDeath(this, 0);
+                        } catch (NoSuchElementException e) {
+                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
+                        }
                     }
                     requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
                 }
@@ -1025,8 +1030,14 @@
 
         public void clearCount(boolean stopSco) {
             synchronized(mScoClients) {
+                if (mStartcount != 0) {
+                    try {
+                        mCb.unlinkToDeath(this, 0);
+                    } catch (NoSuchElementException e) {
+                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
+                    }
+                }
                 mStartcount = 0;
-                mCb.unlinkToDeath(this, 0);
                 if (stopSco) {
                     requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
                 }
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 64d6460..a27df57 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -119,15 +119,26 @@
     public int audioChannels;
 
     /**
-     * Returns the camcorder profile for the given quality level.
+     * Returns the camcorder profile for the default camera at the given
+     * quality level.
      * @param quality the target quality level for the camcorder profile
      */
     public static CamcorderProfile get(int quality) {
+        return get(0, quality);
+    }
+
+    /**
+     * Returns the camcorder profile for the given camera at the given
+     * quality level.
+     * @param cameraId the id for the camera
+     * @param quality the target quality level for the camcorder profile
+     */
+    public static CamcorderProfile get(int cameraId, int quality) {
         if (quality < QUALITY_LOW || quality > QUALITY_HIGH) {
             String errMessage = "Unsupported quality level: " + quality;
             throw new IllegalArgumentException(errMessage);
         }
-        return native_get_camcorder_profile(quality);
+        return native_get_camcorder_profile(cameraId, quality);
     }
 
     static {
@@ -165,5 +176,6 @@
 
     // Methods implemented by JNI
     private static native final void native_init();
-    private static native final CamcorderProfile native_get_camcorder_profile(int quality);
+    private static native final CamcorderProfile native_get_camcorder_profile(
+            int cameraId, int quality);
 }
diff --git a/media/java/android/media/CameraProfile.java b/media/java/android/media/CameraProfile.java
index f8d3935..6a0be08 100644
--- a/media/java/android/media/CameraProfile.java
+++ b/media/java/android/media/CameraProfile.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import java.util.Arrays;
+import java.util.HashMap;
 
 /**
  * The CameraProfile class is used to retrieve the pre-defined still image
@@ -40,36 +41,55 @@
     /*
      * Cache the Jpeg encoding quality parameters
      */
-    private static final int[] sJpegEncodingQualityParameters;
+    private static final HashMap<Integer, int[]> sCache = new HashMap<Integer, int[]>();
 
     /**
      * Returns a pre-defined still image capture (jpeg) quality level
-     * used for the given quality level in the Camera application.
+     * used for the given quality level in the Camera application for
+     * the default camera.
      *
      * @param quality The target quality level
      */
     public static int getJpegEncodingQualityParameter(int quality) {
+        return getJpegEncodingQualityParameter(0, quality);
+    }
+
+    /**
+     * Returns a pre-defined still image capture (jpeg) quality level
+     * used for the given quality level in the Camera application for
+     * the specified camera.
+     *
+     * @param cameraId The id of the camera
+     * @param quality The target quality level
+     */
+    public static int getJpegEncodingQualityParameter(int cameraId, int quality) {
         if (quality < QUALITY_LOW || quality > QUALITY_HIGH) {
             throw new IllegalArgumentException("Unsupported quality level: " + quality);
         }
-        return sJpegEncodingQualityParameters[quality];
+        synchronized (sCache) {
+            int[] levels = sCache.get(cameraId);
+            if (levels == null) {
+                levels = getImageEncodingQualityLevels(cameraId);
+                sCache.put(cameraId, levels);
+            }
+            return levels[quality];
+        }
     }
 
     static {
         System.loadLibrary("media_jni");
         native_init();
-        sJpegEncodingQualityParameters = getImageEncodingQualityLevels();
     }
 
-    private static int[] getImageEncodingQualityLevels() {
-        int nLevels = native_get_num_image_encoding_quality_levels();
+    private static int[] getImageEncodingQualityLevels(int cameraId) {
+        int nLevels = native_get_num_image_encoding_quality_levels(cameraId);
         if (nLevels != QUALITY_HIGH + 1) {
             throw new RuntimeException("Unexpected Jpeg encoding quality levels " + nLevels);
         }
 
         int[] levels = new int[nLevels];
         for (int i = 0; i < nLevels; ++i) {
-            levels[i] = native_get_image_encoding_quality_level(i);
+            levels[i] = native_get_image_encoding_quality_level(cameraId, i);
         }
         Arrays.sort(levels);  // Lower quality level ALWAYS comes before higher one
         return levels;
@@ -77,6 +97,6 @@
 
     // Methods implemented by JNI
     private static native final void native_init();
-    private static native final int native_get_num_image_encoding_quality_levels();
-    private static native final int native_get_image_encoding_quality_level(int index);
+    private static native final int native_get_num_image_encoding_quality_levels(int cameraId);
+    private static native final int native_get_image_encoding_quality_level(int cameraId, int index);
 }
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 7d7533a..cce9fd0 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -162,26 +162,26 @@
 }
 
 static jobject
-android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject thiz, jint quality)
+android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject thiz, jint id, jint quality)
 {
-    LOGV("native_get_camcorder_profile: %d", quality);
+    LOGV("native_get_camcorder_profile: %d %d", id, quality);
     if (quality != CAMCORDER_QUALITY_HIGH && quality != CAMCORDER_QUALITY_LOW) {
         jniThrowException(env, "java/lang/RuntimeException", "Unknown camcorder profile quality");
         return NULL;
     }
 
     camcorder_quality q = static_cast<camcorder_quality>(quality);
-    int duration         = sProfiles->getCamcorderProfileParamByName("duration", q);
-    int fileFormat       = sProfiles->getCamcorderProfileParamByName("file.format", q);
-    int videoCodec       = sProfiles->getCamcorderProfileParamByName("vid.codec",   q);
-    int videoBitRate     = sProfiles->getCamcorderProfileParamByName("vid.bps",     q);
-    int videoFrameRate   = sProfiles->getCamcorderProfileParamByName("vid.fps",     q);
-    int videoFrameWidth  = sProfiles->getCamcorderProfileParamByName("vid.width",   q);
-    int videoFrameHeight = sProfiles->getCamcorderProfileParamByName("vid.height",  q);
-    int audioCodec       = sProfiles->getCamcorderProfileParamByName("aud.codec",   q);
-    int audioBitRate     = sProfiles->getCamcorderProfileParamByName("aud.bps",     q);
-    int audioSampleRate  = sProfiles->getCamcorderProfileParamByName("aud.hz",      q);
-    int audioChannels    = sProfiles->getCamcorderProfileParamByName("aud.ch",      q);
+    int duration         = sProfiles->getCamcorderProfileParamByName("duration",    id, q);
+    int fileFormat       = sProfiles->getCamcorderProfileParamByName("file.format", id, q);
+    int videoCodec       = sProfiles->getCamcorderProfileParamByName("vid.codec",   id, q);
+    int videoBitRate     = sProfiles->getCamcorderProfileParamByName("vid.bps",     id, q);
+    int videoFrameRate   = sProfiles->getCamcorderProfileParamByName("vid.fps",     id, q);
+    int videoFrameWidth  = sProfiles->getCamcorderProfileParamByName("vid.width",   id, q);
+    int videoFrameHeight = sProfiles->getCamcorderProfileParamByName("vid.height",  id, q);
+    int audioCodec       = sProfiles->getCamcorderProfileParamByName("aud.codec",   id, q);
+    int audioBitRate     = sProfiles->getCamcorderProfileParamByName("aud.bps",     id, q);
+    int audioSampleRate  = sProfiles->getCamcorderProfileParamByName("aud.hz",      id, q);
+    int audioChannels    = sProfiles->getCamcorderProfileParamByName("aud.ch",      id, q);
 
     // Check on the values retrieved
     if (duration == -1 || fileFormat == -1 || videoCodec == -1 || audioCodec == -1 ||
@@ -253,17 +253,17 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv *env, jobject thiz, jint cameraId)
 {
     LOGV("native_get_num_image_encoding_quality_levels");
-    return sProfiles->getImageEncodingQualityLevels().size();
+    return sProfiles->getImageEncodingQualityLevels(cameraId).size();
 }
 
 static jint
-android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject thiz, jint cameraId, jint index)
 {
     LOGV("native_get_image_encoding_quality_level");
-    Vector<int> levels = sProfiles->getImageEncodingQualityLevels();
+    Vector<int> levels = sProfiles->getImageEncodingQualityLevels(cameraId);
     if (index < 0 || index >= levels.size()) {
         jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
         return -1;
@@ -287,7 +287,7 @@
 
 static JNINativeMethod gMethodsForCamcorderProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
-    {"native_get_camcorder_profile",           "(I)Landroid/media/CamcorderProfile;",
+    {"native_get_camcorder_profile",           "(II)Landroid/media/CamcorderProfile;",
                                                                          (void *)android_media_MediaProfiles_native_get_camcorder_profile},
 };
 
@@ -302,8 +302,8 @@
 static JNINativeMethod gMethodsForCameraProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_image_encoding_quality_levels",
-                                               "()I",                    (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},
-    {"native_get_image_encoding_quality_level","(I)I",                   (void *)android_media_MediaProfiles_native_get_image_encoding_quality_level},
+                                               "(I)I",                   (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},
+    {"native_get_image_encoding_quality_level","(II)I",                   (void *)android_media_MediaProfiles_native_get_image_encoding_quality_level},
 };
 
 static const char* const kEncoderCapabilitiesClassPathName = "android/media/EncoderCapabilities";
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 1263373..3869389 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -272,7 +272,7 @@
 }
 
 /*static*/ MediaProfiles::CamcorderProfile*
-MediaProfiles::createCamcorderProfile(const char **atts)
+MediaProfiles::createCamcorderProfile(int cameraId, const char **atts)
 {
     CHECK(!strcmp("quality",    atts[0]) &&
           !strcmp("fileFormat", atts[2]) &&
@@ -287,16 +287,47 @@
     CHECK(fileFormat != -1);
 
     MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
+    profile->mCameraId = cameraId;
     profile->mFileFormat = static_cast<output_format>(fileFormat);
     profile->mQuality = static_cast<camcorder_quality>(quality);
     profile->mDuration = atoi(atts[5]);
     return profile;
 }
 
-/*static*/ int
-MediaProfiles::getImageEncodingQualityLevel(const char** atts)
+MediaProfiles::ImageEncodingQualityLevels*
+MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
+{
+    int n = mImageEncodingQualityLevels.size();
+    for (int i = 0; i < n; i++) {
+        ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
+        if (levels->mCameraId == cameraId) {
+            return levels;
+        }
+    }
+    return NULL;
+}
+
+void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
 {
     CHECK(!strcmp("quality", atts[0]));
+    int quality = atoi(atts[1]);
+    LOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
+    ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
+
+    if (levels == NULL) {
+        levels = new ImageEncodingQualityLevels();
+        levels->mCameraId = cameraId;
+        mImageEncodingQualityLevels.add(levels);
+    }
+
+    levels->mLevels.add(quality);
+}
+
+/*static*/ int
+MediaProfiles::getCameraId(const char** atts)
+{
+    if (!atts[0]) return 0;  // default cameraId = 0
+    CHECK(!strcmp("cameraId", atts[0]));
     return atoi(atts[1]);
 }
 
@@ -322,10 +353,13 @@
         profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
     } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
         profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
+    } else if (strcmp("CamcorderProfiles", name) == 0) {
+        profiles->mCurrentCameraId = getCameraId(atts);
     } else if (strcmp("EncoderProfile", name) == 0) {
-        profiles->mCamcorderProfiles.add(createCamcorderProfile(atts));
+        profiles->mCamcorderProfiles.add(
+            createCamcorderProfile(profiles->mCurrentCameraId, atts));
     } else if (strcmp("ImageEncoding", name) == 0) {
-        profiles->mImageEncodingQualityLevels.add(getImageEncodingQualityLevel(atts));
+        profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
     }
 }
 
@@ -383,7 +417,8 @@
         new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
 
     AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
-    CamcorderProfile *profile = new CamcorderProfile;
+    CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
+    profile->mCameraId = 0;
     profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
     profile->mQuality = CAMCORDER_QUALITY_HIGH;
     profile->mDuration = 60;
@@ -402,6 +437,7 @@
         new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
 
     MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
+    profile->mCameraId = 0;
     profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
     profile->mQuality = CAMCORDER_QUALITY_LOW;
     profile->mDuration = 30;
@@ -458,9 +494,12 @@
 /*static*/ void
 MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
 {
-    profiles->mImageEncodingQualityLevels.add(70);
-    profiles->mImageEncodingQualityLevels.add(80);
-    profiles->mImageEncodingQualityLevels.add(90);
+    ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
+    levels->mCameraId = 0;
+    levels->mLevels.add(70);
+    levels->mLevels.add(80);
+    levels->mLevels.add(90);
+    profiles->mImageEncodingQualityLevels.add(levels);
 }
 
 /*static*/ MediaProfiles*
@@ -629,19 +668,24 @@
     return decoders;  // copy out
 }
 
-int MediaProfiles::getCamcorderProfileParamByName(const char *name, camcorder_quality quality) const
+int MediaProfiles::getCamcorderProfileParamByName(const char *name,
+                                                  int cameraId,
+                                                  camcorder_quality quality) const
 {
-    LOGV("getCamcorderProfileParamByName: %s for quality %d", name, quality);
+    LOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
+         name, cameraId, quality);
 
     int index = -1;
     for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
-        if (mCamcorderProfiles[i]->mQuality == quality) {
+        if (mCamcorderProfiles[i]->mCameraId == cameraId &&
+            mCamcorderProfiles[i]->mQuality == quality) {
             index = i;
             break;
         }
     }
     if (index == -1) {
-        LOGE("The given camcorder profile quality %d is not found", quality);
+        LOGE("The given camcorder profile camera %d quality %d is not found",
+             cameraId, quality);
         return -1;
     }
 
@@ -657,13 +701,18 @@
     if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
     if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
 
-    LOGE("The given camcorder profile param name %s is not found", name);
+    LOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
     return -1;
 }
 
-Vector<int> MediaProfiles::getImageEncodingQualityLevels() const
+Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
 {
-    return mImageEncodingQualityLevels;  // copy out
+    Vector<int> result;
+    ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
+    if (levels != NULL) {
+        result = levels->mLevels;  // copy out
+    }
+    return result;
 }
 
 MediaProfiles::~MediaProfiles()
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index c4aeec3..50f74f2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -42,11 +42,16 @@
 
 namespace android {
 
-StagefrightRecorder::StagefrightRecorder() {
+StagefrightRecorder::StagefrightRecorder()
+    : mWriter(NULL),
+      mOutputFd(-1) {
+
+    LOGV("Constructor");
     reset();
 }
 
 StagefrightRecorder::~StagefrightRecorder() {
+    LOGV("Destructor");
     stop();
 
     if (mOutputFd >= 0) {
@@ -56,40 +61,97 @@
 }
 
 status_t StagefrightRecorder::init() {
+    LOGV("init");
     return OK;
 }
 
 status_t StagefrightRecorder::setAudioSource(audio_source as) {
-    mAudioSource = as;
+    LOGV("setAudioSource: %d", as);
+    if (as < AUDIO_SOURCE_DEFAULT ||
+        as >= AUDIO_SOURCE_LIST_END) {
+        LOGE("Invalid audio source: %d", as);
+        return BAD_VALUE;
+    }
+
+    if (as == AUDIO_SOURCE_DEFAULT) {
+        mAudioSource = AUDIO_SOURCE_MIC;
+    } else {
+        mAudioSource = as;
+    }
 
     return OK;
 }
 
 status_t StagefrightRecorder::setVideoSource(video_source vs) {
-    mVideoSource = vs;
+    LOGV("setVideoSource: %d", vs);
+    if (vs < VIDEO_SOURCE_DEFAULT ||
+        vs >= VIDEO_SOURCE_LIST_END) {
+        LOGE("Invalid video source: %d", vs);
+        return BAD_VALUE;
+    }
+
+    if (vs == VIDEO_SOURCE_DEFAULT) {
+        mVideoSource = VIDEO_SOURCE_CAMERA;
+    } else {
+        mVideoSource = vs;
+    }
 
     return OK;
 }
 
 status_t StagefrightRecorder::setOutputFormat(output_format of) {
-    mOutputFormat = of;
+    LOGV("setOutputFormat: %d", of);
+    if (of < OUTPUT_FORMAT_DEFAULT ||
+        of >= OUTPUT_FORMAT_LIST_END) {
+        LOGE("Invalid output format: %d", of);
+        return BAD_VALUE;
+    }
+
+    if (of == OUTPUT_FORMAT_DEFAULT) {
+        mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
+    } else {
+        mOutputFormat = of;
+    }
 
     return OK;
 }
 
 status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
-    mAudioEncoder = ae;
+    LOGV("setAudioEncoder: %d", ae);
+    if (ae < AUDIO_ENCODER_DEFAULT ||
+        ae >= AUDIO_ENCODER_LIST_END) {
+        LOGE("Invalid audio encoder: %d", ae);
+        return BAD_VALUE;
+    }
+
+    if (ae == AUDIO_ENCODER_DEFAULT) {
+        mAudioEncoder = AUDIO_ENCODER_AMR_NB;
+    } else {
+        mAudioEncoder = ae;
+    }
 
     return OK;
 }
 
 status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
-    mVideoEncoder = ve;
+    LOGV("setVideoEncoder: %d", ve);
+    if (ve < VIDEO_ENCODER_DEFAULT ||
+        ve >= VIDEO_ENCODER_LIST_END) {
+        LOGE("Invalid video encoder: %d", ve);
+        return BAD_VALUE;
+    }
+
+    if (ve == VIDEO_ENCODER_DEFAULT) {
+        mVideoEncoder = VIDEO_ENCODER_H263;
+    } else {
+        mVideoEncoder = ve;
+    }
 
     return OK;
 }
 
 status_t StagefrightRecorder::setVideoSize(int width, int height) {
+    LOGV("setVideoSize: %dx%d", width, height);
     if (width <= 0 || height <= 0) {
         LOGE("Invalid video size: %dx%d", width, height);
         return BAD_VALUE;
@@ -103,6 +165,7 @@
 }
 
 status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
+    LOGV("setVideoFrameRate: %d", frames_per_second);
     if (frames_per_second <= 0 || frames_per_second > 30) {
         LOGE("Invalid video frame rate: %d", frames_per_second);
         return BAD_VALUE;
@@ -118,7 +181,7 @@
     LOGV("setCamera");
     if (camera == 0) {
         LOGE("camera is NULL");
-        return UNKNOWN_ERROR;
+        return BAD_VALUE;
     }
 
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -127,7 +190,7 @@
     if (mCamera == 0) {
         LOGE("Unable to connect to camera");
         IPCThreadState::self()->restoreCallingIdentity(token);
-        return UNKNOWN_ERROR;
+        return -EBUSY;
     }
 
     LOGV("Connected to camera");
@@ -141,23 +204,31 @@
 }
 
 status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
+    LOGV("setPreviewSurface: %p", surface.get());
     mPreviewSurface = surface;
 
     return OK;
 }
 
 status_t StagefrightRecorder::setOutputFile(const char *path) {
+    LOGE("setOutputFile(const char*) must not be called");
     // We don't actually support this at all, as the media_server process
     // no longer has permissions to create files.
 
-    return UNKNOWN_ERROR;
+    return -EPERM;
 }
 
 status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
+    LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
     // These don't make any sense, do they?
     CHECK_EQ(offset, 0);
     CHECK_EQ(length, 0);
 
+    if (fd < 0) {
+        LOGE("Invalid file descriptor: %d", fd);
+        return -EBADF;
+    }
+
     if (mOutputFd >= 0) {
         ::close(mOutputFd);
     }
@@ -233,6 +304,7 @@
     LOGV("setParamAudioNumberOfChannels: %d", channels);
     if (channels <= 0 || channels >= 3) {
         LOGE("Invalid number of audio channels: %d", channels);
+        return BAD_VALUE;
     }
 
     // Additional check on the number of channels will be performed later.
@@ -270,21 +342,23 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setParamMaxDurationOrFileSize(int64_t limit,
-        bool limit_is_duration) {
-    LOGV("setParamMaxDurationOrFileSize: limit (%lld) for %s",
-            limit, limit_is_duration?"duration":"size");
-    if (limit_is_duration) {  // limit is in ms
-        if (limit <= 1000) {  // XXX: 1 second
-            LOGE("Max file duration is too short: %lld us", limit);
-        }
-        mMaxFileDurationUs = limit * 1000LL;
-    } else {
-        if (limit <= 1024) {  // XXX: 1 kB
-            LOGE("Max file size is too small: %lld bytes", limit);
-        }
-        mMaxFileSizeBytes = limit;
+status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
+    LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
+    if (timeUs <= 1000000LL) {  // XXX: 1 second
+        LOGE("Max file duration is too short: %lld us", timeUs);
+        return BAD_VALUE;
     }
+    mMaxFileDurationUs = timeUs;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
+    LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
+    if (bytes <= 1024) {  // XXX: 1 kB
+        LOGE("Max file size is too small: %lld bytes", bytes);
+        return BAD_VALUE;
+    }
+    mMaxFileSizeBytes = bytes;
     return OK;
 }
 
@@ -309,7 +383,7 @@
 
 // If interval <  0, only the first frame is I frame, and rest are all P frames
 // If interval == 0, all frames are encoded as I frames. No P frames
-// If interval >  0, it is the time spacing between 2 neighboring I frames
+// If interval >  0, it is the time spacing (seconds) between 2 neighboring I frames
 status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) {
     LOGV("setParamVideoIFramesInterval: %d seconds", interval);
     mIFramesInterval = interval;
@@ -335,6 +409,7 @@
 status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) {
     LOGV("setParamTrackFrameStatus: %d", nFrames);
     if (nFrames <= 0) {
+        LOGE("Invalid number of frames to track: %d", nFrames);
         return BAD_VALUE;
     }
     mTrackEveryNumberOfFrames = nFrames;
@@ -344,26 +419,43 @@
 status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
     LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
     if (timeDurationUs < 20000) {  // Infeasible if shorter than 20 ms?
+        LOGE("Tracking time duration too short: %lld us", timeDurationUs);
         return BAD_VALUE;
     }
     mTrackEveryTimeDurationUs = timeDurationUs;
     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());
     if (key == "max-duration") {
         int64_t max_duration_ms;
         if (safe_strtoi64(value.string(), &max_duration_ms)) {
-            return setParamMaxDurationOrFileSize(
-                    max_duration_ms, true /* limit_is_duration */);
+            return setParamMaxFileDurationUs(1000LL * max_duration_ms);
         }
     } else if (key == "max-filesize") {
         int64_t max_filesize_bytes;
         if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
-            return setParamMaxDurationOrFileSize(
-                    max_filesize_bytes, false /* limit is filesize */);
+            return setParamMaxFileSizeBytes(max_filesize_bytes);
         }
     } else if (key == "interleave-duration-us") {
         int32_t durationUs;
@@ -410,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)) {
@@ -467,7 +569,10 @@
 }
 
 status_t StagefrightRecorder::start() {
+    CHECK(mOutputFd >= 0);
+
     if (mWriter != NULL) {
+        LOGE("File writer is not avaialble");
         return UNKNOWN_ERROR;
     }
 
@@ -486,6 +591,7 @@
             return startAACRecording();
 
         default:
+            LOGE("Unsupported output file format: %d", mOutputFormat);
             return UNKNOWN_ERROR;
     }
 }
@@ -549,7 +655,6 @@
 
     CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
     CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
-    CHECK(mOutputFd >= 0);
 
     CHECK(0 == "AACWriter is not implemented yet");
 
@@ -565,34 +670,34 @@
             mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
             LOGE("Invalid encoder %d used for AMRNB recording",
                     mAudioEncoder);
-            return UNKNOWN_ERROR;
+            return BAD_VALUE;
         }
         if (mSampleRate != 8000) {
             LOGE("Invalid sampling rate %d used for AMRNB recording",
                     mSampleRate);
-            return UNKNOWN_ERROR;
+            return BAD_VALUE;
         }
     } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
         if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
             LOGE("Invlaid encoder %d used for AMRWB recording",
                     mAudioEncoder);
-            return UNKNOWN_ERROR;
+            return BAD_VALUE;
         }
         if (mSampleRate != 16000) {
             LOGE("Invalid sample rate %d used for AMRWB recording",
                     mSampleRate);
-            return UNKNOWN_ERROR;
+            return BAD_VALUE;
         }
     }
     if (mAudioChannels != 1) {
         LOGE("Invalid number of audio channels %d used for amr recording",
                 mAudioChannels);
-        return UNKNOWN_ERROR;
+        return BAD_VALUE;
     }
 
     if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
         LOGE("Invalid audio source: %d", mAudioSource);
-        return UNKNOWN_ERROR;
+        return BAD_VALUE;
     }
 
     sp<MediaSource> audioEncoder = createAudioSource();
@@ -601,7 +706,6 @@
         return UNKNOWN_ERROR;
     }
 
-    CHECK(mOutputFd >= 0);
     mWriter = new AMRWriter(dup(mOutputFd));
     mWriter->addSource(audioEncoder);
 
@@ -668,6 +772,54 @@
     }
 }
 
+status_t StagefrightRecorder::setupCameraSource() {
+    clipVideoBitRate();
+    clipVideoFrameRate();
+    clipVideoFrameWidth();
+    clipVideoFrameHeight();
+
+    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    if (mCamera == 0) {
+        mCamera = Camera::connect(mCameraId);
+        if (mCamera == 0) {
+            LOGE("Camera connection could not be established.");
+            return -EBUSY;
+        }
+        mFlags &= ~FLAGS_HOT_CAMERA;
+        mCamera->lock();
+    }
+
+    // Set the actual video recording frame size
+    CameraParameters params(mCamera->getParameters());
+    params.setPreviewSize(mVideoWidth, mVideoHeight);
+    params.setPreviewFrameRate(mFrameRate);
+    String8 s = params.flatten();
+    CHECK_EQ(OK, mCamera->setParameters(s));
+    CameraParameters newCameraParams(mCamera->getParameters());
+
+    // Check on video frame size
+    int frameWidth = 0, frameHeight = 0;
+    newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
+    if (frameWidth  < 0 || frameWidth  != mVideoWidth ||
+        frameHeight < 0 || frameHeight != mVideoHeight) {
+        LOGE("Failed to set the video frame size to %dx%d",
+                mVideoWidth, mVideoHeight);
+        IPCThreadState::self()->restoreCallingIdentity(token);
+        return UNKNOWN_ERROR;
+    }
+
+    // Check on video frame rate
+    int frameRate = newCameraParams.getPreviewFrameRate();
+    if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
+        LOGE("Failed to set frame rate to %d fps. The actual "
+             "frame rate is %d", mFrameRate, frameRate);
+    }
+
+    CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
+    IPCThreadState::self()->restoreCallingIdentity(token);
+    return OK;
+}
+
 void StagefrightRecorder::clipVideoFrameHeight() {
     LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
     int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
@@ -685,140 +837,116 @@
     }
 }
 
+status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
+    status_t err = setupCameraSource();
+    if (err != OK) return err;
+
+    sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera);
+    CHECK(cameraSource != NULL);
+
+    sp<MetaData> enc_meta = new MetaData;
+    enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
+    enc_meta->setInt32(kKeySampleRate, mFrameRate);
+
+    switch (mVideoEncoder) {
+        case VIDEO_ENCODER_H263:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+            break;
+
+        case VIDEO_ENCODER_MPEG_4_SP:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+            break;
+
+        case VIDEO_ENCODER_H264:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+            break;
+
+        default:
+            CHECK(!"Should not be here, unsupported video encoding.");
+            break;
+    }
+
+    sp<MetaData> meta = cameraSource->getFormat();
+
+    int32_t width, height, stride, sliceHeight;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+    CHECK(meta->findInt32(kKeyStride, &stride));
+    CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+
+    enc_meta->setInt32(kKeyWidth, width);
+    enc_meta->setInt32(kKeyHeight, height);
+    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);
+
+    sp<MediaSource> encoder = OMXCodec::Create(
+            client.interface(), enc_meta,
+            true /* createEncoder */, cameraSource);
+    if (encoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    writer->addSource(encoder);
+    return OK;
+}
+
+status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
+    sp<MediaSource> audioEncoder;
+    switch(mAudioEncoder) {
+        case AUDIO_ENCODER_AMR_NB:
+        case AUDIO_ENCODER_AMR_WB:
+        case AUDIO_ENCODER_AAC:
+            audioEncoder = createAudioSource();
+            break;
+        default:
+            LOGE("Unsupported audio encoder: %d", mAudioEncoder);
+            return UNKNOWN_ERROR;
+    }
+
+    if (audioEncoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    writer->addSource(audioEncoder);
+    return OK;
+}
+
 status_t StagefrightRecorder::startMPEG4Recording() {
-    mWriter = new MPEG4Writer(dup(mOutputFd));
     int32_t totalBitRate = 0;
+    status_t err = OK;
+    sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
 
     // Add audio source first if it exists
     if (mAudioSource != AUDIO_SOURCE_LIST_END) {
-        sp<MediaSource> audioEncoder;
-        switch(mAudioEncoder) {
-            case AUDIO_ENCODER_AMR_NB:
-            case AUDIO_ENCODER_AMR_WB:
-            case AUDIO_ENCODER_AAC:
-                audioEncoder = createAudioSource();
-                break;
-            default:
-                LOGE("Unsupported audio encoder: %d", mAudioEncoder);
-                return UNKNOWN_ERROR;
-        }
-
-        if (audioEncoder == NULL) {
-            return UNKNOWN_ERROR;
-        }
+        err = setupAudioEncoder(writer);
+        if (err != OK) return err;
         totalBitRate += mAudioBitRate;
-        mWriter->addSource(audioEncoder);
     }
     if (mVideoSource == VIDEO_SOURCE_DEFAULT
             || mVideoSource == VIDEO_SOURCE_CAMERA) {
-
-        clipVideoBitRate();
-        clipVideoFrameRate();
-        clipVideoFrameWidth();
-        clipVideoFrameHeight();
-
-        int64_t token = IPCThreadState::self()->clearCallingIdentity();
-        if (mCamera == 0) {
-            mCamera = Camera::connect(mCameraId);
-            mCamera->lock();
-        }
-
-        // Set the actual video recording frame size
-        CameraParameters params(mCamera->getParameters());
-        params.setPreviewSize(mVideoWidth, mVideoHeight);
-        params.setPreviewFrameRate(mFrameRate);
-        String8 s = params.flatten();
-        CHECK_EQ(OK, mCamera->setParameters(s));
-        CameraParameters newCameraParams(mCamera->getParameters());
-
-        // Check on video frame size
-        int frameWidth = 0, frameHeight = 0;
-        newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
-        if (frameWidth  < 0 || frameWidth  != mVideoWidth ||
-            frameHeight < 0 || frameHeight != mVideoHeight) {
-            LOGE("Failed to set the video frame size to %dx%d",
-                    mVideoWidth, mVideoHeight);
-            IPCThreadState::self()->restoreCallingIdentity(token);
-            return UNKNOWN_ERROR;
-        }
-
-        // Check on video frame rate
-        int frameRate = newCameraParams.getPreviewFrameRate();
-        if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
-            LOGE("Failed to set frame rate to %d fps. The actual "
-                 "frame rate is %d", mFrameRate, frameRate);
-        }
-
-        CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
-        IPCThreadState::self()->restoreCallingIdentity(token);
-
-        sp<CameraSource> cameraSource =
-            CameraSource::CreateFromCamera(mCamera);
-
-        CHECK(cameraSource != NULL);
-
-        sp<MetaData> enc_meta = new MetaData;
-        enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
-        enc_meta->setInt32(kKeySampleRate, mFrameRate);
-
-        switch (mVideoEncoder) {
-            case VIDEO_ENCODER_H263:
-                enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
-                break;
-
-            case VIDEO_ENCODER_MPEG_4_SP:
-                enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
-                break;
-
-            case VIDEO_ENCODER_H264:
-                enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-                break;
-
-            default:
-                CHECK(!"Should not be here, unsupported video encoding.");
-                break;
-        }
-
-        sp<MetaData> meta = cameraSource->getFormat();
-
-        int32_t width, height, stride, sliceHeight;
-        CHECK(meta->findInt32(kKeyWidth, &width));
-        CHECK(meta->findInt32(kKeyHeight, &height));
-        CHECK(meta->findInt32(kKeyStride, &stride));
-        CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
-
-        enc_meta->setInt32(kKeyWidth, width);
-        enc_meta->setInt32(kKeyHeight, height);
-        enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
-        enc_meta->setInt32(kKeyStride, stride);
-        enc_meta->setInt32(kKeySliceHeight, sliceHeight);
-
-        OMXClient client;
-        CHECK_EQ(client.connect(), OK);
-
-        sp<MediaSource> encoder =
-            OMXCodec::Create(
-                    client.interface(), enc_meta,
-                    true /* createEncoder */, cameraSource);
-
-        CHECK(mOutputFd >= 0);
+        err = setupVideoEncoder(writer);
+        if (err != OK) return err;
         totalBitRate += mVideoBitRate;
-        mWriter->addSource(encoder);
     }
 
-    {
-        // MPEGWriter specific handling
-        MPEG4Writer *writer = ((MPEG4Writer *) mWriter.get());
-        writer->setInterleaveDuration(mInterleaveDurationUs);
-    }
+    reinterpret_cast<MPEG4Writer *>(writer.get())->
+        setInterleaveDuration(mInterleaveDurationUs);
 
     if (mMaxFileDurationUs != 0) {
-        mWriter->setMaxFileDuration(mMaxFileDurationUs);
+        writer->setMaxFileDuration(mMaxFileDurationUs);
     }
     if (mMaxFileSizeBytes != 0) {
-        mWriter->setMaxFileSize(mMaxFileSizeBytes);
+        writer->setMaxFileSize(mMaxFileSizeBytes);
     }
-    mWriter->setListener(mListener);
     sp<MetaData> meta = new MetaData;
     meta->setInt64(kKeyTime, systemTime() / 1000);
     meta->setInt32(kKeyFileType, mOutputFormat);
@@ -830,11 +958,13 @@
     if (mTrackEveryTimeDurationUs > 0) {
         meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
-    mWriter->start(meta.get());
-    return OK;
+    writer->setListener(mListener);
+    mWriter = writer;
+    return mWriter->start(meta.get());
 }
 
 status_t StagefrightRecorder::pause() {
+    LOGV("pause");
     if (mWriter == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -843,34 +973,37 @@
 }
 
 status_t StagefrightRecorder::stop() {
-    if (mWriter == NULL) {
-        return UNKNOWN_ERROR;
+    LOGV("stop");
+    if (mWriter != NULL) {
+        mWriter->stop();
+        mWriter.clear();
     }
 
-    mWriter->stop();
-    mWriter = NULL;
-
-    return OK;
-}
-
-status_t StagefrightRecorder::close() {
-    stop();
-
     if (mCamera != 0) {
+        LOGV("Disconnect camera");
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
         if ((mFlags & FLAGS_HOT_CAMERA) == 0) {
             LOGV("Camera was cold when we started, stopping preview");
             mCamera->stopPreview();
         }
         mCamera->unlock();
-        mCamera = NULL;
+        mCamera.clear();
         IPCThreadState::self()->restoreCallingIdentity(token);
         mFlags = 0;
     }
+
+    return OK;
+}
+
+status_t StagefrightRecorder::close() {
+    LOGV("close");
+    stop();
+
     return OK;
 }
 
 status_t StagefrightRecorder::reset() {
+    LOGV("reset");
     stop();
 
     // No audio or video source by default
@@ -893,6 +1026,10 @@
     mAudioSourceNode = 0;
     mUse64BitFileOffset = false;
     mCameraId        = 0;
+    mVideoEncoderProfile = -1;
+    mVideoEncoderLevel   = -1;
+    mMaxFileDurationUs = 0;
+    mMaxFileSizeBytes = 0;
     mTrackEveryNumberOfFrames = 0;
     mTrackEveryTimeDurationUs = 0;
     mEncoderProfiles = MediaProfiles::getInstance();
@@ -904,6 +1041,13 @@
 }
 
 status_t StagefrightRecorder::getMaxAmplitude(int *max) {
+    LOGV("getMaxAmplitude");
+
+    if (max == NULL) {
+        LOGE("Null pointer argument");
+        return BAD_VALUE;
+    }
+
     if (mAudioSourceNode != 0) {
         *max = mAudioSourceNode->getMaxAmplitude();
     } else {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index f4488b6..85d2557 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -82,6 +82,8 @@
     int32_t mInterleaveDurationUs;
     int32_t mIFramesInterval;
     int32_t mCameraId;
+    int32_t mVideoEncoderProfile;
+    int32_t mVideoEncoderLevel;
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int32_t mTrackEveryNumberOfFrames;
@@ -97,18 +99,26 @@
     status_t startAMRRecording();
     status_t startAACRecording();
     sp<MediaSource> createAudioSource();
+    status_t setupCameraSource();
+    status_t setupAudioEncoder(const sp<MediaWriter>& writer);
+    status_t setupVideoEncoder(const sp<MediaWriter>& writer);
+
+    // Encoding parameter handling utilities
     status_t setParameter(const String8 &key, const String8 &value);
     status_t setParamAudioEncodingBitRate(int32_t bitRate);
     status_t setParamAudioNumberOfChannels(int32_t channles);
     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);
     status_t setParamInterleaveDuration(int32_t durationUs);
     status_t setParam64BitFileOffset(bool use64BitFileOffset);
-    status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration);
+    status_t setParamMaxFileDurationUs(int64_t timeUs);
+    status_t setParamMaxFileSizeBytes(int64_t bytes);
     void clipVideoBitRate();
     void clipVideoFrameRate();
     void clipVideoFrameWidth();
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/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a52c888..6a4a131 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -34,6 +34,8 @@
 #include <media/mediarecorder.h>
 #include <cutils/properties.h>
 
+#include "include/ESDS.h"
+
 namespace android {
 
 class MPEG4Writer::Track {
@@ -126,6 +128,8 @@
             int32_t *min, int32_t *avg, int32_t *max);
     void findMinMaxChunkDurations(int64_t *min, int64_t *max);
 
+    void getCodecSpecificDataFromInputFormatIfPossible();
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
@@ -678,6 +682,38 @@
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
       mReachedEOS(false) {
+    getCodecSpecificDataFromInputFormatIfPossible();
+}
+
+void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
+    const char *mime;
+    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
+            mCodecSpecificData = malloc(size);
+            mCodecSpecificDataSize = size;
+            memcpy(mCodecSpecificData, data, size);
+            mGotAllCodecSpecificData = true;
+        }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
+            ESDS esds(data, size);
+            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
+                mCodecSpecificData = malloc(size);
+                mCodecSpecificDataSize = size;
+                memcpy(mCodecSpecificData, data, size);
+                mGotAllCodecSpecificData = true;
+            }
+        }
+    }
 }
 
 MPEG4Writer::Track::~Track() {
@@ -721,7 +757,10 @@
     }
 
     int64_t startTimeUs;
-    CHECK(params && params->findInt64(kKeyTime, &startTimeUs));
+    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
+        startTimeUs = 0;
+    }
+
     initTrackingProgressStatus(params);
 
     sp<MetaData> meta = new MetaData;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 02a073e..83f7040 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -149,13 +149,16 @@
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
@@ -171,16 +174,19 @@
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
-    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
+//    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
-    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
+//    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
-    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
+//    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
-    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
+//    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
 #undef OPTIONAL
@@ -334,10 +340,17 @@
         quirks |= kRequiresAllocateBufferOnInputPorts;
         quirks |= kRequiresAllocateBufferOnOutputPorts;
     }
+    if (!strncmp(componentName, "OMX.qcom.7x30.video.encoder.", 28)) {
+    }
     if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
         quirks |= kRequiresAllocateBufferOnOutputPorts;
         quirks |= kDefersOutputBufferAllocation;
     }
+    if (!strncmp(componentName, "OMX.qcom.7x30.video.decoder.", 28)) {
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
+        quirks |= kDefersOutputBufferAllocation;
+    }
 
     if (!strncmp(componentName, "OMX.TI.", 7)) {
         // Apparently I must not use OMX_UseBuffer on either input or
@@ -818,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;
@@ -836,6 +849,7 @@
         }
 
         case OMX_VIDEO_CodingH263:
+            CHECK_EQ(setupH263EncoderParameters(meta), OK);
             break;
 
         case OMX_VIDEO_CodingAVC:
@@ -861,6 +875,142 @@
     return ret;
 }
 
+status_t OMXCodec::setupErrorCorrectionParameters() {
+    OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
+    InitOMXParams(&errorCorrectionType);
+    errorCorrectionType.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoErrorCorrection,
+            &errorCorrectionType, sizeof(errorCorrectionType));
+    CHECK_EQ(err, OK);
+
+    errorCorrectionType.bEnableHEC = OMX_FALSE;
+    errorCorrectionType.bEnableResync = OMX_TRUE;
+    errorCorrectionType.nResynchMarkerSpacing = 256;
+    errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
+    errorCorrectionType.bEnableRVLC = OMX_FALSE;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoErrorCorrection,
+            &errorCorrectionType, sizeof(errorCorrectionType));
+    CHECK_EQ(err, OK);
+    return OK;
+}
+
+status_t OMXCodec::setupBitRate(int32_t bitRate) {
+    OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
+    InitOMXParams(&bitrateType);
+    bitrateType.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoBitrate,
+            &bitrateType, sizeof(bitrateType));
+    CHECK_EQ(err, OK);
+
+    bitrateType.eControlRate = OMX_Video_ControlRateVariable;
+    bitrateType.nTargetBitrate = bitRate;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoBitrate,
+            &bitrateType, sizeof(bitrateType));
+    CHECK_EQ(err, OK);
+    return OK;
+}
+
+status_t OMXCodec::getVideoProfileLevel(
+        const sp<MetaData>& meta,
+        const CodecProfileLevel& defaultProfileLevel,
+        CodecProfileLevel &profileLevel) {
+    CODEC_LOGV("Default profile: %ld, level %ld",
+            defaultProfileLevel.mProfile, defaultProfileLevel.mLevel);
+
+    // Are the default profile and level overwriten?
+    int32_t profile, level;
+    if (!meta->findInt32(kKeyVideoProfile, &profile)) {
+        profile = defaultProfileLevel.mProfile;
+    }
+    if (!meta->findInt32(kKeyVideoLevel, &level)) {
+        level = defaultProfileLevel.mLevel;
+    }
+    CODEC_LOGV("Target profile: %d, level: %d", profile, level);
+
+    // Are the target profile and level supported by the encoder?
+    OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexOutput;
+    for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+        status_t err = mOMX->getParameter(
+                mNode, OMX_IndexParamVideoProfileLevelQuerySupported,
+                &param, sizeof(param));
+
+        if (err != OK) return err;
+
+        int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
+        int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
+        CODEC_LOGV("Supported profile: %ld, level %ld",
+            supportedProfile, supportedLevel);
+
+        if (profile == supportedProfile &&
+            level == supportedLevel) {
+            profileLevel.mProfile = profile;
+            profileLevel.mLevel = level;
+            return OK;
+        }
+    }
+
+    CODEC_LOGE("Target profile (%d) and level (%d) is not supported",
+            profile, level);
+    return BAD_VALUE;
+}
+
+status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) {
+    int32_t iFramesInterval, frameRate, bitRate;
+    bool success = meta->findInt32(kKeyBitRate, &bitRate);
+    success = success && meta->findInt32(kKeySampleRate, &frameRate);
+    success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
+    CHECK(success);
+    OMX_VIDEO_PARAM_H263TYPE h263type;
+    InitOMXParams(&h263type);
+    h263type.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
+    CHECK_EQ(err, OK);
+
+    h263type.nAllowedPictureTypes =
+        OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+
+    h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
+    if (h263type.nPFrames == 0) {
+        h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+    }
+    h263type.nBFrames = 0;
+
+    // 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;
+    h263type.nPictureHeaderRepetition = 0;
+    h263type.nGOBHeaderInterval = 0;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
+    CHECK_EQ(err, OK);
+
+    CHECK_EQ(setupBitRate(bitRate), OK);
+    CHECK_EQ(setupErrorCorrectionParameters(), OK);
+
+    return OK;
+}
+
 status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) {
     int32_t iFramesInterval, frameRate, bitRate;
     bool success = meta->findInt32(kKeyBitRate, &bitRate);
@@ -894,53 +1044,21 @@
     mpeg4type.nHeaderExtension = 0;
     mpeg4type.bReversibleVLC = OMX_FALSE;
 
-    mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
-    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));
     CHECK_EQ(err, OK);
 
-    // ----------------
-
-    OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
-    InitOMXParams(&bitrateType);
-    bitrateType.nPortIndex = kPortIndexOutput;
-
-    err = mOMX->getParameter(
-            mNode, OMX_IndexParamVideoBitrate,
-            &bitrateType, sizeof(bitrateType));
-    CHECK_EQ(err, OK);
-
-    bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = bitRate;
-
-    err = mOMX->setParameter(
-            mNode, OMX_IndexParamVideoBitrate,
-            &bitrateType, sizeof(bitrateType));
-    CHECK_EQ(err, OK);
-
-    // ----------------
-
-    OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
-    InitOMXParams(&errorCorrectionType);
-    errorCorrectionType.nPortIndex = kPortIndexOutput;
-
-    err = mOMX->getParameter(
-            mNode, OMX_IndexParamVideoErrorCorrection,
-            &errorCorrectionType, sizeof(errorCorrectionType));
-    CHECK_EQ(err, OK);
-
-    errorCorrectionType.bEnableHEC = OMX_FALSE;
-    errorCorrectionType.bEnableResync = OMX_TRUE;
-    errorCorrectionType.nResynchMarkerSpacing = 256;
-    errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
-    errorCorrectionType.bEnableRVLC = OMX_FALSE;
-
-    err = mOMX->setParameter(
-            mNode, OMX_IndexParamVideoErrorCorrection,
-            &errorCorrectionType, sizeof(errorCorrectionType));
-    CHECK_EQ(err, OK);
+    CHECK_EQ(setupBitRate(bitRate), OK);
+    CHECK_EQ(setupErrorCorrectionParameters(), OK);
 
     return OK;
 }
@@ -969,44 +1087,46 @@
     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(
             mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
     CHECK_EQ(err, OK);
 
-    OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
-    InitOMXParams(&bitrateType);
-    bitrateType.nPortIndex = kPortIndexOutput;
-
-    err = mOMX->getParameter(
-            mNode, OMX_IndexParamVideoBitrate,
-            &bitrateType, sizeof(bitrateType));
-    CHECK_EQ(err, OK);
-
-    bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = bitRate;
-
-    err = mOMX->setParameter(
-            mNode, OMX_IndexParamVideoBitrate,
-            &bitrateType, sizeof(bitrateType));
-    CHECK_EQ(err, OK);
+    CHECK_EQ(setupBitRate(bitRate), OK);
 
     return OK;
 }
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index b914023..2317de6 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -132,7 +132,10 @@
 }
 
 status_t AACEncoder::start(MetaData *params) {
-    CHECK(!mStarted);
+    if (mStarted) {
+        LOGW("Call start() when encoder already started");
+        return OK;
+    }
 
     mBufferGroup = new MediaBufferGroup;
     mBufferGroup->add_buffer(new MediaBuffer(2048));
@@ -150,7 +153,10 @@
 }
 
 status_t AACEncoder::stop() {
-    CHECK(mStarted);
+    if (!mStarted) {
+        LOGW("Call stop() when encoder has not started");
+        return OK;
+    }
 
     if (mInputBuffer) {
         mInputBuffer->release();
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index 445438f..4c02fe9 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -70,7 +70,10 @@
 }
 
 status_t AMRNBEncoder::start(MetaData *params) {
-    CHECK(!mStarted);
+    if (mStarted) {
+        LOGW("Call start() when encoder already started");
+        return OK;
+    }
 
     mBufferGroup = new MediaBufferGroup;
     mBufferGroup->add_buffer(new MediaBuffer(32));
@@ -97,7 +100,10 @@
 }
 
 status_t AMRNBEncoder::stop() {
-    CHECK(mStarted);
+    if (!mStarted) {
+        LOGW("Call stop() when encoder has not started.");
+        return OK;
+    }
 
     if (mInputBuffer) {
         mInputBuffer->release();
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index b70cff1..4257c6a 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -124,7 +124,10 @@
 }
 
 status_t AMRWBEncoder::start(MetaData *params) {
-    CHECK(!mStarted);
+    if (mStarted) {
+        LOGW("Call start() when encoder already started");
+        return OK;
+    }
 
     mBufferGroup = new MediaBufferGroup;
 
@@ -142,8 +145,10 @@
 }
 
 status_t AMRWBEncoder::stop() {
-    CHECK(mStarted);
-
+    if (!mStarted) {
+        LOGW("Call stop() when encoder has not started");
+        return OK;
+    }
 
     if (mInputBuffer) {
         mInputBuffer->release();
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index e74782f..5b16997 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -42,6 +42,7 @@
         case OMX_COLOR_FormatYUV420Planar:
         case OMX_COLOR_FormatCbYCrY:
         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+        case OMX_COLOR_FormatYUV420SemiPlanar:
             return true;
 
         default:
@@ -71,6 +72,11 @@
                     width, height, srcBits, srcSkip, dstBits, dstSkip);
             break;
 
+        case OMX_COLOR_FormatYUV420SemiPlanar:
+            convertYUV420SemiPlanar(
+                    width, height, srcBits, srcSkip, dstBits, dstSkip);
+            break;
+
         default:
         {
             CHECK(!"Should not be here. Unknown color conversion.");
@@ -279,6 +285,68 @@
     }
 }
 
+void ColorConverter::convertYUV420SemiPlanar(
+        size_t width, size_t height,
+        const void *srcBits, size_t srcSkip,
+        void *dstBits, size_t dstSkip) {
+    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
+    CHECK(dstSkip >= width * 2);
+    CHECK((dstSkip & 3) == 0);
+
+    uint8_t *kAdjustedClip = initClip();
+
+    uint32_t *dst_ptr = (uint32_t *)dstBits;
+    const uint8_t *src_y = (const uint8_t *)srcBits;
+
+    const uint8_t *src_u =
+        (const uint8_t *)src_y + width * height;
+
+    for (size_t y = 0; y < height; ++y) {
+        for (size_t x = 0; x < width; x += 2) {
+            signed y1 = (signed)src_y[x] - 16;
+            signed y2 = (signed)src_y[x + 1] - 16;
+
+            signed v = (signed)src_u[x & ~1] - 128;
+            signed u = (signed)src_u[(x & ~1) + 1] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[b1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[r1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[b2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[r2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src_y += width;
+
+        if (y & 1) {
+            src_u += width;
+        }
+
+        dst_ptr += dstSkip / 4;
+    }
+}
+
 uint8_t *ColorConverter::initClip() {
     static const signed kClipMin = -278;
     static const signed kClipMax = 535;
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/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 831fa2a..cd4f349 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -31,8 +31,9 @@
 ALooperRoster gLooperRoster;
 
 struct ALooper::LooperThread : public Thread {
-    LooperThread(ALooper *looper)
-        : mLooper(looper) {
+    LooperThread(ALooper *looper, bool canCallJava)
+        : Thread(canCallJava),
+          mLooper(looper) {
     }
 
     virtual bool threadLoop() {
@@ -72,7 +73,7 @@
     gLooperRoster.unregisterHandler(handlerID);
 }
 
-status_t ALooper::start(bool runOnCallingThread) {
+status_t ALooper::start(bool runOnCallingThread, bool canCallJava) {
     if (runOnCallingThread) {
         {
             Mutex::Autolock autoLock(mLock);
@@ -96,7 +97,7 @@
         return INVALID_OPERATION;
     }
 
-    mThread = new LooperThread(this);
+    mThread = new LooperThread(this, canCallJava);
 
     status_t err = mThread->run("ALooper");
     if (err != OK) {
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/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index dfd1ae3..26c6d42 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -16,6 +16,8 @@
 
 #include "AMessage.h"
 
+#include <ctype.h>
+
 #include "AAtomizer.h"
 #include "ADebug.h"
 #include "ALooperRoster.h"
@@ -238,4 +240,105 @@
     return msg;
 }
 
+static void appendIndent(AString *s, int32_t indent) {
+    static const char kWhitespace[] =
+        "                                        "
+        "                                        ";
+
+    CHECK_LT((size_t)indent, sizeof(kWhitespace));
+
+    s->append(kWhitespace, indent);
+}
+
+static bool isFourcc(uint32_t what) {
+    return isprint(what & 0xff)
+        && isprint((what >> 8) & 0xff)
+        && isprint((what >> 16) & 0xff)
+        && isprint((what >> 24) & 0xff);
+}
+
+AString AMessage::debugString(int32_t indent) const {
+    AString s = "AMessage(what = ";
+
+    AString tmp;
+    if (isFourcc(mWhat)) {
+        tmp = StringPrintf(
+                "'%c%c%c%c'",
+                (char)(mWhat >> 24),
+                (char)((mWhat >> 16) & 0xff),
+                (char)((mWhat >> 8) & 0xff),
+                (char)(mWhat & 0xff));
+    } else {
+        tmp = StringPrintf("0x%08x", mWhat);
+    }
+    s.append(tmp);
+
+    if (mTarget != 0) {
+        tmp = StringPrintf(", target = %d", mTarget);
+        s.append(tmp);
+    }
+    s.append(") = {\n");
+
+    for (size_t i = 0; i < mNumItems; ++i) {
+        const Item &item = mItems[i];
+
+        switch (item.mType) {
+            case kTypeInt32:
+                tmp = StringPrintf(
+                        "int32_t %s = %d", item.mName, item.u.int32Value);
+                break;
+            case kTypeInt64:
+                tmp = StringPrintf(
+                        "int64_t %s = %lld", item.mName, item.u.int64Value);
+                break;
+            case kTypeSize:
+                tmp = StringPrintf(
+                        "size_t %s = %d", item.mName, item.u.sizeValue);
+                break;
+            case kTypeFloat:
+                tmp = StringPrintf(
+                        "float %s = %f", item.mName, item.u.floatValue);
+                break;
+            case kTypeDouble:
+                tmp = StringPrintf(
+                        "double %s = %f", item.mName, item.u.doubleValue);
+                break;
+            case kTypePointer:
+                tmp = StringPrintf(
+                        "void *%s = %p", item.mName, item.u.ptrValue);
+                break;
+            case kTypeString:
+                tmp = StringPrintf(
+                        "string %s = \"%s\"",
+                        item.mName,
+                        item.u.stringValue->c_str());
+                break;
+            case kTypeObject:
+                tmp = StringPrintf(
+                        "RefBase *%s = %p", item.mName, item.u.refValue);
+                break;
+            case kTypeMessage:
+                tmp = StringPrintf(
+                        "AMessage %s = %s",
+                        item.mName,
+                        static_cast<AMessage *>(
+                            item.u.refValue)->debugString(
+                                indent + strlen(item.mName) + 14).c_str());
+                break;
+            default:
+                TRESPASS();
+        }
+
+        appendIndent(&s, indent);
+        s.append("  ");
+        s.append(tmp);
+        s.append("\n");
+    }
+
+    appendIndent(&s, indent);
+    s.append("}");
+
+    return s;
+}
+
 }  // 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/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 8c621b6..376c64f 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -7,7 +7,9 @@
 #
 LOCAL_SRC_FILES:= \
     activity.cpp \
-    input.cpp
+    input.cpp \
+    looper.cpp \
+    native_window.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 38d8567..015a1ce 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>
 
@@ -27,168 +28,176 @@
 using android::KeyEvent;
 using android::MotionEvent;
 
-int32_t input_event_get_type(const input_event_t* event) {
+int32_t AInputEvent_getType(const AInputEvent* event) {
     return static_cast<const InputEvent*>(event)->getType();
 }
 
-int32_t input_event_get_device_id(const input_event_t* event) {
+int32_t AInputEvent_getDeviceId(const AInputEvent* event) {
     return static_cast<const InputEvent*>(event)->getDeviceId();
 }
 
-int32_t input_event_get_nature(const input_event_t* event) {
+int32_t AInputEvent_getNature(const AInputEvent* event) {
     return static_cast<const InputEvent*>(event)->getNature();
 }
 
-int32_t key_event_get_action(const input_event_t* key_event) {
+int32_t AKeyEvent_getAction(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getAction();
 }
 
-int32_t key_event_get_flags(const input_event_t* key_event) {
+int32_t AKeyEvent_getFlags(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getFlags();
 }
 
-int32_t key_event_get_key_code(const input_event_t* key_event) {
+int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getKeyCode();
 }
 
-int32_t key_event_get_scan_code(const input_event_t* key_event) {
+int32_t AKeyEvent_getScanCode(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getScanCode();
 }
 
-int32_t key_event_get_meta_state(const input_event_t* key_event) {
+int32_t AKeyEvent_getMetaState(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getMetaState();
 }
-int32_t key_event_get_repeat_count(const input_event_t* key_event) {
+int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getRepeatCount();
 }
 
-int64_t key_event_get_down_time(const input_event_t* key_event) {
+int64_t AKeyEvent_getDownTime(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getDownTime();
 }
 
-int64_t key_event_get_event_time(const input_event_t* key_event) {
+int64_t AKeyEvent_getEventTime(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getEventTime();
 }
 
-int32_t motion_event_get_action(const input_event_t* motion_event) {
+int32_t AMotionEvent_getAction(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getAction();
 }
 
-int32_t motion_event_get_meta_state(const input_event_t* motion_event) {
+int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getMetaState();
 }
 
-int32_t motion_event_get_edge_flags(const input_event_t* motion_event) {
+int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event) {
     return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags();
 }
 
-int64_t motion_event_get_down_time(const input_event_t* motion_event) {
+int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getDownTime();
 }
 
-int64_t motion_event_get_event_time(const input_event_t* motion_event) {
+int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getEventTime();
 }
 
-float motion_event_get_x_offset(const input_event_t* motion_event) {
+float AMotionEvent_getXOffset(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getXOffset();
 }
 
-float motion_event_get_y_offset(const input_event_t* motion_event) {
+float AMotionEvent_getYOffset(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getYOffset();
 }
 
-float motion_event_get_x_precision(const input_event_t* motion_event) {
+float AMotionEvent_getXPrecision(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getXPrecision();
 }
 
-float motion_event_get_y_precision(const input_event_t* motion_event) {
+float AMotionEvent_getYPrecision(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getYPrecision();
 }
 
-size_t motion_event_get_pointer_count(const input_event_t* motion_event) {
+size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getPointerCount();
 }
 
-int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index) {
+int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
 }
 
-float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
 }
 
-float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
 }
 
-float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getX(pointer_index);
 }
 
-float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getY(pointer_index);
 }
 
-float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getPressure(pointer_index);
 }
 
-float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index) {
+float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index) {
     return static_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
 }
 
-size_t motion_event_get_history_size(const input_event_t* motion_event) {
+size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getHistorySize();
 }
 
-int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
+int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalEventTime(
             history_index);
 }
 
-float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalRawX(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
             pointer_index, history_index);
 }
 
-float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalRawY(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
             pointer_index, history_index);
 }
 
-float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalX(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalX(
             pointer_index, history_index);
 }
 
-float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalY(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalY(
             pointer_index, history_index);
 }
 
-float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalPressure(
             pointer_index, history_index);
 }
 
-float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index) {
     return static_cast<const MotionEvent*>(motion_event)->getHistoricalSize(
             pointer_index, history_index);
 }
 
-int input_queue_get_fd(input_queue_t* 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_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
+            POLLIN, callback, data);
 }
 
-int input_queue_has_events(input_queue_t* queue) {
+void AInputQueue_detachLooper(AInputQueue* queue) {
+    queue->getPollLoop()->removeCallback(
+            queue->getConsumer().getChannel()->getReceivePipeFd());
+}
+
+int AInputQueue_hasEvents(AInputQueue* queue) {
     struct pollfd pfd;
     
     pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
@@ -200,7 +209,7 @@
     return pfd.revents == POLLIN ? 1 : -1;
 }
 
-int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent) {
+int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) {
     *outEvent = NULL;
     
     int32_t res = queue->getConsumer().receiveDispatchSignal();
@@ -223,8 +232,17 @@
     return 0;
 }
 
-void input_queue_finish_event(input_queue_t* queue, input_event_t* event,
+void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event,
         int handled) {
+    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
+            && ((KeyEvent*)event)->hasDefaultAction()) {
+        // The app didn't handle this, but it may have a default action
+        // associated with it.  We need to hand this back to Java to be
+        // executed.
+        queue->doDefaultKey((KeyEvent*)event);
+        return;
+    }
+    
     int32_t res = queue->getConsumer().sendFinishedSignal();
     if (res != android::OK) {
         LOGW("Failed to send finished signal on channel '%s'.  status=%d",
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
new file mode 100644
index 0000000..6e78bbd
--- /dev/null
+++ b/native/android/looper.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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() {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        loop = new PollLoop();
+        PollLoop::setForThread(loop);
+    }
+    return loop.get();
+}
+
+int32_t ALooper_pollOnce(int timeoutMillis) {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        LOGW("ALooper_pollOnce: No looper for this thread!");
+        return -1;
+    }
+    return loop->pollOnce(timeoutMillis) ? 1 : 0;
+}
+
+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_setCallback(ALooper* looper, int fd, int events,
+        ALooper_callbackFunc* callback, void* data) {
+    static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
+}
+
+int32_t ALooper_removeCallback(ALooper* looper, int fd) {
+    return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
+}
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
new file mode 100644
index 0000000..448cbfc
--- /dev/null
+++ b/native/android/native_window.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "Surface"
+#include <utils/Log.h>
+
+#include <android/native_window.h>
+#include <surfaceflinger/Surface.h>
+
+using android::Surface;
+
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+    int value;
+    int res = window->query(window, what, &value);
+    return res < 0 ? res : value;
+}
+
+int32_t ANativeWindow_getWidth(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+}
+
+int32_t ANativeWindow_getHeight(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+}
+
+int32_t ANativeWindow_getFormat(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+}
+
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
+        int32_t height, int32_t format) {
+    native_window_set_buffers_geometry(window, width, height, format);
+    return 0;
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 2441af0..75be85a 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" {
@@ -125,8 +126,8 @@
  * Input events are opaque structures.  Use the provided accessors functions to
  * read their properties.
  */
-struct input_event_t;
-typedef struct input_event_t input_event_t;
+struct AInputEvent;
+typedef struct AInputEvent AInputEvent;
 
 /*
  * Input event types.
@@ -319,7 +320,7 @@
 /*** Accessors for all input events. ***/
 
 /* Get the input event type. */
-int32_t input_event_get_type(const input_event_t* event);
+int32_t AInputEvent_getType(const AInputEvent* event);
 
 /* Get the id for the device that an input event came from.
  *
@@ -331,128 +332,128 @@
  * other numbers are arbitrary and you shouldn't depend on the values.
  * Use the provided input device query API to obtain information about input devices.
  */
-int32_t input_event_get_device_id(const input_event_t* event);
+int32_t AInputEvent_getDeviceId(const AInputEvent* event);
 
 /* Get the input event nature. */
-int32_t input_event_get_nature(const input_event_t* event);
+int32_t AInputEvent_getNature(const AInputEvent* event);
 
 /*** Accessors for key events only. ***/
 
 /* Get the key event action. */
-int32_t key_event_get_action(const input_event_t* key_event);
+int32_t AKeyEvent_getAction(const AInputEvent* key_event);
 
 /* Get the key event flags. */
-int32_t key_event_get_flags(const input_event_t* key_event);
+int32_t AKeyEvent_getFlags(const AInputEvent* key_event);
 
 /* Get the key code of the key event.
  * This is the physical key that was pressed, not the Unicode character. */
-int32_t key_event_get_key_code(const input_event_t* key_event);
+int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event);
 
 /* Get the hardware key id of this key event.
  * These values are not reliable and vary from device to device. */
-int32_t key_event_get_scan_code(const input_event_t* key_event);
+int32_t AKeyEvent_getScanCode(const AInputEvent* key_event);
 
 /* Get the meta key state. */
-int32_t key_event_get_meta_state(const input_event_t* key_event);
+int32_t AKeyEvent_getMetaState(const AInputEvent* key_event);
 
 /* Get the repeat count of the event.
  * For both key up an key down events, this is the number of times the key has
  * repeated with the first down starting at 0 and counting up from there.  For
  * multiple key events, this is the number of down/up pairs that have occurred. */
-int32_t key_event_get_repeat_count(const input_event_t* key_event);
+int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event);
 
 /* Get the time of the most recent key down event, in the
  * java.lang.System.nanoTime() time base.  If this is a down event,
  * this will be the same as eventTime.
  * Note that when chording keys, this value is the down time of the most recently
  * pressed key, which may not be the same physical key of this event. */
-int64_t key_event_get_down_time(const input_event_t* key_event);
+int64_t AKeyEvent_getDownTime(const AInputEvent* key_event);
 
 /* Get the time this event occurred, in the
  * java.lang.System.nanoTime() time base. */
-int64_t key_event_get_event_time(const input_event_t* key_event);
+int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
 
 /*** Accessors for motion events only. ***/
 
 /* Get the combined motion event action code and pointer index. */
-int32_t motion_event_get_action(const input_event_t* motion_event);
+int32_t AMotionEvent_getAction(const AInputEvent* motion_event);
 
 /* Get the state of any meta / modifier keys that were in effect when the
  * event was generated. */
-int32_t motion_event_get_meta_state(const input_event_t* motion_event);
+int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
 
 /* Get a bitfield indicating which edges, if any, were touched by this motion event.
  * For touch events, clients can use this to determine if the user's finger was
  * touching the edge of the display. */
-int32_t motion_event_get_edge_flags(const input_event_t* motion_event);
+int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event);
 
 /* Get the time when the user originally pressed down to start a stream of
  * position events, in the java.lang.System.nanoTime() time base. */
-int64_t motion_event_get_down_time(const input_event_t* motion_event);
+int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event);
 
 /* Get the time when this specific event was generated,
  * in the java.lang.System.nanoTime() time base. */
-int64_t motion_event_get_event_time(const input_event_t* motion_event);
+int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event);
 
 /* Get the X coordinate offset.
  * For touch events on the screen, this is the delta that was added to the raw
  * screen coordinates to adjust for the absolute position of the containing windows
  * and views. */
-float motion_event_get_x_offset(const input_event_t* motion_event);
+float AMotionEvent_getXOffset(const AInputEvent* motion_event);
 
 /* Get the precision of the Y coordinates being reported.
  * For touch events on the screen, this is the delta that was added to the raw
  * screen coordinates to adjust for the absolute position of the containing windows
  * and views. */
-float motion_event_get_y_offset(const input_event_t* motion_event);
+float AMotionEvent_getYOffset(const AInputEvent* motion_event);
 
 /* Get the precision of the X coordinates being reported.
  * You can multiply this number with an X coordinate sample to find the
  * actual hardware value of the X coordinate. */
-float motion_event_get_x_precision(const input_event_t* motion_event);
+float AMotionEvent_getXPrecision(const AInputEvent* motion_event);
 
 /* Get the precision of the Y coordinates being reported.
  * You can multiply this number with a Y coordinate sample to find the
  * actual hardware value of the Y coordinate. */
-float motion_event_get_y_precision(const input_event_t* motion_event);
+float AMotionEvent_getYPrecision(const AInputEvent* motion_event);
 
 /* Get the number of pointers of data contained in this event.
  * Always >= 1. */
-size_t motion_event_get_pointer_count(const input_event_t* motion_event);
+size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event);
 
 /* Get the pointer identifier associated with a particular pointer
  * data index is this event.  The identifier tells you the actual pointer
  * number associated with the data, accounting for individual pointers
  * going up and down since the start of the current gesture. */
-int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index);
+int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the original raw X coordinate of this event.
  * For touch events on the screen, this is the original location of the event
  * on the screen, before it had been adjusted for the containing window
  * and views. */
-float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the original raw X coordinate of this event.
  * For touch events on the screen, this is the original location of the event
  * on the screen, before it had been adjusted for the containing window
  * and views. */
-float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the current X coordinate of this event for the given pointer index.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the current Y coordinate of this event for the given pointer index.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the current pressure of this event for the given pointer index.
  * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
  * however values higher than 1 may be generated depending on the calibration of
  * the input device. */
-float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the current scaled value of the approximate size for the given pointer index.
  * This represents some approximation of the area of the screen being
@@ -460,17 +461,17 @@
  * touch is normalized with the device specific range of values
  * and scaled to a value between 0 and 1.  The value of size can be used to
  * determine fat touch events. */
-float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the number of historical points in this event.  These are movements that
  * have occurred between this event and the previous event.  This only applies
  * to MOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0.
  * Historical samples are indexed from oldest to newest. */
-size_t motion_event_get_history_size(const input_event_t* motion_event);
+size_t AMotionEvent_get_history_size(const AInputEvent* motion_event);
 
 /* Get the time that a historical movement occurred between this event and
  * the previous event, in the java.lang.System.nanoTime() time base. */
-int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
+int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event,
         size_t history_index);
 
 /* Get the historical raw X coordinate of this event for the given pointer index that
@@ -480,7 +481,7 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_historical_raw_x(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the historical raw Y coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
@@ -489,20 +490,20 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_historical_raw_y(const input_event_t* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index);
 
 /* Get the historical X coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalX(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
 /* Get the historical Y coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalY(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
 /* Get the historical pressure of this event for the given pointer index that
@@ -510,7 +511,7 @@
  * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
  * however values higher than 1 may be generated depending on the calibration of
  * the input device. */
-float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
 /* Get the current scaled value of the approximate size for the given pointer index that
@@ -520,7 +521,7 @@
  * touch is normalized with the device specific range of values
  * and scaled to a value between 0 and 1.  The value of size can be used to
  * determine fat touch events. */
-float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
+float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
 /*
@@ -529,35 +530,38 @@
  * An input queue is the facility through which you retrieve input
  * events.
  */
-struct input_queue_t;
-typedef struct input_queue_t input_queue_t;
+struct AInputQueue;
+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.
  */
-int input_queue_get_fd(input_queue_t* 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
  * input queue.  Returns 1 if the queue has events; 0 if
  * it does not have events; and a negative value if there is an error.
  */
-int input_queue_has_events(input_queue_t* queue);
+int AInputQueue_hasEvents(AInputQueue* queue);
 
 /*
  * Returns the next available event from the queue.  Returns a negative
  * value if no events are available or an error has occurred.
  */
-int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent);
+int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent);
 
 /*
  * Report that dispatching has finished with the given event.
- * This must be called after receiving an event with input_queue_get_event().
+ * This must be called after receiving an event with AInputQueue_get_event().
  */
-void input_queue_finish_event(input_queue_t* queue, input_event_t* event, int handled);
+void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
 
 #ifdef __cplusplus
 }
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
new file mode 100644
index 0000000..90a8983
--- /dev/null
+++ b/native/include/android/looper.h
@@ -0,0 +1,51 @@
+/*
+ * 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
+
+struct ALooper;
+typedef struct ALooper ALooper;
+
+typedef int ALooper_callbackFunc(int fd, int events, void* data);
+
+ALooper* ALooper_forThread();
+
+ALooper* ALooper_prepare();
+
+int32_t ALooper_pollOnce(int timeoutMillis);
+
+void ALooper_acquire(ALooper* looper);
+
+void ALooper_release(ALooper* looper);
+
+void ALooper_setCallback(ALooper* looper, int fd, int events,
+        ALooper_callbackFunc* callback, void* data);
+
+int32_t ALooper_removeCallback(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 a58a7d2..a31c5af 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -24,48 +24,67 @@
 #include <jni.h>
 
 #include <android/input.h>
+#include <android/native_window.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-// Temporary until native surface API is defined.
-struct android_surface_t;
-typedef struct android_surface_t android_surface_t;
-
-struct android_activity_callbacks_t;
+struct ANativeActivityCallbacks;
 
 /**
  * This structure defines the native side of an android.app.NativeActivity.
  * It is created by the framework, and handed to the application's native
  * code as it is being launched.
  */
-typedef struct android_activity_t {
+typedef struct ANativeActivity {
     /**
      * Pointer to the callback function table of the native application.
      * You can set the functions here to your own callbacks.  The callbacks
      * pointer itself here should not be changed; it is allocated and managed
      * for you by the framework.
      */
-    struct android_activity_callbacks_t* callbacks;
+    struct ANativeActivityCallbacks* callbacks;
 
     /**
-     * JNI context for the main thread of the app.
+     * The global handle on the process's Java VM.
+     */
+    JavaVM* vm;
+
+    /**
+     * JNI context for the main thread of the app.  Note that this field
+     * can ONLY be used from the main thread of the process; that is, the
+     * thread that calls into the ANativeActivityCallbacks.
      */
     JNIEnv* env;
-    
+
     /**
      * The NativeActivity Java class.
      */
     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.
      */
     void* instance;
-} android_activity_t;
+} ANativeActivity;
 
 /**
  * These are the callbacks the framework makes into a native application.
@@ -73,18 +92,18 @@
  * By default, all callbacks are NULL; set to a pointer to your own function
  * to have it called.
  */
-typedef struct android_activity_callbacks_t {
+typedef struct ANativeActivityCallbacks {
     /**
      * NativeActivity has started.  See Java documentation for Activity.onStart()
      * for more information.
      */
-    void (*onStart)(android_activity_t* activity);
+    void (*onStart)(ANativeActivity* activity);
     
     /**
      * NativeActivity has resumed.  See Java documentation for Activity.onResume()
      * for more information.
      */
-    void (*onResume)(android_activity_t* activity);
+    void (*onResume)(ANativeActivity* activity);
     
     /**
      * Framework is asking NativeActivity to save its current instance state.
@@ -95,78 +114,68 @@
      * saved state will be persisted, so it can not contain any active
      * entities (pointers to memory, file descriptors, etc).
      */
-    void* (*onSaveInstanceState)(android_activity_t* activity, size_t* outSize);
+    void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize);
     
     /**
      * NativeActivity has paused.  See Java documentation for Activity.onPause()
      * for more information.
      */
-    void (*onPause)(android_activity_t* activity);
+    void (*onPause)(ANativeActivity* activity);
     
     /**
      * NativeActivity has stopped.  See Java documentation for Activity.onStop()
      * for more information.
      */
-    void (*onStop)(android_activity_t* activity);
+    void (*onStop)(ANativeActivity* activity);
     
     /**
      * NativeActivity is being destroyed.  See Java documentation for Activity.onDestroy()
      * for more information.
      */
-    void (*onDestroy)(android_activity_t* activity);
+    void (*onDestroy)(ANativeActivity* activity);
 
     /**
      * Focus has changed in this NativeActivity's window.  This is often used,
      * for example, to pause a game when it loses input focus.
      */
-    void (*onWindowFocusChanged)(android_activity_t* activity, int hasFocus);
+    void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus);
     
     /**
-     * The drawing surface for this native activity has been created.  You
-     * can use the given surface object to start drawing.  NOTE: surface
-     * drawing API is not yet defined.
+     * The drawing window for this native activity has been created.  You
+     * can use the given native window object to start drawing.
      */
-    void (*onSurfaceCreated)(android_activity_t* activity, android_surface_t* surface);
+    void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
 
     /**
-     * The drawing surface for this native activity has changed.  The surface
-     * given here is guaranteed to be the same as the one last given to
-     * onSurfaceCreated.  This is simply to inform you about interesting
-     * changed to that surface.
-     */
-    void (*onSurfaceChanged)(android_activity_t* activity, android_surface_t* surface,
-            int format, int width, int height);
-
-    /**
-     * The drawing surface for this native activity is going to be destroyed.
-     * You MUST ensure that you do not touch the surface object after returning
-     * from this function: in the common case of drawing to the surface from
+     * The drawing window for this native activity is going to be destroyed.
+     * You MUST ensure that you do not touch the window object after returning
+     * from this function: in the common case of drawing to the window from
      * another thread, that means the implementation of this callback must
      * properly synchronize with the other thread to stop its drawing before
      * returning from here.
      */
-    void (*onSurfaceDestroyed)(android_activity_t* activity, android_surface_t* surface);
+    void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window);
     
     /**
      * The input queue for this native activity's window has been created.
      * You can use the given input queue to start retrieving input events.
      */
-    void (*onInputQueueCreated)(android_activity_t* activity, input_queue_t* queue);
+    void (*onInputQueueCreated)(ANativeActivity* activity, AInputQueue* queue);
     
     /**
      * The input queue for this native activity's window is being destroyed.
      * You should no longer try to reference this object upon returning from this
      * function.
      */
-    void (*onInputQueueDestroyed)(android_activity_t* activity, input_queue_t* queue);
+    void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue);
 
     /**
      * The system is running low on memory.  Use this callback to release
      * resources you do not need, to help the system avoid killing more
      * important processes.
      */
-    void (*onLowMemory)(android_activity_t* activity);
-} android_activity_callbacks_t;
+    void (*onLowMemory)(ANativeActivity* activity);
+} ANativeActivityCallbacks;
 
 /**
  * This is the function that must be in the native code to instantiate the
@@ -174,14 +183,14 @@
  * above); if the code is being instantiated from a previously saved instance,
  * the savedState will be non-NULL and point to the saved data.
  */
-typedef void android_activity_create_t(android_activity_t* activity,
+typedef void ANativeActivity_createFunc(ANativeActivity* activity,
         void* savedState, size_t savedStateSize);
 
 /**
  * The name of the function that NativeInstance looks for when launching its
  * native code.
  */
-extern android_activity_create_t android_onCreateActivity;
+extern ANativeActivity_createFunc ANativeActivity_onCreate;
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
new file mode 100644
index 0000000..678ba3d
--- /dev/null
+++ b/native/include/android/native_window.h
@@ -0,0 +1,75 @@
+/*
+ * 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_H
+#define ANDROID_NATIVE_WINDOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Pixel formats that a window can use.
+ */
+enum {
+    WINDOW_FORMAT_RGBA_8888          = 1,
+    WINDOW_FORMAT_RGBX_8888          = 2,
+    WINDOW_FORMAT_RGB_565            = 4,
+};
+
+struct ANativeWindow;
+typedef struct ANativeWindow ANativeWindow;
+
+/*
+ * Return the current width in pixels of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getWidth(ANativeWindow* window);
+
+/*
+ * Return the current height in pixels of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getHeight(ANativeWindow* window);
+
+/*
+ * Return the current pixel format of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getFormat(ANativeWindow* window);
+
+/*
+ * Change the format and size of the window buffers.
+ *
+ * The width and height control the number of pixels in the buffers, not the
+ * dimensions of the window on screen.  If these are different than the
+ * 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
+ * value will come back in force.
+ */
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
+        int32_t height, int32_t format);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index a2c6a7d..25d7697 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -91,10 +91,11 @@
 
 #elif defined(ANDROID)
 
-struct android_native_window_t;
+#include <android/native_window.h>
+
 struct egl_native_pixmap_t;
 
-typedef struct android_native_window_t* EGLNativeWindowType;
+typedef struct ANativeWindow*           EGLNativeWindowType;
 typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
 typedef void*                           EGLNativeDisplayType;
 
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 7cb01d0..54d7307 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -213,7 +213,7 @@
     egl_window_surface_v2_t(
             EGLDisplay dpy, EGLConfig config,
             int32_t depthFormat,
-            android_native_window_t* window);
+            ANativeWindow* window);
 
     ~egl_window_surface_v2_t();
 
@@ -235,7 +235,7 @@
 private:
     status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
     status_t unlock(android_native_buffer_t* buf);
-    android_native_window_t*   nativeWindow;
+    ANativeWindow*   nativeWindow;
     android_native_buffer_t*   buffer;
     android_native_buffer_t*   previousBuffer;
     gralloc_module_t const*    module;
@@ -355,7 +355,7 @@
 egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
         EGLConfig config,
         int32_t depthFormat,
-        android_native_window_t* window)
+        ANativeWindow* window)
     : egl_surface_t(dpy, config, depthFormat), 
     nativeWindow(window), buffer(0), previousBuffer(0), module(0),
     blitengine(0), bits(NULL)
@@ -1300,7 +1300,7 @@
     if (!(surfaceType & EGL_WINDOW_BIT))
         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
 
-    if (static_cast<android_native_window_t*>(window)->common.magic !=
+    if (static_cast<ANativeWindow*>(window)->common.magic !=
             ANDROID_NATIVE_WINDOW_MAGIC) {
         return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
     }
@@ -1323,7 +1323,7 @@
 
     egl_surface_t* surface;
     surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
-            static_cast<android_native_window_t*>(window));
+            static_cast<ANativeWindow*>(window));
 
     if (!surface->initCheck()) {
         // there was a problem in the ctor, the error
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ba09d08..714fd3e 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1045,6 +1045,10 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (cnx) {
+        if (share_list != EGL_NO_CONTEXT) {
+            egl_context_t* const c = get_context(share_list);
+            share_list = c->context;
+        }
         EGLContext context = cnx->egl.eglCreateContext(
                 dp->disp[i].dpy, dp->disp[i].config[index],
                 share_list, attrib_list);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 74d87ba..75045d7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,6 +1,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.systemui"
-        android:sharedUserId="android.uid.system">
+        android:sharedUserId="android.uid.system"
+        android:process="system"
+        >
 
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
 
@@ -10,7 +12,7 @@
         android:icon="@drawable/ic_launcher_settings">
                  
         <service
-            android:name=".statusbar.PhoneStatusBarService"
+            android:name=".statusbar.StatusBarService"
             android:exported="false"
             />
 
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background.9.png
deleted file mode 100644
index 7000eee..0000000
--- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
new file mode 100644
index 0000000..bc127bd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
new file mode 100644
index 0000000..59af804
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
similarity index 100%
copy from packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png
copy to packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png
rename to packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/alert_bar_background.xml b/packages/SystemUI/res/drawable/alert_bar_background.xml
new file mode 100644
index 0000000..24b6aa3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/alert_bar_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/alert_bar_background_pressed" />
+    <item
+         android:drawable="@drawable/alert_bar_background_normal" />
+</selector>
+
diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/intruder_alert.xml
index 58dc333..ba4a774 100644
--- a/packages/SystemUI/res/layout/intruder_alert.xml
+++ b/packages/SystemUI/res/layout/intruder_alert.xml
@@ -21,29 +21,35 @@
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:background="@drawable/alert_bar_background"
-    android:orientation="horizontal"
-    android:focusable="true"
-    android:descendantFocusability="afterDescendants"
+    android:layout_height="32dip"
+    android:layout_width="match_parent"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
     >
         
     <LinearLayout 
+        android:id="@+id/intruder_alert_content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="6dip"
+        android:gravity="center"
         android:animationCache="false"
         android:orientation="horizontal"
+        android:background="@drawable/alert_bar_background"
+        android:clickable="true"
+        android:focusable="true"
+        android:descendantFocusability="afterDescendants"
         >
 
         <ImageView
             android:id="@+id/alertIcon"
             android:layout_width="25dip"
             android:layout_height="25dip"
+            android:layout_marginLeft="6dip"
             android:layout_marginRight="8dip"
             />
         <TextView
             android:id="@+id/alertText"
-            android:textAppearance="@*android:style/TextAppearance.StatusBar.EventContent"
+            android:textAppearance="@style/TextAppearance.StatusBar.IntruderAlert"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 10fa930..816f34a4 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -22,6 +22,7 @@
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
-
-
+    <style name="TextAppearance.StatusBar.IntruderAlert"
+        parent="@android:style/TextAppearance.StatusBar">
+    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
index 0f6723e..f45caf51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
@@ -23,7 +23,7 @@
 
 
 public class CloseDragHandle extends LinearLayout {
-    PhoneStatusBarService mService;
+    StatusBarService mService;
 
     public CloseDragHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index c5b901f..3d85f27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -27,7 +27,7 @@
 
 
 public class ExpandedView extends LinearLayout {
-    PhoneStatusBarService mService;
+    StatusBarService mService;
     int mPrevHeight = -1;
 
     public ExpandedView(Context context, AttributeSet attrs) {
@@ -50,10 +50,10 @@
          super.onLayout(changed, left, top, right, bottom);
          int height = bottom - top;
          if (height != mPrevHeight) {
-             //Slog.d(PhoneStatusBarService.TAG, "height changed old=" + mPrevHeight
+             //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
              //     + " new=" + height);
              mPrevHeight = height;
-             mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
+             mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
          }
      }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
deleted file mode 100644
index 3c14fb5..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar;
-
-import com.android.internal.statusbar.IStatusBar;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
-
-import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.widget.FrameLayout;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.StatusBarPolicy;
-
-public class PhoneStatusBarService extends StatusBarService {
-    static final String TAG = "PhoneStatusBarService";
-    static final boolean SPEW = false;
-
-    public static final String ACTION_STATUSBAR_START
-            = "com.android.internal.policy.statusbar.START";
-
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
-
-    private static final int MSG_ANIMATE = 1000;
-    private static final int MSG_ANIMATE_REVEAL = 1001;
-    private static final int MSG_SHOW_INTRUDER = 1002;
-    private static final int MSG_HIDE_INTRUDER = 1003;
-
-    // will likely move to a resource or other tunable param at some point
-    private static final int INTRUDER_ALERT_DECAY_MS = 10000;
-
-    private class ExpandedDialog extends Dialog {
-        ExpandedDialog(Context context) {
-            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-            switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-                if (!down) {
-                    animateCollapse();
-                }
-                return true;
-            }
-            return super.dispatchKeyEvent(event);
-        }
-    }
-
-    StatusBarPolicy mIconPolicy;
-    
-    int mHeight;
-    int mIconWidth;
-
-    Display mDisplay;
-    StatusBarView mStatusBarView;
-    int mPixelFormat;
-    H mHandler = new H();
-    Object mQueueLock = new Object();
-    
-    // icons
-    LinearLayout mIcons;
-    IconMerger mNotificationIcons;
-    LinearLayout mStatusIcons;
-
-    // expanded notifications
-    Dialog mExpandedDialog;
-    ExpandedView mExpandedView;
-    WindowManager.LayoutParams mExpandedParams;
-    ScrollView mScrollView;
-    View mNotificationLinearLayout;
-    View mExpandedContents;
-    // top bar
-    TextView mNoNotificationsTitle;
-    TextView mClearButton;
-    // drag bar
-    CloseDragHandle mCloseView;
-    // ongoing
-    NotificationData mOngoing = new NotificationData();
-    TextView mOngoingTitle;
-    LinearLayout mOngoingItems;
-    // latest
-    NotificationData mLatest = new NotificationData();
-    TextView mLatestTitle;
-    LinearLayout mLatestItems;
-    // position
-    int[] mPositionTmp = new int[2];
-    boolean mExpanded;
-    boolean mExpandedVisible;
-
-    // the date view
-    DateView mDateView;
-
-    // the tracker view
-    TrackingView mTrackingView;
-    WindowManager.LayoutParams mTrackingParams;
-    int mTrackingPosition; // the position of the top of the tracking view.
-    private boolean mPanelSlightlyVisible;
-
-    // ticker
-    private Ticker mTicker;
-    private View mTickerView;
-    private boolean mTicking;
-    
-    // Tracking finger for opening/closing.
-    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
-    boolean mTracking;
-    VelocityTracker mVelocityTracker;
-    
-    static final int ANIM_FRAME_DURATION = (1000/60);
-    
-    boolean mAnimating;
-    long mCurAnimationTime;
-    float mDisplayHeight;
-    float mAnimY;
-    float mAnimVel;
-    float mAnimAccel;
-    long mAnimLastTime;
-    boolean mAnimatingReveal = false;
-    int mViewDelta;
-    int[] mAbsPos = new int[2];
-    
-    // for disabling the status bar
-    int mDisabled = 0;
-
-    // for immersive activities
-    private View mIntruderAlertView;
-
-    /**
-     * Construct the service, add the status bar view to the window manager
-     */
-    @Override
-    public void onCreate() {
-        // First set up our views and stuff.
-        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
-        makeStatusBarView(this);
-
-        // Next, call super.onCreate(), which will populate our views.
-        super.onCreate();
-
-        // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new StatusBarPolicy(this);
-    }
-
-    // ================================================================================
-    // Constructing the view
-    // ================================================================================
-    private void makeStatusBarView(Context context) {
-        Resources res = context.getResources();
-
-        mHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mIconWidth = mHeight;
-
-        ExpandedView expanded = (ExpandedView)View.inflate(context,
-                R.layout.status_bar_expanded, null);
-        expanded.mService = this;
-
-        mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
-        mIntruderAlertView.setVisibility(View.GONE);
-        mIntruderAlertView.setClickable(true);
-        mIntruderAlertView.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                Slog.d(TAG, "Intruder Alert clicked!");
-                mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
-            }
-        });
-
-        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
-        sb.mService = this;
-
-        // figure out which pixel-format to use for the status bar.
-        mPixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = sb.getBackground();
-        if (bg != null) {
-            mPixelFormat = bg.getOpacity();
-        }
-
-        mStatusBarView = sb;
-        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
-        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
-        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
-        mTickerView = sb.findViewById(R.id.ticker);
-        mDateView = (DateView)sb.findViewById(R.id.date);
-
-        mExpandedDialog = new ExpandedDialog(context);
-        mExpandedView = expanded;
-        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
-        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
-        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
-        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
-        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
-        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
-        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
-        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
-        mOngoingTitle.setVisibility(View.GONE);
-        mLatestTitle.setVisibility(View.GONE);
-        
-        mTicker = new MyTicker(context, sb);
-
-        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
-        tickerView.mTicker = mTicker;
-
-        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
-        mTrackingView.mService = this;
-        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
-        mCloseView.mService = this;
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        // the more notifications icon
-        StatusBarIconView moreView = new StatusBarIconView(this, "more");
-        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
-        mNotificationIcons.addMoreView(moreView,
-                new LinearLayout.LayoutParams(mIconWidth, mHeight));
-
-        // set the inital view visibility
-        setAreThereNotifications();
-        mDateView.setVisibility(View.INVISIBLE);
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        context.registerReceiver(mBroadcastReceiver, filter);
-    }
-
-    @Override
-    protected void addStatusBarView() {
-        final StatusBarView view = mStatusBarView;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                mHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
-                PixelFormat.RGBX_8888);
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBar");
-        // TODO lp.windowAnimations = R.style.Animation_StatusBar;
-
-        WindowManagerImpl.getDefault().addView(view, lp);
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                mHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.y += mHeight * 1.5; // for now
-        lp.setTitle("IntruderAlert");
-        lp.windowAnimations = android.R.style.Animation_Dialog;
-
-        WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
-    }
-
-    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(this, slot);
-        view.set(icon);
-        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconWidth, mHeight));
-    }
-
-    public void updateIcon(String slot, int index, int viewIndex,
-            StatusBarIcon old, StatusBarIcon icon) {
-        Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " old=" + old + " icon=" + icon);
-        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
-        view.set(icon);
-    }
-
-    public void removeIcon(String slot, int index, int viewIndex) {
-        Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
-        mStatusIcons.removeViewAt(viewIndex);
-    }
-
-    public void addNotification(IBinder key, StatusBarNotification notification) {
-        StatusBarIconView iconView = addNotificationViews(key, notification);
-        if (iconView == null) return;
-
-        boolean immersive = false;
-        try {
-            immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
-            Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
-        } catch (RemoteException ex) {
-        }
-        if (immersive) {
-            if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
-                Slog.d(TAG, "Presenting high-priority notification in immersive activity");
-                // @@@ special new transient ticker mode
-                // 1. Populate mIntruderAlertView
-
-                ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
-                TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
-                alertIcon.setImageDrawable(StatusBarIconView.getIcon(
-                    alertIcon.getContext(), 
-                    iconView.getStatusBarIcon()));
-                alertText.setText(notification.notification.tickerText);
-
-                // 2. Animate mIntruderAlertView in
-                mHandler.removeMessages(MSG_HIDE_INTRUDER);
-                mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
-                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
-
-                // 3. Set alarm to age the notification off (TODO)
-                
-            }
-        } else if (notification.notification.fullScreenIntent != null) {
-            // not immersive & a full-screen alert should be shown
-            Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive; sending fullScreenIntent");
-            try {
-                notification.notification.fullScreenIntent.send();
-            } catch (PendingIntent.CanceledException e) {
-            }
-        } else {
-            // usual case: status bar visible & not immersive
-
-            // show the ticker
-            tick(notification);
-        }
-
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-    }
-
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
-
-        NotificationData oldList;
-        int oldIndex = mOngoing.findEntry(key);
-        if (oldIndex >= 0) {
-            oldList = mOngoing;
-        } else {
-            oldIndex = mLatest.findEntry(key);
-            if (oldIndex < 0) {
-                Slog.w(TAG, "updateNotification for unknown key: " + key);
-                return;
-            }
-            oldList = mLatest;
-        }
-        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
-        final StatusBarNotification oldNotification = oldEntry.notification;
-        final RemoteViews oldContentView = oldNotification.notification.contentView;
-
-        final RemoteViews contentView = notification.notification.contentView;
-
-        if (false) {
-            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " expanded=" + oldEntry.expanded
-                    + " contentView=" + oldContentView);
-            Slog.d(TAG, "new notification: when=" + notification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " contentView=" + contentView);
-        }
-
-        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
-        // didn't change.
-        if (notification.notification.when == oldNotification.notification.when
-                && notification.isOngoing() == oldNotification.isOngoing()
-                && oldEntry.expanded != null
-                && contentView != null && oldContentView != null
-                && contentView.getPackage() != null
-                && oldContentView.getPackage() != null
-                && oldContentView.getPackage().equals(contentView.getPackage())
-                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
-            Slog.d(TAG, "reusing notification");
-            oldEntry.notification = notification;
-            try {
-                // Reapply the RemoteViews
-                contentView.reapply(this, oldEntry.content);
-                // update the contentIntent
-                final PendingIntent contentIntent = notification.notification.contentIntent;
-                if (contentIntent != null) {
-                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
-                                notification.pkg, notification.tag, notification.id));
-                }
-                // Update the icon.
-                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                        notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number);
-                if (!oldEntry.icon.set(ic)) {
-                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
-                    return;
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(key);
-                addNotificationViews(key, notification);
-            }
-        } else {
-            Slog.d(TAG, "not reusing notification");
-            removeNotificationViews(key);
-            addNotificationViews(key, notification);
-        }
-
-        // Restart the ticker if it's still running
-        tick(notification);
-
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-    }
-
-    public void removeNotification(IBinder key) {
-        Slog.d(TAG, "removeNotification key=" + key);
-        StatusBarNotification old = removeNotificationViews(key);
-
-        if (old != null) {
-            // Cancel the ticker if it's still running
-            mTicker.removeEntry(old);
-
-            // Recalculate the position of the sliding windows and the titles.
-            setAreThereNotifications();
-            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        }
-    }
-
-    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
-        final int latestSize = mLatest.size();
-        if (isOngoing) {
-            return latestSize + (mOngoing.size() - viewIndex);
-        } else {
-            return latestSize - viewIndex;
-        }
-    }
-
-    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
-        Notification n = notification.notification;
-        RemoteViews remoteViews = n.contentView;
-        if (remoteViews == null) {
-            return null;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = n.contentIntent;
-        if (contentIntent != null) {
-            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
-                        notification.tag, notification.id));
-        }
-
-        View expanded = null;
-        Exception exception = null;
-        try {
-            expanded = remoteViews.apply(this, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (expanded == null) {
-            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
-            Slog.e(TAG, "couldn't inflate view for notification " + ident);
-            return null;
-        } else {
-            content.addView(expanded);
-            row.setDrawingCacheEnabled(true);
-        }
-
-        return new View[] { row, content, expanded };
-    }
-
-    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
-        NotificationData list;
-        ViewGroup parent;
-        final boolean isOngoing = notification.isOngoing();
-        if (isOngoing) {
-            list = mOngoing;
-            parent = mOngoingItems;
-        } else {
-            list = mLatest;
-            parent = mLatestItems;
-        }
-        // Construct the expanded view.
-        final View[] views = makeNotificationView(notification, parent);
-        if (views == null) {
-            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
-                    + notification);
-            return null;
-        }
-        final View row = views[0];
-        final View content = views[1];
-        final View expanded = views[2];
-        // Construct the icon.
-        final StatusBarIconView iconView = new StatusBarIconView(this,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id));
-        final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
-                    notification.notification.iconLevel, notification.notification.number);
-        if (!iconView.set(ic)) {
-            handleNotificationError(key, notification, "Coulding create icon: " + ic);
-            return null;
-        }
-        // Add the expanded view.
-        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
-        parent.addView(row, viewIndex);
-        // Add the icon.
-        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
-        mNotificationIcons.addView(iconView, iconIndex,
-                new LinearLayout.LayoutParams(mIconWidth, mHeight));
-
-        return iconView;
-    }
-
-    StatusBarNotification removeNotificationViews(IBinder key) {
-        NotificationData.Entry entry = mOngoing.remove(key);
-        if (entry == null) {
-            entry = mLatest.remove(key);
-            if (entry == null) {
-                Slog.w(TAG, "removeNotification for unknown key: " + key);
-                return null;
-            }
-        }
-        // Remove the expanded view.
-        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
-        // Remove the icon.
-        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
-
-        return entry.notification;
-    }
-
-    private void setAreThereNotifications() {
-        boolean ongoing = mOngoing.hasVisibleItems();
-        boolean latest = mLatest.hasVisibleItems();
-
-        // (no ongoing notifications are clearable)
-        if (mLatest.hasClearableItems()) {
-            mClearButton.setVisibility(View.VISIBLE);
-        } else {
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-
-        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
-        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
-
-        if (ongoing || latest) {
-            mNoNotificationsTitle.setVisibility(View.GONE);
-        } else {
-            mNoNotificationsTitle.setVisibility(View.VISIBLE);
-        }
-    }
-
-
-    /**
-     * State is one or more of the DISABLE constants from StatusBarManager.
-     */
-    public void disable(int state) {
-        final int old = mDisabled;
-        final int diff = state ^ old;
-        mDisabled = state;
-
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
-                mTicker.halt();
-            }
-        }
-    }
-
-    /**
-     * All changes to the status bar and notifications funnel through here and are batched.
-     */
-    private class H extends Handler {
-        public void handleMessage(Message m) {
-            switch (m.what) {
-                case MSG_ANIMATE:
-                    doAnimation();
-                    break;
-                case MSG_ANIMATE_REVEAL:
-                    doRevealAnimation();
-                    break;
-                case MSG_SHOW_INTRUDER:
-                    setIntruderAlertVisibility(true);
-                    break;
-                case MSG_HIDE_INTRUDER:
-                    setIntruderAlertVisibility(false);
-                    break;
-            }
-        }
-    }
-
-    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // Because 'v' is a ViewGroup, all its children will be (un)selected
-            // too, which allows marqueeing to work.
-            v.setSelected(hasFocus);
-        }
-    };
-
-    private void makeExpandedVisible() {
-        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = true;
-        visibilityChanged(true);
-        
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mExpandedView.requestFocus(View.FOCUS_FORWARD);
-        mTrackingView.setVisibility(View.VISIBLE);
-        
-        if (!mTicking) {
-            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-    }
-    
-    public void animateExpand() {
-        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        prepareTracking(0, true);
-        performFling(0, 2000.0f, true);
-    }
-    
-    public void animateCollapse() {
-        if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
-                    + " mAnimating=" + mAnimating
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel);
-        }
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating) {
-            y = (int)mAnimY;
-        } else {
-            y = mDisplay.getHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -2000.0f, true);
-    }
-    
-    void performExpand() {
-        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        mExpanded = true;
-        makeExpandedVisible();
-        updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
-        if (false) postStartTracing();
-    }
-
-    void performCollapse() {
-        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
-                + " mExpandedVisible=" + mExpandedVisible);
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = false;
-        visibilityChanged(false);
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mTrackingView.setVisibility(View.GONE);
-
-        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
-            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
-        
-        if (!mExpanded) {
-            return;
-        }
-        mExpanded = false;
-    }
-
-    void doAnimation() {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation");
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim();
-            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplay.getHeight()-1) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                updateExpandedViewPos(EXPANDED_FULL_OPEN);
-                performExpand();
-            }
-            else if (mAnimY < mStatusBarView.getHeight()) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                updateExpandedViewPos(0);
-                performCollapse();
-            }
-            else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-            }
-        }
-    }
-
-    void stopTracking() {
-        mTracking = false;
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
-    void incrementAnim() {
-        long now = SystemClock.uptimeMillis();
-        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTime = now;                                        // ms
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void doRevealAnimation() {
-        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
-        if (mAnimatingReveal && mAnimating && mAnimY < h) {
-            incrementAnim();
-            if (mAnimY >= h) {
-                mAnimY = h;
-                updateExpandedViewPos((int)mAnimY);
-            } else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                        mCurAnimationTime);
-            }
-        }
-    }
-    
-    void prepareTracking(int y, boolean opening) {
-        mTracking = true;
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            mAnimAccel = 2000.0f;
-            mAnimVel = 200;
-            mAnimY = mStatusBarView.getHeight();
-            updateExpandedViewPos((int)mAnimY);
-            mAnimating = true;
-            mAnimatingReveal = true;
-            mHandler.removeMessages(MSG_ANIMATE);
-            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-            long now = SystemClock.uptimeMillis();
-            mAnimLastTime = now;
-            mCurAnimationTime = now + ANIM_FRAME_DURATION;
-            mAnimating = true;
-            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                    mCurAnimationTime);
-            makeExpandedVisible();
-        } else {
-            // it's open, close it?
-            if (mAnimating) {
-                mAnimating = false;
-                mHandler.removeMessages(MSG_ANIMATE);
-            }
-            updateExpandedViewPos(y + mViewDelta);
-        }
-    }
-    
-    void performFling(int y, float vel, boolean always) {
-        mAnimatingReveal = false;
-        mDisplayHeight = mDisplay.getHeight();
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        long now = SystemClock.uptimeMillis();
-        mAnimLastTime = now;
-        mCurAnimationTime = now + ANIM_FRAME_DURATION;
-        mAnimating = true;
-        mHandler.removeMessages(MSG_ANIMATE);
-        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-        stopTracking();
-    }
-    
-    boolean interceptTouchEvent(MotionEvent event) {
-        if (SPEW) {
-            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
-                + mDisabled);
-        }
-
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-        
-        final int statusBarSize = mStatusBarView.getHeight();
-        final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
-            if (!mExpanded) {
-                mViewDelta = statusBarSize - y;
-            } else {
-                mTrackingView.getLocationOnScreen(mAbsPos);
-                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
-            }
-            if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-
-                // We drop events at the edge of the screen to make the windowshade come
-                // down by accident less, especially when pushing open a device with a keyboard
-                // that rotates (like g1 and droid)
-                int x = (int)event.getRawX();
-                final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
-                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
-                }
-            }
-        } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
-            final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
-                if (mAnimatingReveal && y < minY) {
-                    // nothing
-                } else  {
-                    mAnimatingReveal = false;
-                    updateExpandedViewPos(y + mViewDelta);
-                }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > 150.0f) {
-                    xVel = 150.0f; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (negative) {
-                    vel = -vel;
-                }
-                
-                performFling((int)event.getRawY(), vel, false);
-            }
-            
-        }
-        return false;
-    }
-
-    private class Launcher implements View.OnClickListener {
-        private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
-
-        Launcher(PendingIntent intent, String pkg, String tag, int id) {
-            mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
-        }
-
-        public void onClick(View v) {
-            try {
-                // The intent we are sending is for the application, which
-                // won't have permission to immediately start an activity after
-                // the user switches to home.  We know it is safe to do at this
-                // point, so make sure new activity switches are now allowed.
-                ActivityManagerNative.getDefault().resumeAppSwitches();
-            } catch (RemoteException e) {
-            }
-            int[] pos = new int[2];
-            v.getLocationOnScreen(pos);
-            Intent overlay = new Intent();
-            overlay.setSourceBounds(
-                    new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
-            try {
-                mIntent.send(PhoneStatusBarService.this, 0, overlay);
-            } catch (PendingIntent.CanceledException e) {
-                // the stack trace isn't very helpful here.  Just log the exception message.
-                Slog.w(TAG, "Sending contentIntent failed: " + e);
-            }
-            try {
-                mBarService.onNotificationClick(mPkg, mTag, mId);
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-            animateCollapse();
-        }
-    }
-
-    private void tick(StatusBarNotification n) {
-        // Show the ticker if one is requested. Also don't do this
-        // until status bar window is attached to the window manager,
-        // because...  well, what's the point otherwise?  And trying to
-        // run a ticker without being attached will crash!
-        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
-            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
-                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                mTicker.addEntry(n);
-            }
-        }
-    }
-
-    /**
-     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
-     * about the failure.
-     *
-     * WARNING: this will call back into us.  Don't hold any locks.
-     */
-    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
-        removeNotification(key);
-        try {
-            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
-        } catch (RemoteException ex) {
-            // The end is nigh.
-        }
-    }
-
-    private class MyTicker extends Ticker {
-        MyTicker(Context context, StatusBarView sb) {
-            super(context, sb);
-        }
-        
-        @Override
-        void tickerStarting() {
-            mTicking = true;
-            mIcons.setVisibility(View.GONE);
-            mTickerView.setVisibility(View.VISIBLE);
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
-            if (mExpandedVisible) {
-                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
-            }
-        }
-
-        @Override
-        void tickerDone() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
-            }
-        }
-
-        void tickerHalting() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-            }
-        }
-    }
-
-    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
-        public void onAnimationEnd(Animation animation) {
-            mTicking = false;
-        }
-        public void onAnimationRepeat(Animation animation) {
-        }
-        public void onAnimationStart(Animation animation) {
-        }
-    };
-
-    private Animation loadAnim(int id, Animation.AnimationListener listener) {
-        Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id);
-        if (listener != null) {
-            anim.setAnimationListener(listener);
-        }
-        return anim;
-    }
-
-    public String viewInfo(View v) {
-        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
-                + " " + v.getWidth() + "x" + v.getHeight() + ")";
-    }
-
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump StatusBar from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-        
-        synchronized (mQueueLock) {
-            pw.println("Current Status Bar state:");
-            pw.println("  mExpanded=" + mExpanded
-                    + ", mExpandedVisible=" + mExpandedVisible);
-            pw.println("  mTicking=" + mTicking);
-            pw.println("  mTracking=" + mTracking);
-            pw.println("  mAnimating=" + mAnimating
-                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
-                    + ", mAnimAccel=" + mAnimAccel);
-            pw.println("  mCurAnimationTime=" + mCurAnimationTime
-                    + " mAnimLastTime=" + mAnimLastTime);
-            pw.println("  mDisplayHeight=" + mDisplayHeight
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplayHeight=" + mDisplayHeight);
-            pw.println("  mExpandedParams: " + mExpandedParams);
-            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
-            pw.println("  mExpandedDialog: " + mExpandedDialog);
-            pw.println("  mTrackingParams: " + mTrackingParams);
-            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
-            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
-            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
-            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
-            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
-            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
-            pw.println("  mCloseView: " + viewInfo(mCloseView));
-            pw.println("  mTickerView: " + viewInfo(mTickerView));
-            pw.println("  mScrollView: " + viewInfo(mScrollView)
-                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
-            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
-        }
-        /*
-        synchronized (mNotificationData) {
-            int N = mNotificationData.ongoingCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getOngoing(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-            N = mNotificationData.latestCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getLatest(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-        }
-        */
-        
-        if (false) {
-            pw.println("see the logcat for a dump of the views we have created.");
-            // must happen on ui thread
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mStatusBarView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mStatusBarView.getWidth() + "x"
-                                + mStatusBarView.getHeight());
-                        mStatusBarView.debug();
-
-                        mExpandedView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mExpandedView.getWidth() + "x"
-                                + mExpandedView.getHeight());
-                        mExpandedView.debug();
-
-                        mTrackingView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mTrackingView.getWidth() + "x"
-                                + mTrackingView.getHeight());
-                        mTrackingView.debug();
-                    }
-                });
-        }
-    }
-
-    void onBarViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Tracking View --------------
-        pixelFormat = PixelFormat.RGBX_8888;
-        bg = mTrackingView.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                pixelFormat);
-//        lp.token = mStatusBarView.getWindowToken();
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("TrackingView");
-        lp.y = mTrackingPosition;
-        mTrackingParams = lp;
-
-        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
-    }
-
-    void onTrackingViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Expanded View --------------
-        pixelFormat = PixelFormat.TRANSLUCENT;
-
-        final int disph = mDisplay.getHeight();
-        lp = mExpandedDialog.getWindow().getAttributes();
-        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        lp.height = getExpandedHeight();
-        lp.x = 0;
-        mTrackingPosition = lp.y = -disph; // sufficiently large negative
-        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_DITHER
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.format = pixelFormat;
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBarExpanded");
-        mExpandedDialog.getWindow().setAttributes(lp);
-        mExpandedDialog.getWindow().setFormat(pixelFormat);
-        mExpandedParams = lp;
-
-        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        mExpandedDialog.setContentView(mExpandedView,
-                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                           ViewGroup.LayoutParams.MATCH_PARENT));
-        mExpandedDialog.getWindow().setBackgroundDrawable(null);
-        mExpandedDialog.show();
-        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
-    }
-
-    void setDateViewVisibility(boolean visible, int anim) {
-        mDateView.setUpdates(visible);
-        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        mDateView.startAnimation(loadAnim(anim, null));
-    }
-
-    void setNotificationIconVisibility(boolean visible, int anim) {
-        int old = mNotificationIcons.getVisibility();
-        int v = visible ? View.VISIBLE : View.INVISIBLE;
-        if (old != v) {
-            mNotificationIcons.setVisibility(v);
-            mNotificationIcons.startAnimation(loadAnim(anim, null));
-        }
-    }
-
-    void updateExpandedViewPos(int expandedPosition) {
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition);
-        }
-
-        int h = mStatusBarView.getHeight();
-        int disph = mDisplay.getHeight();
-
-        // If the expanded view is not visible, make sure they're still off screen.
-        // Maybe the view was resized.
-        if (!mExpandedVisible) {
-            if (mTrackingView != null) {
-                mTrackingPosition = -disph;
-                if (mTrackingParams != null) {
-                    mTrackingParams.y = mTrackingPosition;
-                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-                }
-            }
-            if (mExpandedParams != null) {
-                mExpandedParams.y = -disph;
-                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-            }
-            return;
-        }
-
-        // tracking view...
-        int pos;
-        if (expandedPosition == EXPANDED_FULL_OPEN) {
-            pos = h;
-        }
-        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
-            pos = mTrackingPosition;
-        }
-        else {
-            if (expandedPosition <= disph) {
-                pos = expandedPosition;
-            } else {
-                pos = disph;
-            }
-            pos -= disph-h;
-        }
-        mTrackingPosition = mTrackingParams.y = pos;
-        mTrackingParams.height = disph-h;
-        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-
-        if (mExpandedParams != null) {
-            mCloseView.getLocationInWindow(mPositionTmp);
-            final int closePos = mPositionTmp[1];
-
-            mExpandedContents.getLocationInWindow(mPositionTmp);
-            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
-
-            mExpandedParams.y = pos + mTrackingView.getHeight()
-                    - (mTrackingParams.height-closePos) - contentsBottom;
-            int max = h;
-            if (mExpandedParams.y > max) {
-                mExpandedParams.y = max;
-            }
-            int min = mTrackingPosition;
-            if (mExpandedParams.y < min) {
-                mExpandedParams.y = min;
-            }
-
-            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
-            if (!visible) {
-                // if the contents aren't visible, move the expanded view way off screen
-                // because the window itself extends below the content view.
-                mExpandedParams.y = -disph;
-            }
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-
-            // As long as this isn't just a repositioning that's not supposed to affect
-            // the user's perception of what's showing, call to say that the visibility
-            // has changed. (Otherwise, someone else will call to do that).
-            if (expandedPosition != EXPANDED_LEAVE_ALONE) {
-                Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
-                visibilityChanged(visible);
-            }
-        }
-
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition
-                    + " mExpandedParams.y=" + mExpandedParams.y
-                    + " mExpandedParams.height=" + mExpandedParams.height);
-        }
-    }
-
-    int getExpandedHeight() {
-        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
-    }
-
-    void updateExpandedHeight() {
-        if (mExpandedView != null) {
-            mExpandedParams.height = getExpandedHeight();
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-    }
-
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    void visibilityChanged(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            try {
-                mBarService.onPanelRevealed();
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        }
-    }
-
-    void performDisableActions(int net) {
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIcons.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-    }
-
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            try {
-                mBarService.onClearAllNotifications();
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-            animateCollapse();
-        }
-    };
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                //collapse();
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                updateResources();
-            }
-        }
-    };
-
-    private void setIntruderAlertVisibility(boolean vis) {
-        mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
-    }
-
-    /**
-     * Reload some of our resources when the configuration changes.
-     * 
-     * We don't reload everything when the configuration changes -- we probably
-     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
-     * meantime, just update the things that we know change.
-     */
-    void updateResources() {
-        Resources res = getResources();
-
-        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
-        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
-        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
-        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        if (false) Slog.v(TAG, "updateResources");
-    }
-
-    //
-    // tracing
-    //
-
-    void postStartTracing() {
-        mHandler.postDelayed(mStartTracing, 3000);
-    }
-
-    void vibrate() {
-        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
-        vib.vibrate(250);
-    }
-
-    Runnable mStartTracing = new Runnable() {
-        public void run() {
-            vibrate();
-            SystemClock.sleep(250);
-            Slog.d(TAG, "startTracing");
-            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
-            mHandler.postDelayed(mStopTracing, 10000);
-        }
-    };
-
-    Runnable mStopTracing = new Runnable() {
-        public void run() {
-            android.os.Debug.stopMethodTracing();
-            Slog.d(TAG, "stopTracing");
-            vibrate();
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index bc1e798..d98bd7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -65,7 +65,7 @@
         if (!iconEquals) {
             Drawable drawable = getIcon(icon);
             if (drawable == null) {
-                Slog.w(PhoneStatusBarService.TAG, "No icon for slot " + mSlot);
+                Slog.w(StatusBarService.TAG, "No icon for slot " + mSlot);
                 return false;
             }
             setImageDrawable(drawable);
@@ -99,7 +99,7 @@
             try {
                 r = context.getPackageManager().getResourcesForApplication(icon.iconPackage);
             } catch (PackageManager.NameNotFoundException ex) {
-                Slog.e(PhoneStatusBarService.TAG, "Icon package not found: " + icon.iconPackage);
+                Slog.e(StatusBarService.TAG, "Icon package not found: " + icon.iconPackage);
                 return null;
             }
         } else {
@@ -113,7 +113,7 @@
         try {
             return r.getDrawable(icon.iconId);
         } catch (RuntimeException e) {
-            Slog.w(PhoneStatusBarService.TAG, "Icon not found in "
+            Slog.w(StatusBarService.TAG, "Icon not found in "
                   + (icon.iconPackage != null ? icon.iconId : "<system>")
                   + ": " + Integer.toHexString(icon.iconId));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index d200886..07bcce7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -17,39 +17,189 @@
 package com.android.systemui.statusbar;
 
 import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.PixelFormat;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 
-import java.util.Arrays;
-import java.util.ArrayList;
+import android.app.ActivityManagerNative;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.FrameLayout;
 
-public abstract class StatusBarService extends Service implements CommandQueue.Callbacks {
-    private static final String TAG = "StatusBarService";
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.StatusBarPolicy;
+
+
+
+public class StatusBarService extends Service implements CommandQueue.Callbacks {
+    static final String TAG = "StatusBarService";
+    static final boolean SPEW = false;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    static final int EXPANDED_LEAVE_ALONE = -10000;
+    static final int EXPANDED_FULL_OPEN = -10001;
+
+    private static final int MSG_ANIMATE = 1000;
+    private static final int MSG_ANIMATE_REVEAL = 1001;
+    private static final int MSG_SHOW_INTRUDER = 1002;
+    private static final int MSG_HIDE_INTRUDER = 1003;
+
+    // will likely move to a resource or other tunable param at some point
+    private static final int INTRUDER_ALERT_DECAY_MS = 10000;
+
+    StatusBarPolicy mIconPolicy;
 
     CommandQueue mCommandQueue;
     IStatusBarService mBarService;
 
+    int mIconSize;
+    Display mDisplay;
+    StatusBarView mStatusBarView;
+    int mPixelFormat;
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+
+    // icons
+    LinearLayout mIcons;
+    IconMerger mNotificationIcons;
+    LinearLayout mStatusIcons;
+
+    // expanded notifications
+    Dialog mExpandedDialog;
+    ExpandedView mExpandedView;
+    WindowManager.LayoutParams mExpandedParams;
+    ScrollView mScrollView;
+    View mNotificationLinearLayout;
+    View mExpandedContents;
+    // top bar
+    TextView mNoNotificationsTitle;
+    TextView mClearButton;
+    // drag bar
+    CloseDragHandle mCloseView;
+    // ongoing
+    NotificationData mOngoing = new NotificationData();
+    TextView mOngoingTitle;
+    LinearLayout mOngoingItems;
+    // latest
+    NotificationData mLatest = new NotificationData();
+    TextView mLatestTitle;
+    LinearLayout mLatestItems;
+    // position
+    int[] mPositionTmp = new int[2];
+    boolean mExpanded;
+    boolean mExpandedVisible;
+
+    // the date view
+    DateView mDateView;
+
+    // the tracker view
+    TrackingView mTrackingView;
+    WindowManager.LayoutParams mTrackingParams;
+    int mTrackingPosition; // the position of the top of the tracking view.
+    private boolean mPanelSlightlyVisible;
+
+    // ticker
+    private Ticker mTicker;
+    private View mTickerView;
+    private boolean mTicking;
+
+    // Tracking finger for opening/closing.
+    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
+    boolean mTracking;
+    VelocityTracker mVelocityTracker;
+
+    static final int ANIM_FRAME_DURATION = (1000/60);
+
+    boolean mAnimating;
+    long mCurAnimationTime;
+    float mDisplayHeight;
+    float mAnimY;
+    float mAnimVel;
+    float mAnimAccel;
+    long mAnimLastTime;
+    boolean mAnimatingReveal = false;
+    int mViewDelta;
+    int[] mAbsPos = new int[2];
+
+    // for disabling the status bar
+    int mDisabled = 0;
+
+    private class ExpandedDialog extends Dialog {
+        ExpandedDialog(Context context) {
+            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+            switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_BACK:
+                if (!down) {
+                    animateCollapse();
+                }
+                return true;
+            }
+            return super.dispatchKeyEvent(event);
+        }
+    }
+
+
     @Override
     public void onCreate() {
+        // First set up our views and stuff.
+        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        makeStatusBarView(this);
+
         // Connect in to the status bar manager service
         StatusBarIconList iconList = new StatusBarIconList();
         ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
@@ -87,6 +237,9 @@
 
         // Put up the view
         addStatusBarView();
+
+        // Lastly, call to the icon policy to install/update all the icons.
+        mIconPolicy = new StatusBarPolicy(this);
     }
 
     @Override
@@ -94,6 +247,9 @@
         // we're never destroyed
     }
 
+    // for immersive activities
+    private View mIntruderAlertView;
+
     /**
      * Nobody binds to us.
      */
@@ -102,9 +258,1349 @@
         return null;
     }
 
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+    private void makeStatusBarView(Context context) {
+        Resources res = context.getResources();
+
+        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
+        ExpandedView expanded = (ExpandedView)View.inflate(context,
+                R.layout.status_bar_expanded, null);
+        expanded.mService = this;
+
+        mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
+        mIntruderAlertView.setVisibility(View.GONE);
+        mIntruderAlertView.setClickable(true);
+
+        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+        sb.mService = this;
+
+        // figure out which pixel-format to use for the status bar.
+        mPixelFormat = PixelFormat.TRANSLUCENT;
+        Drawable bg = sb.getBackground();
+        if (bg != null) {
+            mPixelFormat = bg.getOpacity();
+        }
+
+        mStatusBarView = sb;
+        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
+        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
+        mTickerView = sb.findViewById(R.id.ticker);
+        mDateView = (DateView)sb.findViewById(R.id.date);
+
+        mExpandedDialog = new ExpandedDialog(context);
+        mExpandedView = expanded;
+        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
+        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+        mClearButton.setOnClickListener(mClearButtonListener);
+        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+
+        mOngoingTitle.setVisibility(View.GONE);
+        mLatestTitle.setVisibility(View.GONE);
+
+        mTicker = new MyTicker(context, sb);
+
+        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+        tickerView.mTicker = mTicker;
+
+        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
+        mTrackingView.mService = this;
+        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+        mCloseView.mService = this;
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        // the more notifications icon
+        StatusBarIconView moreView = new StatusBarIconView(this, "more");
+        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
+        mNotificationIcons.addMoreView(moreView,
+                new LinearLayout.LayoutParams(mIconSize, mIconSize));
+
+        // set the inital view visibility
+        setAreThereNotifications();
+        mDateView.setVisibility(View.INVISIBLE);
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        context.registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    protected void addStatusBarView() {
+        Resources res = getResources();
+        final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+
+        final StatusBarView view = mStatusBarView;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                height,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
+                PixelFormat.RGBX_8888);
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBar");
+        // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+
+        WindowManagerImpl.getDefault().addView(view, lp);
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                PixelFormat.TRANSLUCENT);
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.y += height * 1.5; // FIXME
+        lp.setTitle("IntruderAlert");
+        lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
+
+        WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
+    }
+
+    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " icon=" + icon);
+        StatusBarIconView view = new StatusBarIconView(this, slot);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+    }
+
+    public void updateIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " old=" + old + " icon=" + icon);
+        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+    }
+
+    public void removeIcon(String slot, int index, int viewIndex) {
+        if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+        mStatusIcons.removeViewAt(viewIndex);
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        StatusBarIconView iconView = addNotificationViews(key, notification);
+        if (iconView == null) return;
+
+        boolean immersive = false;
+        try {
+            immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
+            Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
+        } catch (RemoteException ex) {
+        }
+        if (immersive) {
+            if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
+                Slog.d(TAG, "Presenting high-priority notification in immersive activity");
+                // @@@ special new transient ticker mode
+                // 1. Populate mIntruderAlertView
+
+                ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
+                TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
+                alertIcon.setImageDrawable(StatusBarIconView.getIcon(
+                    alertIcon.getContext(),
+                    iconView.getStatusBarIcon()));
+                alertText.setText(notification.notification.tickerText);
+
+                View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
+                button.setOnClickListener(
+                    new Launcher(notification.notification.contentIntent,
+                        notification.pkg, notification.tag, notification.id));
+
+                // 2. Animate mIntruderAlertView in
+                mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
+
+                // 3. Set alarm to age the notification off (TODO)
+                mHandler.removeMessages(MSG_HIDE_INTRUDER);
+                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
+            }
+        } else if (notification.notification.fullScreenIntent != null) {
+            // not immersive & a full-screen alert should be shown
+            Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+                    + " sending fullScreenIntent");
+            try {
+                notification.notification.fullScreenIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+            }
+        } else {
+            // usual case: status bar visible & not immersive
+
+            // show the ticker
+            tick(notification);
+        }
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
+
+        NotificationData oldList;
+        int oldIndex = mOngoing.findEntry(key);
+        if (oldIndex >= 0) {
+            oldList = mOngoing;
+        } else {
+            oldIndex = mLatest.findEntry(key);
+            if (oldIndex < 0) {
+                Slog.w(TAG, "updateNotification for unknown key: " + key);
+                return;
+            }
+            oldList = mLatest;
+        }
+        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
+        final StatusBarNotification oldNotification = oldEntry.notification;
+        final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+        final RemoteViews contentView = notification.notification.contentView;
+
+        if (false) {
+            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " expanded=" + oldEntry.expanded
+                    + " contentView=" + oldContentView);
+            Slog.d(TAG, "new notification: when=" + notification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " contentView=" + contentView);
+        }
+
+        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
+        // didn't change.
+        if (notification.notification.when == oldNotification.notification.when
+                && notification.isOngoing() == oldNotification.isOngoing()
+                && oldEntry.expanded != null
+                && contentView != null && oldContentView != null
+                && contentView.getPackage() != null
+                && oldContentView.getPackage() != null
+                && oldContentView.getPackage().equals(contentView.getPackage())
+                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+            if (SPEW) Slog.d(TAG, "reusing notification");
+            oldEntry.notification = notification;
+            try {
+                // Reapply the RemoteViews
+                contentView.reapply(this, oldEntry.content);
+                // update the contentIntent
+                final PendingIntent contentIntent = notification.notification.contentIntent;
+                if (contentIntent != null) {
+                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
+                                notification.pkg, notification.tag, notification.id));
+                }
+                // Update the icon.
+                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+                        notification.notification.icon, notification.notification.iconLevel,
+                        notification.notification.number);
+                if (!oldEntry.icon.set(ic)) {
+                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+                    return;
+                }
+            }
+            catch (RuntimeException e) {
+                // It failed to add cleanly.  Log, and remove the view from the panel.
+                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                removeNotificationViews(key);
+                addNotificationViews(key, notification);
+            }
+        } else {
+            if (SPEW) Slog.d(TAG, "not reusing notification");
+            removeNotificationViews(key);
+            addNotificationViews(key, notification);
+        }
+
+        // Restart the ticker if it's still running
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void removeNotification(IBinder key) {
+        if (SPEW) Slog.d(TAG, "removeNotification key=" + key);
+        StatusBarNotification old = removeNotificationViews(key);
+
+        if (old != null) {
+            // Cancel the ticker if it's still running
+            mTicker.removeEntry(old);
+
+            // Recalculate the position of the sliding windows and the titles.
+            setAreThereNotifications();
+            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        }
+    }
+
+    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
+        final int latestSize = mLatest.size();
+        if (isOngoing) {
+            return latestSize + (mOngoing.size() - viewIndex);
+        } else {
+            return latestSize - viewIndex;
+        }
+    }
+
+    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
+        Notification n = notification.notification;
+        RemoteViews remoteViews = n.contentView;
+        if (remoteViews == null) {
+            return null;
+        }
+
+        // create the row view
+        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
+
+        // bind the click event to the content area
+        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        content.setOnFocusChangeListener(mFocusChangeListener);
+        PendingIntent contentIntent = n.contentIntent;
+        if (contentIntent != null) {
+            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
+                        notification.tag, notification.id));
+        }
+
+        View expanded = null;
+        Exception exception = null;
+        try {
+            expanded = remoteViews.apply(this, content);
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (expanded == null) {
+            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
+            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+            return null;
+        } else {
+            content.addView(expanded);
+            row.setDrawingCacheEnabled(true);
+        }
+
+        return new View[] { row, content, expanded };
+    }
+
+    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
+        NotificationData list;
+        ViewGroup parent;
+        final boolean isOngoing = notification.isOngoing();
+        if (isOngoing) {
+            list = mOngoing;
+            parent = mOngoingItems;
+        } else {
+            list = mLatest;
+            parent = mLatestItems;
+        }
+        // Construct the expanded view.
+        final View[] views = makeNotificationView(notification, parent);
+        if (views == null) {
+            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+                    + notification);
+            return null;
+        }
+        final View row = views[0];
+        final View content = views[1];
+        final View expanded = views[2];
+        // Construct the icon.
+        final StatusBarIconView iconView = new StatusBarIconView(this,
+                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+        final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number);
+        if (!iconView.set(ic)) {
+            handleNotificationError(key, notification, "Coulding create icon: " + ic);
+            return null;
+        }
+        // Add the expanded view.
+        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
+        parent.addView(row, viewIndex);
+        // Add the icon.
+        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
+        mNotificationIcons.addView(iconView, iconIndex,
+                new LinearLayout.LayoutParams(mIconSize, mIconSize));
+        return iconView;
+    }
+
+    StatusBarNotification removeNotificationViews(IBinder key) {
+        NotificationData.Entry entry = mOngoing.remove(key);
+        if (entry == null) {
+            entry = mLatest.remove(key);
+            if (entry == null) {
+                Slog.w(TAG, "removeNotification for unknown key: " + key);
+                return null;
+            }
+        }
+        // Remove the expanded view.
+        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
+        // Remove the icon.
+        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
+
+        return entry.notification;
+    }
+
+    private void setAreThereNotifications() {
+        boolean ongoing = mOngoing.hasVisibleItems();
+        boolean latest = mLatest.hasVisibleItems();
+
+        // (no ongoing notifications are clearable)
+        if (mLatest.hasClearableItems()) {
+            mClearButton.setVisibility(View.VISIBLE);
+        } else {
+            mClearButton.setVisibility(View.INVISIBLE);
+        }
+
+        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
+        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
+
+        if (ongoing || latest) {
+            mNoNotificationsTitle.setVisibility(View.GONE);
+        } else {
+            mNoNotificationsTitle.setVisibility(View.VISIBLE);
+        }
+    }
+
+
     /**
-     * Implement this to add the main status bar view.
+     * State is one or more of the DISABLE constants from StatusBarManager.
      */
-    protected abstract void addStatusBarView();
+    public void disable(int state) {
+        final int old = mDisabled;
+        final int diff = state ^ old;
+        mDisabled = state;
+
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+                mTicker.halt();
+            }
+        }
+    }
+
+    /**
+     * All changes to the status bar and notifications funnel through here and are batched.
+     */
+    private class H extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+                case MSG_ANIMATE_REVEAL:
+                    doRevealAnimation();
+                    break;
+                case MSG_SHOW_INTRUDER:
+                    setIntruderAlertVisibility(true);
+                    break;
+                case MSG_HIDE_INTRUDER:
+                    setIntruderAlertVisibility(false);
+                    break;
+            }
+        }
+    }
+
+    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+        public void onFocusChange(View v, boolean hasFocus) {
+            // Because 'v' is a ViewGroup, all its children will be (un)selected
+            // too, which allows marqueeing to work.
+            v.setSelected(hasFocus);
+        }
+    };
+
+    private void makeExpandedVisible() {
+        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = true;
+        visibilityChanged(true);
+
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mExpandedView.requestFocus(View.FOCUS_FORWARD);
+        mTrackingView.setVisibility(View.VISIBLE);
+
+        if (!mTicking) {
+            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+    }
+
+    public void animateExpand() {
+        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        prepareTracking(0, true);
+        performFling(0, 2000.0f, true);
+    }
+
+    public void animateCollapse() {
+        if (SPEW) {
+            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+                    + " mExpandedVisible=" + mExpandedVisible
+                    + " mExpanded=" + mExpanded
+                    + " mAnimating=" + mAnimating
+                    + " mAnimY=" + mAnimY
+                    + " mAnimVel=" + mAnimVel);
+        }
+
+        if (!mExpandedVisible) {
+            return;
+        }
+
+        int y;
+        if (mAnimating) {
+            y = (int)mAnimY;
+        } else {
+            y = mDisplay.getHeight()-1;
+        }
+        // Let the fling think that we're open so it goes in the right direction
+        // and doesn't try to re-open the windowshade.
+        mExpanded = true;
+        prepareTracking(y, false);
+        performFling(y, -2000.0f, true);
+    }
+
+    void performExpand() {
+        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        mExpanded = true;
+        makeExpandedVisible();
+        updateExpandedViewPos(EXPANDED_FULL_OPEN);
+
+        if (false) postStartTracing();
+    }
+
+    void performCollapse() {
+        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+                + " mExpandedVisible=" + mExpandedVisible);
+
+        if (!mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = false;
+        visibilityChanged(false);
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mTrackingView.setVisibility(View.GONE);
+
+        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
+
+        if (!mExpanded) {
+            return;
+        }
+        mExpanded = false;
+    }
+
+    void doAnimation() {
+        if (mAnimating) {
+            if (SPEW) Slog.d(TAG, "doAnimation");
+            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+            incrementAnim();
+            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+            if (mAnimY >= mDisplay.getHeight()-1) {
+                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
+                mAnimating = false;
+                updateExpandedViewPos(EXPANDED_FULL_OPEN);
+                performExpand();
+            }
+            else if (mAnimY < mStatusBarView.getHeight()) {
+                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
+                mAnimating = false;
+                updateExpandedViewPos(0);
+                performCollapse();
+            }
+            else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+            }
+        }
+    }
+
+    void stopTracking() {
+        mTracking = false;
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+
+    void incrementAnim() {
+        long now = SystemClock.uptimeMillis();
+        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
+        final float y = mAnimY;
+        final float v = mAnimVel;                                   // px/s
+        final float a = mAnimAccel;                                 // px/s/s
+        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
+        mAnimVel = v + (a*t);                                       // px/s
+        mAnimLastTime = now;                                        // ms
+        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
+        //        + " mAnimAccel=" + mAnimAccel);
+    }
+
+    void doRevealAnimation() {
+        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
+        if (mAnimatingReveal && mAnimating && mAnimY < h) {
+            incrementAnim();
+            if (mAnimY >= h) {
+                mAnimY = h;
+                updateExpandedViewPos((int)mAnimY);
+            } else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                        mCurAnimationTime);
+            }
+        }
+    }
+
+    void prepareTracking(int y, boolean opening) {
+        mTracking = true;
+        mVelocityTracker = VelocityTracker.obtain();
+        if (opening) {
+            mAnimAccel = 2000.0f;
+            mAnimVel = 200;
+            mAnimY = mStatusBarView.getHeight();
+            updateExpandedViewPos((int)mAnimY);
+            mAnimating = true;
+            mAnimatingReveal = true;
+            mHandler.removeMessages(MSG_ANIMATE);
+            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+            long now = SystemClock.uptimeMillis();
+            mAnimLastTime = now;
+            mCurAnimationTime = now + ANIM_FRAME_DURATION;
+            mAnimating = true;
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                    mCurAnimationTime);
+            makeExpandedVisible();
+        } else {
+            // it's open, close it?
+            if (mAnimating) {
+                mAnimating = false;
+                mHandler.removeMessages(MSG_ANIMATE);
+            }
+            updateExpandedViewPos(y + mViewDelta);
+        }
+    }
+
+    void performFling(int y, float vel, boolean always) {
+        mAnimatingReveal = false;
+        mDisplayHeight = mDisplay.getHeight();
+
+        mAnimY = y;
+        mAnimVel = vel;
+
+        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+
+        if (mExpanded) {
+            if (!always && (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+                // We are expanded, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the expanded position.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are expanded and are now going to animate away.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        } else {
+            if (always || (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+                // We are collapsed, and they moved enough to allow us to
+                // expand.  Animate in the notifications.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are collapsed, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the collapsed position.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        }
+        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+        //        + " mAnimAccel=" + mAnimAccel);
+
+        long now = SystemClock.uptimeMillis();
+        mAnimLastTime = now;
+        mCurAnimationTime = now + ANIM_FRAME_DURATION;
+        mAnimating = true;
+        mHandler.removeMessages(MSG_ANIMATE);
+        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+        stopTracking();
+    }
+
+    boolean interceptTouchEvent(MotionEvent event) {
+        if (SPEW) {
+            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+                + mDisabled);
+        }
+
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return false;
+        }
+
+        final int statusBarSize = mStatusBarView.getHeight();
+        final int hitSize = statusBarSize*2;
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            final int y = (int)event.getRawY();
+
+            if (!mExpanded) {
+                mViewDelta = statusBarSize - y;
+            } else {
+                mTrackingView.getLocationOnScreen(mAbsPos);
+                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
+            }
+            if ((!mExpanded && y < hitSize) ||
+                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+
+                // We drop events at the edge of the screen to make the windowshade come
+                // down by accident less, especially when pushing open a device with a keyboard
+                // that rotates (like g1 and droid)
+                int x = (int)event.getRawX();
+                final int edgeBorder = mEdgeBorder;
+                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+                    mVelocityTracker.addMovement(event);
+                }
+            }
+        } else if (mTracking) {
+            mVelocityTracker.addMovement(event);
+            final int minY = statusBarSize + mCloseView.getHeight();
+            if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                int y = (int)event.getRawY();
+                if (mAnimatingReveal && y < minY) {
+                    // nothing
+                } else  {
+                    mAnimatingReveal = false;
+                    updateExpandedViewPos(y + mViewDelta);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                mVelocityTracker.computeCurrentVelocity(1000);
+
+                float yVel = mVelocityTracker.getYVelocity();
+                boolean negative = yVel < 0;
+
+                float xVel = mVelocityTracker.getXVelocity();
+                if (xVel < 0) {
+                    xVel = -xVel;
+                }
+                if (xVel > 150.0f) {
+                    xVel = 150.0f; // limit how much we care about the x axis
+                }
+
+                float vel = (float)Math.hypot(yVel, xVel);
+                if (negative) {
+                    vel = -vel;
+                }
+
+                performFling((int)event.getRawY(), vel, false);
+            }
+
+        }
+        return false;
+    }
+
+    private class Launcher implements View.OnClickListener {
+        private PendingIntent mIntent;
+        private String mPkg;
+        private String mTag;
+        private int mId;
+
+        Launcher(PendingIntent intent, String pkg, String tag, int id) {
+            mIntent = intent;
+            mPkg = pkg;
+            mTag = tag;
+            mId = id;
+        }
+
+        public void onClick(View v) {
+            try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+            } catch (RemoteException e) {
+            }
+
+            if (mIntent != null) {
+                int[] pos = new int[2];
+                v.getLocationOnScreen(pos);
+                Intent overlay = new Intent();
+                overlay.setSourceBounds(
+                        new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+                try {
+                    mIntent.send(StatusBarService.this, 0, overlay);
+                } catch (PendingIntent.CanceledException e) {
+                    // the stack trace isn't very helpful here.  Just log the exception message.
+                    Slog.w(TAG, "Sending contentIntent failed: " + e);
+                }
+            }
+
+            try {
+                mBarService.onNotificationClick(mPkg, mTag, mId);
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+
+            // close the shade if it was open
+            animateCollapse();
+
+            // If this click was on the intruder alert, hide that instead
+            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+        }
+    }
+
+    private void tick(StatusBarNotification n) {
+        // Show the ticker if one is requested. Also don't do this
+        // until status bar window is attached to the window manager,
+        // because...  well, what's the point otherwise?  And trying to
+        // run a ticker without being attached will crash!
+        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+                mTicker.addEntry(n);
+            }
+        }
+    }
+
+    /**
+     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+     * about the failure.
+     *
+     * WARNING: this will call back into us.  Don't hold any locks.
+     */
+    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
+        removeNotification(key);
+        try {
+            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
+        } catch (RemoteException ex) {
+            // The end is nigh.
+        }
+    }
+
+    private class MyTicker extends Ticker {
+        MyTicker(Context context, StatusBarView sb) {
+            super(context, sb);
+        }
+
+        @Override
+        void tickerStarting() {
+            mTicking = true;
+            mIcons.setVisibility(View.GONE);
+            mTickerView.setVisibility(View.VISIBLE);
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+            if (mExpandedVisible) {
+                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
+            }
+        }
+
+        @Override
+        void tickerDone() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
+            }
+        }
+
+        void tickerHalting() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+            }
+        }
+    }
+
+    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
+        public void onAnimationEnd(Animation animation) {
+            mTicking = false;
+        }
+        public void onAnimationRepeat(Animation animation) {
+        }
+        public void onAnimationStart(Animation animation) {
+        }
+    };
+
+    private Animation loadAnim(int id, Animation.AnimationListener listener) {
+        Animation anim = AnimationUtils.loadAnimation(StatusBarService.this, id);
+        if (listener != null) {
+            anim.setAnimationListener(listener);
+        }
+        return anim;
+    }
+
+    public String viewInfo(View v) {
+        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+                + " " + v.getWidth() + "x" + v.getHeight() + ")";
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mQueueLock) {
+            pw.println("Current Status Bar state:");
+            pw.println("  mExpanded=" + mExpanded
+                    + ", mExpandedVisible=" + mExpandedVisible);
+            pw.println("  mTicking=" + mTicking);
+            pw.println("  mTracking=" + mTracking);
+            pw.println("  mAnimating=" + mAnimating
+                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+                    + ", mAnimAccel=" + mAnimAccel);
+            pw.println("  mCurAnimationTime=" + mCurAnimationTime
+                    + " mAnimLastTime=" + mAnimLastTime);
+            pw.println("  mDisplayHeight=" + mDisplayHeight
+                    + " mAnimatingReveal=" + mAnimatingReveal
+                    + " mViewDelta=" + mViewDelta);
+            pw.println("  mDisplayHeight=" + mDisplayHeight);
+            pw.println("  mExpandedParams: " + mExpandedParams);
+            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
+            pw.println("  mExpandedDialog: " + mExpandedDialog);
+            pw.println("  mTrackingParams: " + mTrackingParams);
+            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
+            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
+            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
+            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
+            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
+            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+            pw.println("  mCloseView: " + viewInfo(mCloseView));
+            pw.println("  mTickerView: " + viewInfo(mTickerView));
+            pw.println("  mScrollView: " + viewInfo(mScrollView)
+                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
+        }
+        /*
+        synchronized (mNotificationData) {
+            int N = mNotificationData.ongoingCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getOngoing(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+            N = mNotificationData.latestCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getLatest(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+        }
+        */
+
+        if (false) {
+            pw.println("see the logcat for a dump of the views we have created.");
+            // must happen on ui thread
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        mStatusBarView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mStatusBarView.getWidth() + "x"
+                                + mStatusBarView.getHeight());
+                        mStatusBarView.debug();
+
+                        mExpandedView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mExpandedView.getWidth() + "x"
+                                + mExpandedView.getHeight());
+                        mExpandedView.debug();
+
+                        mTrackingView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mTrackingView.getWidth() + "x"
+                                + mTrackingView.getHeight());
+                        mTrackingView.debug();
+                    }
+                });
+        }
+    }
+
+    void onBarViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Tracking View --------------
+        pixelFormat = PixelFormat.RGBX_8888;
+        bg = mTrackingView.getBackground();
+        if (bg != null) {
+            pixelFormat = bg.getOpacity();
+        }
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                pixelFormat);
+//        lp.token = mStatusBarView.getWindowToken();
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("TrackingView");
+        lp.y = mTrackingPosition;
+        mTrackingParams = lp;
+
+        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
+    }
+
+    void onTrackingViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Expanded View --------------
+        pixelFormat = PixelFormat.TRANSLUCENT;
+
+        final int disph = mDisplay.getHeight();
+        lp = mExpandedDialog.getWindow().getAttributes();
+        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        lp.height = getExpandedHeight();
+        lp.x = 0;
+        mTrackingPosition = lp.y = -disph; // sufficiently large negative
+        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_DITHER
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        lp.format = pixelFormat;
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBarExpanded");
+        mExpandedDialog.getWindow().setAttributes(lp);
+        mExpandedDialog.getWindow().setFormat(pixelFormat);
+        mExpandedParams = lp;
+
+        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mExpandedDialog.setContentView(mExpandedView,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                           ViewGroup.LayoutParams.MATCH_PARENT));
+        mExpandedDialog.getWindow().setBackgroundDrawable(null);
+        mExpandedDialog.show();
+        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
+    }
+
+    void setDateViewVisibility(boolean visible, int anim) {
+        mDateView.setUpdates(visible);
+        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        mDateView.startAnimation(loadAnim(anim, null));
+    }
+
+    void setNotificationIconVisibility(boolean visible, int anim) {
+        int old = mNotificationIcons.getVisibility();
+        int v = visible ? View.VISIBLE : View.INVISIBLE;
+        if (old != v) {
+            mNotificationIcons.setVisibility(v);
+            mNotificationIcons.startAnimation(loadAnim(anim, null));
+        }
+    }
+
+    void updateExpandedViewPos(int expandedPosition) {
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition);
+        }
+
+        int h = mStatusBarView.getHeight();
+        int disph = mDisplay.getHeight();
+
+        // If the expanded view is not visible, make sure they're still off screen.
+        // Maybe the view was resized.
+        if (!mExpandedVisible) {
+            if (mTrackingView != null) {
+                mTrackingPosition = -disph;
+                if (mTrackingParams != null) {
+                    mTrackingParams.y = mTrackingPosition;
+                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+                }
+            }
+            if (mExpandedParams != null) {
+                mExpandedParams.y = -disph;
+                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+            }
+            return;
+        }
+
+        // tracking view...
+        int pos;
+        if (expandedPosition == EXPANDED_FULL_OPEN) {
+            pos = h;
+        }
+        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
+            pos = mTrackingPosition;
+        }
+        else {
+            if (expandedPosition <= disph) {
+                pos = expandedPosition;
+            } else {
+                pos = disph;
+            }
+            pos -= disph-h;
+        }
+        mTrackingPosition = mTrackingParams.y = pos;
+        mTrackingParams.height = disph-h;
+        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+
+        if (mExpandedParams != null) {
+            mCloseView.getLocationInWindow(mPositionTmp);
+            final int closePos = mPositionTmp[1];
+
+            mExpandedContents.getLocationInWindow(mPositionTmp);
+            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
+            mExpandedParams.y = pos + mTrackingView.getHeight()
+                    - (mTrackingParams.height-closePos) - contentsBottom;
+            int max = h;
+            if (mExpandedParams.y > max) {
+                mExpandedParams.y = max;
+            }
+            int min = mTrackingPosition;
+            if (mExpandedParams.y < min) {
+                mExpandedParams.y = min;
+            }
+
+            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+            if (!visible) {
+                // if the contents aren't visible, move the expanded view way off screen
+                // because the window itself extends below the content view.
+                mExpandedParams.y = -disph;
+            }
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+
+            // As long as this isn't just a repositioning that's not supposed to affect
+            // the user's perception of what's showing, call to say that the visibility
+            // has changed. (Otherwise, someone else will call to do that).
+            if (expandedPosition != EXPANDED_LEAVE_ALONE) {
+                if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
+                visibilityChanged(visible);
+            }
+        }
+
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition
+                    + " mExpandedParams.y=" + mExpandedParams.y
+                    + " mExpandedParams.height=" + mExpandedParams.height);
+        }
+    }
+
+    int getExpandedHeight() {
+        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+    }
+
+    void updateExpandedHeight() {
+        if (mExpandedView != null) {
+            mExpandedParams.height = getExpandedHeight();
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    void visibilityChanged(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            try {
+                mBarService.onPanelRevealed();
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        }
+    }
+
+    void performDisableActions(int net) {
+        int old = mDisabled;
+        int diff = net ^ old;
+        mDisabled = net;
+
+        // act accordingly
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mNotificationIcons.setVisibility(View.INVISIBLE);
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                mTicker.halt();
+            }
+        }
+    }
+
+    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            try {
+                mBarService.onClearAllNotifications();
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    };
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                //collapse();
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+        }
+    };
+
+    private void setIntruderAlertVisibility(boolean vis) {
+        mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Reload some of our resources when the configuration changes.
+     *
+     * We don't reload everything when the configuration changes -- we probably
+     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
+     * meantime, just update the things that we know change.
+     */
+    void updateResources() {
+        Resources res = getResources();
+
+        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
+        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
+        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
+        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        if (false) Slog.v(TAG, "updateResources");
+    }
+
+    //
+    // tracing
+    //
+
+    void postStartTracing() {
+        mHandler.postDelayed(mStartTracing, 3000);
+    }
+
+    void vibrate() {
+        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+        vib.vibrate(250);
+    }
+
+    Runnable mStartTracing = new Runnable() {
+        public void run() {
+            vibrate();
+            SystemClock.sleep(250);
+            Slog.d(TAG, "startTracing");
+            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
+            mHandler.postDelayed(mStopTracing, 10000);
+        }
+    };
+
+    Runnable mStopTracing = new Runnable() {
+        public void run() {
+            android.os.Debug.stopMethodTracing();
+            Slog.d(TAG, "stopTracing");
+            vibrate();
+        }
+    };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 466cc75..1e140b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -34,7 +34,7 @@
 
     static final int DIM_ANIM_TIME = 400;
     
-    PhoneStatusBarService mService;
+    StatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
     ViewGroup mNotificationIcons;
@@ -94,7 +94,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
index c59eb6a..9108eee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
@@ -26,7 +26,7 @@
 
 public class TrackingView extends LinearLayout {
     final Display mDisplay;
-    PhoneStatusBarService mService;
+    StatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
 
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 3e2c122..25de8b0 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -38,9 +38,11 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.hardware.Usb;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.BatteryManager;
+import android.os.Bundle;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -111,8 +113,6 @@
     private boolean mNotificationPulseEnabled;
 
     // for adb connected notifications
-    private boolean mUsbConnected;
-    private boolean mAdbEnabled = false;
     private boolean mAdbNotificationShown = false;
     private Notification mAdbNotification;
 
@@ -346,12 +346,14 @@
                     mBatteryFull = batteryFull;
                     updateLights();
                 }
-            } else if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
-                mUsbConnected = true;
-                updateAdbNotification();
-            } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
-                mUsbConnected = false;
-                updateAdbNotification();
+            } else if (action.equals(Usb.ACTION_USB_STATE)) {
+                Bundle extras = intent.getExtras();
+                boolean usbConnected = extras.getBoolean(Usb.USB_CONNECTED);
+                boolean adbEnabled = (Usb.USB_FUNCTION_ENABLED.equals(
+                                    extras.getString(Usb.USB_FUNCTION_ADB)));
+                updateAdbNotification(usbConnected && adbEnabled);
+            } else if (action.equals(Usb.ACTION_USB_DISCONNECTED)) {
+                updateAdbNotification(false);
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
@@ -397,8 +399,6 @@
 
         void observe() {
             ContentResolver resolver = mContext.getContentResolver();
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ADB_ENABLED), false, this);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
             update();
@@ -410,12 +410,6 @@
 
         public void update() {
             ContentResolver resolver = mContext.getContentResolver();
-            boolean adbEnabled = Settings.Secure.getInt(resolver,
-                        Settings.Secure.ADB_ENABLED, 0) != 0;
-            if (mAdbEnabled != adbEnabled) {
-                mAdbEnabled = adbEnabled;
-                updateAdbNotification();
-            }
             boolean pulseEnabled = Settings.System.getInt(resolver,
                         Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
             if (mNotificationPulseEnabled != pulseEnabled) {
@@ -464,8 +458,7 @@
         // register for battery changed notifications
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(Intent.ACTION_UMS_CONNECTED);
-        filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
+        filter.addAction(Usb.ACTION_USB_STATE);
         filter.addAction(Intent.ACTION_SCREEN_ON);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
@@ -1137,8 +1130,8 @@
     // This is here instead of StatusBarPolicy because it is an important
     // security feature that we don't want people customizing the platform
     // to accidentally lose.
-    private void updateAdbNotification() {
-        if (mAdbEnabled && mUsbConnected) {
+    private void updateAdbNotification(boolean adbEnabled) {
+        if (adbEnabled) {
             if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
                 return;
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7130636..c01680e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -80,7 +80,8 @@
                 android.os.Process.THREAD_PRIORITY_FOREGROUND);
 
         BinderInternal.disableBackgroundScheduling(true);
-        
+        android.os.Process.setCanSelfBackground(false);
+
         String factoryTestStr = SystemProperties.get("ro.factorytest");
         int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                 : Integer.parseInt(factoryTestStr);
diff --git a/services/java/com/android/server/UsbObserver.java b/services/java/com/android/server/UsbObserver.java
index 3993a7f..d08fe9b 100644
--- a/services/java/com/android/server/UsbObserver.java
+++ b/services/java/com/android/server/UsbObserver.java
@@ -159,6 +159,16 @@
     }
 
     private final Handler mHandler = new Handler() {
+        private void addEnabledFunctions(Intent intent) {
+            // include state of all USB functions in our extras
+            for (int i = 0; i < mEnabledFunctions.size(); i++) {
+                intent.putExtra(mEnabledFunctions.get(i), Usb.USB_FUNCTION_ENABLED);
+            }
+            for (int i = 0; i < mDisabledFunctions.size(); i++) {
+                intent.putExtra(mDisabledFunctions.get(i), Usb.USB_FUNCTION_DISABLED);
+            }
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -174,21 +184,21 @@
                         // Send an Intent containing connected/disconnected state
                         // and the enabled/disabled state of all USB functions
                         Intent intent;
-                        if (mUsbConfig != 0) {
+                        boolean usbConnected = (mUsbConfig != 0);
+                        if (usbConnected) {
                             intent = new Intent(Usb.ACTION_USB_CONNECTED);
-
-                            // include state of all USB functions in our extras
-                            for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                                intent.putExtra(mEnabledFunctions.get(i), Usb.USB_FUNCTION_ENABLED);
-                            }
-                            for (int i = 0; i < mDisabledFunctions.size(); i++) {
-                                intent.putExtra(mDisabledFunctions.get(i), Usb.USB_FUNCTION_DISABLED);
-                            }
+                            addEnabledFunctions(intent);
                         } else {
                             intent = new Intent(Usb.ACTION_USB_DISCONNECTED);
                         }
+                        mContext.sendBroadcast(intent);
 
-                        mContext.sendBroadcast(intent, android.Manifest.permission.ACCESS_USB);
+                        // send a sticky broadcast for clients interested in both connect and disconnect
+                        intent = new Intent(Usb.ACTION_USB_STATE);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                        intent.putExtra(Usb.USB_CONNECTED, usbConnected);
+                        addEnabledFunctions(intent);
+                        mContext.sendStickyBroadcast(intent);
                     }
                     break;
             }
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index d4133f3..a742093 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -57,20 +57,10 @@
     static final boolean RECORD_KERNEL_THREADS = true;
 
     static final int MONITOR = 2718;
-    static final int GLOBAL_PSS = 2719;
 
     static final int TIME_TO_RESTART = DB ? 15*1000 : 60*1000;
     static final int TIME_TO_WAIT = TIME_TO_RESTART / 2;
 
-    static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
-    static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60;      // 2 hours
-    static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
-    static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
-    static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024;    // 8MB
-    static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024;   // 12MB
-
-    static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60;           // 1:00am
-    static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60;             // 5:00am
     static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60;   // 5 minutes
     static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60;        // 3 minutes
     static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
@@ -79,14 +69,12 @@
     static final int REBOOT_DEFAULT_START_TIME = 3*60*60;                  // 3:00am
     static final int REBOOT_DEFAULT_WINDOW = 60*60;                        // within 1 hour
 
-    static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
     static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
 
     static Watchdog sWatchdog;
 
     /* This handler will be used to post message back onto the main thread */
     final Handler mHandler;
-    final Runnable mGlobalPssCollected;
     final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
     ContentResolver mResolver;
     BatteryService mBattery;
@@ -97,31 +85,9 @@
     boolean mForceKillSystem;
     Monitor mCurrentMonitor;
 
-    PssRequestor mPhoneReq;
     int mPhonePid;
-    int mPhonePss;
-
-    long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
-    boolean mHavePss;
-    long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
-    boolean mHaveGlobalPss;
-    final MemMonitor mSystemMemMonitor = new MemMonitor("system",
-            Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
-            Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
-            MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
-            Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD,
-            MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
-    final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
-            Settings.Secure.MEMCHECK_PHONE_ENABLED,
-            Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
-            MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
-            Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
-            MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
 
     final Calendar mCalendar = Calendar.getInstance();
-    long mMemcheckLastTime;
-    long mMemcheckExecStartTime;
-    long mMemcheckExecEndTime;
     int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
     int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
     boolean mNeedScheduledCheck;
@@ -140,126 +106,13 @@
     int mReqRecheckInterval= -1;  // >= 0 if a specific recheck interval has been requested
 
     /**
-     * This class monitors the memory in a particular process.
-     */
-    final class MemMonitor {
-        final String mProcessName;
-        final String mEnabledSetting;
-        final String mSoftSetting;
-        final String mHardSetting;
-
-        int mSoftThreshold;
-        int mHardThreshold;
-        boolean mEnabled;
-        long mLastPss;
-
-        static final int STATE_OK = 0;
-        static final int STATE_SOFT = 1;
-        static final int STATE_HARD = 2;
-        int mState;
-
-        MemMonitor(String processName, String enabledSetting,
-                String softSetting, int defSoftThreshold,
-                String hardSetting, int defHardThreshold) {
-            mProcessName = processName;
-            mEnabledSetting = enabledSetting;
-            mSoftSetting = softSetting;
-            mHardSetting = hardSetting;
-            mSoftThreshold = defSoftThreshold;
-            mHardThreshold = defHardThreshold;
-        }
-
-        void retrieveSettings(ContentResolver resolver) {
-            mSoftThreshold = Settings.Secure.getInt(
-                    resolver, mSoftSetting, mSoftThreshold);
-            mHardThreshold = Settings.Secure.getInt(
-                    resolver, mHardSetting, mHardThreshold);
-            mEnabled = Settings.Secure.getInt(
-                    resolver, mEnabledSetting, 0) != 0;
-        }
-
-        boolean checkLocked(long curTime, int pid, int pss) {
-            mLastPss = pss;
-            if (mLastPss < mSoftThreshold) {
-                mState = STATE_OK;
-            } else if (mLastPss < mHardThreshold) {
-                mState = STATE_SOFT;
-            } else {
-                mState = STATE_HARD;
-            }
-            EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
-
-            if (mState == STATE_OK) {
-                // Memory is good, don't recover.
-                return false;
-            }
-
-            if (mState == STATE_HARD) {
-                // Memory is really bad, kill right now.
-                EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
-                        mHardThreshold, mLastPss);
-                return mEnabled;
-            }
-
-            // It is time to schedule a reset...
-            // Check if we are currently within the time to kill processes due
-            // to memory use.
-            computeMemcheckTimesLocked(curTime);
-            String skipReason = null;
-            if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
-                skipReason = "time";
-            } else {
-                skipReason = shouldWeBeBrutalLocked(curTime);
-            }
-            EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
-                    mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
-            if (skipReason != null) {
-                mNeedScheduledCheck = true;
-                return false;
-            }
-            return mEnabled;
-        }
-
-        void clear() {
-            mLastPss = 0;
-            mState = STATE_OK;
-        }
-    }
-
-    /**
      * Used for scheduling monitor callbacks and checking memory usage.
      */
     final class HeartbeatHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case GLOBAL_PSS: {
-                    if (mHaveGlobalPss) {
-                        // During the last pass we collected pss information, so
-                        // now it is time to report it.
-                        mHaveGlobalPss = false;
-                        if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
-                        logGlobalMemory();
-                    }
-                } break;
-
                 case MONITOR: {
-                    if (mHavePss) {
-                        // During the last pass we collected pss information, so
-                        // now it is time to report it.
-                        mHavePss = false;
-                        if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
-                        checkMemory();
-                    }
-
-                    if (mHaveGlobalPss) {
-                        // During the last pass we collected pss information, so
-                        // now it is time to report it.
-                        mHaveGlobalPss = false;
-                        if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
-                        logGlobalMemory();
-                    }
-
                     long now = SystemClock.uptimeMillis();
 
                     // See if we should force a reboot.
@@ -274,32 +127,6 @@
                         checkReboot(false);
                     }
 
-                    // See if we should check memory conditions.
-                    long memCheckInterval = Settings.Secure.getLong(
-                            mResolver, Settings.Secure.MEMCHECK_INTERVAL,
-                            MEMCHECK_DEFAULT_INTERVAL) * 1000;
-                    if ((mLastMemCheckTime+memCheckInterval) < now) {
-                        // It is now time to collect pss information.  This
-                        // is async so we won't report it now.  And to keep
-                        // things simple, we will assume that everyone has
-                        // reported back by the next MONITOR message.
-                        mLastMemCheckTime = now;
-                        if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
-                        collectMemory();
-                        mHavePss = true;
-
-                        long memCheckRealtimeInterval = Settings.Secure.getLong(
-                                mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL,
-                                MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
-                        long realtimeNow = SystemClock.elapsedRealtime();
-                        if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
-                            mLastMemCheckRealtime = realtimeNow;
-                            if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
-                            collectGlobalMemory();
-                            mHaveGlobalPss = true;
-                        }
-                    }
-
                     final int size = mMonitors.size();
                     for (int i = 0 ; i < size ; i++) {
                         mCurrentMonitor = mMonitors.get(i);
@@ -315,20 +142,6 @@
         }
     }
 
-    final class GlobalPssCollected implements Runnable {
-        public void run() {
-            mHandler.sendEmptyMessage(GLOBAL_PSS);
-        }
-    }
-
-    final class CheckupReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context c, Intent intent) {
-            if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
-            checkMemory();
-        }
-    }
-
     final class RebootReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context c, Intent intent) {
@@ -359,27 +172,6 @@
         void monitor();
     }
 
-    public interface PssRequestor {
-        void requestPss();
-    }
-
-    public class PssStats {
-        public int mEmptyPss;
-        public int mEmptyCount;
-        public int mBackgroundPss;
-        public int mBackgroundCount;
-        public int mServicePss;
-        public int mServiceCount;
-        public int mVisiblePss;
-        public int mVisibleCount;
-        public int mForegroundPss;
-        public int mForegroundCount;
-
-        public int mNoPssCount;
-
-        public int mProcDeaths[] = new int[10];
-    }
-
     public static Watchdog getInstance() {
         if (sWatchdog == null) {
             sWatchdog = new Watchdog();
@@ -391,7 +183,6 @@
     private Watchdog() {
         super("watchdog");
         mHandler = new HeartbeatHandler();
-        mGlobalPssCollected = new GlobalPssCollected();
     }
 
     public void init(Context context, BatteryService battery,
@@ -403,11 +194,6 @@
         mAlarm = alarm;
         mActivity = activity;
 
-        context.registerReceiver(new CheckupReceiver(),
-                new IntentFilter(CHECKUP_ACTION));
-        mCheckupIntent = PendingIntent.getBroadcast(context,
-                0, new Intent(CHECKUP_ACTION), 0);
-
         context.registerReceiver(new RebootReceiver(),
                 new IntentFilter(REBOOT_ACTION));
         mRebootIntent = PendingIntent.getBroadcast(context,
@@ -420,20 +206,10 @@
         mBootTime = System.currentTimeMillis();
     }
 
-    public void processStarted(PssRequestor req, String name, int pid) {
+    public void processStarted(String name, int pid) {
         synchronized (this) {
             if ("com.android.phone".equals(name)) {
-                mPhoneReq = req;
                 mPhonePid = pid;
-                mPhonePss = 0;
-            }
-        }
-    }
-
-    public void reportPss(PssRequestor req, String name, int pss) {
-        synchronized (this) {
-            if (mPhoneReq == req) {
-                mPhonePss = pss;
             }
         }
     }
@@ -447,152 +223,6 @@
         }
     }
 
-    /**
-     * Retrieve memory usage information from specific processes being
-     * monitored.  This is an async operation, so must be done before doing
-     * memory checks.
-     */
-    void collectMemory() {
-        synchronized (this) {
-            if (mPhoneReq != null) {
-                mPhoneReq.requestPss();
-            }
-        }
-    }
-
-    /**
-     * Retrieve memory usage over all application processes.  This is an
-     * async operation, so must be done before doing memory checks.
-     */
-    void collectGlobalMemory() {
-        mActivity.requestPss(mGlobalPssCollected);
-    }
-
-    /**
-     * Check memory usage in the system, scheduling kills/reboots as needed.
-     * This always runs on the mHandler thread.
-     */
-    void checkMemory() {
-        boolean needScheduledCheck;
-        long curTime;
-        long nextTime = 0;
-
-        long recheckInterval = Settings.Secure.getLong(
-                mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
-                MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
-
-        mSystemMemMonitor.retrieveSettings(mResolver);
-        mPhoneMemMonitor.retrieveSettings(mResolver);
-        retrieveBrutalityAmount();
-
-        synchronized (this) {
-            curTime = System.currentTimeMillis();
-            mNeedScheduledCheck = false;
-
-            // How is the system doing?
-            if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
-                    (int)Process.getPss(Process.myPid()))) {
-                // Not good!  Time to suicide.
-                mForceKillSystem = true;
-                notifyAll();
-                return;
-            }
-
-            // How is the phone process doing?
-            if (mPhoneReq != null) {
-                if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
-                        mPhonePss)) {
-                    // Just kill the phone process and let it restart.
-                    Slog.i(TAG, "Watchdog is killing the phone process");
-                    Process.killProcess(mPhonePid);
-                }
-            } else {
-                mPhoneMemMonitor.clear();
-            }
-
-            needScheduledCheck = mNeedScheduledCheck;
-            if (needScheduledCheck) {
-                // Something is going bad, but now is not a good time to
-                // tear things down...  schedule an alarm to check again soon.
-                nextTime = curTime + recheckInterval;
-                if (nextTime < mMemcheckExecStartTime) {
-                    nextTime = mMemcheckExecStartTime;
-                } else if (nextTime >= mMemcheckExecEndTime){
-                    // Need to check during next exec time...  so that needs
-                    // to be computed.
-                    if (localLOGV) Slog.v(TAG, "Computing next time range");
-                    computeMemcheckTimesLocked(nextTime);
-                    nextTime = mMemcheckExecStartTime;
-                }
-
-                if (localLOGV) {
-                    mCalendar.setTimeInMillis(nextTime);
-                    Slog.v(TAG, "Next Alarm Time: " + mCalendar);
-                }
-            }
-        }
-
-        if (needScheduledCheck) {
-            if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for "
-                    + ((nextTime-curTime)/1000/60) + "m from now");
-            mAlarm.remove(mCheckupIntent);
-            mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
-        } else {
-            if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
-            mAlarm.remove(mCheckupIntent);
-        }
-    }
-
-    final PssStats mPssStats = new PssStats();
-    final String[] mMemInfoFields = new String[] {
-            "MemFree:", "Buffers:", "Cached:",
-            "Active:", "Inactive:",
-            "AnonPages:", "Mapped:", "Slab:",
-            "SReclaimable:", "SUnreclaim:", "PageTables:" };
-    final long[] mMemInfoSizes = new long[mMemInfoFields.length];
-    final String[] mVMStatFields = new String[] {
-            "pgfree ", "pgactivate ", "pgdeactivate ",
-            "pgfault ", "pgmajfault " };
-    final long[] mVMStatSizes = new long[mVMStatFields.length];
-    final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
-    long mLastLogGlobalMemoryTime;
-
-    void logGlobalMemory() {
-        PssStats stats = mPssStats;
-        mActivity.collectPss(stats);
-        EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
-                stats.mEmptyPss, stats.mEmptyCount,
-                stats.mBackgroundPss, stats.mBackgroundCount,
-                stats.mServicePss, stats.mServiceCount,
-                stats.mVisiblePss, stats.mVisibleCount,
-                stats.mForegroundPss, stats.mForegroundCount,
-                stats.mNoPssCount);
-        EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
-                stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
-                stats.mProcDeaths[3], stats.mProcDeaths[4]);
-        Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
-        for (int i=0; i<mMemInfoSizes.length; i++) {
-            mMemInfoSizes[i] *= 1024;
-        }
-        EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
-                (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
-                (int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
-                (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
-                (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
-        long now = SystemClock.uptimeMillis();
-        long dur = now - mLastLogGlobalMemoryTime;
-        mLastLogGlobalMemoryTime = now;
-        Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
-        for (int i=0; i<mVMStatSizes.length; i++) {
-            long v = mVMStatSizes[i];
-            mVMStatSizes[i] -= mPrevVMStatSizes[i];
-            mPrevVMStatSizes[i] = v;
-        }
-        EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur,
-                (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
-                (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
-    }
-
     void checkReboot(boolean fromAlarm) {
         int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
                 : Settings.Secure.getInt(
@@ -730,47 +360,6 @@
         return null;
     }
 
-    /**
-     * Compute the times during which we next would like to perform process
-     * restarts.
-     *
-     * @param curTime The current system time.
-     */
-    void computeMemcheckTimesLocked(long curTime) {
-        if (mMemcheckLastTime == curTime) {
-            return;
-        }
-
-        mMemcheckLastTime = curTime;
-
-        long memcheckExecStartTime = Settings.Secure.getLong(
-                mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME,
-                MEMCHECK_DEFAULT_EXEC_START_TIME);
-        long memcheckExecEndTime = Settings.Secure.getLong(
-                mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME,
-                MEMCHECK_DEFAULT_EXEC_END_TIME);
-
-        mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
-                memcheckExecEndTime);
-        if (mMemcheckExecEndTime < curTime) {
-            memcheckExecStartTime += 24*60*60;
-            memcheckExecEndTime += 24*60*60;
-            mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
-                    memcheckExecEndTime);
-        }
-        mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
-                memcheckExecStartTime);
-
-        if (localLOGV) {
-            mCalendar.setTimeInMillis(curTime);
-            Slog.v(TAG, "Current Time: " + mCalendar);
-            mCalendar.setTimeInMillis(mMemcheckExecStartTime);
-            Slog.v(TAG, "Start Check Time: " + mCalendar);
-            mCalendar.setTimeInMillis(mMemcheckExecEndTime);
-            Slog.v(TAG, "End Check Time: " + mCalendar);
-        }
-    }
-
     static long computeCalendarTime(Calendar c, long curTime,
             long secondsSinceMidnight) {
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index bf86b23..483f9eb 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -572,6 +572,7 @@
                     mHaveInputMethods);
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_DISPLAY);
+            android.os.Process.setCanSelfBackground(false);
 
             synchronized (this) {
                 mService = s;
@@ -607,6 +608,7 @@
             //        Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_FOREGROUND);
+            android.os.Process.setCanSelfBackground(false);
             mPolicy.init(mContext, mService, mPM);
 
             synchronized (this) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2c6806b..93122c4 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -880,7 +880,6 @@
             if (localLOGV) Slog.v(
                 TAG, "Death received in " + this
                 + " for thread " + mAppThread.asBinder());
-            removeRequestedPss(mApp);
             synchronized(ActivityManagerService.this) {
                 appDiedLocked(mApp, mPid, mAppThread);
             }
@@ -1260,6 +1259,7 @@
 
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_FOREGROUND);
+            android.os.Process.setCanSelfBackground(false);
 
             ActivityManagerService m = new ActivityManagerService();
 
@@ -1785,7 +1785,7 @@
                     hostingNameStr != null ? hostingNameStr : "");
             
             if (app.persistent) {
-                Watchdog.getInstance().processStarted(app, app.processName, pid);
+                Watchdog.getInstance().processStarted(app.processName, pid);
             }
             
             StringBuilder buf = mStringBuilder;
@@ -5662,123 +5662,6 @@
         return killed;
     }
     
-    public void reportPss(IApplicationThread caller, int pss) {
-        Watchdog.PssRequestor req;
-        String name;
-        ProcessRecord callerApp;
-        synchronized (this) {
-            if (caller == null) {
-                return;
-            }
-            callerApp = getRecordForAppLocked(caller);
-            if (callerApp == null) {
-                return;
-            }
-            callerApp.lastPss = pss;
-            req = callerApp;
-            name = callerApp.processName;
-        }
-        Watchdog.getInstance().reportPss(req, name, pss);
-        if (!callerApp.persistent) {
-            removeRequestedPss(callerApp);
-        }
-    }
-    
-    public void requestPss(Runnable completeCallback) {
-        ArrayList<ProcessRecord> procs;
-        synchronized (this) {
-            mRequestPssCallback = completeCallback;
-            mRequestPssList.clear();
-            for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                ProcessRecord proc = mLruProcesses.get(i);
-                if (!proc.persistent) {
-                    mRequestPssList.add(proc);
-                }
-            }
-            procs = new ArrayList<ProcessRecord>(mRequestPssList);
-        }
-        
-        int oldPri = Process.getThreadPriority(Process.myTid()); 
-        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-        for (int i=procs.size()-1; i>=0; i--) {
-            ProcessRecord proc = procs.get(i);
-            proc.lastPss = 0;
-            proc.requestPss();
-        }
-        Process.setThreadPriority(oldPri);
-    }
-    
-    void removeRequestedPss(ProcessRecord proc) {
-        Runnable callback = null;
-        synchronized (this) {
-            if (mRequestPssList.remove(proc)) {
-                if (mRequestPssList.size() == 0) {
-                    callback = mRequestPssCallback;
-                    mRequestPssCallback = null;
-                }
-            }
-        }
-        
-        if (callback != null) {
-            callback.run();
-        }
-    }
-    
-    public void collectPss(Watchdog.PssStats stats) {
-        stats.mEmptyPss = 0;
-        stats.mEmptyCount = 0;
-        stats.mBackgroundPss = 0;
-        stats.mBackgroundCount = 0;
-        stats.mServicePss = 0;
-        stats.mServiceCount = 0;
-        stats.mVisiblePss = 0;
-        stats.mVisibleCount = 0;
-        stats.mForegroundPss = 0;
-        stats.mForegroundCount = 0;
-        stats.mNoPssCount = 0;
-        synchronized (this) {
-            int i;
-            int NPD = mProcDeaths.length < stats.mProcDeaths.length
-                    ? mProcDeaths.length : stats.mProcDeaths.length;
-            int aggr = 0;
-            for (i=0; i<NPD; i++) {
-                aggr += mProcDeaths[i];
-                stats.mProcDeaths[i] = aggr;
-            }
-            while (i<stats.mProcDeaths.length) {
-                stats.mProcDeaths[i] = 0;
-                i++;
-            }
-            
-            for (i=mLruProcesses.size()-1; i>=0; i--) {
-                ProcessRecord proc = mLruProcesses.get(i);
-                if (proc.persistent) {
-                    continue;
-                }
-                //Slog.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
-                if (proc.lastPss == 0) {
-                    stats.mNoPssCount++;
-                    continue;
-                }
-                if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
-                    if (proc.empty) {
-                        stats.mEmptyPss += proc.lastPss;
-                        stats.mEmptyCount++;
-                    } else {
-                        stats.mBackgroundPss += proc.lastPss;
-                        stats.mBackgroundCount++;
-                    }
-                } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
-                    stats.mVisiblePss += proc.lastPss;
-                    stats.mVisibleCount++;
-                } else {
-                    stats.mForegroundPss += proc.lastPss;
-                    stats.mForegroundCount++;
-                }
-            }
-        }
-    }
-    
     public final void startRunning(String pkg, String cls, String action,
             String data) {
         synchronized(this) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 18fd9d6..18b1acb 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -39,7 +39,7 @@
  * Full information about a particular process that
  * is currently running.
  */
-class ProcessRecord implements Watchdog.PssRequestor {
+class ProcessRecord {
     final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
     final String processName;   // name of the process
@@ -264,16 +264,6 @@
         }
     }
     
-    public void requestPss() {
-        IApplicationThread localThread = thread;
-        if (localThread != null) {
-            try {
-                localThread.requestPss();
-            } catch (RemoteException e) {
-            }
-        }
-    }
-    
     public String toShortString() {
         if (shortStringName != null) {
             return shortStringName;
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 0106e6c..d0f856b 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -374,6 +374,9 @@
     int32_t identifyTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
 
+    bool interceptKeyBeforeDispatching(const InputTarget& target,
+            const KeyEvent* keyEvent, uint32_t policyFlags);
+
     void pokeUserActivityIfNeeded(int32_t windowType, int32_t eventType);
     void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
     bool checkInjectionPermission(const InputWindow* window,
@@ -395,7 +398,7 @@
 
 NativeInputManager::NativeInputManager(jobject callbacksObj) :
     mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1),
-    mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(-1),
+    mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0),
     mDispatchEnabled(true), mDispatchFrozen(false), mWindowsReady(true),
     mFocusedWindow(NULL), mTouchDown(false), mTouchedWindow(NULL),
     mFocusedApplication(NULL) {
@@ -633,8 +636,6 @@
         }
     }
 
-    // TODO Be smarter about which keys cause us to request interception during dispatch.
-    actions |= InputReaderPolicyInterface::ACTION_INTERCEPT_DISPATCH;
     return actions;
 }
 
@@ -1530,34 +1531,11 @@
         windowType = focusedWindow->layoutParamsType;
     } // release lock
 
-    if (policyFlags & POLICY_FLAG_INTERCEPT_DISPATCH) {
-        const InputTarget& target = outTargets.top();
-
-        JNIEnv* env = jniEnv();
-
-        jobject inputChannelObj = getInputChannelObjLocal(env, target.inputChannel);
-        if (inputChannelObj) {
-            jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
-                    gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                    inputChannelObj, keyEvent->getKeyCode(), keyEvent->getMetaState(),
-                    keyEvent->getAction() == KEY_EVENT_ACTION_DOWN,
-                    keyEvent->getRepeatCount(), policyFlags);
-            bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatch");
-
-            env->DeleteLocalRef(inputChannelObj);
-
-            if (error) {
-                return INPUT_EVENT_INJECTION_FAILED;
-            }
-
-            if (consumed) {
-                outTargets.clear();
-                return INPUT_EVENT_INJECTION_SUCCEEDED;
-            }
-        } else {
-            LOGW("Could not apply key dispatch policy because input channel '%s' is "
-                    "no longer valid.", target.inputChannel->getName().string());
-        }
+    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);
@@ -1656,6 +1634,29 @@
     return INPUT_EVENT_INJECTION_SUCCEEDED;
 }
 
+bool NativeInputManager::interceptKeyBeforeDispatching(const InputTarget& target,
+        const KeyEvent* keyEvent, uint32_t policyFlags) {
+    JNIEnv* env = jniEnv();
+
+    jobject inputChannelObj = getInputChannelObjLocal(env, target.inputChannel);
+    if (inputChannelObj) {
+        jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
+                gCallbacksClassInfo.interceptKeyBeforeDispatching,
+                inputChannelObj, keyEvent->getKeyCode(), keyEvent->getMetaState(),
+                keyEvent->getAction() == KEY_EVENT_ACTION_DOWN,
+                keyEvent->getRepeatCount(), policyFlags);
+        bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+
+        env->DeleteLocalRef(inputChannelObj);
+
+        return consumed && ! error;
+    } else {
+        LOGW("Could not apply key dispatch policy because input channel '%s' is "
+                "no longer valid.", target.inputChannel->getName().string());
+        return false;
+    }
+}
+
 void NativeInputManager::pokeUserActivityIfNeeded(int32_t windowType, int32_t eventType) {
     if (windowType != TYPE_KEYGUARD) {
         nsecs_t eventTime = now();
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 0b41dd8..59d7cde 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "GpsLocationProvider"
 
-//#define LOG_NDDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include "JNIHelp.h"
 #include "jni.h"
@@ -66,7 +66,6 @@
 
 static void location_callback(GpsLocation* location)
 {
-    LOGD("location_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
             (jdouble)location->latitude, (jdouble)location->longitude,
@@ -78,16 +77,13 @@
 
 static void status_callback(GpsStatus* status)
 {
-    LOGD("status_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    LOGD("env: %p obj: %p\n", env, mCallbacksObj);
     env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void sv_status_callback(GpsSvStatus* sv_status)
 {
-    LOGD("sv_status_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
@@ -96,7 +92,6 @@
 
 static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
 {
-    LOGD("nmea_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     // The Java code will call back to read these values
     // We do this to avoid creating unnecessary String objects
@@ -108,7 +103,6 @@
 
 static void set_capabilities_callback(uint32_t capabilities)
 {
-    LOGD("set_capabilities_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -116,19 +110,16 @@
 
 static void acquire_wakelock_callback()
 {
-    LOGD("acquire_wakelock_callback\n");
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
 }
 
 static void release_wakelock_callback()
 {
-    LOGD("release_wakelock_callback\n");
     release_wake_lock(WAKE_LOCK_NAME);
 }
 
 static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
 {
-    LOGD("create_thread_callback\n");
     return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
 }
 
@@ -146,7 +137,6 @@
 
 static void xtra_download_request_callback()
 {
-    LOGD("xtra_download_request_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -159,7 +149,6 @@
 
 static void agps_status_callback(AGpsStatus* agps_status)
 {
-    LOGD("agps_status_callback\n");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
                         agps_status->type, agps_status->status);
@@ -241,8 +230,6 @@
 
 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
 {
-    LOGD("android_location_GpsLocationProvider_init obj: %p\n", obj);
-
     // this must be set before calling into the HAL library
     if (!mCallbacksObj)
         mCallbacksObj = env->NewGlobalRef(obj);
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 8c343b5..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);
@@ -104,6 +105,8 @@
                     0,
                     fullScreenIntent,
                     PendingIntent.FLAG_CANCEL_CURRENT);
+                // if you tap on it you should get the original alert box
+                not.contentIntent = not.fullScreenIntent;
                 mNotificationManager.notify(id, not);
             }
         },