Merge "Bluetooth 5 AdvertisingSet implementation (2/4)"
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index 91e026c..08da8e0 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -118,6 +118,14 @@
   return env->NewStringUTF(c_address);
 }
 
+static std::vector<uint8_t> toVector(JNIEnv* env, jbyteArray ba) {
+  jbyte* data_data = env->GetByteArrayElements(ba, NULL);
+  uint16_t data_len = (uint16_t)env->GetArrayLength(ba);
+  std::vector<uint8_t> data_vec(data_data, data_data + data_len);
+  env->ReleaseByteArrayElements(ba, data_data, JNI_ABORT);
+  return data_vec;
+}
+
 namespace android {
 
 /**
@@ -176,7 +184,13 @@
  * Advertiser callback methods
  */
 static jmethodID method_onAdvertisingSetStarted;
-static jmethodID method_onAdvertisingSetEnabled;
+static jmethodID method_onAdvertisingEnabled;
+static jmethodID method_onAdvertisingDataSet;
+static jmethodID method_onScanResponseDataSet;
+static jmethodID method_onAdvertisingParametersUpdated;
+static jmethodID method_onPeriodicAdvertisingParametersUpdated;
+static jmethodID method_onPeriodicAdvertisingDataSet;
+static jmethodID method_onPeriodicAdvertisingEnable;
 
 /**
  * Static variables
@@ -1545,9 +1559,21 @@
 
 static void advertiseClassInitNative(JNIEnv* env, jclass clazz) {
   method_onAdvertisingSetStarted =
-      env->GetMethodID(clazz, "onAdvertisingSetStarted", "(III)V");
-  method_onAdvertisingSetEnabled =
-      env->GetMethodID(clazz, "onAdvertisingSetEnabled", "(IZI)V");
+      env->GetMethodID(clazz, "onAdvertisingSetStarted", "(IIII)V");
+  method_onAdvertisingEnabled =
+      env->GetMethodID(clazz, "onAdvertisingEnabled", "(IZI)V");
+  method_onAdvertisingDataSet =
+      env->GetMethodID(clazz, "onAdvertisingDataSet", "(II)V");
+  method_onScanResponseDataSet =
+      env->GetMethodID(clazz, "onScanResponseDataSet", "(II)V");
+  method_onAdvertisingParametersUpdated =
+      env->GetMethodID(clazz, "onAdvertisingParametersUpdated", "(III)V");
+  method_onPeriodicAdvertisingParametersUpdated = env->GetMethodID(
+      clazz, "onPeriodicAdvertisingParametersUpdated", "(II)V");
+  method_onPeriodicAdvertisingDataSet =
+      env->GetMethodID(clazz, "onPeriodicAdvertisingDataSet", "(II)V");
+  method_onPeriodicAdvertisingEnable =
+      env->GetMethodID(clazz, "onPeriodicAdvertisingEnable", "(IZI)V");
 }
 
 static void advertiseInitializeNative(JNIEnv* env, jobject object) {
@@ -1638,12 +1664,12 @@
 }
 
 static void ble_advertising_set_started_cb(int reg_id, uint8_t advertiser_id,
-                                           uint8_t status) {
+                                           int8_t tx_power, uint8_t status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mAdvertiseCallbacksObj,
                                method_onAdvertisingSetStarted, reg_id,
-                               advertiser_id, status);
+                               advertiser_id, tx_power, status);
 }
 
 static void ble_advertising_set_timeout_cb(uint8_t advertiser_id,
@@ -1651,7 +1677,7 @@
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mAdvertiseCallbacksObj,
-                               method_onAdvertisingSetEnabled, advertiser_id,
+                               method_onAdvertisingEnabled, advertiser_id,
                                false, status);
 }
 
@@ -1700,6 +1726,116 @@
   sGattIf->advertiser->Unregister(advertiser_id);
 }
 
+static void callJniCallback(jmethodID method, uint8_t advertiser_id,
+                            uint8_t status) {
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+  sCallbackEnv->CallVoidMethod(mAdvertiseCallbacksObj, method, advertiser_id,
+                               status);
+}
+
+static void enableSetCb(uint8_t advertiser_id, bool enable, uint8_t status) {
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+  sCallbackEnv->CallVoidMethod(mAdvertiseCallbacksObj,
+                               method_onAdvertisingEnabled, advertiser_id,
+                               enable, status);
+}
+
+static void enableAdvertisingSetNative(JNIEnv* env, jobject object,
+                                       jint advertiser_id, jboolean enable,
+                                       jint timeout) {
+  if (!sGattIf) return;
+
+  sGattIf->advertiser->Enable(
+      advertiser_id, enable, base::Bind(&enableSetCb, advertiser_id, enable),
+      timeout / 1000, base::Bind(&enableSetCb, advertiser_id, false));
+}
+
+static void setAdvertisingDataNative(JNIEnv* env, jobject object,
+                                     jint advertiser_id, jbyteArray data) {
+  if (!sGattIf) return;
+
+  sGattIf->advertiser->SetData(
+      advertiser_id, false, toVector(env, data),
+      base::Bind(&callJniCallback, method_onAdvertisingDataSet, advertiser_id));
+}
+
+static void setScanResponseDataNative(JNIEnv* env, jobject object,
+                                      jint advertiser_id, jbyteArray data) {
+  if (!sGattIf) return;
+
+  sGattIf->advertiser->SetData(
+      advertiser_id, true, toVector(env, data),
+      base::Bind(&callJniCallback, method_onScanResponseDataSet,
+                 advertiser_id));
+}
+
+static void setAdvertisingParametersNativeCb(uint8_t advertiser_id,
+                                             uint8_t status, int8_t tx_power) {
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+  sCallbackEnv->CallVoidMethod(mCallbacksObj,
+                               method_onAdvertisingParametersUpdated,
+                               advertiser_id, tx_power, status);
+}
+
+static void setAdvertisingParametersNative(JNIEnv* env, jobject object,
+                                           jint advertiser_id,
+                                           jobject parameters) {
+  if (!sGattIf) return;
+
+  // TODO: must learn somehow wether scan response is set ?
+  AdvertiseParameters params =
+      parseParams(env, parameters, false /*TODO: put proper value here!!!*/);
+  sGattIf->advertiser->SetParameters(
+      advertiser_id, params,
+      base::Bind(setAdvertisingParametersNativeCb, advertiser_id));
+}
+
+static void setPeriodicAdvertisingParametersNative(
+    JNIEnv* env, jobject object, jint advertiser_id,
+    jobject periodic_parameters) {
+  if (!sGattIf) return;
+
+  PeriodicAdvertisingParameters periodicParams =
+      parsePeriodicParams(env, periodic_parameters);
+  sGattIf->advertiser->SetPeriodicAdvertisingParameters(
+      advertiser_id, periodicParams,
+      base::Bind(&callJniCallback,
+                 method_onPeriodicAdvertisingParametersUpdated, advertiser_id));
+}
+
+static void setPeriodicAdvertisingDataNative(JNIEnv* env, jobject object,
+                                             jint advertiser_id,
+                                             jbyteArray data) {
+  if (!sGattIf) return;
+
+  sGattIf->advertiser->SetPeriodicAdvertisingData(
+      advertiser_id, toVector(env, data),
+      base::Bind(&callJniCallback, method_onPeriodicAdvertisingDataSet,
+                 advertiser_id));
+}
+
+static void enablePeriodicSetCb(uint8_t advertiser_id, bool enable,
+                                uint8_t status) {
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+  sCallbackEnv->CallVoidMethod(mCallbacksObj,
+                               method_onPeriodicAdvertisingEnable,
+                               advertiser_id, enable, status);
+}
+
+static void setPeriodicAdvertisingEnableNative(JNIEnv* env, jobject object,
+                                               jint advertiser_id,
+                                               jboolean enable) {
+  if (!sGattIf) return;
+
+  sGattIf->advertiser->SetPeriodicAdvertisingEnable(
+      advertiser_id, enable,
+      base::Bind(&enablePeriodicSetCb, advertiser_id, enable));
+}
+
 static void gattTestNative(JNIEnv* env, jobject object, jint command,
                            jlong uuid1_lsb, jlong uuid1_msb, jstring bda1,
                            jint p1, jint p2, jint p3, jint p4, jint p5) {
@@ -1736,6 +1872,19 @@
      "le/PeriodicAdvertisingParameters;[BII)V",
      (void*)startAdvertisingSetNative},
     {"stopAdvertisingSetNative", "(I)V", (void*)stopAdvertisingSetNative},
+    {"enableAdvertisingSetNative", "(IZI)V", (void*)enableAdvertisingSetNative},
+    {"setAdvertisingDataNative", "(I[B)V", (void*)setAdvertisingDataNative},
+    {"setScanResponseDataNative", "(I[B)V", (void*)setScanResponseDataNative},
+    {"setAdvertisingParametersNative",
+     "(ILandroid/bluetooth/le/AdvertisingSetParameters;)V",
+     (void*)setAdvertisingParametersNative},
+    {"setPeriodicAdvertisingParametersNative",
+     "(ILandroid/bluetooth/le/PeriodicAdvertisingParameters;)V",
+     (void*)setPeriodicAdvertisingParametersNative},
+    {"setPeriodicAdvertisingDataNative", "(I[B)V",
+     (void*)setPeriodicAdvertisingDataNative},
+    {"setPeriodicAdvertisingEnableNative", "(IZ)V",
+     (void*)setPeriodicAdvertisingEnableNative},
 };
 
 // JNI functions defined in ScanManager class.
diff --git a/src/com/android/bluetooth/gatt/AdvertiseManager.java b/src/com/android/bluetooth/gatt/AdvertiseManager.java
index 19c939f..2b981ec 100644
--- a/src/com/android/bluetooth/gatt/AdvertiseManager.java
+++ b/src/com/android/bluetooth/gatt/AdvertiseManager.java
@@ -134,7 +134,8 @@
         return entry;
     }
 
-    void onAdvertisingSetStarted(int reg_id, int advertiser_id, int status) throws Exception {
+    void onAdvertisingSetStarted(int reg_id, int advertiser_id, int tx_power, int status)
+            throws Exception {
         if (DBG)
             Log.d(TAG, "onAdvertisingSetStarted() - reg_id=" + reg_id + ", advertiser_id="
                             + advertiser_id + ", status=" + status);
@@ -158,10 +159,10 @@
             mAdvertisers.remove(binder);
         }
 
-        callback.onAdvertisingSetStarted(advertiser_id, status);
+        callback.onAdvertisingSetStarted(advertiser_id, tx_power, status);
     }
 
-    void onAdvertisingSetEnabled(int advertiser_id, boolean enable, int status) throws Exception {
+    void onAdvertisingEnabled(int advertiser_id, boolean enable, int status) throws Exception {
         logd("onAdvertisingSetEnabled() - advertiser_id=" + advertiser_id + ", enable=" + enable
                 + ", status=" + status);
 
@@ -222,6 +223,125 @@
         stopAdvertisingSetNative(advertiser_id);
     }
 
+    void enableAdvertisingSet(int advertiserId, boolean enable, int timeout) {
+        enableAdvertisingSetNative(advertiserId, enable, timeout);
+    }
+
+    void setAdvertisingData(int advertiserId, AdvertiseData data) {
+        String deviceName = AdapterService.getAdapterService().getName();
+        setAdvertisingDataNative(
+                advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
+    }
+
+    void setScanResponseData(int advertiserId, AdvertiseData data) {
+        String deviceName = AdapterService.getAdapterService().getName();
+        setScanResponseDataNative(
+                advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
+    }
+
+    void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) {
+        setAdvertisingParametersNative(advertiserId, parameters);
+    }
+
+    void setPeriodicAdvertisingParameters(
+            int advertiserId, PeriodicAdvertisingParameters parameters) {
+        setPeriodicAdvertisingParametersNative(advertiserId, parameters);
+    }
+
+    void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) {
+        String deviceName = AdapterService.getAdapterService().getName();
+        setPeriodicAdvertisingDataNative(
+                advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
+    }
+
+    void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) {
+        setPeriodicAdvertisingEnableNative(advertiserId, enable);
+    }
+
+    void onAdvertisingDataSet(int advertiser_id, int status) throws Exception {
+        logd("onAdvertisingDataSet() advertiser_id=" + advertiser_id + ", status=" + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onAdvertisingDataSet() - bad advertiser_id " + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onAdvertisingDataSet(advertiser_id, status);
+    }
+
+    void onScanResponseDataSet(int advertiser_id, int status) throws Exception {
+        logd("onScanResponseDataSet() advertiser_id=" + advertiser_id + ", status=" + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onScanResponseDataSet() - bad advertiser_id " + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onScanResponseDataSet(advertiser_id, status);
+    }
+
+    void onAdvertisingParametersUpdated(int advertiser_id, int tx_power, int status)
+            throws Exception {
+        logd("onAdvertisingParametersUpdated() advertiser_id=" + advertiser_id + ", tx_power="
+                + tx_power + ", status=" + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onAdvertisingParametersUpdated() - bad advertiser_id " + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onAdvertisingParametersUpdated(advertiser_id, tx_power, status);
+    }
+
+    void onPeriodicAdvertisingParametersUpdated(int advertiser_id, int status) throws Exception {
+        logd("onPeriodicAdvertisingParametersUpdated() advertiser_id=" + advertiser_id + ", status="
+                + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onPeriodicAdvertisingParametersUpdated() - bad advertiser_id "
+                            + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onPeriodicAdvertisingParametersUpdated(advertiser_id, status);
+    }
+
+    void onPeriodicAdvertisingDataSet(int advertiser_id, int status) throws Exception {
+        logd("onPeriodicAdvertisingDataSet() advertiser_id=" + advertiser_id + ", status="
+                + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onPeriodicAdvertisingDataSet() - bad advertiser_id " + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onPeriodicAdvertisingDataSet(advertiser_id, status);
+    }
+
+    void onPeriodicAdvertisingEnable(int advertiser_id, boolean enable, int status)
+            throws Exception {
+        logd("onPeriodicAdvertisingEnable() advertiser_id=" + advertiser_id + ", status=" + status);
+
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiser_id);
+        if (entry == null) {
+            Log.i(TAG, "onAdvertisingSetEnable() - bad advertiser_id " + advertiser_id);
+            return;
+        }
+
+        IAdvertisingSetCallback callback = entry.getValue().callback;
+        callback.onPeriodicAdvertisingEnable(advertiser_id, enable, status);
+    }
+
     private void logd(String s) {
         if (DBG) {
             Log.d(TAG, s);
@@ -239,6 +359,14 @@
             byte[] advertiseData, byte[] scanResponse,
             PeriodicAdvertisingParameters periodicParameters, byte[] periodicData, int timeout,
             int reg_id);
-
     private native void stopAdvertisingSetNative(int advertiser_id);
+    private native void enableAdvertisingSetNative(int advertiserId, boolean enable, int timeout);
+    private native void setAdvertisingDataNative(int advertiserId, byte[] data);
+    private native void setScanResponseDataNative(int advertiserId, byte[] data);
+    private native void setAdvertisingParametersNative(
+            int advertiserId, AdvertisingSetParameters parameters);
+    private native void setPeriodicAdvertisingParametersNative(
+            int advertiserId, PeriodicAdvertisingParameters parameters);
+    private native void setPeriodicAdvertisingDataNative(int advertiserId, byte[] data);
+    private native void setPeriodicAdvertisingEnableNative(int advertiserId, boolean enable);
 }
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 3ca5363..03cf7ed 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -559,48 +559,48 @@
             service.stopAdvertisingSet(callback);
         }
 
-        public void enableAdverisingSet(int advertiserId, boolean enable, int timeout) {
+        public void enableAdvertisingSet(int advertiserId, boolean enable, int timeout) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.enableAdvertisingSet(advertiserId, enable, timeout);
         }
 
         public void setAdvertisingData(int advertiserId, AdvertiseData data) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setAdvertisingData(advertiserId, data);
         }
 
         public void setScanResponseData(int advertiserId, AdvertiseData data) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setScanResponseData(advertiserId, data);
         }
 
         public void setAdvertisingParameters(
                 int advertiserId, AdvertisingSetParameters parameters) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setAdvertisingParameters(advertiserId, parameters);
         }
 
         public void setPeriodicAdvertisingParameters(
                 int advertiserId, PeriodicAdvertisingParameters parameters) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setPeriodicAdvertisingParameters(advertiserId, parameters);
         }
 
         public void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setPeriodicAdvertisingData(advertiserId, data);
         }
 
-        public void periodicAdvertisingEnable(int advertiserId, boolean enable) {
+        public void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) {
             GattService service = getService();
             if (service == null) return;
-            // TODO: implement
+            service.setPeriodicAdvertisingEnable(advertiserId, enable);
         }
 
         @Override
@@ -1423,17 +1423,51 @@
             AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
             AdvertiseData periodicData, int timeout, IAdvertisingSetCallback callback) {
         enforceAdminPermission();
-
         mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse,
                 periodicParameters, periodicData, timeout, callback);
     }
 
     void stopAdvertisingSet(IAdvertisingSetCallback callback) {
         enforceAdminPermission();
-
         mAdvertiseManager.stopAdvertisingSet(callback);
     }
 
+    void enableAdvertisingSet(int advertiserId, boolean enable, int timeout) {
+        enforceAdminPermission();
+        mAdvertiseManager.enableAdvertisingSet(advertiserId, enable, timeout);
+    }
+
+    void setAdvertisingData(int advertiserId, AdvertiseData data) {
+        enforceAdminPermission();
+        mAdvertiseManager.setAdvertisingData(advertiserId, data);
+    }
+
+    void setScanResponseData(int advertiserId, AdvertiseData data) {
+        enforceAdminPermission();
+        mAdvertiseManager.setScanResponseData(advertiserId, data);
+    }
+
+    void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) {
+        enforceAdminPermission();
+        mAdvertiseManager.setAdvertisingParameters(advertiserId, parameters);
+    }
+
+    void setPeriodicAdvertisingParameters(
+            int advertiserId, PeriodicAdvertisingParameters parameters) {
+        enforceAdminPermission();
+        mAdvertiseManager.setPeriodicAdvertisingParameters(advertiserId, parameters);
+    }
+
+    void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) {
+        enforceAdminPermission();
+        mAdvertiseManager.setPeriodicAdvertisingData(advertiserId, data);
+    }
+
+    void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) {
+        enforceAdminPermission();
+        mAdvertiseManager.setPeriodicAdvertisingEnable(advertiserId, enable);
+    }
+
     /**************************************************************************
      * GATT Service functions - CLIENT
      *************************************************************************/