//class BluetoothLEServiceData ////////////////////////////////////////////////////
var BluetoothLEServiceData = function(data) {
Object.defineProperties(this, {
- serviceuuids : {value: data.serviceData, writable: true, enumerable: true},
+ serviceuuid : {value: data.serviceData, writable: true, enumerable: true},
data : {value: data.data, writable: true, enumerable: true}
});
};
//class BluetoothLEAdvertiseData ////////////////////////////////////////////////////
var BluetoothLEAdvertiseData = function(data) {
Object.defineProperties(this, {
- name : {value: false, writable: true, enumerable: true},
+ includeName : {value: false, writable: true, enumerable: true},
serviceuuids : {value: ["dummyUuids"], writable: true, enumerable: true},
solicitationuuids : {value: ["dummySolicitationuuids"], writable: true, enumerable: true},
appearance : {value: 123456, writable: true, enumerable: true},
- txpowerLevel : {value: false, writable: true, enumerable: true},
+ includeTxPowerLevel : {value: false, writable: true, enumerable: true},
serviceData : {value: ["dummyServiceData"], writable: true, enumerable: true},
manufacturerData : {value: null, writable: true, enumerable: true}
});
};
})();
+var _bleAdvertiseListener = (function() {
+ var kListenerName = 'BluetoothLEAdvertiseCallback';
+ var successCallback;
+ var errorCallback;
+ var listenerRegistered = false;
+
+ function callback(event) {
+ var d;
+
+ switch (event.action) {
+ case 'onstate':
+ if (successCallback) {
+ successCallback(native.getResultObject(event));
+ }
+ return;
+
+ case 'onerror':
+ if (errorCallback) {
+ errorCallback(native.getErrorObject(event));
+ }
+ return;
+
+ default:
+ console.log('Unknown mode: ' + event.action);
+ return;
+ }
+ }
+
+ function addListener(s, e) {
+ successCallback = s;
+ errorCallback = e;
+
+ if (!listenerRegistered) {
+ native.addListener(kListenerName, callback);
+ listenerRegistered = true;
+ }
+ }
+
+ function removeListener() {
+ if (listenerRegistered) {
+ native.removeListener(kListenerName, callback);
+ listenerRegistered = false;
+ }
+
+ successCallback = undefined;
+ errorCallback = undefined;
+ }
+
+ return {
+ addListener: addListener,
+ removeListener: removeListener
+ };
+})();
+
//class BluetoothLEAdapter ////////////////////////////////////////////////////
var BluetoothLEAdapter = function() {
};
}
};
+var _BluetoothAdvertisePacketType = {
+ ADVERTISE: 'ADVERTISE',
+ SCAN_RESPONSE: 'SCAN_RESPONSE'
+};
+
+var _BluetoothAdvertisingMode = {
+ BALANCED: 'BALANCED',
+ LOW_LATENCY: 'LOW_LATENCY',
+ LOW_ENERGY: 'LOW_ENERGY'
+};
+
BluetoothLEAdapter.prototype.startAdvertise = function() {
- console.log('Entered BluetoothLEAdapter.startAdvertise()');
+ console.log('Entered BluetoothLEAdapter.startAdvertise()');
- xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
- //TODO validate
- //TODO call c++ layer
+ xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
+
+ var args = AV.validateMethod(arguments, [{
+ name: 'advertiseData',
+ type: AV.Types.PLATFORM_OBJECT,
+ values: BluetoothLEAdvertiseData
+ }, {
+ name: 'packetType',
+ type: AV.Types.ENUM,
+ values: T.getValues(_BluetoothAdvertisePacketType)
+ }, {
+ name: 'successCallback',
+ type: AV.Types.FUNCTION
+ }, {
+ name: 'errorCallback',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ }, {
+ name: 'mode',
+ type: AV.Types.ENUM,
+ values: T.getValues(_BluetoothAdvertisingMode),
+ optional: true,
+ nullable: true
+ }, {
+ name: 'connectable',
+ type: AV.Types.BOOLEAN,
+ optional: true,
+ nullable: true
+ }]);
+
+ var callArgs = {
+ advertiseData: args.advertiseData,
+ packetType: args.packetType,
+ mode: T.isNullOrUndefined(args.mode) ? _BluetoothAdvertisingMode.BALANCED : args.mode,
+ connectable: T.isNullOrUndefined(args.connectable) ? true : args.connectable
+ };
+
+ var result = native.callSync('BluetoothLEAdapter_startAdvertise', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+
+ _bleAdvertiseListener.addListener(args.successCallback, args.errorCallback);
};
BluetoothLEAdapter.prototype.stopAdvertise = function() {
- console.log('Entered BluetoothLEAdapter.stopAdvertise()');
+ console.log('Entered BluetoothLEAdapter.stopAdvertise()');
- xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
- //TODO validate
- //TODO call c++ layer
+ xwalk.utils.checkPrivilegeAccess(Privilege.BLUETOOTH);
+
+ // TODO: when should we call _bleAdvertiseListener.removeListener()?
+
+ var result = native.callSync('BluetoothLEAdapter_stopAdvertise', {});
+
+ if (native.isFailure(result)) {
+ _bleAdvertiseListener.removeListener();
+ throw native.getErrorObject(result);
+ }
};
//class BluetoothGATTService ////////////////////////////////////////////////////
namespace {
+class ParsedDataHolder {
+ public:
+ ParsedDataHolder() : valid_(false) {}
+ virtual ~ParsedDataHolder() {}
+
+ bool valid() const {
+ return valid_;
+ }
+
+ protected:
+ void set_valid() {
+ valid_ = true;
+ }
+
+ private:
+ bool valid_;
+};
+
+class BluetoothLEServiceData : public ParsedDataHolder {
+ public:
+ BluetoothLEServiceData()
+ : ParsedDataHolder() {
+ }
+
+ const std::string& uuid() const {
+ return uuid_;
+ }
+
+ const std::string& data() const {
+ return data_;
+ }
+
+ static bool Construct(const picojson::value& obj,
+ BluetoothLEServiceData* out) {
+ if (!obj.is<picojson::object>() ||
+ !ParseUUID(obj, out) ||
+ !ParseData(obj, out)) {
+ return false;
+ }
+
+ out->set_valid();
+
+ return true;
+ }
+
+ private:
+ static bool ParseUUID(const picojson::value& obj,
+ BluetoothLEServiceData* out) {
+ const auto& uuid = obj.get("serviceuuid");
+ if (uuid.is<std::string>()) {
+ out->uuid_ = uuid.get<std::string>();
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseData(const picojson::value& obj,
+ BluetoothLEServiceData* out) {
+ const auto& data = obj.get("data");
+ if (data.is<std::string>()) {
+ out->data_ = data.get<std::string>();
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ std::string uuid_;
+ std::string data_;
+};
+
+class BluetoothLEManufacturerData : public ParsedDataHolder {
+ public:
+ BluetoothLEManufacturerData()
+ : ParsedDataHolder(),
+ id_(-1) {
+ }
+
+ int id() const {
+ return id_;
+ }
+
+ const std::string& data() const {
+ return data_;
+ }
+
+ static bool Construct(const picojson::value& obj,
+ BluetoothLEManufacturerData* out) {
+ if (!obj.is<picojson::object>() ||
+ !ParseId(obj, out) ||
+ !ParseData(obj, out)) {
+ return false;
+ }
+
+ out->set_valid();
+
+ return true;
+ }
+
+ private:
+ static bool ParseId(const picojson::value& obj,
+ BluetoothLEManufacturerData* out) {
+ const auto& id = obj.get("id");
+ if (id.is<std::string>()) {
+ try {
+ out->id_ = std::stoi(id.get<std::string>());
+ } catch (...) {
+ LoggerE("Failed to convert string to int: %s", id.get<std::string>().c_str());
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseData(const picojson::value& obj,
+ BluetoothLEManufacturerData* out) {
+ const auto& data = obj.get("data");
+ if (data.is<std::string>()) {
+ out->data_ = data.get<std::string>();
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ int id_;
+ std::string data_;
+};
+
+class BluetoothLEAdvertiseData : public ParsedDataHolder {
+ public:
+ BluetoothLEAdvertiseData()
+ : ParsedDataHolder(),
+ include_name_(false),
+ appearance_(0), // 0 means unknown
+ include_tx_power_level_(false) {
+ }
+
+ bool include_name() const {
+ return include_name_;
+ }
+
+ const std::vector<std::string>& service_uuids() const {
+ return service_uuids_;
+ }
+
+ const std::vector<std::string>& solicitation_uuids() const {
+ return solicitation_uuids_;
+ }
+
+ int appearance() const {
+ return appearance_;
+ }
+
+ bool include_tx_power_level() const {
+ return include_tx_power_level_;
+ }
+
+ const std::vector<BluetoothLEServiceData>& service_data() const {
+ return service_data_;
+ }
+
+ const BluetoothLEManufacturerData& manufacturer_data() const {
+ return manufacturer_data_;
+ }
+
+ static bool Construct(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ if (!obj.is<picojson::object>() ||
+ !ParseIncludeName(obj, out) ||
+ !ParseServiceUUIDs(obj, out) ||
+ !ParseSolicitationUUIDs(obj, out) ||
+ !ParseAppearance(obj, out) ||
+ !ParseIncludeTxPowerLevel(obj, out) ||
+ !ParseServiceData(obj, out) ||
+ !ParseManufacturerData(obj, out)) {
+ return false;
+ }
+
+ out->set_valid();
+
+ return true;
+ }
+
+ private:
+ static bool ParseIncludeName(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& include_name = obj.get("includeName");
+ if (include_name.is<bool>()) {
+ out->include_name_ = include_name.get<bool>();
+ } else if (!include_name.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseServiceUUIDs(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& service_uuids = obj.get("serviceuuids");
+ if (service_uuids.is<picojson::array>()) {
+ for (const auto& i : service_uuids.get<picojson::array>()) {
+ if (i.is<std::string>()) {
+ out->service_uuids_.push_back(i.get<std::string>());
+ } else {
+ return false;
+ }
+ }
+ } else if (!service_uuids.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseSolicitationUUIDs(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& solicitation_uuids = obj.get("solicitationuuids");
+ if (solicitation_uuids.is<picojson::array>()) {
+ for (const auto& i : solicitation_uuids.get<picojson::array>()) {
+ if (i.is<std::string>()) {
+ out->solicitation_uuids_.push_back(i.get<std::string>());
+ } else {
+ return false;
+ }
+ }
+ } else if (!solicitation_uuids.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseAppearance(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& appearance = obj.get("appearance");
+ if (appearance.is<double>()) {
+ out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
+ } else if (!appearance.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseIncludeTxPowerLevel(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
+ if (include_tx_power_level.is<bool>()) {
+ out->include_tx_power_level_ = include_tx_power_level.get<bool>();
+ } else if (!include_tx_power_level.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseServiceData(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& service_data = obj.get("serviceData");
+ if (service_data.is<picojson::array>()) {
+ for (const auto& i : service_data.get<picojson::array>()) {
+ BluetoothLEServiceData data;
+ if (BluetoothLEServiceData::Construct(i, &data)) {
+ out->service_data_.push_back(std::move(data));
+ } else {
+ return false;
+ }
+ }
+ } else if (!service_data.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ParseManufacturerData(const picojson::value& obj,
+ BluetoothLEAdvertiseData* out) {
+ const auto& manufacturer_data = obj.get("manufacturerData");
+ BluetoothLEManufacturerData data;
+ if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
+ out->manufacturer_data_ = std::move(data);
+ } else if (!manufacturer_data.is<picojson::null>()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool include_name_;
+ std::vector<std::string> service_uuids_;
+ std::vector<std::string> solicitation_uuids_;
+ int appearance_;
+ bool include_tx_power_level_;
+ std::vector<BluetoothLEServiceData> service_data_;
+ BluetoothLEManufacturerData manufacturer_data_;
+};
+
// utility functions
bool ToBool(bt_adapter_le_state_e state) {
const std::string kOnScanFinished = "onfinished";
const std::string kOnScanError = "onerror";
const std::string kScanEvent = "BluetoothLEScanCallback";
+// advertise-related
+const std::string kOnAdvertiseState = "onstate";
+const std::string kOnAdvertiseError = "onerror";
+const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
} // namespace
BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
: instance_(instance),
enabled_(false),
- scanning_(false) {
+ scanning_(false),
+ bt_advertiser_(nullptr) {
LoggerD("Entered");
bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
if (scanning_) {
bt_adapter_le_stop_scan();
}
+ if (bt_advertiser_) {
+ bt_adapter_le_stop_advertising(bt_advertiser_);
+ bt_adapter_le_destroy_advertiser(bt_advertiser_);
+ }
bt_adapter_le_disable();
}
void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
LoggerD("Entered");
+
+ const auto& json_advertise_data = data.get("advertiseData");
+ const auto& json_packet_type = data.get("packetType");
+ const auto& json_mode = data.get("mode");
+ const auto& json_connectable = data.get("connectable");
+
+ if (!json_advertise_data.is<picojson::object>() ||
+ !json_packet_type.is<std::string>() ||
+ !json_mode.is<std::string>() ||
+ !json_connectable.is<bool>()) {
+ ReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"), &out);
+ return;
+ }
+
+ BluetoothLEAdvertiseData advertise_data;
+ if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
+ ReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
+ return;
+ }
+
+ bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
+ {
+ const auto& str_packet_type = json_packet_type.get<std::string>();
+ if ("ADVERTISE" == str_packet_type) {
+ packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
+ } else if ("SCAN_RESPONSE" == str_packet_type) {
+ packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
+ } else {
+ ReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out);
+ return;
+ }
+ }
+
+ bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
+ {
+ const auto& str_mode = json_mode.get<std::string>();
+ if ("BALANCED" == str_mode) {
+ mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
+ } else if ("LOW_LATENCY" == str_mode) {
+ mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
+ } else if ("LOW_ENERGY" == str_mode) {
+ mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
+ } else {
+ ReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"), &out);
+ return;
+ }
+ }
+
+ if (nullptr != bt_advertiser_) {
+ LoggerE("Advertise in progress");
+ ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out);
+ return;
+ }
+
+ bt_advertiser_h advertiser = nullptr;
+
+ int ret = bt_adapter_le_create_advertiser(&advertiser);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_create_advertiser() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type,
+ int (*)(bt_advertiser_h)> advertiser_ptr(advertiser, &bt_adapter_le_destroy_advertiser); // automatically release the memory
+
+ // configure advertiser
+
+ ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
+ advertise_data.include_name());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_set_advertising_device_name() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ for (const auto& i : advertise_data.service_uuids()) {
+ ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
+ i.c_str());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_add_advertising_service_uuid() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+ }
+
+ for (const auto& i : advertise_data.solicitation_uuids()) {
+ ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser,
+ packet_type,
+ i.c_str());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+ }
+
+ ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
+ advertise_data.appearance());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_set_advertising_appearance() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
+ advertise_data.include_tx_power_level());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_set_advertising_tx_power_level() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ for (const auto& i : advertise_data.service_data()) {
+ ret = bt_adapter_le_add_advertising_service_data(advertiser, packet_type,
+ i.uuid().c_str(),
+ i.data().c_str(),
+ i.data().length());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_add_advertising_service_data() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+ }
+
+ const auto& manufacturer_data = advertise_data.manufacturer_data();
+ if (manufacturer_data.valid()) {
+ ret = bt_adapter_le_add_advertising_manufacturer_data(advertiser,
+ packet_type,
+ manufacturer_data.id(),
+ manufacturer_data.data().c_str(),
+ manufacturer_data.data().length());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+ }
+
+ ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_set_advertising_mode() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_adapter_le_set_advertising_connectable() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
+ return;
+ }
+
+ // advertiser is ready, let's start advertising
+ ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
+ if (BT_ERROR_NONE != ret) {
+ if (BT_ERROR_NOW_IN_PROGRESS == ret) {
+ ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out);
+ return;
+ }
+
+ LoggerE("bt_adapter_le_start_advertising_new() failed with: %d", ret);
+ ReportError(util::GetBluetoothError(ret, "Failed to start advertising"), &out);
+ return;
+ }
+
+ // everything went well, we want to store the pointer, so unique_ptr should no longer manage the memory
+ bt_advertiser_ = advertiser_ptr.release();
+ ReportSuccess(out);
}
void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
LoggerD("Entered");
+
+ if (nullptr != bt_advertiser_) {
+ int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
+ if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
+ LoggerE("bt_adapter_le_stop_advertising() failed with: %d", ret);
+ ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out);
+ return;
+ }
+
+ ret = bt_adapter_le_destroy_advertiser(bt_advertiser_);
+ if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
+ LoggerE("bt_adapter_le_destroy_advertiser() failed with: %d", ret);
+ ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"), &out);
+ return;
+ }
+
+ bt_advertiser_ = nullptr;
+ } else {
+ LoggerD("Advertising is not in progress");
+ }
+
+ ReportSuccess(out);
}
void BluetoothLEAdapter::OnStateChanged(int result,
adapter->instance_.FireEvent(kScanEvent, value);
}
+void BluetoothLEAdapter::OnAdvertiseResult(
+ int result, bt_advertiser_h advertiser,
+ bt_adapter_le_advertising_state_e adv_state, void* user_data) {
+ LoggerD("Entered, result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser, adv_state, user_data);
+
+ auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
+
+ if (!adapter) {
+ LoggerE("user_data is NULL");
+ return;
+ }
+
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ if (BT_ERROR_NONE != result) {
+ LoggerE("Error during advertising: %d", result);
+ ReportError(util::GetBluetoothError(result, "Error during advertising"), data_obj);
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
+ } else {
+ const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
+ LoggerD("Advertise state is: %s", state);
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
+ ReportSuccess(picojson::value(state), *data_obj);
+ }
+
+ adapter->instance_.FireEvent(kAdvertiseEvent, value);
+}
+
} // namespace bluetooth
} // namespace extension