Merge change I0f73439a into eclair

* changes:
  Partially fix bug 2111240 Detect docking / undocking event by reporting to the AudioPolicyManager a new forced usage AudioSystem::FOR_DOCK which can take the FORCE_NONE, FORCE_BT_DOCK or FORCE_WIRED_ACCESSORY values. This CL is complemented by an update of the APM to take into account the FOR_DOCK usage.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 467812e..1115f92 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -691,6 +691,20 @@
                     if (rd != null) {
                         rd.performReceive(intent, resultCode, data, extras,
                                 ordered, sticky);
+                    } else {
+                        // The activity manager dispatched a broadcast to a registered
+                        // receiver in this process, but before it could be delivered the
+                        // receiver was unregistered.  Acknowledge the broadcast on its
+                        // behalf so that the system's broadcast sequence can continue.
+                        if (DEBUG_BROADCAST) {
+                            Log.i(TAG, "Broadcast to unregistered receiver");
+                        }
+                        IActivityManager mgr = ActivityManagerNative.getDefault();
+                        try {
+                            mgr.finishReceiver(this, resultCode, data, extras, false);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Couldn't finish broadcast to unregistered receiver");
+                        }
                     }
                 }
             }
@@ -716,8 +730,8 @@
                     BroadcastReceiver receiver = mReceiver;
                     if (DEBUG_BROADCAST) {
                         int seq = mCurIntent.getIntExtra("seq", -1);
-                        Log.i(TAG, "Dispathing broadcast " + mCurIntent.getAction() + " seq=" + seq
-                                + " to " + mReceiver);
+                        Log.i(TAG, "Dispatching broadcast " + mCurIntent.getAction()
+                                + " seq=" + seq + " to " + mReceiver);
                     }
                     if (receiver == null) {
                         return;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 7df3637..fda9b81 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -199,6 +199,22 @@
         }
     }
 
+    /** Check if any A2DP sink is in Non Disconnected state
+     * i.e playing, connected, connecting, disconnecting.
+     * @return a unmodifiable set of connected A2DP sinks, or null on error.
+     * @hide
+     */
+    public Set<BluetoothDevice> getNonDisconnectedSinks() {
+        if (DBG) log("getNonDisconnectedSinks()");
+        try {
+            return Collections.unmodifiableSet(
+                    new HashSet<BluetoothDevice>(Arrays.asList(mService.getNonDisconnectedSinks())));
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return null;
+        }
+    }
+
     /** Get the state of an A2DP sink
      *  @param device Remote BT device.
      *  @return State code, one of STATE_
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 002cf4e..168fe3b 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -29,6 +29,7 @@
     boolean suspendSink(in BluetoothDevice device);
     boolean resumeSink(in BluetoothDevice device);
     BluetoothDevice[] getConnectedSinks();  // change to Set<> once AIDL supports
+    BluetoothDevice[] getNonDisconnectedSinks();  // change to Set<> once AIDL supports
     int getSinkState(in BluetoothDevice device);
     boolean setSinkPriority(in BluetoothDevice device, int priority);
     int getSinkPriority(in BluetoothDevice device);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8f1c671..799bc22 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1142,7 +1142,6 @@
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.accounts.AccountManager} for receiving intents at a
      * time of your choosing.
-     * TODO STOPSHIP perform a final review of the the account apis before shipping
      *
      * @see #getSystemService
      * @see android.accounts.AccountManager
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8d69814..a96e896 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -540,10 +540,33 @@
  * {@link #putExtra}.
  *
  * <ul>
- *     <li> {@link #EXTRA_TEMPLATE}
+ *     <li> {@link #EXTRA_ALARM_COUNT}
+ *     <li> {@link #EXTRA_BCC}
+ *     <li> {@link #EXTRA_CC}
+ *     <li> {@link #EXTRA_CHANGED_COMPONENT_NAME}
+ *     <li> {@link #EXTRA_DATA_REMOVED}
+ *     <li> {@link #EXTRA_DOCK_STATE}
+ *     <li> {@link #EXTRA_DOCK_STATE_CAR}
+ *     <li> {@link #EXTRA_DOCK_STATE_DESK}
+ *     <li> {@link #EXTRA_DOCK_STATE_UNDOCKED}
+ *     <li> {@link #EXTRA_DONT_KILL_APP}
+ *     <li> {@link #EXTRA_EMAIL}
+ *     <li> {@link #EXTRA_INITIAL_INTENTS}
  *     <li> {@link #EXTRA_INTENT}
+ *     <li> {@link #EXTRA_KEY_EVENT}
+ *     <li> {@link #EXTRA_PHONE_NUMBER}
+ *     <li> {@link #EXTRA_REMOTE_INTENT_TOKEN}
+ *     <li> {@link #EXTRA_REPLACING}
+ *     <li> {@link #EXTRA_SHORTCUT_ICON}
+ *     <li> {@link #EXTRA_SHORTCUT_ICON_RESOURCE}
+ *     <li> {@link #EXTRA_SHORTCUT_INTENT}
  *     <li> {@link #EXTRA_STREAM}
+ *     <li> {@link #EXTRA_SHORTCUT_NAME}
+ *     <li> {@link #EXTRA_SUBJECT}
+ *     <li> {@link #EXTRA_TEMPLATE}
  *     <li> {@link #EXTRA_TEXT}
+ *     <li> {@link #EXTRA_TITLE}
+ *     <li> {@link #EXTRA_UID}
  * </ul>
  *
  * <h3>Flags</h3>
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index ac159f4..d90536c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -930,8 +930,8 @@
         /**
          * Gets the supported preview sizes.
          *
-         * @return a List of Size object. null if preview size setting is not
-         *         supported.
+         * @return a List of Size object. This method will always return a list
+         *         with at least one element.
          */
         public List<Size> getSupportedPreviewSizes() {
             String str = get(KEY_PREVIEW_SIZE + SUPPORTED_VALUES_SUFFIX);
@@ -1065,8 +1065,8 @@
         /**
          * Gets the supported preview formats.
          *
-         * @return a List of Integer objects. null if preview format setting is
-         *         not supported.
+         * @return a List of Integer objects. This method will always return a
+         *         list with at least one element.
          */
         public List<Integer> getSupportedPreviewFormats() {
             String str = get(KEY_PREVIEW_FORMAT + SUPPORTED_VALUES_SUFFIX);
@@ -1104,8 +1104,8 @@
         /**
          * Gets the supported picture sizes.
          *
-         * @return a List of Size objects. null if picture size setting is not
-         *         supported.
+         * @return a List of Size objects. This method will always return a list
+         *         with at least one element.
          */
         public List<Size> getSupportedPictureSizes() {
             String str = get(KEY_PICTURE_SIZE + SUPPORTED_VALUES_SUFFIX);
@@ -1143,12 +1143,18 @@
         /**
          * Gets the supported picture formats.
          *
-         * @return a List of Integer objects (values are PixelFormat.XXX). null
-         *         if picture setting is not supported.
+         * @return a List of Integer objects (values are PixelFormat.XXX). This
+         *         method will always return a list with at least one element.
          */
         public List<Integer> getSupportedPictureFormats() {
-            String str = get(KEY_PICTURE_SIZE + SUPPORTED_VALUES_SUFFIX);
-            return splitInt(str);
+            String str = get(KEY_PICTURE_FORMAT + SUPPORTED_VALUES_SUFFIX);
+            ArrayList<Integer> formats = new ArrayList<Integer>();
+            for (String s : split(str)) {
+                int f = pixelFormatForCameraFormat(s);
+                if (f == PixelFormat.UNKNOWN) continue;
+                formats.add(f);
+            }
+            return formats;
         }
 
         private String cameraFormatForPixelFormat(int pixel_format) {
@@ -1443,8 +1449,8 @@
         /**
          * Gets the supported focus modes.
          *
-         * @return a List of FOCUS_MODE_XXX string constants. null if focus mode
-         *         setting is not supported.
+         * @return a List of FOCUS_MODE_XXX string constants. This method will
+         *         always return a list with at least one element.
          */
         public List<String> getSupportedFocusModes() {
             String str = get(KEY_FOCUS_MODE + SUPPORTED_VALUES_SUFFIX);
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 46de708..f2e132b5 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -376,6 +376,16 @@
         return sinks.toArray(new BluetoothDevice[sinks.size()]);
     }
 
+    public synchronized BluetoothDevice[] getNonDisconnectedSinks() {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+                new int[] {BluetoothA2dp.STATE_CONNECTED,
+                           BluetoothA2dp.STATE_PLAYING,
+                           BluetoothA2dp.STATE_CONNECTING,
+                           BluetoothA2dp.STATE_DISCONNECTING});
+        return sinks.toArray(new BluetoothDevice[sinks.size()]);
+    }
+
     public synchronized int getSinkState(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         Integer state = mAudioDevices.get(device);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index e960491..0d0d245 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -546,12 +546,14 @@
 
         boolean authorized = false;
         ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
+        BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+
         // Bluez sends the UUID of the local service being accessed, _not_ the
         // remote service
         if (mBluetoothService.isEnabled() &&
                 (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
-                        || BluetoothUuid.isAdvAudioDist(uuid))) {
-            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+                        || BluetoothUuid.isAdvAudioDist(uuid)) &&
+                        (a2dp.getNonDisconnectedSinks().size() == 0)) {
             BluetoothDevice device = mAdapter.getRemoteDevice(address);
             authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
             if (authorized) {
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 957f2dd..b6ac14a 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -40,27 +40,36 @@
     }
 
     public void uploadToTexture(int baseMipLevel) {
+        mRS.validate();
+        mRS.validateSurface();
         mRS.nAllocationUploadToTexture(mID, baseMipLevel);
     }
 
     public void uploadToBufferObject() {
+        mRS.validate();
+        mRS.validateSurface();
         mRS.nAllocationUploadToBufferObject(mID);
     }
 
     public void data(int[] d) {
+        mRS.validate();
         subData1D(0, mType.getElementCount(), d);
     }
     public void data(short[] d) {
+        mRS.validate();
         subData1D(0, mType.getElementCount(), d);
     }
     public void data(byte[] d) {
+        mRS.validate();
         subData1D(0, mType.getElementCount(), d);
     }
     public void data(float[] d) {
+        mRS.validate();
         subData1D(0, mType.getElementCount(), d);
     }
 
     private void data1DChecks(int off, int count, int len, int dataSize) {
+        mRS.validate();
         if((off < 0) || (count < 1) || ((off + count) > mType.getElementCount())) {
             throw new IllegalArgumentException("Offset or Count out of bounds.");
         }
@@ -93,30 +102,37 @@
 
 
     public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
+        mRS.validate();
         mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
     }
 
     public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
+        mRS.validate();
         mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
     }
 
     public void readData(int[] d) {
+        mRS.validate();
         mRS.nAllocationRead(mID, d);
     }
 
     public void readData(float[] d) {
+        mRS.validate();
         mRS.nAllocationRead(mID, d);
     }
 
     public void data(Object o) {
+        mRS.validate();
         mRS.nAllocationSubDataFromObject(mID, mType, 0, o);
     }
 
     public void read(Object o) {
+        mRS.validate();
         mRS.nAllocationSubReadFromObject(mID, mType, 0, o);
     }
 
     public void subData(int offset, Object o) {
+        mRS.validate();
         mRS.nAllocationSubDataFromObject(mID, mType, offset, o);
     }
 
@@ -127,27 +143,33 @@
         }
 
         public void setConstraint(Dimension dim, int value) {
+            mRS.validate();
             mRS.nAdapter1DSetConstraint(mID, dim.mID, value);
         }
 
         public void data(int[] d) {
+            mRS.validate();
             mRS.nAdapter1DData(mID, d);
         }
 
         public void data(float[] d) {
+            mRS.validate();
             mRS.nAdapter1DData(mID, d);
         }
 
         public void subData(int off, int count, int[] d) {
+            mRS.validate();
             mRS.nAdapter1DSubData(mID, off, count, d);
         }
 
         public void subData(int off, int count, float[] d) {
+            mRS.validate();
             mRS.nAdapter1DSubData(mID, off, count, d);
         }
     }
 
     public Adapter1D createAdapter1D() {
+        mRS.validate();
         int id = mRS.nAdapter1DCreate();
         if (id != 0) {
             mRS.nAdapter1DBindAllocation(id, mID);
@@ -163,27 +185,33 @@
         }
 
         public void setConstraint(Dimension dim, int value) {
+            mRS.validate();
             mRS.nAdapter2DSetConstraint(mID, dim.mID, value);
         }
 
         public void data(int[] d) {
+            mRS.validate();
             mRS.nAdapter2DData(mID, d);
         }
 
         public void data(float[] d) {
+            mRS.validate();
             mRS.nAdapter2DData(mID, d);
         }
 
         public void subData(int xoff, int yoff, int w, int h, int[] d) {
+            mRS.validate();
             mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
         }
 
         public void subData(int xoff, int yoff, int w, int h, float[] d) {
+            mRS.validate();
             mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
         }
     }
 
     public Adapter2D createAdapter2D() {
+        mRS.validate();
         int id = mRS.nAdapter2DCreate();
         if (id != 0) {
             mRS.nAdapter2DBindAllocation(id, mID);
@@ -202,6 +230,7 @@
     static public Allocation createTyped(RenderScript rs, Type type)
         throws IllegalArgumentException {
 
+        rs.validate();
         if(type.mID == 0) {
             throw new IllegalStateException("Bad Type");
         }
@@ -212,6 +241,7 @@
     static public Allocation createSized(RenderScript rs, Element e, int count)
         throws IllegalArgumentException {
 
+        rs.validate();
         Type.Builder b = new Type.Builder(rs, e);
         b.add(Dimension.X, count);
         Type t = b.create();
@@ -226,6 +256,7 @@
     static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
         throws IllegalArgumentException {
 
+        rs.validate();
         int id = rs.nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
         return new Allocation(id, rs, null);
     }
@@ -233,6 +264,7 @@
     static public Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
         throws IllegalArgumentException {
 
+        rs.validate();
         int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
         return new Allocation(id, rs, null);
     }
@@ -240,6 +272,7 @@
     static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
         throws IllegalArgumentException {
 
+        rs.validate();
         InputStream is = null;
         try {
             final TypedValue value = new TypedValue();
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 73d8266..ee9b098 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -284,6 +284,7 @@
     }
 
     public static Element createFromClass(RenderScript rs, Class c) {
+        rs.validate();
         Field[] fields = c.getFields();
         Builder b = new Builder(rs);
 
@@ -322,6 +323,7 @@
     }
 
     void init() {
+        mRS.validate();
         internalCreate(mRS, this);
     }
 
@@ -483,6 +485,7 @@
         }
 
         public Element create() {
+            mRS.validate();
             Element e = new Element(mRS, mEntryCount);
             java.lang.System.arraycopy(mEntries, 0, e.mEntries, 0, mEntryCount);
             e.init();
diff --git a/graphics/java/android/renderscript/Light.java b/graphics/java/android/renderscript/Light.java
index 115ae03..aab656f 100644
--- a/graphics/java/android/renderscript/Light.java
+++ b/graphics/java/android/renderscript/Light.java
@@ -30,10 +30,12 @@
     }
 
     public void setColor(float r, float g, float b) {
+        mRS.validate();
         mRS.nLightSetColor(mID, r, g, b);
     }
 
     public void setPosition(float x, float y, float z) {
+        mRS.validate();
         mRS.nLightSetPosition(mID, x, y, z);
     }
 
@@ -65,6 +67,7 @@
         }
 
         public Light create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 392d93d..1a72578 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -47,6 +47,7 @@
 
     public void bindTexture(Allocation va, int slot)
         throws IllegalArgumentException {
+        mRS.validate();
         if((slot < 0) || (slot >= MAX_SLOT)) {
             throw new IllegalArgumentException("Slot ID out of range.");
         }
@@ -56,6 +57,7 @@
 
     public void bindSampler(Sampler vs, int slot)
         throws IllegalArgumentException {
+        mRS.validate();
         if((slot < 0) || (slot >= MAX_SLOT)) {
             throw new IllegalArgumentException("Slot ID out of range.");
         }
@@ -149,6 +151,7 @@
         }
 
         public ProgramFragment create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java
index ab327f1..56f9bf4 100644
--- a/graphics/java/android/renderscript/ProgramRaster.java
+++ b/graphics/java/android/renderscript/ProgramRaster.java
@@ -46,11 +46,13 @@
     }
 
     public void setLineWidth(float w) {
+        mRS.validate();
         mLineWidth = w;
         mRS.nProgramRasterSetLineWidth(mID, w);
     }
 
     public void setPointSize(float s) {
+        mRS.validate();
         mPointSize = s;
         mRS.nProgramRasterSetPointSize(mID, s);
     }
@@ -98,6 +100,7 @@
         }
 
         public ProgramRaster create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index 5cbe1b2..69be245 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -162,6 +162,7 @@
         }
 
         public ProgramStore create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index ddb23ac..ba97d5b 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -34,6 +34,7 @@
     }
 
     public void bindAllocation(MatrixAllocation va) {
+        mRS.validate();
         mRS.nProgramVertexBindAllocation(mID, va.mAlloc.mID);
     }
 
@@ -88,6 +89,7 @@
         }
 
         public ProgramVertex create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index c42f647..0d8b675 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -242,6 +242,18 @@
         }
     }
 
+    void validate() {
+        if (mContext == 0) {
+            throw new IllegalStateException("Calling RS with no Context active.");
+        }
+    }
+
+    void validateSurface() {
+        if (mSurface == null) {
+            throw new IllegalStateException("Uploading data to GL with no surface.");
+        }
+    }
+
     public void contextSetPriority(Priority p) {
         nContextSetPriority(p.mID);
     }
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
index 5e0b110..625a576 100644
--- a/graphics/java/android/renderscript/Sampler.java
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -100,6 +100,7 @@
         }
 
         public Sampler create() {
+            mRS.validate();
             return internalCreate(mRS, this);
         }
     }
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 35791a3..57ccfa3 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -48,22 +48,27 @@
     }
 
     public void bindAllocation(Allocation va, int slot) {
+        mRS.validate();
         mRS.nScriptBindAllocation(mID, va.mID, slot);
     }
 
     public void setClearColor(float r, float g, float b, float a) {
+        mRS.validate();
         mRS.nScriptSetClearColor(mID, r, g, b, a);
     }
 
     public void setClearDepth(float d) {
+        mRS.validate();
         mRS.nScriptSetClearDepth(mID, d);
     }
 
     public void setClearStencil(int stencil) {
+        mRS.validate();
         mRS.nScriptSetClearStencil(mID, stencil);
     }
 
     public void setTimeZone(String timeZone) {
+        mRS.validate();
         try {
             mRS.nScriptSetTimeZone(mID, timeZone.getBytes("UTF-8"));
         } catch (java.io.UnsupportedEncodingException e) {
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index 3d10e3b..f45074e 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -35,18 +35,22 @@
     }
 
     public void bindVertexAllocation(Allocation a, int slot) {
+        mRS.validate();
         mRS.nSimpleMeshBindVertex(mID, a.mID, slot);
     }
 
     public void bindIndexAllocation(Allocation a) {
+        mRS.validate();
         mRS.nSimpleMeshBindIndex(mID, a.mID);
     }
 
     public Allocation createVertexAllocation(int slot) {
+        mRS.validate();
         return Allocation.createTyped(mRS, mVertexTypes[slot]);
     }
 
     public Allocation createIndexAllocation() {
+        mRS.validate();
         return Allocation.createTyped(mRS, mIndexType);
     }
 
@@ -162,6 +166,7 @@
         }
 
         public SimpleMesh create() {
+            mRS.validate();
             SimpleMesh sm = internalCreate(mRS, this);
             sm.mVertexTypes = new Type[mVertexTypeCount];
             for(int ct=0; ct < mVertexTypeCount; ct++) {
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index f3f6e4f..2024cc0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1111,7 +1111,6 @@
 {
     track->mState = TrackBase::TERMINATED;
     if (mActiveTracks.indexOf(track) < 0) {
-        LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
         deleteTrackName_l(track->name());
     }
@@ -1511,6 +1510,7 @@
 // deleteTrackName_l() must be called with ThreadBase::mLock held
 void AudioFlinger::MixerThread::deleteTrackName_l(int name)
 {
+    LOGV("remove track (%d) and delete from mixer", name);
     mAudioMixer->deleteTrackName(name);
 }
 
@@ -1922,6 +1922,9 @@
 
 AudioFlinger::DuplicatingThread::~DuplicatingThread()
 {
+    for (size_t i = 0; i < mOutputTracks.size(); i++) {
+        mOutputTracks[i]->destroy();
+    }
     mOutputTracks.clear();
 }
 
@@ -2044,17 +2047,6 @@
         outputTracks.clear();
     }
 
-    { // scope for the mLock
-
-        Mutex::Autolock _l(mLock);
-        if (!mStandby) {
-            LOGV("DuplicatingThread() exiting out of standby");
-            for (size_t i = 0; i < mOutputTracks.size(); i++) {
-                mOutputTracks[i]->destroy();
-            }
-        }
-    }
-
     return false;
 }
 
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 52074ca..3652f0a 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -113,14 +113,14 @@
 }
 
 
-bool Context::runScript(Script *s, uint32_t launchID)
+uint32_t Context::runScript(Script *s, uint32_t launchID)
 {
     ObjectBaseRef<ProgramFragment> frag(mFragment);
     ObjectBaseRef<ProgramVertex> vtx(mVertex);
     ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore);
     ObjectBaseRef<ProgramRaster> raster(mRaster);
 
-    bool ret = s->run(this, launchID);
+    uint32_t ret = s->run(this, launchID);
 
     mFragment.set(frag);
     mVertex.set(vtx);
@@ -130,11 +130,9 @@
 }
 
 
-bool Context::runRootScript()
+uint32_t Context::runRootScript()
 {
-    if (props.mLogTimes) {
-        timerSet(RS_TIMER_CLEAR_SWAP);
-    }
+    timerSet(RS_TIMER_CLEAR_SWAP);
     rsAssert(mRootScript->mEnviroment.mIsRoot);
 
     eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
@@ -154,11 +152,9 @@
         glClear(GL_COLOR_BUFFER_BIT);
     }
 
-    if (this->props.mLogTimes) {
-        timerSet(RS_TIMER_SCRIPT);
-    }
+    timerSet(RS_TIMER_SCRIPT);
     mStateFragmentStore.mLast.clear();
-    bool ret = runScript(mRootScript.get(), 0);
+    uint32_t ret = runScript(mRootScript.get(), 0);
 
     GLenum err = glGetError();
     if (err != GL_NO_ERROR) {
@@ -212,13 +208,19 @@
         total += mTimers[ct];
     }
     uint64_t frame = mTimeFrame - mTimeLastFrame;
+    mTimeMSLastFrame = frame / 1000000;
+    mTimeMSLastScript = mTimers[RS_TIMER_SCRIPT] / 1000000;
+    mTimeMSLastSwap = mTimers[RS_TIMER_CLEAR_SWAP] / 1000000;
 
-    LOGV("RS: Frame (%lli),   Script %2.1f (%lli),  Clear & Swap %2.1f (%lli),  Idle %2.1f (%lli),  Internal %2.1f (%lli)",
-         frame / 1000000,
-         100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000,
-         100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimers[RS_TIMER_CLEAR_SWAP] / 1000000,
-         100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
-         100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000);
+
+    if (props.mLogTimes) {
+        LOGV("RS: Frame (%i),   Script %2.1f (%i),  Clear & Swap %2.1f (%i),  Idle %2.1f (%lli),  Internal %2.1f (%lli)",
+             mTimeMSLastFrame,
+             100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimeMSLastScript,
+             100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimeMSLastSwap,
+             100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
+             100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000);
+    }
 }
 
 void Context::setupCheck()
@@ -242,6 +244,7 @@
      rsc->mNativeThreadId = gettid();
 
      setpriority(PRIO_PROCESS, rsc->mNativeThreadId, ANDROID_PRIORITY_DISPLAY);
+     rsc->mThreadPriority = ANDROID_PRIORITY_DISPLAY;
 
      rsc->props.mLogTimes = getProp("debug.rs.profile");
      rsc->props.mLogScripts = getProp("debug.rs.script");
@@ -279,22 +282,26 @@
          mDraw &= (rsc->mRootScript.get() != NULL);
          mDraw &= (rsc->mWndSurface != NULL);
 
+         uint32_t targetTime = 0;
          if (mDraw) {
-             mDraw = rsc->runRootScript() && !rsc->mPaused;
-             if (rsc->props.mLogTimes) {
-                 rsc->timerSet(RS_TIMER_CLEAR_SWAP);
-             }
+             targetTime = rsc->runRootScript();
+             mDraw = targetTime && !rsc->mPaused;
+             rsc->timerSet(RS_TIMER_CLEAR_SWAP);
              eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
-             if (rsc->props.mLogTimes) {
-                 rsc->timerFrame();
-                 rsc->timerSet(RS_TIMER_INTERNAL);
-                 rsc->timerPrint();
-                 rsc->timerReset();
-             }
+             rsc->timerFrame();
+             rsc->timerSet(RS_TIMER_INTERNAL);
+             rsc->timerPrint();
+             rsc->timerReset();
          }
          if (rsc->mObjDestroy.mNeedToEmpty) {
              rsc->objDestroyOOBRun();
          }
+         if (rsc->mThreadPriority > 0 && targetTime) {
+             int32_t t = (targetTime - (int32_t)(rsc->mTimeMSLastScript + rsc->mTimeMSLastSwap)) * 1000;
+             if (t > 0) {
+                 usleep(t);
+             }
+         }
      }
 
      LOGV("RS Thread exiting");
@@ -330,6 +337,7 @@
     // the wallpapers can become completly unresponsive at times.
     // This is probably not what we want for something the user is actively
     // looking at.
+    mThreadPriority = p;
 #if 0
     SchedPolicy pol = SP_FOREGROUND;
     if (p > 0) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 4e0f653..1770ee6 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -105,7 +105,7 @@
 
     uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait);
     bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace);
-    bool runScript(Script *s, uint32_t launchID);
+    uint32_t runScript(Script *s, uint32_t launchID);
 
     void initToClient();
     void deinitToClient();
@@ -194,6 +194,7 @@
 
     uint32_t mWidth;
     uint32_t mHeight;
+    int32_t mThreadPriority;
 
     bool mRunning;
     bool mExit;
@@ -226,7 +227,7 @@
     void initEGL();
     void deinitEGL();
 
-    bool runRootScript();
+    uint32_t runRootScript();
 
     static void * threadProc(void *);
 
@@ -241,6 +242,9 @@
     uint64_t mTimeLast;
     uint64_t mTimeFrame;
     uint64_t mTimeLastFrame;
+    uint32_t mTimeMSLastFrame;
+    uint32_t mTimeMSLastScript;
+    uint32_t mTimeMSLastSwap;
 };
 
 }
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index bc40854..5f4a536 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -70,7 +70,7 @@
 
 
     virtual void setupScript() = 0;
-    virtual bool run(Context *, uint32_t launchID) = 0;
+    virtual uint32_t run(Context *, uint32_t launchID) = 0;
 };
 
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 073d98b..f11b862 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -60,7 +60,7 @@
 }
 
 
-bool ScriptC::run(Context *rsc, uint32_t launchIndex)
+uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex)
 {
     Context::ScriptTLSStruct * tls =
     (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
@@ -85,9 +85,9 @@
     }
     setupScript();
 
-    bool ret = false;
+    uint32_t ret = 0;
     tls->mScript = this;
-    ret = mProgram.mScript(launchIndex) != 0;
+    ret = mProgram.mScript(launchIndex);
     tls->mScript = NULL;
     return ret;
 }
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 69afc18..35abadf 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -55,7 +55,7 @@
     ACCscript*    mAccScript;
 
     virtual void setupScript();
-    virtual bool run(Context *, uint32_t launchID);
+    virtual uint32_t run(Context *, uint32_t launchID);
 };
 
 class ScriptCState
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index eb017bf..137c5c0 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -120,9 +120,7 @@
         source->onTransaction(flags);
     uint32_t res = LayerBase::doTransaction(flags);
     // we always want filtering for these surfaces
-    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
-        mUseLinearFiltering = true;
-    }
+    mUseLinearFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
     return res;
 }
 
@@ -371,25 +369,33 @@
         // note that the size of this buffer doesn't really matter,
         // the final image will always be drawn with proper aspect ratio.
 
-        int w = buffers.w;
-        int h = buffers.h;
+        int w = layer.mTransformedBounds.width();
+        int h = layer.mTransformedBounds.height();
+        if (buffers.w * h != buffers.h * w) {
+            int t = w; w = h; h = t;
+        }
+        if (buffers.w * h == buffers.h * w) {
+            // same pixel area, don't use filtering
+            layer.mUseLinearFiltering = false;
+        }
+
         mTempGraphicBuffer.clear();
         mTempGraphicBuffer = new GraphicBuffer(
-                w, h, HAL_PIXEL_FORMAT_RGBX_8888,
+                w, h, HAL_PIXEL_FORMAT_RGB_565,
                 GraphicBuffer::USAGE_HW_TEXTURE |
                 GraphicBuffer::USAGE_HW_2D);
 
         if (mTempGraphicBuffer->initCheck() == NO_ERROR) {
             NativeBuffer& dst(mTempBuffer);
             dst.img.w = mTempGraphicBuffer->getStride();
-            dst.img.h = mTempGraphicBuffer->getHeight();
+            dst.img.h = h;
             dst.img.format = mTempGraphicBuffer->getPixelFormat();
             dst.img.handle = (native_handle_t *)mTempGraphicBuffer->handle;
             dst.img.base = 0;
             dst.crop.l = 0;
             dst.crop.t = 0;
-            dst.crop.r = mTempGraphicBuffer->getWidth();
-            dst.crop.b = mTempGraphicBuffer->getHeight();
+            dst.crop.r = w;
+            dst.crop.b = h;
         } else {
             mTempGraphicBuffer.clear();
         }
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index cd62ed1..7763549 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -875,53 +875,51 @@
         synchronized(mListeners) {
             boolean wasNavigating = mNavigating;
             mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
-    
-            if (wasNavigating == mNavigating) {
-                return;
-            }
-            
-            if (mNavigating) {
+
+            if (mNavigating && !mWakeLock.isHeld()) {
                 if (DEBUG) Log.d(TAG, "Acquiring wakelock");
                  mWakeLock.acquire();
             }
-        
-            int size = mListeners.size();
-            for (int i = 0; i < size; i++) {
-                Listener listener = mListeners.get(i);
+
+            if (wasNavigating != mNavigating) {
+                int size = mListeners.size();
+                for (int i = 0; i < size; i++) {
+                    Listener listener = mListeners.get(i);
+                    try {
+                        if (mNavigating) {
+                            listener.mListener.onGpsStarted();
+                        } else {
+                            listener.mListener.onGpsStopped();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException in reportStatus");
+                        mListeners.remove(listener);
+                        // adjust for size of list changing
+                        size--;
+                    }
+                }
+
                 try {
-                    if (mNavigating) {
-                        listener.mListener.onGpsStarted(); 
-                    } else {
-                        listener.mListener.onGpsStopped(); 
+                    // update battery stats
+                    for (int i=mClientUids.size() - 1; i >= 0; i--) {
+                        int uid = mClientUids.keyAt(i);
+                        if (mNavigating) {
+                            mBatteryStats.noteStartGps(uid);
+                        } else {
+                            mBatteryStats.noteStopGps(uid);
+                        }
                     }
                 } catch (RemoteException e) {
                     Log.w(TAG, "RemoteException in reportStatus");
-                    mListeners.remove(listener);
-                    // adjust for size of list changing
-                    size--;
                 }
+
+                // send an intent to notify that the GPS has been enabled or disabled.
+                Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
+                intent.putExtra(EXTRA_ENABLED, mNavigating);
+                mContext.sendBroadcast(intent);
             }
 
-            try {
-                // update battery stats
-                for (int i=mClientUids.size() - 1; i >= 0; i--) {
-                    int uid = mClientUids.keyAt(i);
-                    if (mNavigating) {
-                        mBatteryStats.noteStartGps(uid);
-                    } else {
-                        mBatteryStats.noteStopGps(uid);
-                    }
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "RemoteException in reportStatus");
-            }
-
-            // send an intent to notify that the GPS has been enabled or disabled.
-            Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
-            intent.putExtra(EXTRA_ENABLED, mNavigating);
-            mContext.sendBroadcast(intent);
-
-            if (!mNavigating) {
+            if (status == GPS_STATUS_ENGINE_OFF && mWakeLock.isHeld()) {
                 if (DEBUG) Log.d(TAG, "Releasing wakelock");
                 mWakeLock.release();
             }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 32ad6c6..b29e769 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -25,6 +25,7 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -62,6 +63,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -109,7 +111,7 @@
     private int mMulticastDisabled;
 
     private final IBatteryStats mBatteryStats;
-    
+
     /**
      * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a
      * Settings.Gservices value is not present. This timeout value is chosen as
@@ -161,7 +163,7 @@
      * Last UID that asked to enable WIFI.
      */
     private int mLastEnableUid = Process.myUid();
-    
+
     /**
      * Number of allowed radio frequency channels in various regulatory domains.
      * This list is sufficient for 802.11b/g networks (2.4GHz range).
@@ -176,7 +178,7 @@
         mWifiStateTracker = tracker;
         mWifiStateTracker.enableRssiPolling(true);
         mBatteryStats = BatteryStatsService.getService();
-        
+
         mScanResultCache = new LinkedHashMap<String, ScanResult>(
             SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
                 /*
@@ -395,7 +397,7 @@
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-        
+
         // Update state
         mWifiState = wifiState;
 
@@ -1365,11 +1367,16 @@
                 }
                 mPluggedType = pluggedType;
             } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
-                boolean isBluetoothPlaying =
-                        intent.getIntExtra(
-                                BluetoothA2dp.EXTRA_SINK_STATE,
-                                BluetoothA2dp.STATE_DISCONNECTED) == BluetoothA2dp.STATE_PLAYING;
+                BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+                Set<BluetoothDevice> sinks = a2dp.getConnectedSinks();
+                boolean isBluetoothPlaying = false;
+                for (BluetoothDevice sink : sinks) {
+                    if (a2dp.getSinkState(sink) == BluetoothA2dp.STATE_PLAYING) {
+                        isBluetoothPlaying = true;
+                    }
+                }
                 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
+
             } else {
                 return;
             }
@@ -1381,7 +1388,7 @@
          * Determines whether the Wi-Fi chipset should stay awake or be put to
          * sleep. Looks at the setting for the sleep policy and the current
          * conditions.
-         * 
+         *
          * @see #shouldDeviceStayAwake(int, int)
          */
         private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
@@ -1400,7 +1407,7 @@
                 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
             }
         }
-        
+
         /**
          * Determine whether the bit value corresponding to {@code pluggedType} is set in
          * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
@@ -1489,7 +1496,7 @@
         intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter);
     }
-    
+
     private boolean isAirplaneSensitive() {
         String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
                 Settings.System.AIRPLANE_MODE_RADIOS);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 44c9f0f..cd74522 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6014,7 +6014,9 @@
                 
                 if (res != null && returnWhat == RETURN_PENDING_POINTER) {
                     synchronized (mWindowMap) {
-                        if (mWallpaperTarget == win || mSendingPointersToWallpaper) {
+                        if ((mWallpaperTarget == win &&
+                                win.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD)
+                                || mSendingPointersToWallpaper) {
                             sendPointerToWallpaperLocked(win, res, res.getEventTime());
                         }
                     }
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 2b9d18f..bee0930 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -283,7 +283,7 @@
     private IBinder mBluetoothIcon;
     private IconData mBluetoothData;
     private int mBluetoothHeadsetState;
-    private int mBluetoothA2dpState;
+    private boolean mBluetoothA2dpConnected;
     private int mBluetoothPbapState;
     private boolean mBluetoothEnabled;
 
@@ -455,7 +455,7 @@
         } else {
             mBluetoothEnabled = false;
         }
-        mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
+        mBluetoothA2dpConnected = false;
         mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
         mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
         mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
@@ -636,12 +636,12 @@
         int flags =  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                 | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-        
+
         if (!mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_slowBlur)) {
             flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
         }
-        
+
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -1083,7 +1083,6 @@
 
     private final void updateBluetooth(Intent intent) {
         int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
-
         String action = intent.getAction();
         if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
             int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
@@ -1092,8 +1091,12 @@
             mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
                     BluetoothHeadset.STATE_ERROR);
         } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
-            mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE,
-                    BluetoothA2dp.STATE_DISCONNECTED);
+            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+            if (a2dp.getConnectedSinks().size() != 0) {
+                mBluetoothA2dpConnected = true;
+            } else {
+                mBluetoothA2dpConnected = false;
+            }
         } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
             mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
                     BluetoothPbap.STATE_DISCONNECTED);
@@ -1101,9 +1104,7 @@
             return;
         }
 
-        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
-                mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
-                mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
+        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
                 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
             iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
         }
diff --git a/tests/LotsOfApps/Android.mk b/tests/LotsOfApps/Android.mk
index 3019f5c..8d0cfa3 100644
--- a/tests/LotsOfApps/Android.mk
+++ b/tests/LotsOfApps/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index fc750e2..1e322bd 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -255,6 +255,8 @@
                 mWifiStateTracker.notifyDriverStopped();
             } else if (state.equals("STARTED")) {
                 mWifiStateTracker.notifyDriverStarted();
+            } else if (state.equals("HANGED")) {
+                mWifiStateTracker.notifyDriverHung();
             }
         }
 
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index b7d3a6e..f97f21b 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -87,12 +87,19 @@
     /**
      * The driver is started or stopped. The object will be the state: true for
      * started, false for stopped.
-     */ 
+     */
     private static final int EVENT_DRIVER_STATE_CHANGED              = 12;
     private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT     = 13;
     private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT  = 14;
 
     /**
+     * The driver state indication.
+     */
+    private static final int DRIVER_STARTED                          = 0;
+    private static final int DRIVER_STOPPED                          = 1;
+    private static final int DRIVER_HUNG                             = 2;
+
+    /**
      * Interval in milliseconds between polling for connection
      * status items that are not sent via asynchronous events.
      * An example is RSSI (signal strength).
@@ -556,7 +563,7 @@
         mRunState = RUN_STATE_STOPPED;
 
         // Send a driver stopped message to our handler
-        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, 0, 0).sendToTarget();
+        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, DRIVER_STOPPED, 0).sendToTarget();
     }
 
     /**
@@ -565,9 +572,17 @@
      */
     void notifyDriverStarted() {
         // Send a driver started message to our handler
-        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, 1, 0).sendToTarget();
+        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, DRIVER_STARTED, 0).sendToTarget();
     }
-    
+
+    /**
+     * Send the tracker a notification that the Wi-Fi driver has hung and needs restarting.
+     */
+    void notifyDriverHung() {
+        // Send a driver hanged message to our handler
+        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, DRIVER_HUNG, 0).sendToTarget();
+    }
+
     /**
      * Set the interval timer for polling connection information
      * that is not delivered asynchronously.
@@ -1155,17 +1170,16 @@
                     }
                 }
                 break;
-                
+
             case EVENT_DRIVER_STATE_CHANGED:
-                boolean driverStarted = msg.arg1 != 0;
-                
                 // Wi-Fi driver state changed:
-                // [31- 1] Reserved for future use
-                // [ 0- 0] Driver start (1) or stopped (0)   
-                eventLogParam = driverStarted ? 1 : 0;
-                EventLog.writeEvent(EVENTLOG_DRIVER_STATE_CHANGED, eventLogParam);
-                
-                if (driverStarted) {
+                // 0 STARTED
+                // 1 STOPPED
+                // 2 HUNG
+                EventLog.writeEvent(EVENTLOG_DRIVER_STATE_CHANGED, msg.arg1);
+
+                switch (msg.arg1) {
+                case DRIVER_STARTED:
                     /**
                      * Set the number of allowed radio channels according
                      * to the system setting, since it gets reset by the
@@ -1184,6 +1198,15 @@
                             }
                         }
                     }
+                    break;
+                case DRIVER_HUNG:
+                    Log.e(TAG, "Wifi Driver reports HUNG - reloading.");
+                    /**
+                     * restart the driver - toggle off and on
+                     */
+                    mWM.setWifiEnabled(false);
+                    mWM.setWifiEnabled(true);
+                    break;
                 }
                 noteRunState();
                 break;