Initial Health Profile implementation

Change-Id: I22f35073ceb131d84df6b233d1b63d20fa1b4451
diff --git a/Android.mk b/Android.mk
index 64300e2..8481e72 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,7 @@
 	core/java/android/bluetooth/IBluetoothCallback.aidl \
 	core/java/android/bluetooth/IBluetoothHeadset.aidl \
 	core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
+	core/java/android/bluetooth/IBluetoothHealth.aidl \
 	core/java/android/bluetooth/IBluetoothHealthCallback.aidl \
 	core/java/android/bluetooth/IBluetoothInputDevice.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 7797d94..2df33a6 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -239,7 +239,7 @@
      * results once close() has been called. Multiple invocations of close()
      * are ok.
      */
-    /*package*/ synchronized void close() {
+    /*package*/ void close() {
         if (DBG) log("close()");
         if (mConnection != null) {
             mContext.unbindService(mConnection);
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index f4aee98..5dad291 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,7 +16,10 @@
 
 package android.bluetooth;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -146,13 +149,11 @@
                 new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
 
         if (mService != null) {
-            //TODO(BT
-            /*
             try {
                 result = mService.registerAppConfiguration(config, wrapper);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -172,13 +173,11 @@
     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
         boolean result = false;
         if (mService != null && isEnabled() && config != null) {
-            //TODO(BT
-            /*
             try {
                 result = mService.unregisterAppConfiguration(config);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -203,13 +202,11 @@
             BluetoothHealthAppConfiguration config) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
                 config != null) {
-            //TODO(BT
-            /*
             try {
                 return mService.connectChannelToSource(device, config);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -234,13 +231,11 @@
             BluetoothHealthAppConfiguration config, int channelType) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
                 config != null) {
-            //TODO(BT
-            /*
             try {
                 return mService.connectChannelToSink(device, config, channelType);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -265,13 +260,11 @@
             BluetoothHealthAppConfiguration config, int channelId) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
                 config != null) {
-            //TODO(BT
-            /*
             try {
                 return mService.disconnectChannel(device, config, channelId);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -296,13 +289,11 @@
             BluetoothHealthAppConfiguration config) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
                 config != null) {
-            //TODO(BT
-            /*
             try {
                 return mService.getMainChannelFd(device, config);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -328,13 +319,11 @@
     @Override
     public int getConnectionState(BluetoothDevice device) {
         if (mService != null && isEnabled() && isValidDevice(device)) {
-            //TODO(BT
-            /*
             try {
                 return mService.getHealthDeviceConnectionState(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
-            }*/
+            }
         } else {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
@@ -358,14 +347,12 @@
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
         if (mService != null && isEnabled()) {
-            //TODO(BT
-            /*
             try {
                 return mService.getConnectedHealthDevices();
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return new ArrayList<BluetoothDevice>();
-            }*/
+            }
         }
         if (mService == null) Log.w(TAG, "Proxy not attached to service");
         return new ArrayList<BluetoothDevice>();
@@ -392,14 +379,12 @@
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         if (mService != null && isEnabled()) {
-            //TODO(BT
-            /*
             try {
                 return mService.getHealthDevicesMatchingConnectionStates(states);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return new ArrayList<BluetoothDevice>();
-            }*/
+            }
         }
         if (mService == null) Log.w(TAG, "Proxy not attached to service");
         return new ArrayList<BluetoothDevice>();
@@ -445,35 +430,50 @@
     /** Health App Configuration un-registration failure */
     public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
 
+    private Context mContext;
     private ServiceListener mServiceListener;
-    private IBluetooth mService;
+    private IBluetoothHealth mService;
     BluetoothAdapter mAdapter;
 
     /**
      * Create a BluetoothHealth proxy object.
      */
-    /*package*/ BluetoothHealth(Context mContext, ServiceListener l) {
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
+        mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (b != null) {
-            mService = IBluetooth.Stub.asInterface(b);
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, this);
-            }
-        } else {
-            Log.w(TAG, "Bluetooth Service not available!");
-
-            // Instead of throwing an exception which prevents people from going
-            // into Wireless settings in the emulator. Let it crash later when it is actually used.
-            mService = null;
+        if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth Health Service");
         }
     }
 
     /*package*/ void close() {
+        if (DBG) log("close()");
+        if (mConnection != null) {
+            mContext.unbindService(mConnection);
+            mConnection = null;
+        }
         mServiceListener = null;
     }
 
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "Proxy object connected");
+            mService = IBluetoothHealth.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
+            }
+        }
+    };
+
     private boolean isEnabled() {
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
 
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index c59c62c..80a3d61 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -18,9 +18,7 @@
 
 import android.bluetooth.IBluetoothCallback;
 import android.bluetooth.IBluetoothStateChangeCallback;
-import android.bluetooth.IBluetoothHealthCallback;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHealthAppConfiguration;
 import android.os.ParcelUuid;
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/java/android/bluetooth/IBluetoothHealth.aidl b/core/java/android/bluetooth/IBluetoothHealth.aidl
new file mode 100644
index 0000000..e741da4
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHealth.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHealthAppConfiguration;
+import android.bluetooth.IBluetoothHealthCallback;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * API for Bluetooth Health service
+ *
+ * {@hide}
+ */
+interface IBluetoothHealth
+{
+    boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
+        in IBluetoothHealthCallback callback);
+    boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
+    boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
+    boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
+        int channelType);
+    boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
+    ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
+    List<BluetoothDevice> getConnectedHealthDevices();
+    List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
+    int getHealthDeviceConnectionState(in BluetoothDevice device);
+}