throw native.getErrorObject(result);
}
};
+
+ BluetoothGATTCharacteristic.prototype.addValueChangeListener = function() {
+ console.log('Entered BluetoothGATTCharacteristic.addValueChangeListener()');
+
+ xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
+
+ var args = AV.validateMethod(arguments, [{
+ name: 'callback',
+ type: AV.Types.FUNCTION
+ }]);
+
+ var callArgs = { handle: handle_, address : address_ };
+
+ var callback = function(event) {
+ if (event.handle === handle_) {
+ args.callback(toByteArray(native.getResultObject(event)));
+ }
+ };
+
+ return _bluetoothGATTCharacteristicListener.addListener(callback, callArgs);
+ };
+
+ BluetoothGATTCharacteristic.prototype.removeValueChangeListener = function() {
+ console.log('Entered BluetoothGATTCharacteristic.removeValueChangeListener()');
+
+ var args = AV.validateMethod(arguments, [{
+ name: 'watchID',
+ type: AV.Types.LONG
+ }]);
+
+ var callArgs = { handle: handle_, address : address_ };
+
+ return _bluetoothGATTCharacteristicListener.removeListener(args.watchID, callArgs);
+ };
};
+
/**
* Creates a manager for specified listener event. Manager handles multiple
* registered listeners
* This function should have following signature:
* void callback(listener, event);
* @param {string} addListenerId - optional parameter. If specified, this native
- * method will be called synchronously when first
+ * method will be called synchronously when
* listener is added.
* @param {string} removeListenerId - optional parameter. If specified, this native
- * method will be called synchronously when last
+ * method will be called synchronously when
* listener is removed.
+ * @param {bool} repeatNativeCall - optional parameter. If specified, the addListenerId
+ * and removeListenerId methods will be called synchronously
+ * each time listener is added/removed. Otherwise they are
+ * going to be called just once: when first listener is added
+ * and last listener is removed.
*
* @return {object} object which allows to add or remove callbacks for specified listener
*/
-function _multipleListenerBuilder(name, callback, addListenerId, removeListenerId) {
+function _multipleListenerBuilder(name, callback, addListenerId, removeListenerId, repeatNativeCall) {
var listenerName = name;
var addId = addListenerId;
var removeId = removeListenerId;
var callbackFunction = callback;
var listeners = {};
var nextId = 1;
+ var jsListenerRegistered = false;
+ var nativeListenerRegistered = false;
+ var repeatNativeListenerCall = repeatNativeCall;
function innerCallback(event) {
for (var watchId in listeners) {
}
}
- function addListener(callback) {
+ function addListener(callback, args) {
var id = ++nextId;
- if (!listenerRegistered) {
- if (addId) {
- var result = native.callSync(addId, {});
- if (native.isFailure(result)) {
- throw native.getErrorObject(result);
- }
+ if (addId && (!nativeListenerRegistered || repeatNativeListenerCall)) {
+ var result = native.callSync(addId, args || {});
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
}
+ nativeListenerRegistered = true;
+ }
+
+ if (!jsListenerRegistered) {
native.addListener(listenerName, innerCallback);
- listenerRegistered = true;
+ jsListenerRegistered = true;
}
listeners[id] = callback;
return id;
}
- function removeListener(watchId) {
+ function removeListener(watchId, args) {
if (listeners.hasOwnProperty(watchId)) {
delete listeners[watchId];
}
- if (listenerRegistered && T.isEmptyObject(listeners)) {
- if (removeId) {
- native.callSync(removeId, {});
- }
+ if (removeId && ((nativeListenerRegistered && T.isEmptyObject(listeners)) || repeatNativeListenerCall)) {
+ native.callSync(removeId, args || {});
+ nativeListenerRegistered = false;
+ }
+
+ if (jsListenerRegistered && T.isEmptyObject(listeners)) {
native.removeListener(listenerName, innerCallback);
- listenerRegistered = false;
+ jsListenerRegistered = false;
}
}
var _bluetoothGATTCharacteristicListener = _multipleListenerBuilder(
'BluetoothGATTCharacteristicValueChangeListener',
- function(listener, data) {
- var d = [];
- data.value.forEach(function(b) {
- d.push(Converter.toByte(b));
- });
- listener(d);
+ function(listener, event) {
+ listener(event);
},
'BluetoothGATTCharacteristic_addValueChangeListener',
- 'BluetoothGATTCharacteristic_removeValueChangeListener'
+ 'BluetoothGATTCharacteristic_removeValueChangeListener',
+ true
);
var _bleConnectChangeListener = _multipleListenerBuilder(
'BluetoothLEDevice_removeConnectStateChangeListener'
);
-BluetoothGATTCharacteristic.prototype.addValueChangeListener = function() {
- console.log('Entered BluetoothGATTCharacteristic.addValueChangeListener()');
-
- xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
-
- var args = AV.validateMethod(arguments, [{
- name: 'callback',
- type: AV.Types.FUNCTION
- }]);
-
- return _bluetoothGATTCharacteristicListener.addListener(args.callback);
-};
-
-BluetoothGATTCharacteristic.prototype.removeValueChangeListener = function() {
- console.log('Entered BluetoothGATTCharacteristic.removeValueChangeListener()');
-
- var args = AV.validateMethod(arguments, [{
- name: 'watchID',
- type: AV.Types.LONG
- }]);
-
- return _bluetoothGATTCharacteristicListener.removeListener(args.watchID);
-};
-
//class BluetoothGATTDescriptor ////////////////////////////////////////////////////
var BluetoothGATTDescriptor = function(address) {
var handle_ = data.handle;
const std::string kWritable = "isWritable";
const std::string kWriteNoResponse = "isWriteNoResponse";
+const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener";
bool IsProperty (int propertyBits, bt_gatt_property_e property) {
return (propertyBits & property) == 0;
LoggerD("Entered");
for (auto it : gatt_clients_) {
+ // unregister callback, ignore errors
+ bt_gatt_client_unset_characteristic_value_changed_cb(it.second);
LoggerD("destroying client for address: %s", it.first.c_str());
bt_gatt_client_destroy(it.second);
}
}
ReportSuccess(out);
}
+
+void BluetoothGATTService::AddValueChangeListener(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ const auto& address = args.get("address").get<std::string>();
+ if (!IsStillConnected(address)) {
+ LoggerE("Device with address %s is no longer connected", address.c_str());
+ ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+ "Device is not connected"), &out);
+ return;
+ }
+
+ bt_gatt_h handle = (bt_gatt_h)static_cast<long>(args.get(kHandle).get<double>());
+
+ int ret = bt_gatt_client_set_characteristic_value_changed_cb(handle, OnCharacteristicValueChanged, this);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out);
+ } else {
+ ReportSuccess(out);
+ }
+}
+
+void BluetoothGATTService::RemoveValueChangeListener(
+ const picojson::value& args, picojson::object& out) {
+ LoggerD("Entered");
+ const auto& address = args.get("address").get<std::string>();
+ if (!IsStillConnected(address)) {
+ LoggerE("Device with address %s is no longer connected", address.c_str());
+ ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+ "Device is not connected"), &out);
+ return;
+ }
+
+ bt_gatt_h handle = (bt_gatt_h)static_cast<long>(args.get(kHandle).get<double>());
+
+ int ret = bt_gatt_client_unset_characteristic_value_changed_cb(handle);
+
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to unregister listener"), &out);
+ } else {
+ ReportSuccess(out);
+ }
+}
+
+void BluetoothGATTService::OnCharacteristicValueChanged(
+ bt_gatt_h characteristic, char* value, int length, void* user_data) {
+ LoggerD("Entered, characteristic: [%p], len: [d], user_data: [%p]", characteristic, length, user_data);
+
+ auto service = static_cast<BluetoothGATTService*>(user_data);
+
+ if (!service) {
+ LoggerE("user_data is NULL");
+ return;
+ }
+
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object result_obj = result.get<picojson::object>();
+
+ result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)characteristic)));
+
+ picojson::value byte_array = picojson::value(picojson::array());
+ picojson::array& byte_array_obj = byte_array.get<picojson::array>();
+
+ for (size_t i = 0 ; i < length; ++i) {
+ byte_array_obj.push_back(picojson::value(std::to_string(value[i])));
+ }
+
+ ReportSuccess(byte_array, result_obj);
+
+ service->instance_.FireEvent(kOnValueChanged, result);
+}
+
} // namespace bluetooth
} // namespace extension