Update code for public Bluetooth APIs

Change-Id: Iab22e4ae3206f9085b2d53b8b18dc2abd6197226
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
index 0835431..947eaf6 100644
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
@@ -26,6 +26,7 @@
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -99,28 +100,26 @@
                     cachedDeviceMgr.showUnbondMessage(device, reason);
                 }
 
-            } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
-                int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);
-                int oldState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, 0);
-                if (newState == BluetoothHeadset.STATE_DISCONNECTED &&
-                        oldState == BluetoothHeadset.STATE_CONNECTING) {
+            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+                int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+                int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+                if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+                        oldState == BluetoothProfile.STATE_CONNECTING) {
                     Log.i(TAG, "Failed to connect BT headset");
                 }
 
                 mManager.getCachedDeviceManager().onProfileStateChanged(device,
-                        Profile.HEADSET, newState);
-
-            } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
-                int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
-                int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
-                if (newState == BluetoothA2dp.STATE_DISCONNECTED &&
-                        oldState == BluetoothA2dp.STATE_CONNECTING) {
+                    Profile.HEADSET, newState);
+            } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
+                int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+                int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+                if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+                        oldState == BluetoothProfile.STATE_CONNECTING) {
                     Log.i(TAG, "Failed to connect BT A2DP");
                 }
 
                 mManager.getCachedDeviceManager().onProfileStateChanged(device,
                         Profile.A2DP, newState);
-
             } else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
                 final int newState = intent.getIntExtra(
                         BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, 0);
@@ -191,9 +190,9 @@
         filter.addAction(BluetoothDevice.ACTION_PAIRING_CANCEL);
 
         // Fine-grained state broadcasts
-        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
-        filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
         filter.addAction(BluetoothPan.ACTION_PAN_STATE_CHANGED);
+        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_UUID);
 
diff --git a/src/com/android/settings/bluetooth/DockEventReceiver.java b/src/com/android/settings/bluetooth/DockEventReceiver.java
index 6d11972..88bc02f 100644
--- a/src/com/android/settings/bluetooth/DockEventReceiver.java
+++ b/src/com/android/settings/bluetooth/DockEventReceiver.java
@@ -23,6 +23,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -80,7 +81,12 @@
                     if (DEBUG) Log.e(TAG, "Unknown state");
                     break;
             }
-        } else if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction()) ||
+                   BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+                    BluetoothProfile.STATE_CONNECTED);
+            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+
             /*
              *  Reconnect to the dock if:
              *  1) it is a dock
@@ -93,35 +99,8 @@
                 return;
             }
 
-            int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
-                    BluetoothHeadset.STATE_CONNECTED);
-            if (newState != BluetoothHeadset.STATE_DISCONNECTED) return;
-
-            int source = intent.getIntExtra(BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR,
-                    BluetoothHeadset.LOCAL_DISCONNECT);
-            if (source != BluetoothHeadset.REMOTE_DISCONNECT) return;
-
-            // Too bad, the dock state can't be checked from a BroadcastReceiver.
-            Intent i = new Intent(intent);
-            i.setClass(context, DockService.class);
-            beginStartingService(context, i);
-
-        } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) {
-            /*
-             *  Reconnect to the dock if:
-             *  1) it is a dock
-             *  2) it is an unexpected disconnect i.e. didn't go through disconnecting state
-             *  3) the dock is still docked (check can only be done in the Service)
-             */
-            if (device == null) {
-                if (DEBUG) Log.d(TAG, "Device is missing");
-                return;
-            }
-
-            int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
-            int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
-            if (newState == BluetoothA2dp.STATE_DISCONNECTED &&
-                    oldState != BluetoothA2dp.STATE_DISCONNECTING) {
+            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+                    oldState != BluetoothProfile.STATE_DISCONNECTING) {
                 // Too bad, the dock state can't be checked from a BroadcastReceiver.
                 Intent i = new Intent(intent);
                 i.setClass(context, DockService.class);
diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java
index db24554..47d4076 100644
--- a/src/com/android/settings/bluetooth/DockService.java
+++ b/src/com/android/settings/bluetooth/DockService.java
@@ -27,6 +27,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -178,7 +179,7 @@
          * This assumes that the intent sender has checked that this is a dock
          * and that the intent is for a disconnect
          */
-        if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+        if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
             BluetoothDevice disconnectedDevice = intent
                     .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
 
@@ -188,7 +189,7 @@
                 handleUnexpectedDisconnect(disconnectedDevice, Profile.HEADSET, startId);
             }
             return START_NOT_STICKY;
-        } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) {
+        } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
             BluetoothDevice disconnectedDevice = intent
                     .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
 
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
index 4ba06da..d503325 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
@@ -23,6 +23,7 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.util.Config;
@@ -117,11 +118,21 @@
         mEventRedirector = new BluetoothEventRedirector(this);
         mEventRedirector.start();
 
-        mBluetoothA2dp = new BluetoothA2dp(context);
+        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
 
         return true;
     }
 
+    private BluetoothProfile.ServiceListener mProfileListener =
+      new BluetoothProfile.ServiceListener() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mBluetoothA2dp = (BluetoothA2dp) proxy;
+        }
+        public void onServiceDisconnected(int profile) {
+            mBluetoothA2dp = null;
+        }
+    };
+
     public BluetoothAdapter getBluetoothAdapter() {
         return mAdapter;
     }
@@ -184,12 +195,11 @@
                 }
 
                 // If we are playing music, don't scan unless forced.
-                Set<BluetoothDevice> sinks = mBluetoothA2dp.getConnectedSinks();
-                if (sinks != null) {
-                    for (BluetoothDevice sink : sinks) {
-                        if (mBluetoothA2dp.getSinkState(sink) == BluetoothA2dp.STATE_PLAYING) {
-                            return;
-                        }
+                if (mBluetoothA2dp != null) {
+                    Set<BluetoothDevice> sinks = mBluetoothA2dp.getConnectedDevices();
+                    if (sinks.size() > 0) {
+                        BluetoothDevice sink = sinks.toArray(new BluetoothDevice[sinks.size()])[0];
+                        if (mBluetoothA2dp.isA2dpPlaying(sink)) return;
                     }
                 }
             }
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
index 6193a4e..7e11887 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
@@ -19,10 +19,12 @@
 import com.android.settings.R;
 
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.os.Handler;
 import android.os.ParcelUuid;
@@ -237,42 +239,58 @@
     /**
      * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
      */
-    private static class A2dpProfileManager extends LocalBluetoothProfileManager {
+    private static class A2dpProfileManager extends LocalBluetoothProfileManager
+          implements BluetoothProfile.ServiceListener {
         private BluetoothA2dp mService;
 
+        // TODO(): The calls must wait for mService. Its not null just
+        // because it runs in the system server.
         public A2dpProfileManager(LocalBluetoothManager localManager) {
             super(localManager);
-            mService = new BluetoothA2dp(localManager.getContext());
+            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+            adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.A2DP);
+
+        }
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mService = (BluetoothA2dp) proxy;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            mService = null;
         }
 
         @Override
         public Set<BluetoothDevice> getConnectedDevices() {
-            return mService.getNonDisconnectedSinks();
+            return mService.getDevicesMatchingConnectionStates(
+                  new int[] {BluetoothProfile.STATE_CONNECTED,
+                             BluetoothProfile.STATE_CONNECTING,
+                             BluetoothProfile.STATE_DISCONNECTING});
         }
 
         @Override
         public boolean connect(BluetoothDevice device) {
-            Set<BluetoothDevice> sinks = mService.getNonDisconnectedSinks();
+            Set<BluetoothDevice> sinks = getConnectedDevices();
             if (sinks != null) {
                 for (BluetoothDevice sink : sinks) {
-                    mService.disconnectSink(sink);
+                    mService.disconnect(sink);
                 }
             }
-            return mService.connectSink(device);
+            return mService.connect(device);
         }
 
         @Override
         public boolean disconnect(BluetoothDevice device) {
             // Downgrade priority as user is disconnecting the sink.
-            if (mService.getSinkPriority(device) > BluetoothA2dp.PRIORITY_ON) {
-                mService.setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
+            if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
             }
-            return mService.disconnectSink(device);
+            return mService.disconnect(device);
         }
 
         @Override
         public int getConnectionStatus(BluetoothDevice device) {
-            return convertState(mService.getSinkState(device));
+            return convertState(mService.getConnectionState(device));
         }
 
         @Override
@@ -288,35 +306,35 @@
 
         @Override
         public boolean isPreferred(BluetoothDevice device) {
-            return mService.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
+            return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
         }
 
         @Override
         public int getPreferred(BluetoothDevice device) {
-            return mService.getSinkPriority(device);
+            return mService.getPriority(device);
         }
 
         @Override
         public void setPreferred(BluetoothDevice device, boolean preferred) {
             if (preferred) {
-                if (mService.getSinkPriority(device) < BluetoothA2dp.PRIORITY_ON) {
-                    mService.setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
+                if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
                 }
             } else {
-                mService.setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
+                mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
             }
         }
 
         @Override
         public int convertState(int a2dpState) {
             switch (a2dpState) {
-            case BluetoothA2dp.STATE_CONNECTED:
+            case BluetoothProfile.STATE_CONNECTED:
                 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
-            case BluetoothA2dp.STATE_CONNECTING:
+            case BluetoothProfile.STATE_CONNECTING:
                 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
-            case BluetoothA2dp.STATE_DISCONNECTED:
+            case BluetoothProfile.STATE_DISCONNECTED:
                 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
-            case BluetoothA2dp.STATE_DISCONNECTING:
+            case BluetoothProfile.STATE_DISCONNECTING:
                 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
             case BluetoothA2dp.STATE_PLAYING:
                 return SettingsBtStatus.CONNECTION_STATUS_ACTIVE;
@@ -335,17 +353,23 @@
      * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
      */
     private static class HeadsetProfileManager extends LocalBluetoothProfileManager
-            implements BluetoothHeadset.ServiceListener {
+            implements BluetoothProfile.ServiceListener {
         private BluetoothHeadset mService;
         private Handler mUiHandler = new Handler();
         private boolean profileReady = false;
 
+        // TODO(): The calls must get queued if mService becomes null.
+        // It can happen  when phone app crashes for some reason.
+        // All callers should have service listeners. Dock Service is the only
+        // one right now.
         public HeadsetProfileManager(LocalBluetoothManager localManager) {
             super(localManager);
-            mService = new BluetoothHeadset(localManager.getContext(), this);
+            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+            adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.HEADSET);
         }
 
-        public void onServiceConnected() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mService = (BluetoothHeadset) proxy;
             profileReady = true;
             // This could be called on a non-UI thread, funnel to UI thread.
             mUiHandler.post(new Runnable() {
@@ -354,11 +378,15 @@
                      * We just bound to the service, so refresh the UI of the
                      * headset device.
                      */
-                    BluetoothDevice device = mService.getCurrentHeadset();
-                    if (device == null) return;
+                    Set<BluetoothDevice> deviceSet = mService.getConnectedDevices();
+                    if (deviceSet.size() == 0) return;
+
+                    BluetoothDevice[] devices =
+                        deviceSet.toArray(new BluetoothDevice[deviceSet.size()]);
+
                     mLocalManager.getCachedDeviceManager()
-                            .onProfileStateChanged(device, Profile.HEADSET,
-                                                   BluetoothHeadset.STATE_CONNECTED);
+                            .onProfileStateChanged(devices[0], Profile.HEADSET,
+                                                   BluetoothProfile.STATE_CONNECTED);
                 }
             });
 
@@ -370,7 +398,8 @@
             }
         }
 
-        public void onServiceDisconnected() {
+        public void onServiceDisconnected(int profile) {
+            mService = null;
             profileReady = false;
             if (mServiceListeners.size() > 0) {
                 Iterator<ServiceListener> it = mServiceListeners.iterator();
@@ -387,34 +416,24 @@
 
         @Override
         public Set<BluetoothDevice> getConnectedDevices() {
-            Set<BluetoothDevice> devices = null;
-            BluetoothDevice device = mService.getCurrentHeadset();
-            if (device != null) {
-                devices = new HashSet<BluetoothDevice>();
-                devices.add(device);
-            }
-            return devices;
+            return mService.getConnectedDevices();
         }
 
         @Override
         public boolean connect(BluetoothDevice device) {
-            // Since connectHeadset fails if already connected to a headset, we
-            // disconnect from any headset first
-            BluetoothDevice currDevice = mService.getCurrentHeadset();
-            if (currDevice != null) {
-                mService.disconnectHeadset(currDevice);
-            }
-            return mService.connectHeadset(device);
+            return mService.connect(device);
         }
 
         @Override
         public boolean disconnect(BluetoothDevice device) {
-            if (mService.getCurrentHeadset().equals(device)) {
+            Set<BluetoothDevice> deviceSet = getConnectedDevices();
+            BluetoothDevice[] devices = deviceSet.toArray(new BluetoothDevice[deviceSet.size()]);
+            if (devices.length != 0 && devices[0].equals(device)) {
                 // Downgrade prority as user is disconnecting the headset.
-                if (mService.getPriority(device) > BluetoothHeadset.PRIORITY_ON) {
-                    mService.setPriority(device, BluetoothHeadset.PRIORITY_ON);
+                if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
                 }
-                return mService.disconnectHeadset(device);
+                return mService.disconnect(device);
             } else {
                 return false;
             }
@@ -422,9 +441,11 @@
 
         @Override
         public int getConnectionStatus(BluetoothDevice device) {
-            BluetoothDevice currentDevice = mService.getCurrentHeadset();
-            return currentDevice != null && currentDevice.equals(device)
-                    ? convertState(mService.getState(device))
+            Set<BluetoothDevice> deviceSet = getConnectedDevices();
+            BluetoothDevice[] devices = deviceSet.toArray(new BluetoothDevice[deviceSet.size()]);
+
+            return devices.length > 0 && devices[0].equals(device)
+                    ? convertState(mService.getConnectionState(device))
                     : SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
         }
 
@@ -441,7 +462,7 @@
 
         @Override
         public boolean isPreferred(BluetoothDevice device) {
-            return mService.getPriority(device) > BluetoothHeadset.PRIORITY_OFF;
+            return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
         }
 
         @Override
@@ -452,22 +473,22 @@
         @Override
         public void setPreferred(BluetoothDevice device, boolean preferred) {
             if (preferred) {
-                if (mService.getPriority(device) < BluetoothHeadset.PRIORITY_ON) {
-                    mService.setPriority(device, BluetoothHeadset.PRIORITY_ON);
+                if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
                 }
             } else {
-                mService.setPriority(device, BluetoothHeadset.PRIORITY_OFF);
+                mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
             }
         }
 
         @Override
         public int convertState(int headsetState) {
             switch (headsetState) {
-            case BluetoothHeadset.STATE_CONNECTED:
+            case BluetoothProfile.STATE_CONNECTED:
                 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
-            case BluetoothHeadset.STATE_CONNECTING:
+            case BluetoothProfile.STATE_CONNECTING:
                 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
-            case BluetoothHeadset.STATE_DISCONNECTED:
+            case BluetoothProfile.STATE_DISCONNECTED:
                 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
             default:
                 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;