Implement ACTION_CONNECTION_STATE_CHANGED intent.

Change-Id: I6b5783c189c9796ebd85d9d54bdcb07949bef27e
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index f0252b7..1eb269d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -92,4 +92,6 @@
     List<BluetoothDevice> getConnectedPanDevices();
     boolean connectPanDevice(in BluetoothDevice device);
     boolean disconnectPanDevice(in BluetoothDevice device);
+
+    void sendConnectionStateChange(in BluetoothDevice device, int state, int prevState);
 }
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 61e2305..19f6a32 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -534,6 +534,8 @@
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
             if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
+
+            mBluetoothService.sendConnectionStateChange(device, state, prevState);
         }
     }
 
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 660f9ab..65047c0 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -162,6 +162,7 @@
     private final HashMap<BluetoothDevice, Pair<Integer, String>> mPanDevices;
     private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
 
+    private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
 
     private static String mDockAddress;
     private String mDockPin;
@@ -411,6 +412,10 @@
         mAdapterProperties.clear();
         mServiceRecordToPid.clear();
 
+        mProfilesConnected = 0;
+        mProfilesConnecting = 0;
+        mProfilesDisconnecting = 0;
+
         if (saveSetting) {
             persistBluetoothOnSetting(false);
         }
@@ -1563,6 +1568,7 @@
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         if (DBG) log("Pan Device state : device: " + device + " State:" + prevState + "->" + state);
+        sendConnectionStateChange(device, state, prevState);
     }
 
     /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
@@ -1790,7 +1796,7 @@
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         if (DBG) log("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
-
+        sendConnectionStateChange(device, state, prevState);
     }
 
     /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) {
@@ -2731,6 +2737,75 @@
         }
     }
 
+    public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
+                                                        int prevState) {
+        if (updateCountersAndCheckForConnectionStateChange(device, state, prevState)) {
+            state = getAdapterConnectionState(state);
+            prevState = getAdapterConnectionState(prevState);
+            Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+            intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, state);
+            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevState);
+            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+            log("CONNECTION_STATE_CHANGE: " + device + ": " + prevState + "-> " + state);
+        }
+    }
+
+    private int getAdapterConnectionState(int state) {
+        switch (state) {
+            case BluetoothProfile.STATE_CONNECTING:
+                return BluetoothAdapter.STATE_CONNECTING;
+            case BluetoothProfile.STATE_CONNECTED:
+              return BluetoothAdapter.STATE_CONNECTED;
+            case BluetoothProfile.STATE_DISCONNECTING:
+              return BluetoothAdapter.STATE_DISCONNECTING;
+            case BluetoothProfile.STATE_DISCONNECTED:
+              return BluetoothAdapter.STATE_DISCONNECTED;
+            default:
+              Log.e(TAG, "Error in getAdapterConnectionState");
+              return -1;
+        }
+    }
+
+    private boolean updateCountersAndCheckForConnectionStateChange(BluetoothDevice device,
+                                                                   int state,
+                                                                   int prevState) {
+        switch (state) {
+            case BluetoothProfile.STATE_CONNECTING:
+                mProfilesConnecting++;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+                if (mProfilesConnected > 0 || mProfilesConnecting > 1) return false;
+
+                break;
+            case BluetoothProfile.STATE_CONNECTED:
+                if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+
+                mProfilesConnected++;
+
+                if (mProfilesConnected > 1) return false;
+                break;
+            case BluetoothProfile.STATE_DISCONNECTING:
+                mProfilesDisconnecting++;
+                mProfilesConnected--;
+
+                if (mProfilesConnected > 0 || mProfilesDisconnecting > 1) return false;
+
+                break;
+            case BluetoothProfile.STATE_DISCONNECTED:
+                if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+
+                if (prevState == BluetoothAdapter.STATE_CONNECTED) {
+                    mProfilesConnected--;
+                }
+
+                if (mProfilesConnected  > 0 || mProfilesConnecting > 0) return false;
+                break;
+        }
+        return true;
+    }
+
     private static void log(String msg) {
         Log.d(TAG, msg);
     }