Automated import from //branches/master/...@141912,141912
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 3c50707..5c4e56d 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -58,6 +58,7 @@
     private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
 
     private static final int MESSAGE_CONNECT_TO = 1;
+    private static final int MESSAGE_DISCONNECT = 2;
 
     private final Context mContext;
     private final IntentFilter mIntentFilter;
@@ -65,6 +66,11 @@
     private final AudioManager mAudioManager;
     private final BluetoothDevice mBluetooth;
 
+    // list of disconnected sinks to process after a delay
+    private final ArrayList<String> mPendingDisconnects = new ArrayList<String>();
+    // number of active sinks
+    private int mSinkCount = 0; 
+
     private class SinkState {
         public String address;
         public int state;
@@ -164,6 +170,9 @@
                     connectSink(address);
                 }
                 break;
+            case MESSAGE_DISCONNECT:
+                handleDeferredDisconnect((String)msg.obj);
+                break;
             }
         }
     };
@@ -338,6 +347,9 @@
     }
 
     private synchronized void onSinkConnected(String path) {
+        // if we are reconnected, do not process previous disconnect event.
+        mPendingDisconnects.remove(path);
+
         if (mAudioDevices == null) return;
         // bluez 3.36 quietly disconnects the previous sink when a new sink
         // is connected, so we need to mark all previously connected sinks as
@@ -363,8 +375,23 @@
     }
 
     private synchronized void onSinkDisconnected(String path) {
-        mAudioManager.setBluetoothA2dpOn(false);
-        updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+        // This is to work around a problem in bluez that results 
+        // sink disconnect events being sent, immediately followed by a reconnect.
+        // To avoid unnecessary audio routing changes, we defer handling
+        // sink disconnects until after a short delay.
+        mPendingDisconnects.add(path);
+        Message msg = Message.obtain(mHandler, MESSAGE_DISCONNECT, path);
+        mHandler.sendMessageDelayed(msg, 2000);
+    }
+
+    private synchronized void handleDeferredDisconnect(String path) {
+        if (mPendingDisconnects.contains(path)) {
+            mPendingDisconnects.remove(path);
+            if (mSinkCount == 1) {
+                mAudioManager.setBluetoothA2dpOn(false);
+            }
+            updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+        }
     }
 
     private synchronized void onSinkPlaying(String path) {
@@ -432,6 +459,13 @@
 
         if (state != prevState) {
             if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state);
+            
+            // keep track of the number of active sinks
+            if (prevState == BluetoothA2dp.STATE_DISCONNECTED) {
+                mSinkCount++;
+            } else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
+                mSinkCount--;
+            }
 
             Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
             intent.putExtra(BluetoothIntent.ADDRESS, address);
@@ -441,7 +475,8 @@
 
             if ((prevState == BluetoothA2dp.STATE_CONNECTED ||
                  prevState == BluetoothA2dp.STATE_PLAYING) &&
-                    (state != BluetoothA2dp.STATE_CONNECTED &&
+                    (state != BluetoothA2dp.STATE_CONNECTING &&
+                     state != BluetoothA2dp.STATE_CONNECTED &&
                      state != BluetoothA2dp.STATE_PLAYING)) {
                 // disconnected
                 intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);