Added various apis and fixed existing ones
BluetoothFacade.java
Removed unregistering reciever as it was causing crashes

BluetoothRfcommFacade.java
Cleared file descriptors on closing of a rfcomm socket

GattFacade.java
Added api gattServerGetConnectedDevices
Added api gattServerSendResponse
Fixed api gattReadCharacteristic

Change-Id: I005bf4d5c274f827f124e4a2a454a978d0acc21d
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
index 552a775..01dcd4c 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
@@ -307,7 +307,13 @@
     @Rpc(description = "Cancel the current device discovery process.",
          returns = "true on success, false on error")
     public Boolean bluetoothCancelDiscovery() {
-        mService.unregisterReceiver(mDiscoveryReceiver);
+        //TODO (tturney): Figure out why bluetoothStartDiscovery sometimes
+        //doesn't register the reiever.
+        try {
+            mService.unregisterReceiver(mDiscoveryReceiver);
+        } catch (IllegalArgumentException e) {
+            Log.d("IllegalArgumentExeption found when trying to unregister reciever");
+        }
         return mBluetoothAdapter.cancelDiscovery();
     }
 
@@ -332,7 +338,7 @@
         return mBluetoothAdapter.configHciSnoopLog(value);
     }
 
-    @Rpc(description = "Get ")
+    @Rpc(description = "Get Bluetooth controller activity energy info.")
     public String bluetoothGetControllerActivityEnergyInfo(
         @RpcParameter(name = "value")
         Integer value
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
index 433be3d..bcf7b8c 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
@@ -22,6 +22,7 @@
 import android.bluetooth.BluetoothServerSocket;
 import android.bluetooth.BluetoothSocket;
 import android.content.IntentFilter;
+import android.os.ParcelFileDescriptor;
 
 import com.googlecode.android_scripting.Log;
 import com.googlecode.android_scripting.facade.FacadeManager;
@@ -40,6 +41,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
+import java.lang.reflect.Field;
 
 import org.apache.commons.codec.binary.Base64Codec;
 
@@ -399,9 +401,28 @@
     return mDevice.getName();
   }
 
+  private synchronized void clearFileDescriptor() {
+    try {
+      Field field = BluetoothSocket.class.getDeclaredField("mPfd");
+      field.setAccessible(true);
+      ParcelFileDescriptor mPfd = (ParcelFileDescriptor) field.get(mSocket);
+      if (mPfd == null)
+        return;
+      mPfd.close();
+      mPfd = null;
+      try { field.set(mSocket, mPfd); }
+      catch(Exception e) {
+          Log.d("Exception setting mPfd = null in cleanCloseFix(): " + e.toString());
+      }
+    } catch (Exception e) {
+        Log.w("ParcelFileDescriptor could not be cleanly closed.", e);
+    }
+  }
+
   public void stop() {
     if (mSocket != null) {
       try {
+        clearFileDescriptor();
         mSocket.close();
       } catch (IOException e) {
         Log.e(e);
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattFacade.java
index e453906..da0bf3d 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattFacade.java
@@ -46,6 +46,7 @@
     private final HashMap<Integer, myBluetoothGattServerCallback> mBluetoothGattServerCallbackList;
     private final HashMap<Integer, BluetoothGattService> mGattServiceList;
     private final HashMap<Integer, List<BluetoothGattService>> mBluetoothGattDiscoveredServicesList;
+    private final HashMap<Integer, List<BluetoothDevice>> mGattServerDiscoveredDevicesList;
     private static int GattCallbackCount;
     private static int BluetoothGattDiscoveredServicesCount;
     private static int BluetoothGattCount;
@@ -76,6 +77,7 @@
         mBluetoothGattServerCallbackList = new HashMap<Integer, myBluetoothGattServerCallback>();
         mGattServiceList = new HashMap<Integer, BluetoothGattService>();
         mBluetoothGattDiscoveredServicesList = new HashMap<Integer, List<BluetoothGattService>>();
+        mGattServerDiscoveredDevicesList = new HashMap<Integer, List<BluetoothDevice>>();
     }
 
     /**
@@ -130,6 +132,67 @@
     }
 
     /**
+     * Get connected devices of the gatt server
+     * @param gattServerIndex the gatt server index
+     * @throws Exception
+    */
+    @Rpc(description = "Return a list of connected gatt devices.")
+    public List<BluetoothDevice> gattServerGetConnectedDevices(
+        @RpcParameter(name = "gattServerIndex")
+        Integer gattServerIndex) throws Exception {
+        if (mBluetoothGattServerList.get(gattServerIndex) == null) {
+            throw new Exception("Invalid gattServerIndex: "
+                    + Integer.toString(gattServerIndex));
+        }
+        List<BluetoothDevice> connectedDevices = mBluetoothManager.getConnectedDevices(
+                BluetoothProfile.GATT_SERVER);
+        mGattServerDiscoveredDevicesList.put(gattServerIndex, connectedDevices);
+        return connectedDevices;
+    }
+
+    /**
+     * Get connected devices of the gatt server
+     * @param gattServerIndex the gatt server index
+     * @param bluetoothDeviceIndex the remotely connected bluetooth device
+     * @param requestId the ID of the request that was received with the callback
+     * @param status the status of the request to be sent to the remote devices
+     * @param offset value offset for partial read/write response
+     * @param value the value of the attribute that was read/written
+     * @throws Exception
+    */
+    @Rpc(description = "Send a response after a write.")
+    public void gattServerSendResponse(
+        @RpcParameter(name = "gattServerIndex")
+        Integer gattServerIndex,
+        @RpcParameter(name = "bluetoothDeviceIndex")
+        Integer bluetoothDeviceIndex,
+        @RpcParameter(name = "requestId")
+        Integer requestId,
+        @RpcParameter(name = "status")
+        Integer status,
+        @RpcParameter(name = "offset")
+        Integer offset,
+        @RpcParameter(name = "value")
+        String value) throws Exception {
+
+        BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex);
+        if (gattServer == null)
+            throw new Exception("Invalid gattServerIndex: "
+                    + Integer.toString(gattServerIndex));
+        List <BluetoothDevice> connectedDevices =
+            mGattServerDiscoveredDevicesList.get(gattServerIndex);
+        if (connectedDevices == null)
+            throw new Exception("Connected device list empty for gattServerIndex:"
+                    + Integer.toString(gattServerIndex));
+        BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex);
+        if (bluetoothDevice == null)
+            throw new Exception("Invalid bluetoothDeviceIndex: "
+                    + Integer.toString(bluetoothDeviceIndex));
+        gattServer.sendResponse(bluetoothDevice, requestId, status, offset,
+                ConvertUtils.convertStringToByteArray(value));
+    }
+
+    /**
      * Create a new bluetooth gatt service
      * @param uuid the UUID that characterises the service
      * @param serviceType the service type
@@ -518,30 +581,39 @@
 
     /**
      * Reads the requested characteristic from the associated remote device.
-     *
-     * @param index the bluetooth gatt index
-     * @param characteristicIndex the characteristic index
+     * @param gattIndex the BluetoothGatt server accociated with the device
+     * @param discoveredServiceListIndex the index returned from the discovered
+     * services callback
+     * @param serviceIndex the service index of the discovered services
+     * @param characteristicUuid the characteristic uuid to read
      * @return true, if the read operation was initiated successfully
      * @throws Exception
      */
     @Rpc(description = "Reads the requested characteristic from the associated remote device.")
     public boolean gattReadCharacteristic(
-        @RpcParameter(name = "index")
-        Integer index,
-        @RpcParameter(name = "characteristicIndex")
-        Integer characteristicIndex
-        ) throws Exception {
-        if (mBluetoothGattList.get(index) != null) {
-            if (mCharacteristicList.get(characteristicIndex) != null) {
-                return mBluetoothGattList.get(index).readCharacteristic(
-                        mCharacteristicList.get(characteristicIndex));
-            } else {
-                throw new Exception("Invalid characteristicIndex input:"
-                        + characteristicIndex);
-            }
-        } else {
-            throw new Exception("Invalid index input:" + index);
-        }
+        @RpcParameter(name = "gattIndex") Integer gattIndex,
+        @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
+        @RpcParameter(name = "serviceIndex") Integer serviceIndex,
+        @RpcParameter(name = "characteristicUuid") String characteristicUuid) throws Exception {
+      BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
+      if (bluetoothGatt == null) {
+        throw new Exception("Invalid gattIndex " + gattIndex);
+      }
+      List<BluetoothGattService> discoveredServiceList =
+          mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
+      if (discoveredServiceList == null) {
+        throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
+      }
+      BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
+      if (gattService == null) {
+        throw new Exception("Invalid serviceIndex " + serviceIndex);
+      }
+      UUID cUuid = UUID.fromString(characteristicUuid);
+      BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
+      if (gattCharacteristic == null) {
+        throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
+      }
+      return bluetoothGatt.readCharacteristic(gattCharacteristic);
     }
 
     /**