27fd38f8d921625f2486adb8944a580a6ad1bd69
[platform/core/api/webapi-plugins.git] / src / bluetooth / bluetooth_le_adapter.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "bluetooth/bluetooth_le_adapter.h"
18
19 #include "common/logger.h"
20 #include "common/tools.h"
21
22 #include "bluetooth/bluetooth_instance.h"
23 #include "bluetooth/bluetooth_le_device.h"
24 #include "bluetooth/bluetooth_privilege.h"
25 #include "bluetooth/bluetooth_util.h"
26 using common::optional;
27
28 namespace extension {
29 namespace bluetooth {
30
31 namespace {
32
33 const std::string kData = "data";
34 const std::string kUuid = "uuid";
35 const std::string kUuids = "uuids";
36 const std::string kSolicitationUuids = "solicitationuuids";
37 const std::string kServiceData = "serviceData";
38
39 class ParsedDataHolder {
40  public:
41   ParsedDataHolder() : valid_(false) {
42     ScopeLogger();
43   }
44   virtual ~ParsedDataHolder() {
45     ScopeLogger();
46   }
47
48   bool valid() const {
49     return valid_;
50   }
51
52  protected:
53   void set_valid() {
54     valid_ = true;
55   }
56
57  private:
58   bool valid_;
59 };
60
61 class HexData {
62  public:
63   HexData() : length_(0) {
64   }
65
66   void Parse(const std::string& d) {
67     ScopeLogger();
68     const char* p_data = d.c_str();
69     int size = d.length();
70     if (size > 2 && (d.find("0x", 0) == 0 || d.find("0X", 0) == 0)) {
71       p_data += 2;
72       size -= 2;
73     }
74     length_ = size / 2;
75     pointer_.reset(new char[length_]);
76     common::tools::HexToBin(p_data, size, (unsigned char*)pointer(), length_);
77   }
78
79   const char* pointer() const {
80     return pointer_.get();
81   }
82
83   int length() const {
84     return length_;
85   }
86
87  private:
88   std::unique_ptr<char[]> pointer_;
89   int length_;
90 };
91
92 class BluetoothLEServiceData : public ParsedDataHolder {
93  public:
94   const UUID& uuid() const {
95     return uuid_;
96   }
97
98   const HexData& data() const {
99     return data_;
100   }
101
102   static optional<BluetoothLEServiceData> Construct(const picojson::value& service_data_obj) {
103     ScopeLogger();
104
105     const auto& data = service_data_obj.get(kData);
106     const auto& uuid_str = service_data_obj.get(kUuid);
107     if (!data.is<std::string>() || !uuid_str.is<std::string>()) {
108       LoggerE("Invalid data type in service data");
109       return {};
110     }
111
112     auto uuid = UUID::create(uuid_str.get<std::string>());
113     if (!uuid) {
114       return {};
115     }
116
117     return BluetoothLEServiceData{std::move(*uuid), data.get<std::string>()};
118   }
119
120  private:
121   BluetoothLEServiceData(UUID&& uuid, const std::string& data_str) : uuid_{std::move(uuid)} {
122     ScopeLogger("UUID: %s, data_str: %s", uuid_.uuid_128_bit.c_str(), data_str.c_str());
123
124     data_.Parse(data_str);
125
126     set_valid();
127   }
128
129   const UUID uuid_;
130   HexData data_;
131 };
132
133 class BluetoothLEManufacturerData : public ParsedDataHolder {
134  public:
135   const std::string& id() const {
136     return id_;
137   }
138
139   const HexData& data() const {
140     return data_;
141   }
142
143   static bool Construct(const picojson::value& obj, BluetoothLEManufacturerData* out) {
144     ScopeLogger();
145     if (!obj.is<picojson::object>() || !ParseId(obj, out) || !ParseData(obj, out)) {
146       return false;
147     }
148
149     out->set_valid();
150
151     return true;
152   }
153
154  private:
155   static bool ParseId(const picojson::value& obj, BluetoothLEManufacturerData* out) {
156     ScopeLogger();
157     const auto& id = obj.get("id");
158     if (id.is<std::string>()) {
159       out->id_ = id.get<std::string>();
160     } else {
161       return false;
162     }
163
164     return true;
165   }
166
167   static bool ParseData(const picojson::value& obj, BluetoothLEManufacturerData* out) {
168     ScopeLogger();
169
170     const auto& val_data = obj.get("data");
171
172     if (val_data.is<std::string>()) {
173       out->data_.Parse(val_data.get<std::string>());
174       return true;
175     } else {
176       return false;
177     }
178   }
179
180   std::string id_;
181   HexData data_;
182 };
183
184 class BluetoothLEAdvertiseData : public ParsedDataHolder {
185  public:
186   BluetoothLEAdvertiseData()
187       : ParsedDataHolder(),
188         include_name_(false),
189         appearance_(0),  // 0 means unknown
190         include_tx_power_level_(false) {
191     ScopeLogger();
192   }
193
194   bool include_name() const {
195     return include_name_;
196   }
197
198   const std::vector<UUID>& service_uuids() const {
199     return service_uuids_;
200   }
201
202   const std::vector<UUID>& solicitation_uuids() const {
203     return solicitation_uuids_;
204   }
205
206   int appearance() const {
207     return appearance_;
208   }
209
210   bool include_tx_power_level() const {
211     return include_tx_power_level_;
212   }
213
214   const std::vector<BluetoothLEServiceData>& service_data() const {
215     return service_data_;
216   }
217
218   const BluetoothLEManufacturerData& manufacturer_data() const {
219     return manufacturer_data_;
220   }
221
222   static bool Construct(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
223     ScopeLogger();
224     if (!obj.is<picojson::object>() || !ParseIncludeName(obj, out) ||
225         !ParseServiceUUIDs(obj, out) || !ParseSolicitationUUIDs(obj, out) ||
226         !ParseAppearance(obj, out) || !ParseIncludeTxPowerLevel(obj, out) ||
227         !ParseServiceData(obj, out) || !ParseManufacturerData(obj, out)) {
228       return false;
229     }
230
231     out->set_valid();
232
233     return true;
234   }
235
236  private:
237   static bool ParseIncludeName(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
238     ScopeLogger();
239     const auto& include_name = obj.get("includeName");
240     if (include_name.is<bool>()) {
241       out->include_name_ = include_name.get<bool>();
242     } else if (!include_name.is<picojson::null>()) {
243       return false;
244     }
245
246     return true;
247   }
248
249   static bool ParseServiceUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
250     ScopeLogger();
251     const auto& service_uuids = obj.get(kUuids);
252     if (service_uuids.is<picojson::array>()) {
253       for (const auto& uuid : service_uuids.get<picojson::array>()) {
254         if (!uuid.is<std::string>()) {
255           LoggerE("uuid is not a string");
256           return false;
257         }
258
259         auto uuid_obj = UUID::create(uuid.get<std::string>());
260         if (uuid_obj) {
261           out->service_uuids_.push_back(*uuid_obj);
262         } else {
263           return false;
264         }
265       }
266     } else if (!service_uuids.is<picojson::null>()) {
267       LoggerE("Invalid service_uuids type");
268       return false;
269     }
270
271     return true;
272   }
273
274   static bool ParseSolicitationUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
275     ScopeLogger();
276     const auto& solicitation_uuids = obj.get(kSolicitationUuids);
277     if (solicitation_uuids.is<picojson::array>()) {
278       for (const auto& uuid : solicitation_uuids.get<picojson::array>()) {
279         if (!uuid.is<std::string>()) {
280           LoggerE("uuid is not a string");
281           return false;
282         }
283
284         auto uuid_obj = UUID::create(uuid.get<std::string>());
285         if (uuid_obj) {
286           out->solicitation_uuids_.push_back(*uuid_obj);
287         } else {
288           return false;
289         }
290       }
291     } else if (!solicitation_uuids.is<picojson::null>()) {
292       return false;
293     }
294
295     return true;
296   }
297
298   static bool ParseAppearance(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
299     ScopeLogger();
300     const auto& appearance = obj.get("appearance");
301     if (appearance.is<double>()) {
302       out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
303     } else if (!appearance.is<picojson::null>()) {
304       return false;
305     }
306
307     return true;
308   }
309
310   static bool ParseIncludeTxPowerLevel(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
311     ScopeLogger();
312     const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
313     if (include_tx_power_level.is<bool>()) {
314       out->include_tx_power_level_ = include_tx_power_level.get<bool>();
315     } else if (!include_tx_power_level.is<picojson::null>()) {
316       return false;
317     }
318
319     return true;
320   }
321
322   static bool ParseServiceData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
323     ScopeLogger();
324
325     const auto& service_data_obj = obj.get(kServiceData);
326     if (service_data_obj.is<picojson::null>()) {
327       return true;
328     } else if (!service_data_obj.is<picojson::object>()) {
329       return false;
330     }
331
332     /*
333      * Currently, only advertising of a single service data object is supported
334      * by the Web API. In the future, support for advertising arrays of those
335      * may be added.
336      *
337      * TODO: if supported, parse here the whole array of service data instances.
338      */
339     auto service_data = BluetoothLEServiceData::Construct(service_data_obj);
340     if (!service_data) {
341       return false;
342     }
343
344     out->service_data_.emplace_back(std::move(*service_data));
345     return true;
346   }
347
348   static bool ParseManufacturerData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
349     ScopeLogger();
350     const auto& manufacturer_data = obj.get("manufacturerData");
351     BluetoothLEManufacturerData data;
352     if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
353       out->manufacturer_data_ = std::move(data);
354     } else if (!manufacturer_data.is<picojson::null>()) {
355       return false;
356     }
357
358     return true;
359   }
360
361   bool include_name_;
362   std::vector<UUID> service_uuids_;
363   std::vector<UUID> solicitation_uuids_;
364   int appearance_;
365   bool include_tx_power_level_;
366   std::vector<BluetoothLEServiceData> service_data_;
367   BluetoothLEManufacturerData manufacturer_data_;
368 };
369
370 // utility functions
371
372 bool ToBool(bt_adapter_le_state_e state) {
373   return (BT_ADAPTER_LE_ENABLED == state) ? true : false;
374 }
375
376 // constants
377 const std::string kAction = "action";
378 // scan-related
379 const std::string kOnScanSuccess = "onsuccess";
380 const std::string kOnScanError = "onerror";
381 const std::string kScanEvent = "BluetoothLEScanCallback";
382 // advertise-related
383 const std::string kOnAdvertiseState = "onstate";
384 const std::string kOnAdvertiseError = "onerror";
385 const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
386
387 }  // namespace
388
389 using common::ErrorCode;
390 using common::PlatformResult;
391 using common::tools::ReportError;
392 using common::tools::ReportSuccess;
393
394 BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
395     : instance_(instance), enabled_(false), scanning_(false), bt_advertiser_(nullptr) {
396   ScopeLogger();
397
398   bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
399
400   int ret = bt_adapter_le_get_state(&le_state);
401
402   if (BT_ERROR_NONE == ret) {
403     enabled_ = ToBool(le_state);
404
405     ret = bt_adapter_le_set_state_changed_cb(OnStateChanged, this);
406     if (BT_ERROR_NONE != ret) {
407       LoggerE("Failed to register BTLE state changed listener.");
408     }
409   } else {
410     LoggerE("Failed to obtain current state of BTLE.");
411   }
412 }
413
414 BluetoothLEAdapter::~BluetoothLEAdapter() {
415   ScopeLogger();
416   bt_adapter_le_unset_state_changed_cb();
417   if (scanning_) {
418     bt_adapter_le_stop_scan();
419   }
420   if (bt_advertiser_) {
421     bt_adapter_le_stop_advertising(bt_advertiser_);
422     bt_adapter_le_destroy_advertiser(bt_advertiser_);
423   }
424 }
425
426 void BluetoothLEAdapter::StartScan(const picojson::value& data, picojson::object& out) {
427   ScopeLogger();
428   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
429                                               &out);
430
431   int ret = bt_adapter_le_start_scan(OnScanResult, this);
432
433   if (BT_ERROR_NONE != ret) {
434     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
435       LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Scan already in progress"),
436                         &out, ("Scan in progress %d (%s)", ret, get_error_message(ret)));
437     } else {
438       // other errors are reported asynchronously
439       picojson::value value = picojson::value(picojson::object());
440       picojson::object* data_obj = &value.get<picojson::object>();
441       data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
442       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to start scan"), data_obj,
443                         ("Failed to start scan: %d (%s)", ret, get_error_message(ret)));
444       instance_.FireEvent(kScanEvent, value);
445     }
446   } else {
447     scanning_ = true;
448     ReportSuccess(out);
449   }
450 }
451
452 void BluetoothLEAdapter::StopScan(const picojson::value& data, picojson::object& out) {
453   ScopeLogger();
454   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
455                                               &out);
456
457   int ret = bt_adapter_le_stop_scan();
458
459   if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
460     LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop scan"), &out,
461                       ("Failed to stop scan: %d (%s)", ret, get_error_message(ret)));
462   } else {
463     scanning_ = false;
464     ReportSuccess(out);
465   }
466 }
467
468 void BluetoothLEAdapter::IsScanning(picojson::object& out) {
469   ScopeLogger();
470
471   bool is_scanning;
472   int ret = bt_adapter_le_is_discovering(&is_scanning);
473
474   if (BT_ERROR_NONE != ret) {
475     LogAndReportError(
476         PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to check for scanning in progress"), &out,
477         ("Failed to check for scanning in progress: %d (%s)", ret, get_error_message(ret)));
478   } else {
479     scanning_ = is_scanning;
480     ReportSuccess(picojson::value(is_scanning), out);
481   }
482 }
483
484 void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
485   ScopeLogger();
486   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
487                                               &out);
488
489   const auto& json_advertise_data = data.get("advertiseData");
490   const auto& json_packet_type = data.get("packetType");
491   const auto& json_mode = data.get("mode");
492   const auto& json_connectable = data.get("connectable");
493
494   if (!json_advertise_data.is<picojson::object>() || !json_packet_type.is<std::string>() ||
495       !json_mode.is<std::string>() || !json_connectable.is<bool>()) {
496     LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"),
497                       &out);
498     return;
499   }
500
501   BluetoothLEAdvertiseData advertise_data;
502   if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
503     LogAndReportError(
504         PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
505     return;
506   }
507
508   bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
509   {
510     const auto& str_packet_type = json_packet_type.get<std::string>();
511     if ("ADVERTISE" == str_packet_type) {
512       packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
513     } else if ("SCAN_RESPONSE" == str_packet_type) {
514       packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
515     } else {
516       LogAndReportError(
517           PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out,
518           ("Wrong packet_type: %s", str_packet_type.c_str()));
519       return;
520     }
521   }
522
523   bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
524   {
525     const auto& str_mode = json_mode.get<std::string>();
526     if ("BALANCED" == str_mode) {
527       mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
528     } else if ("LOW_LATENCY" == str_mode) {
529       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
530     } else if ("LOW_ENERGY" == str_mode) {
531       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
532     } else {
533       LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"),
534                         &out, ("Wrong mode: %s", str_mode.c_str()));
535       return;
536     }
537   }
538
539   if (nullptr != bt_advertiser_) {
540     LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"),
541                       &out);
542     return;
543   }
544
545   bt_advertiser_h advertiser = nullptr;
546
547   int ret = bt_adapter_le_create_advertiser(&advertiser);
548   if (BT_ERROR_NONE != ret) {
549     LogAndReportError(
550         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
551         ("bt_adapter_le_create_advertiser() failed with: %d, (%s)", ret, get_error_message(ret)));
552     return;
553   }
554
555   std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type, int (*)(bt_advertiser_h)>
556       advertiser_ptr(advertiser,
557                      &bt_adapter_le_destroy_advertiser);  // automatically release the memory
558
559   // configure advertiser
560   if (advertise_data.include_name()) {
561     ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
562                                                     advertise_data.include_name());
563     if (BT_ERROR_NONE != ret) {
564       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
565                         ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
566                          get_error_message(ret)));
567       return;
568     }
569   }
570
571   for (const auto& uuid : advertise_data.service_uuids()) {
572     /*
573      * This native function accepts 16 or 128 bit UUIDs.
574      * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
575      *
576      * Note:
577      * The documentation of Native Bluetooth API says, this function advertises 128-bit UUIDs,
578      * that have 32-bit equivalents in the full 128-bit form.
579      * However, as of the day of writing this comment, packets advertised
580      * by the device contain these UUIDs in their 32-bit formats,
581      * i.e. AD fields with 0x04 («Incomplete List of 32-bit Service Class UUIDs») type.
582      * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
583      */
584     ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
585                                                      uuid.uuid_128_bit.c_str());
586     if (BT_ERROR_NONE != ret) {
587       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
588                         ("bt_adapter_le_add_advertising_service_uuid() failed with: %d (%s)", ret,
589                          get_error_message(ret)));
590       return;
591     }
592   }
593
594   for (const auto& uuid : advertise_data.solicitation_uuids()) {
595     /*
596      * This native function accepts 16 or 128 bit UUIDs.
597      * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
598      *
599      * Note:
600      * The documentation of Native Bluetooth API says, it advertises 128-bit UUIDs,
601      * that have 32-bit equivalents in the full 128-bit form.
602      * However, as of the day of writing this comment, packets advertised
603      * by the device contain these UUIDs in their 32-bit formats,
604      * i.e. AD fields with 0x1F («List of 32-bit Service Solicitation UUIDs») type.
605      * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
606      */
607     ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, packet_type,
608                                                                   uuid.uuid_128_bit.c_str());
609     if (BT_ERROR_NONE != ret) {
610       LogAndReportError(
611           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
612           ("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d (%s)", ret,
613            get_error_message(ret)));
614       return;
615     }
616   }
617
618   ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
619                                                  advertise_data.appearance());
620   if (BT_ERROR_NONE != ret) {
621     LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
622                       ("bt_adapter_le_set_advertising_appearance() failed with: %d (%s)", ret,
623                        get_error_message(ret)));
624     return;
625   }
626
627   if (advertise_data.include_tx_power_level()) {
628     ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
629                                                        advertise_data.include_tx_power_level());
630     if (BT_ERROR_NONE != ret) {
631       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
632                         ("bt_adapter_le_set_advertising_tx_power_level() failed with: %d (%s)", ret,
633                          get_error_message(ret)));
634       return;
635     }
636   }
637
638   if (advertise_data.service_data().empty()) {
639     LoggerD("service data is empty");
640   } else {
641     for (const auto& service_data_obj : advertise_data.service_data()) {
642       ret = bt_adapter_le_add_advertising_service_data(
643           advertiser, packet_type, service_data_obj.uuid().ShortestPossibleFormat().c_str(),
644           service_data_obj.data().pointer(), service_data_obj.data().length());
645       if (BT_ERROR_NONE != ret) {
646         std::string error_message = "Failed to create advertiser";
647         if (BT_ERROR_QUOTA_EXCEEDED == ret && !service_data_obj.uuid().To16Bit()) {
648           error_message =
649               "Failed to start advertising: only 16 bit values of BluetoothLEServiceData::uuid are "
650               "supported";
651         }
652
653         LogAndReportError(util::GetBluetoothError(ret, error_message), &out,
654                           ("bt_adapter_le_add_advertising_service_data() failed with: %d (%s)", ret,
655                            get_error_message(ret)));
656         return;
657       }
658     }
659   }
660
661   const auto& manufacturer_data = advertise_data.manufacturer_data();
662   if (manufacturer_data.id().empty() && nullptr == manufacturer_data.data().pointer()) {
663     LoggerD("manufacturerData is empty");
664   } else {
665     if (manufacturer_data.valid()) {
666       ret = bt_adapter_le_add_advertising_manufacturer_data(
667           advertiser, packet_type, atoi(manufacturer_data.id().c_str()),
668           manufacturer_data.data().pointer(), manufacturer_data.data().length());
669       if (BT_ERROR_NONE != ret) {
670         LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
671                           ("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d (%s)",
672                            ret, get_error_message(ret)));
673         return;
674       }
675     }
676   }
677
678   ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
679   if (BT_ERROR_NONE != ret) {
680     LogAndReportError(
681         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
682         ("bt_adapter_le_set_advertising_mode() failed with: %d (%s)", ret, get_error_message(ret)));
683     return;
684   }
685
686   ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
687   if (BT_ERROR_NONE != ret) {
688     LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
689                       ("bt_adapter_le_set_advertising_connectable() failed with: %d (%s)", ret,
690                        get_error_message(ret)));
691     return;
692   }
693
694   // advertiser is ready, let's start advertising
695   ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
696   if (BT_ERROR_NONE != ret) {
697     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
698       LogAndReportError(
699           PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out,
700           ("bt_adapter_le_start_advertising_new error: %d (%s)", ret, get_error_message(ret)));
701       return;
702     }
703
704     LogAndReportError(util::GetBluetoothError(ret, "Failed to start advertising"), &out,
705                       ("bt_adapter_le_start_advertising_new() failed with: %d (%s)", ret,
706                        get_error_message(ret)));
707     return;
708   }
709
710   // everything went well, we want to store the pointer, so unique_ptr should no longer manage the
711   // memory
712   bt_advertiser_ = advertiser_ptr.release();
713   ReportSuccess(out);
714 }
715
716 void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
717   ScopeLogger();
718   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
719                                               &out);
720
721   if (nullptr != bt_advertiser_) {
722     int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
723     if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
724       LogAndReportError(
725           PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out,
726           ("bt_adapter_le_stop_advertising() failed with: %d (%s)", ret, get_error_message(ret)));
727       return;
728     }
729
730     bt_advertiser_ = nullptr;
731   } else {
732     LoggerD("Advertising is not in progress");
733   }
734
735   ReportSuccess(out);
736 }
737
738 void BluetoothLEAdapter::OnStateChanged(int result, bt_adapter_le_state_e adapter_le_state,
739                                         void* user_data) {
740   ScopeLogger();
741
742   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
743
744   if (!adapter) {
745     LoggerE("user_data is NULL");
746     return;
747   }
748
749   adapter->enabled_ = ToBool(adapter_le_state);
750 }
751
752 void BluetoothLEAdapter::OnScanResult(int result, bt_adapter_le_device_scan_result_info_s* info,
753                                       void* user_data) {
754   ScopeLogger("result: %d, info: %p, data: %p", result, info, user_data);
755
756   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
757
758   if (!adapter) {
759     LoggerE("user_data is NULL");
760     return;
761   }
762
763   picojson::value value = picojson::value(picojson::object());
764   picojson::object* data_obj = &value.get<picojson::object>();
765
766   if (BT_ERROR_NONE != result) {
767     LogAndReportError(util::GetBluetoothError(result, "Error during scanning"), data_obj,
768                       ("Error during scanning: %d (%s)", result, get_error_message(result)));
769     data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
770   } else {
771     // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
772     if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
773       // device found
774       LoggerD("Device found");
775       picojson::value data{picojson::object{}};
776       const auto& ret = BluetoothLEDevice::ToJson(info, &data.get<picojson::object>());
777       if (ret) {
778         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanSuccess)));
779         data_obj->insert(std::make_pair(kData, data));
780       } else {
781         LogAndReportError(ret, data_obj, ("Failed to parse Bluetooth LE device"));
782         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
783       }
784     }
785   }
786
787   adapter->instance_.FireEvent(kScanEvent, value);
788 }
789
790 void BluetoothLEAdapter::OnAdvertiseResult(int result, bt_advertiser_h advertiser,
791                                            bt_adapter_le_advertising_state_e adv_state,
792                                            void* user_data) {
793   ScopeLogger("result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser,
794               adv_state, user_data);
795
796   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
797
798   if (!adapter) {
799     LoggerE("user_data is NULL");
800     return;
801   }
802
803   picojson::value value = picojson::value(picojson::object());
804   picojson::object* data_obj = &value.get<picojson::object>();
805
806   if (BT_ERROR_NONE != result) {
807     LogAndReportError(util::GetBluetoothError(result, "Error during advertising"), data_obj,
808                       ("Error during advertising: %d (%s)", result, get_error_message(result)));
809     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
810   } else {
811     const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
812     LoggerD("Advertise state is: %s", state);
813     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
814     ReportSuccess(picojson::value(state), *data_obj);
815     if (adv_state == BT_ADAPTER_LE_ADVERTISING_STOPPED) {
816       LoggerD("Advertiser destroy");
817       int ret = bt_adapter_le_destroy_advertiser(advertiser);
818       if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
819         LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"),
820                           data_obj, ("bt_adapter_le_destroy_advertiser() failed with: %d (%s)", ret,
821                                      get_error_message(ret)));
822         return;
823       }
824     }
825   }
826
827   adapter->instance_.FireEvent(kAdvertiseEvent, value);
828 }
829
830 }  // namespace bluetooth
831 }  // namespace extension