Merge change Ib548dbb2 into eclair

* changes:
  improve video performance to minimize the tearing effect seen in 720p movies
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/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/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 9b41f83..78215b0 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -103,7 +103,7 @@
     private boolean mSystemReady;
     private ArrayList<Intent> mDeferredBroadcasts;
 
-    private static class NetworkAttributes {
+    private class NetworkAttributes {
         /**
          * Class for holding settings read from resources.
          */
@@ -111,7 +111,6 @@
         public int mType;
         public int mRadio;
         public int mPriority;
-        public NetworkInfo.State mLastState;
         public NetworkAttributes(String init) {
             String fragments[] = init.split(",");
             mName = fragments[0].toLowerCase();
@@ -132,7 +131,6 @@
                 mType = ConnectivityManager.TYPE_MOBILE_HIPRI;
             }
             mPriority = Integer.parseInt(fragments[2]);
-            mLastState = NetworkInfo.State.UNKNOWN;
         }
         public boolean isDefault() {
             return (mType == mRadio);
@@ -140,7 +138,7 @@
     }
     NetworkAttributes[] mNetAttributes;
 
-    private static class RadioAttributes {
+    private class RadioAttributes {
         public String mName;
         public int mPriority;
         public int mSimultaneity;
@@ -1216,22 +1214,9 @@
             switch (msg.what) {
                 case NetworkStateTracker.EVENT_STATE_CHANGED:
                     info = (NetworkInfo) msg.obj;
-                    int type = info.getType();
-                    NetworkInfo.State state = info.getState();
-                    if(mNetAttributes[type].mLastState == state) {
-                        if (DBG) {
-                            // TODO - remove this after we validate the dropping doesn't break anything
-                            Log.d(TAG, "Dropping ConnectivityChange for " +
-                                    info.getTypeName() +": " +
-                                    state + "/" + info.getDetailedState());
-                        }
-                        return;
-                    }
-                    mNetAttributes[type].mLastState = state;
-
                     if (DBG) Log.d(TAG, "ConnectivityChange for " +
                             info.getTypeName() + ": " +
-                            state + "/" + info.getDetailedState());
+                            info.getState() + "/" + info.getDetailedState());
 
                     // Connectivity state changed:
                     // [31-13] Reserved for future use
@@ -1249,9 +1234,10 @@
                     if (info.getDetailedState() ==
                             NetworkInfo.DetailedState.FAILED) {
                         handleConnectionFailure(info);
-                    } else if (state == NetworkInfo.State.DISCONNECTED) {
+                    } else if (info.getState() ==
+                            NetworkInfo.State.DISCONNECTED) {
                         handleDisconnect(info);
-                    } else if (state == NetworkInfo.State.SUSPENDED) {
+                    } else if (info.getState() == NetworkInfo.State.SUSPENDED) {
                         // TODO: need to think this over.
                         // the logic here is, handle SUSPENDED the same as
                         // DISCONNECTED. The only difference being we are
@@ -1260,7 +1246,7 @@
                         // opportunity to handle DISCONNECTED and SUSPENDED
                         // differently, or not.
                         handleDisconnect(info);
-                    } else if (state == NetworkInfo.State.CONNECTED) {
+                    } else if (info.getState() == NetworkInfo.State.CONNECTED) {
                         handleConnect(info);
                     }
                     break;
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;