Changed long inputs to Strings due to serializable issues with byte arrays.
Changed byte[] returns to Strings also due to serializable issues.
byte[] inputs now must be passed as comma separated Strings.
Added ble start advertising with scanrecord.
Changed an input of an RPC function from List<String> to String[]
since there were type problems from python to java.
Also uncommented onConnectionCongested which I'm not sure why it got
commented out to begin with.
Added classic le scan and le advertise callbacks/generators/start/stop/shutdown
.Fixed some documentation.

Change-Id: Ib0099b46ae506e6d649d755c405468a0c092e18c
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothGattFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothGattFacade.java
index 45ec352..48c2d50 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothGattFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothGattFacade.java
@@ -770,15 +770,15 @@
             mResults.clear();
         }
 
-//        @Override
-//        public void onConnectionCongested(BluetoothGatt gatt, boolean congested) {
-//            Log.d("gatt_connect change onConnectionCongested " + mEventType + " " + index);
-//            mResults.putString("Type", "onConnectionCongested");
-//            mResults.putBoolean("Congested", congested);
-//            mEventFacade
-//                    .postEvent(mEventType + index + "onConnectionCongested", mResults.clone());
-//            mResults.clear();
-//        }
+        @Override
+        public void onConnectionCongested(BluetoothGatt gatt, boolean congested) {
+            Log.d("gatt_connect change onConnectionCongested " + mEventType + " " + index);
+            mResults.putString("Type", "onConnectionCongested");
+            mResults.putBoolean("Congested", congested);
+            mEventFacade
+                    .postEvent(mEventType + index + "onConnectionCongested", mResults.clone());
+            mResults.clear();
+        }
     }
 
     @Override
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
index 952b9ab..f90fb2d 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
@@ -16,7 +16,6 @@
 
 package com.googlecode.android_scripting.facade.bluetooth;
 
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -42,6 +41,7 @@
 import com.googlecode.android_scripting.rpc.RpcParameter;
 import com.googlecode.android_scripting.rpc.RpcStartEvent;
 import com.googlecode.android_scripting.rpc.RpcStopEvent;
+import com.googlecode.android_scripting.ConvertUtils;
 
 /**
  * BluetoothLe Advertise functions.
@@ -53,9 +53,11 @@
     private final EventFacade mEventFacade;
     private BluetoothAdapter mBluetoothAdapter;
     private static int BleAdvertiseCallbackCount;
+    private static int ClassicBleAdvertiseCallbackCount;
     private static int BleAdvertiseSettingsCount;
     private static int BleAdvertiseDataCount;
     private final HashMap<Integer, myAdvertiseCallback> mAdvertiseCallbackList;
+    private final HashMap<Integer, myClassicAdvertiseCallback> mClassicAdvertiseCallbackList;
     private final BluetoothLeAdvertiser mAdvertise;
     private final Service mService;
     private Builder mAdvertiseDataBuilder;
@@ -75,6 +77,7 @@
                 });
         mEventFacade = manager.getReceiver(EventFacade.class);
         mAdvertiseCallbackList = new HashMap<Integer, myAdvertiseCallback>();
+        mClassicAdvertiseCallbackList = new HashMap<Integer, myClassicAdvertiseCallback>();
         mAdvertise = mBluetoothAdapter.getBluetoothLeAdvertiser();
         mAdvertiseDataList = new HashMap<Integer, AdvertisementData>();
         mAdvertiseSettingsList = new HashMap<Integer, AdvertiseSettings>();
@@ -98,6 +101,21 @@
     }
 
     /**
+     * Constructs a myClassicAdvertiseCallback obj and returns its index
+     *
+     * @return myClassicAdvertiseCallback.index
+     */
+    @Rpc(description = "Generate a new myClassicAdvertisement Object")
+    public Integer genClassicBleAdvertiseCallback() {
+        ClassicBleAdvertiseCallbackCount += 1;
+        int index = ClassicBleAdvertiseCallbackCount;
+        myClassicAdvertiseCallback mCallback = new myClassicAdvertiseCallback(index);
+        mClassicAdvertiseCallbackList.put(mCallback.index,
+                mCallback);
+        return mCallback.index;
+    }
+
+    /**
      * Constructs a AdvertisementData obj and returns its index
      *
      * @return index
@@ -199,9 +217,31 @@
     }
 
     /**
+     * Stops a classic ble advertisement
+     *
+     * @param index the id of the advertisement to stop advertising on
+     * @throws Exception
+     */
+    @Rpc(description = "Stops an ongoing classic ble advertisement scan")
+    @RpcStopEvent("BleAdvertise")
+    public void stopClassicBleAdvertising(
+            @RpcParameter(name = "index")
+            Integer index) throws Exception {
+        if (mClassicAdvertiseCallbackList.get(index) != null) {
+            Log.d("bluetooth_le_classic mAdvertise " + index);
+            mBluetoothAdapter.stopAdvertising(mClassicAdvertiseCallbackList
+                    .get(index));
+        } else {
+            throw new Exception("Invalid index input:" + Integer.toString(index));
+        }
+    }
+
+    /**
      * Starts ble advertising
      *
-     * @param index the myAdvertisement object to start advertising on
+     * @param callbackIndex The advertisementCallback index
+     * @param dataIndex the advertisementData index
+     * @param settingsIndex the advertisementsettings index
      * @throws Exception
      */
     @Rpc(description = "Starts ble advertisement")
@@ -237,6 +277,84 @@
     }
 
     /**
+     * Starts ble advertising with a scanResponse. ScanResponses are created in the same way
+     * AdvertisementData is created since they share the same object type.
+     *
+     * @param callbackIndex The advertisementCallback index
+     * @param dataIndex the advertisementData index
+     * @param settingsIndex the advertisementsettings index
+     * @param scanResponseIndex the scanResponse index
+     * @throws Exception
+     */
+    @Rpc(description = "Starts ble advertisement")
+    @RpcStartEvent("BleAdvertising")
+    public void startBleAdvertisingWithScanResponse(
+            @RpcParameter(name = "callbackIndex")
+            Integer callbackIndex,
+            @RpcParameter(name = "dataIndex")
+            Integer dataIndex,
+            @RpcParameter(name = "settingsIndex")
+            Integer settingsIndex,
+            @RpcParameter(name = "scanResponseIndex")
+            Integer scanResponseIndex
+            ) throws Exception {
+        AdvertisementData mData = new AdvertisementData.Builder().build();
+        AdvertiseSettings mSettings = new AdvertiseSettings.Builder().build();
+        AdvertisementData mScanResponse = new AdvertisementData.Builder().build();
+
+        if (mAdvertiseDataList.get(dataIndex) != null) {
+            mData = mAdvertiseDataList.get(dataIndex);
+        } else {
+            throw new Exception("Invalid dataIndex input:" + Integer.toString(dataIndex));
+        }
+        if (mAdvertiseSettingsList.get(settingsIndex) != null) {
+            mSettings = mAdvertiseSettingsList.get(settingsIndex);
+        } else {
+            throw new Exception("Invalid settingsIndex input:" + Integer.toString(settingsIndex));
+        }
+        if (mAdvertiseDataList.get(scanResponseIndex) != null) {
+            mScanResponse = mAdvertiseDataList.get(settingsIndex);
+        } else {
+            throw new Exception("Invalid scanResponseIndex input:"
+                    + Integer.toString(settingsIndex));
+        }
+        if (mAdvertiseCallbackList.get(callbackIndex) != null) {
+            Log.d("bluetooth_le starting a background scan on callback index: "
+                    + Integer.toString(callbackIndex));
+            mAdvertise
+                    .startAdvertising(mSettings, mData, mScanResponse,
+                            mAdvertiseCallbackList.get(callbackIndex));
+        } else {
+            throw new Exception("Invalid callbackIndex input" + Integer.toString(callbackIndex));
+        }
+    }
+
+    /**
+     * Starts Classic ble advertising
+     *
+     * @param callbackIndex The advertisementCallback index
+     * @throws Exception
+     */
+    @Rpc(description = "Starts ble advertisement")
+    @RpcStartEvent("BleAdvertising")
+    public void startClassicBleAdvertising(
+            @RpcParameter(name = "callbackIndex")
+            Integer callbackIndex,
+            @RpcParameter(name = "dataIndex")
+            Integer dataIndex,
+            @RpcParameter(name = "settingsIndex")
+            Integer settingsIndex
+            ) throws Exception {
+        if (mClassicAdvertiseCallbackList.get(callbackIndex) != null) {
+            Log.d("bluetooth_le starting a background scan on callback index: "
+                    + Integer.toString(callbackIndex));
+            mBluetoothAdapter.startAdvertising(mClassicAdvertiseCallbackList.get(callbackIndex));
+        } else {
+            throw new Exception("Invalid callbackIndex input" + Integer.toString(callbackIndex));
+        }
+    }
+
+    /**
      * Set ble advertisement data include tx power level
      *
      * @param includeTxPowerLevel boolean whether to include the tx power level or not in the
@@ -335,7 +453,7 @@
      * @throws Exception
      */
     @Rpc(description = "Get ble advertisement data manufacturer id")
-    public Integer getAdvertisementDataManufactrereId(
+    public Integer getAdvertisementDataManufacturerId(
             @RpcParameter(name = "index")
             Integer index) throws Exception {
         if (mAdvertiseDataList.get(index) != null) {
@@ -355,12 +473,12 @@
      * @throws Exception
      */
     @Rpc(description = "Get ble advertisement Manufacturer Specific Data")
-    public byte[] getAdvertisementDataManufacturerSpecificData(
+    public String getAdvertisementDataManufacturerSpecificData(
             @RpcParameter(name = "index")
             Integer index) throws Exception {
         if (mAdvertiseDataList.get(index) != null) {
             AdvertisementData mData = mAdvertiseDataList.get(index);
-            return mData.getManufacturerSpecificData();
+            return ConvertUtils.convertByteArrayToString(mData.getManufacturerSpecificData());
         } else {
             throw new Exception("Invalid index input:" + Integer.toString(index));
         }
@@ -374,12 +492,12 @@
      * @throws Exception
      */
     @Rpc(description = "Get ble advertisement Service Data")
-    public byte[] getAdvertisementDataServiceData(
+    public String getAdvertisementDataServiceData(
             @RpcParameter(name = "index")
             Integer index) throws Exception {
         if (mAdvertiseDataList.get(index) != null) {
             AdvertisementData mData = mAdvertiseDataList.get(index);
-            return mData.getServiceData();
+            return ConvertUtils.convertByteArrayToString(mData.getServiceData());
         } else {
             throw new Exception("Invalid index input:" + Integer.toString(index));
         }
@@ -437,7 +555,7 @@
     @Rpc(description = "Set ble advertisement data service uuids")
     public void setAdvertisementDataSetServiceUuids(
             @RpcParameter(name = "uuidList")
-            List<String> uuidList
+            String[] uuidList
             ) {
         ArrayList<ParcelUuid> mUuids = new ArrayList<ParcelUuid>();
         for (String uuid : uuidList) {
@@ -458,11 +576,11 @@
             @RpcParameter(name = "serviceDataUuid")
             String serviceDataUuid,
             @RpcParameter(name = "serviceData")
-            long serviceData
+            String serviceData
             ) {
         mAdvertiseDataBuilder.setServiceData(
                 ParcelUuid.fromString(serviceDataUuid),
-                BigInteger.valueOf(serviceData).toByteArray());
+                ConvertUtils.convertStringToByteArray(serviceData));
     }
 
     /**
@@ -477,10 +595,10 @@
             @RpcParameter(name = "manufacturerId")
             Integer manufacturerId,
             @RpcParameter(name = "manufacturerSpecificData")
-            long manufacturerSpecificData
+            String manufacturerSpecificData
             ) {
         mAdvertiseDataBuilder.setManufacturerData(manufacturerId,
-                BigInteger.valueOf(manufacturerSpecificData).toByteArray());
+                ConvertUtils.convertStringToByteArray(manufacturerSpecificData));
     }
 
     /**
@@ -540,7 +658,6 @@
         public void onSuccess(AdvertiseSettings settingsInEffect) {
             Log.d("bluetooth_le_advertisement onSuccess " + mEventType + " "
                     + index);
-            mResults.putInt("ID", index);
             mResults.putString("Type", "onSuccess");
             mResults.putParcelable("SettingsInEffect", settingsInEffect);
             mEventFacade.postEvent(mEventType + index + "onSuccess", mResults.clone());
@@ -551,7 +668,6 @@
         public void onFailure(int errorCode) {
             Log.d("bluetooth_le_advertisement onFailure " + mEventType + " "
                     + index);
-            mResults.putInt("ID", index);
             mResults.putString("Type", "onFailure");
             mResults.putInt("ErrorCode", errorCode);
             mEventFacade.postEvent(mEventType + index + "onFailure",
@@ -560,6 +676,42 @@
         }
     }
 
+    private class myClassicAdvertiseCallback implements
+            android.bluetooth.BluetoothAdapter.AdvertiseCallback {
+        public Integer index;
+        private final Bundle mResults;
+        String mEventType;
+
+        public myClassicAdvertiseCallback(int idx) {
+            index = idx;
+            mEventType = "BleAdvertise";
+            mResults = new Bundle();
+        }
+
+        @Override
+        public void onAdvertiseStart(int status) {
+            Log.d("bluetooth_classic_le_advertisement onAdvertiseStart " + mEventType + " "
+                    + index);
+            mResults.putString("Type", "onAdvertiseStart");
+            mResults.putInt("Status", status);
+            mEventFacade.postEvent(mEventType + index + "onAdvertiseStart",
+                    mResults.clone());
+            mResults.clear();
+        }
+
+        @Override
+        public void onAdvertiseStop(int status) {
+            Log.d("bluetooth_classic_le_advertisement onAdvertiseStop " + mEventType + " "
+                    + index);
+            mResults.putString("Type", "onAdvertiseStop");
+            mResults.putInt("Status", status);
+            mEventFacade.postEvent(mEventType + index + "onAdvertiseStop",
+                    mResults.clone());
+            mResults.clear();
+        }
+
+    }
+
     @Override
     public void shutdown() {
         if (mAdvertiseCallbackList.isEmpty() == false) {
@@ -574,6 +726,16 @@
             mAdvertiseSettingsList.clear();
             mAdvertiseDataList.clear();
         }
+
+        if (mClassicAdvertiseCallbackList.isEmpty() == false) {
+            for (myClassicAdvertiseCallback mAdvertise : mClassicAdvertiseCallbackList
+                    .values()) {
+                if (mAdvertise != null) {
+                    mBluetoothAdapter.stopAdvertising(mAdvertise);
+                }
+            }
+            mAdvertiseCallbackList.clear();
+        }
     }
 
 }
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeScanFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeScanFacade.java
index be44ee5..718a53d 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeScanFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeScanFacade.java
@@ -251,27 +251,25 @@
         if (mScanCallbackList.get(callbackIndex) != null) {
             mScanner.startScan(mScanFilters, mScanSettings, mScanCallbackList.get(callbackIndex));
         } else {
-            throw new Exception("Invalid filterListIndex input:" 
+            throw new Exception("Invalid filterListIndex input:"
                     + Integer.toString(filterListIndex));
         }
     }
 
     /**
-     * Get a ble batch Scan results
+     * Trigger onBatchScanResults
      *
-     * @param flush the results
      * @throws Exception
      */
     @Rpc(description = "Gets the results of the ble ScanCallback")
-    public List<ScanResult> getBatchScanResults(
+    public void flushPendingScanResults(
             @RpcParameter(name = "callbackIndex")
-            Integer callbackIndex,
-            @RpcParameter(name = "flush")
-            Boolean flush) throws Exception {
+            Integer callbackIndex
+            ) throws Exception {
         if (mScanCallbackList.get(callbackIndex) != null) {
-            return mBluetoothAdapter
-                    .getBluetoothLeScanner().getBatchScanResults(
-                            mScanCallbackList.get(callbackIndex), flush);
+            mBluetoothAdapter
+                    .getBluetoothLeScanner().flushPendingScanResults(
+                            mScanCallbackList.get(callbackIndex));
         } else {
             throw new Exception("Invalid callbackIndex input:"
                     + Integer.toString(callbackIndex));
@@ -298,8 +296,9 @@
             @RpcParameter(name = "scanResultType")
             Integer scanResultType) {
         mScanSettingsBuilder.setCallbackType(callbackType);
-        mScanSettingsBuilder.setCallbackType(scanMode);
-        mScanSettingsBuilder.setCallbackType(scanResultType);
+        mScanSettingsBuilder.setScanMode(scanMode);
+        mScanSettingsBuilder.setScanResultType(scanResultType);
+        mScanSettingsBuilder.setReportDelayNanos(reportDelayNanos);
     }
 
     /**
diff --git a/Utils/src/com/googlecode/android_scripting/ConvertUtils.java b/Utils/src/com/googlecode/android_scripting/ConvertUtils.java
new file mode 100644
index 0000000..4d1fcfa
--- /dev/null
+++ b/Utils/src/com/googlecode/android_scripting/ConvertUtils.java
@@ -0,0 +1,45 @@
+
+package com.googlecode.android_scripting;
+
+public class ConvertUtils {
+
+    private ConvertUtils() {
+        // This class will be
+    }
+
+    /**
+     * Converts a String of comma separated bytes to a byte array
+     *
+     * @param value The value to convert
+     * @return the byte array
+     */
+    public static byte[] convertStringToByteArray(String value) {
+        String[] parseString = value.split(",");
+        byte[] byteArray = new byte[parseString.length];
+        for (int i = 0; i < parseString.length; i++) {
+            byte byteValue = Byte.valueOf(parseString[i].trim());
+            byteArray[i] = byteValue;
+        }
+        return byteArray;
+    }
+
+    /**
+     * Converts a byte array to a comma separated String
+     *
+     * @param byteArray
+     * @return comma separated string of bytes
+     */
+    public static String convertByteArrayToString(byte[] byteArray) {
+        String ret = "";
+        for (int i = 0; i < byteArray.length; i++) {
+            if ((i + 1) != byteArray.length) {
+                ret = ret + Byte.valueOf(byteArray[i]) + ",";
+            }
+            else {
+                ret = ret + Byte.valueOf(byteArray[i]);
+            }
+        }
+        return ret;
+    }
+
+}
diff --git a/Utils/src/com/googlecode/android_scripting/StringUtils.java b/Utils/src/com/googlecode/android_scripting/StringUtils.java
deleted file mode 100644
index b705b7f..0000000
--- a/Utils/src/com/googlecode/android_scripting/StringUtils.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.googlecode.android_scripting;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-public class StringUtils {
-
-  private StringUtils() {
-    // Utility class.
-  }
-
-  public static String join(Collection<String> collection, String delimiter) {
-    StringBuffer buffer = new StringBuffer();
-    Iterator<String> iter = collection.iterator();
-    while (iter.hasNext()) {
-      buffer.append(iter.next());
-      if (iter.hasNext()) {
-        buffer.append(delimiter);
-      }
-    }
-    return buffer.toString();
-  }
-}
diff --git a/Utils/src/com/googlecode/android_scripting/interpreter/ExternalClassLoader.java b/Utils/src/com/googlecode/android_scripting/interpreter/ExternalClassLoader.java
index 361c219..1f2caa3 100644
--- a/Utils/src/com/googlecode/android_scripting/interpreter/ExternalClassLoader.java
+++ b/Utils/src/com/googlecode/android_scripting/interpreter/ExternalClassLoader.java
@@ -1,22 +1,33 @@
 package com.googlecode.android_scripting.interpreter;
 
-import com.googlecode.android_scripting.StringUtils;
-
 import dalvik.system.DexClassLoader;
 
 import java.util.Collection;
+import java.util.Iterator;
 
 public class ExternalClassLoader {
 
   public Object load(Collection<String> dexPaths, Collection<String> nativePaths, String className)
       throws Exception {
     String dexOutputDir = "/sdcard/dexoutput";
-    String joinedDexPaths = StringUtils.join(dexPaths, ":");
-    String joinedNativeLibPaths = nativePaths != null ? StringUtils.join(nativePaths, ":") : null;
+    String joinedDexPaths = join(dexPaths, ":");
+    String joinedNativeLibPaths = nativePaths != null ? join(nativePaths, ":") : null;
     DexClassLoader loader =
         new DexClassLoader(joinedDexPaths, dexOutputDir, joinedNativeLibPaths, this.getClass()
             .getClassLoader());
     Class<?> classToLoad = Class.forName(className, true, loader);
     return classToLoad.newInstance();
   }
+
+    private static String join(Collection<String> collection, String delimiter) {
+        StringBuffer buffer = new StringBuffer();
+        Iterator<String> iter = collection.iterator();
+        while (iter.hasNext()) {
+            buffer.append(iter.next());
+            if (iter.hasNext()) {
+                buffer.append(delimiter);
+            }
+        }
+        return buffer.toString();
+    }
 }
\ No newline at end of file