Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / bluetooth_low_energy / bluetooth_low_energy_api.cc
blobb4485484671a6095f9e00abd9de45e0667f5e5ec
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
14 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
15 #include "chrome/common/extensions/api/bluetooth_low_energy.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/browser/event_router.h"
18 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
19 #include "extensions/common/permissions/permissions_data.h"
20 #include "extensions/common/switches.h"
22 #if defined(OS_CHROMEOS)
23 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
24 #endif
26 using content::BrowserContext;
27 using content::BrowserThread;
29 namespace apibtle = extensions::api::bluetooth_low_energy;
31 namespace extensions {
33 namespace {
35 const char kErrorAdapterNotInitialized[] =
36 "Could not initialize Bluetooth adapter";
37 const char kErrorAlreadyConnected[] = "Already connected";
38 const char kErrorAlreadyNotifying[] = "Already notifying";
39 const char kErrorAuthenticationFailed[] = "Authentication failed";
40 const char kErrorCanceled[] = "Request canceled";
41 const char kErrorGattNotSupported[] = "Operation not supported by this service";
42 const char kErrorHigherSecurity[] = "Higher security needed";
43 const char kErrorInProgress[] = "In progress";
44 const char kErrorInsufficientAuthorization[] = "Insufficient authorization";
45 const char kErrorInvalidLength[] = "Invalid attribute value length";
46 const char kErrorNotConnected[] = "Not connected";
47 const char kErrorNotFound[] = "Instance not found";
48 const char kErrorNotNotifying[] = "Not notifying";
49 const char kErrorOperationFailed[] = "Operation failed";
50 const char kErrorPermissionDenied[] = "Permission denied";
51 const char kErrorPlatformNotSupported[] =
52 "This operation is not supported on the current platform";
53 const char kErrorTimeout[] = "Operation timed out";
54 const char kErrorUnsupportedDevice[] =
55 "This device is not supported on the current platform";
56 const char kErrorInvalidAdvertisementLength[] = "Invalid advertisement length";
57 const char kStatusAdvertisementAlreadyExists[] =
58 "An advertisement is already advertising";
59 const char kStatusAdvertisementDoesNotExist[] =
60 "This advertisement does not exist";
62 // Returns the correct error string based on error status |status|. This is used
63 // to set the value of |chrome.runtime.lastError.message| and should not be
64 // passed |BluetoothLowEnergyEventRouter::kStatusSuccess|.
65 std::string StatusToString(BluetoothLowEnergyEventRouter::Status status) {
66 switch (status) {
67 case BluetoothLowEnergyEventRouter::kStatusErrorPermissionDenied:
68 return kErrorPermissionDenied;
69 case BluetoothLowEnergyEventRouter::kStatusErrorNotFound:
70 return kErrorNotFound;
71 case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyConnected:
72 return kErrorAlreadyConnected;
73 case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyNotifying:
74 return kErrorAlreadyNotifying;
75 case BluetoothLowEnergyEventRouter::kStatusErrorNotConnected:
76 return kErrorNotConnected;
77 case BluetoothLowEnergyEventRouter::kStatusErrorInsufficientAuthorization:
78 return kErrorInsufficientAuthorization;
79 case BluetoothLowEnergyEventRouter::kStatusErrorNotNotifying:
80 return kErrorNotNotifying;
81 case BluetoothLowEnergyEventRouter::kStatusErrorInProgress:
82 return kErrorInProgress;
83 case BluetoothLowEnergyEventRouter::kStatusErrorAuthenticationFailed:
84 return kErrorAuthenticationFailed;
85 case BluetoothLowEnergyEventRouter::kStatusErrorHigherSecurity:
86 return kErrorHigherSecurity;
87 case BluetoothLowEnergyEventRouter::kStatusErrorCanceled:
88 return kErrorCanceled;
89 case BluetoothLowEnergyEventRouter::kStatusErrorTimeout:
90 return kErrorTimeout;
91 case BluetoothLowEnergyEventRouter::kStatusErrorUnsupportedDevice:
92 return kErrorUnsupportedDevice;
93 case BluetoothLowEnergyEventRouter::kStatusErrorInvalidLength:
94 return kErrorInvalidLength;
95 case BluetoothLowEnergyEventRouter::kStatusErrorGattNotSupported:
96 return kErrorGattNotSupported;
97 case BluetoothLowEnergyEventRouter::kStatusSuccess:
98 NOTREACHED();
99 break;
100 default:
101 return kErrorOperationFailed;
103 return "";
106 extensions::BluetoothLowEnergyEventRouter* GetEventRouter(
107 BrowserContext* context) {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI);
109 return extensions::BluetoothLowEnergyAPI::Get(context)->event_router();
112 void DoWorkCallback(const base::Callback<bool()>& callback) {
113 DCHECK(!callback.is_null());
114 callback.Run();
117 scoped_ptr<device::BluetoothAdvertisement::ManufacturerData>
118 CreateManufacturerData(
119 std::vector<linked_ptr<apibtle::ManufacturerData>>* manufacturer_data) {
120 scoped_ptr<device::BluetoothAdvertisement::ManufacturerData> created_data(
121 new device::BluetoothAdvertisement::ManufacturerData());
122 for (const auto& it : *manufacturer_data) {
123 std::vector<uint8_t> data(it->data.size());
124 std::copy(it->data.begin(), it->data.end(), data.begin());
125 (*created_data)[it->id] = data;
127 return created_data;
130 scoped_ptr<device::BluetoothAdvertisement::ServiceData> CreateServiceData(
131 std::vector<linked_ptr<apibtle::ServiceData>>* service_data) {
132 scoped_ptr<device::BluetoothAdvertisement::ServiceData> created_data(
133 new device::BluetoothAdvertisement::ServiceData());
134 for (const auto& it : *service_data) {
135 std::vector<uint8_t> data(it->data.size());
136 std::copy(it->data.begin(), it->data.end(), data.begin());
137 (*created_data)[it->uuid] = data;
139 return created_data;
142 } // namespace
145 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI> >
146 g_factory = LAZY_INSTANCE_INITIALIZER;
148 // static
149 BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>*
150 BluetoothLowEnergyAPI::GetFactoryInstance() {
151 return g_factory.Pointer();
154 // static
155 BluetoothLowEnergyAPI* BluetoothLowEnergyAPI::Get(BrowserContext* context) {
156 DCHECK_CURRENTLY_ON(BrowserThread::UI);
157 return GetFactoryInstance()->Get(context);
160 BluetoothLowEnergyAPI::BluetoothLowEnergyAPI(BrowserContext* context)
161 : event_router_(new BluetoothLowEnergyEventRouter(context)) {
162 DCHECK_CURRENTLY_ON(BrowserThread::UI);
165 BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
168 void BluetoothLowEnergyAPI::Shutdown() {
169 DCHECK_CURRENTLY_ON(BrowserThread::UI);
172 namespace api {
174 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
177 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
180 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
181 DCHECK_CURRENTLY_ON(BrowserThread::UI);
183 if (!BluetoothManifestData::CheckLowEnergyPermitted(extension())) {
184 error_ = kErrorPermissionDenied;
185 return false;
188 BluetoothLowEnergyEventRouter* event_router =
189 GetEventRouter(browser_context());
190 if (!event_router->IsBluetoothSupported()) {
191 SetError(kErrorPlatformNotSupported);
192 return false;
195 // It is safe to pass |this| here as ExtensionFunction is refcounted.
196 if (!event_router->InitializeAdapterAndInvokeCallback(base::Bind(
197 &DoWorkCallback,
198 base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork, this)))) {
199 SetError(kErrorAdapterNotInitialized);
200 return false;
203 return true;
206 bool BluetoothLowEnergyConnectFunction::DoWork() {
207 DCHECK_CURRENTLY_ON(BrowserThread::UI);
209 BluetoothLowEnergyEventRouter* event_router =
210 GetEventRouter(browser_context());
212 // The adapter must be initialized at this point, but return an error instead
213 // of asserting.
214 if (!event_router->HasAdapter()) {
215 SetError(kErrorAdapterNotInitialized);
216 SendResponse(false);
217 return false;
220 scoped_ptr<apibtle::Connect::Params> params(
221 apibtle::Connect::Params::Create(*args_));
222 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
224 bool persistent = false; // Not persistent by default.
225 apibtle::ConnectProperties* properties = params.get()->properties.get();
226 if (properties)
227 persistent = properties->persistent;
229 event_router->Connect(
230 persistent,
231 extension(),
232 params->device_address,
233 base::Bind(&BluetoothLowEnergyConnectFunction::SuccessCallback, this),
234 base::Bind(&BluetoothLowEnergyConnectFunction::ErrorCallback, this));
236 return true;
239 void BluetoothLowEnergyConnectFunction::SuccessCallback() {
240 SendResponse(true);
243 void BluetoothLowEnergyConnectFunction::ErrorCallback(
244 BluetoothLowEnergyEventRouter::Status status) {
245 SetError(StatusToString(status));
246 SendResponse(false);
249 bool BluetoothLowEnergyDisconnectFunction::DoWork() {
250 DCHECK_CURRENTLY_ON(BrowserThread::UI);
252 BluetoothLowEnergyEventRouter* event_router =
253 GetEventRouter(browser_context());
255 // The adapter must be initialized at this point, but return an error instead
256 // of asserting.
257 if (!event_router->HasAdapter()) {
258 SetError(kErrorAdapterNotInitialized);
259 SendResponse(false);
260 return false;
263 scoped_ptr<apibtle::Disconnect::Params> params(
264 apibtle::Disconnect::Params::Create(*args_));
265 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
267 event_router->Disconnect(
268 extension(),
269 params->device_address,
270 base::Bind(&BluetoothLowEnergyDisconnectFunction::SuccessCallback, this),
271 base::Bind(&BluetoothLowEnergyDisconnectFunction::ErrorCallback, this));
273 return true;
276 void BluetoothLowEnergyDisconnectFunction::SuccessCallback() {
277 SendResponse(true);
280 void BluetoothLowEnergyDisconnectFunction::ErrorCallback(
281 BluetoothLowEnergyEventRouter::Status status) {
282 SetError(StatusToString(status));
283 SendResponse(false);
286 bool BluetoothLowEnergyGetServiceFunction::DoWork() {
287 DCHECK_CURRENTLY_ON(BrowserThread::UI);
289 BluetoothLowEnergyEventRouter* event_router =
290 GetEventRouter(browser_context());
292 // The adapter must be initialized at this point, but return an error instead
293 // of asserting.
294 if (!event_router->HasAdapter()) {
295 SetError(kErrorAdapterNotInitialized);
296 SendResponse(false);
297 return false;
300 scoped_ptr<apibtle::GetService::Params> params(
301 apibtle::GetService::Params::Create(*args_));
302 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
304 apibtle::Service service;
305 BluetoothLowEnergyEventRouter::Status status =
306 event_router->GetService(params->service_id, &service);
307 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
308 SetError(StatusToString(status));
309 SendResponse(false);
310 return false;
313 results_ = apibtle::GetService::Results::Create(service);
314 SendResponse(true);
316 return true;
319 bool BluetoothLowEnergyGetServicesFunction::DoWork() {
320 DCHECK_CURRENTLY_ON(BrowserThread::UI);
322 BluetoothLowEnergyEventRouter* event_router =
323 GetEventRouter(browser_context());
325 // The adapter must be initialized at this point, but return an error instead
326 // of asserting.
327 if (!event_router->HasAdapter()) {
328 SetError(kErrorAdapterNotInitialized);
329 SendResponse(false);
330 return false;
333 scoped_ptr<apibtle::GetServices::Params> params(
334 apibtle::GetServices::Params::Create(*args_));
335 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
337 BluetoothLowEnergyEventRouter::ServiceList service_list;
338 if (!event_router->GetServices(params->device_address, &service_list)) {
339 SetError(kErrorNotFound);
340 SendResponse(false);
341 return false;
344 results_ = apibtle::GetServices::Results::Create(service_list);
345 SendResponse(true);
347 return true;
350 bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() {
351 DCHECK_CURRENTLY_ON(BrowserThread::UI);
353 BluetoothLowEnergyEventRouter* event_router =
354 GetEventRouter(browser_context());
356 // The adapter must be initialized at this point, but return an error instead
357 // of asserting.
358 if (!event_router->HasAdapter()) {
359 SetError(kErrorAdapterNotInitialized);
360 SendResponse(false);
361 return false;
364 scoped_ptr<apibtle::GetCharacteristic::Params> params(
365 apibtle::GetCharacteristic::Params::Create(*args_));
366 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
368 apibtle::Characteristic characteristic;
369 BluetoothLowEnergyEventRouter::Status status =
370 event_router->GetCharacteristic(
371 extension(), params->characteristic_id, &characteristic);
372 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
373 SetError(StatusToString(status));
374 SendResponse(false);
375 return false;
378 // Manually construct the result instead of using
379 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
380 // enums correctly.
381 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
382 SendResponse(true);
384 return true;
387 bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() {
388 DCHECK_CURRENTLY_ON(BrowserThread::UI);
390 BluetoothLowEnergyEventRouter* event_router =
391 GetEventRouter(browser_context());
393 // The adapter must be initialized at this point, but return an error instead
394 // of asserting.
395 if (!event_router->HasAdapter()) {
396 SetError(kErrorAdapterNotInitialized);
397 SendResponse(false);
398 return false;
401 scoped_ptr<apibtle::GetCharacteristics::Params> params(
402 apibtle::GetCharacteristics::Params::Create(*args_));
403 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
405 BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list;
406 BluetoothLowEnergyEventRouter::Status status =
407 event_router->GetCharacteristics(
408 extension(), params->service_id, &characteristic_list);
409 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
410 SetError(StatusToString(status));
411 SendResponse(false);
412 return false;
415 // Manually construct the result instead of using
416 // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
417 // enums correctly.
418 scoped_ptr<base::ListValue> result(new base::ListValue());
419 for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter =
420 characteristic_list.begin();
421 iter != characteristic_list.end();
422 ++iter)
423 result->Append(apibtle::CharacteristicToValue(iter->get()).release());
425 SetResult(result.release());
426 SendResponse(true);
428 return true;
431 bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() {
432 DCHECK_CURRENTLY_ON(BrowserThread::UI);
434 BluetoothLowEnergyEventRouter* event_router =
435 GetEventRouter(browser_context());
437 // The adapter must be initialized at this point, but return an error instead
438 // of asserting.
439 if (!event_router->HasAdapter()) {
440 SetError(kErrorAdapterNotInitialized);
441 SendResponse(false);
442 return false;
445 scoped_ptr<apibtle::GetIncludedServices::Params> params(
446 apibtle::GetIncludedServices::Params::Create(*args_));
447 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
449 BluetoothLowEnergyEventRouter::ServiceList service_list;
450 BluetoothLowEnergyEventRouter::Status status =
451 event_router->GetIncludedServices(params->service_id, &service_list);
452 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
453 SetError(StatusToString(status));
454 SendResponse(false);
455 return false;
458 results_ = apibtle::GetIncludedServices::Results::Create(service_list);
459 SendResponse(true);
461 return true;
464 bool BluetoothLowEnergyGetDescriptorFunction::DoWork() {
465 DCHECK_CURRENTLY_ON(BrowserThread::UI);
467 BluetoothLowEnergyEventRouter* event_router =
468 GetEventRouter(browser_context());
470 // The adapter must be initialized at this point, but return an error instead
471 // of asserting.
472 if (!event_router->HasAdapter()) {
473 SetError(kErrorAdapterNotInitialized);
474 SendResponse(false);
475 return false;
478 scoped_ptr<apibtle::GetDescriptor::Params> params(
479 apibtle::GetDescriptor::Params::Create(*args_));
480 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
482 apibtle::Descriptor descriptor;
483 BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptor(
484 extension(), params->descriptor_id, &descriptor);
485 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
486 SetError(StatusToString(status));
487 SendResponse(false);
488 return false;
491 // Manually construct the result instead of using
492 // apibtle::GetDescriptor::Result::Create as it doesn't convert lists of enums
493 // correctly.
494 SetResult(apibtle::DescriptorToValue(&descriptor).release());
495 SendResponse(true);
497 return true;
500 bool BluetoothLowEnergyGetDescriptorsFunction::DoWork() {
501 DCHECK_CURRENTLY_ON(BrowserThread::UI);
503 BluetoothLowEnergyEventRouter* event_router =
504 GetEventRouter(browser_context());
506 // The adapter must be initialized at this point, but return an error instead
507 // of asserting.
508 if (!event_router->HasAdapter()) {
509 SetError(kErrorAdapterNotInitialized);
510 SendResponse(false);
511 return false;
514 scoped_ptr<apibtle::GetDescriptors::Params> params(
515 apibtle::GetDescriptors::Params::Create(*args_));
516 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
518 BluetoothLowEnergyEventRouter::DescriptorList descriptor_list;
519 BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptors(
520 extension(), params->characteristic_id, &descriptor_list);
521 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
522 SetError(StatusToString(status));
523 SendResponse(false);
524 return false;
527 // Manually construct the result instead of using
528 // apibtle::GetDescriptors::Result::Create as it doesn't convert lists of
529 // enums correctly.
530 scoped_ptr<base::ListValue> result(new base::ListValue());
531 for (BluetoothLowEnergyEventRouter::DescriptorList::iterator iter =
532 descriptor_list.begin();
533 iter != descriptor_list.end();
534 ++iter)
535 result->Append(apibtle::DescriptorToValue(iter->get()).release());
537 SetResult(result.release());
538 SendResponse(true);
540 return true;
543 bool BluetoothLowEnergyReadCharacteristicValueFunction::DoWork() {
544 DCHECK_CURRENTLY_ON(BrowserThread::UI);
546 BluetoothLowEnergyEventRouter* event_router =
547 GetEventRouter(browser_context());
549 // The adapter must be initialized at this point, but return an error instead
550 // of asserting.
551 if (!event_router->HasAdapter()) {
552 SetError(kErrorAdapterNotInitialized);
553 SendResponse(false);
554 return false;
557 scoped_ptr<apibtle::ReadCharacteristicValue::Params> params(
558 apibtle::ReadCharacteristicValue::Params::Create(*args_));
559 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
561 instance_id_ = params->characteristic_id;
562 event_router->ReadCharacteristicValue(
563 extension(),
564 instance_id_,
565 base::Bind(
566 &BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback,
567 this),
568 base::Bind(
569 &BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback,
570 this));
572 return true;
575 void BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback() {
576 // Obtain info on the characteristic and see whether or not the characteristic
577 // is still around.
578 apibtle::Characteristic characteristic;
579 BluetoothLowEnergyEventRouter::Status status =
580 GetEventRouter(browser_context())
581 ->GetCharacteristic(extension(), instance_id_, &characteristic);
582 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
583 SetError(StatusToString(status));
584 SendResponse(false);
585 return;
588 // Manually construct the result instead of using
589 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
590 // enums correctly.
591 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
592 SendResponse(true);
595 void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback(
596 BluetoothLowEnergyEventRouter::Status status) {
597 SetError(StatusToString(status));
598 SendResponse(false);
601 bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
602 DCHECK_CURRENTLY_ON(BrowserThread::UI);
604 BluetoothLowEnergyEventRouter* event_router =
605 GetEventRouter(browser_context());
607 // The adapter must be initialized at this point, but return an error instead
608 // of asserting.
609 if (!event_router->HasAdapter()) {
610 SetError(kErrorAdapterNotInitialized);
611 SendResponse(false);
612 return false;
615 scoped_ptr<apibtle::WriteCharacteristicValue::Params> params(
616 apibtle::WriteCharacteristicValue::Params::Create(*args_));
617 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
619 std::vector<uint8> value(params->value.begin(), params->value.end());
620 event_router->WriteCharacteristicValue(
621 extension(),
622 params->characteristic_id,
623 value,
624 base::Bind(
625 &BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback,
626 this),
627 base::Bind(
628 &BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback,
629 this));
631 return true;
634 void BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback() {
635 results_ = apibtle::WriteCharacteristicValue::Results::Create();
636 SendResponse(true);
639 void BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback(
640 BluetoothLowEnergyEventRouter::Status status) {
641 SetError(StatusToString(status));
642 SendResponse(false);
645 bool BluetoothLowEnergyStartCharacteristicNotificationsFunction::DoWork() {
646 DCHECK_CURRENTLY_ON(BrowserThread::UI);
648 BluetoothLowEnergyEventRouter* event_router =
649 GetEventRouter(browser_context());
651 // The adapter must be initialized at this point, but return an error instead
652 // of asserting.
653 if (!event_router->HasAdapter()) {
654 SetError(kErrorAdapterNotInitialized);
655 SendResponse(false);
656 return false;
659 scoped_ptr<apibtle::StartCharacteristicNotifications::Params> params(
660 apibtle::StartCharacteristicNotifications::Params::Create(*args_));
661 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
663 bool persistent = false; // Not persistent by default.
664 apibtle::NotificationProperties* properties = params.get()->properties.get();
665 if (properties)
666 persistent = properties->persistent;
668 event_router->StartCharacteristicNotifications(
669 persistent,
670 extension(),
671 params->characteristic_id,
672 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
673 SuccessCallback,
674 this),
675 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
676 ErrorCallback,
677 this));
679 return true;
682 void
683 BluetoothLowEnergyStartCharacteristicNotificationsFunction::SuccessCallback() {
684 SendResponse(true);
687 void BluetoothLowEnergyStartCharacteristicNotificationsFunction::ErrorCallback(
688 BluetoothLowEnergyEventRouter::Status status) {
689 SetError(StatusToString(status));
690 SendResponse(false);
693 bool BluetoothLowEnergyStopCharacteristicNotificationsFunction::DoWork() {
694 DCHECK_CURRENTLY_ON(BrowserThread::UI);
696 BluetoothLowEnergyEventRouter* event_router =
697 GetEventRouter(browser_context());
699 // The adapter must be initialized at this point, but return an error instead
700 // of asserting.
701 if (!event_router->HasAdapter()) {
702 SetError(kErrorAdapterNotInitialized);
703 SendResponse(false);
704 return false;
707 scoped_ptr<apibtle::StopCharacteristicNotifications::Params> params(
708 apibtle::StopCharacteristicNotifications::Params::Create(*args_));
709 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
711 event_router->StopCharacteristicNotifications(
712 extension(),
713 params->characteristic_id,
714 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
715 SuccessCallback,
716 this),
717 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
718 ErrorCallback,
719 this));
721 return true;
724 void
725 BluetoothLowEnergyStopCharacteristicNotificationsFunction::SuccessCallback() {
726 SendResponse(true);
729 void BluetoothLowEnergyStopCharacteristicNotificationsFunction::ErrorCallback(
730 BluetoothLowEnergyEventRouter::Status status) {
731 SetError(StatusToString(status));
732 SendResponse(false);
735 bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
736 DCHECK_CURRENTLY_ON(BrowserThread::UI);
738 BluetoothLowEnergyEventRouter* event_router =
739 GetEventRouter(browser_context());
741 // The adapter must be initialized at this point, but return an error instead
742 // of asserting.
743 if (!event_router->HasAdapter()) {
744 SetError(kErrorAdapterNotInitialized);
745 SendResponse(false);
746 return false;
749 scoped_ptr<apibtle::ReadDescriptorValue::Params> params(
750 apibtle::ReadDescriptorValue::Params::Create(*args_));
751 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
753 instance_id_ = params->descriptor_id;
754 event_router->ReadDescriptorValue(
755 extension(),
756 instance_id_,
757 base::Bind(
758 &BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback,
759 this),
760 base::Bind(&BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback,
761 this));
763 return true;
766 void BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback() {
767 // Obtain info on the descriptor and see whether or not the descriptor is
768 // still around.
769 apibtle::Descriptor descriptor;
770 BluetoothLowEnergyEventRouter::Status status =
771 GetEventRouter(browser_context())
772 ->GetDescriptor(extension(), instance_id_, &descriptor);
773 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
774 SetError(StatusToString(status));
775 SendResponse(false);
776 return;
779 // Manually construct the result instead of using
780 // apibtle::GetDescriptor::Results::Create as it doesn't convert lists of
781 // enums correctly.
782 SetResult(apibtle::DescriptorToValue(&descriptor).release());
783 SendResponse(true);
786 void BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback(
787 BluetoothLowEnergyEventRouter::Status status) {
788 SetError(StatusToString(status));
789 SendResponse(false);
792 bool BluetoothLowEnergyWriteDescriptorValueFunction::DoWork() {
793 DCHECK_CURRENTLY_ON(BrowserThread::UI);
795 BluetoothLowEnergyEventRouter* event_router =
796 GetEventRouter(browser_context());
798 // The adapter must be initialized at this point, but return an error instead
799 // of asserting.
800 if (!event_router->HasAdapter()) {
801 SetError(kErrorAdapterNotInitialized);
802 SendResponse(false);
803 return false;
806 scoped_ptr<apibtle::WriteDescriptorValue::Params> params(
807 apibtle::WriteDescriptorValue::Params::Create(*args_));
808 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
810 std::vector<uint8> value(params->value.begin(), params->value.end());
811 event_router->WriteDescriptorValue(
812 extension(),
813 params->descriptor_id,
814 value,
815 base::Bind(
816 &BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback,
817 this),
818 base::Bind(&BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback,
819 this));
821 return true;
824 void BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback() {
825 results_ = apibtle::WriteDescriptorValue::Results::Create();
826 SendResponse(true);
829 void BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback(
830 BluetoothLowEnergyEventRouter::Status status) {
831 SetError(StatusToString(status));
832 SendResponse(false);
835 BluetoothLowEnergyAdvertisementFunction::
836 BluetoothLowEnergyAdvertisementFunction()
837 : advertisements_manager_(nullptr) {
840 BluetoothLowEnergyAdvertisementFunction::
841 ~BluetoothLowEnergyAdvertisementFunction() {
844 int BluetoothLowEnergyAdvertisementFunction::AddAdvertisement(
845 BluetoothApiAdvertisement* advertisement) {
846 DCHECK(advertisements_manager_);
847 return advertisements_manager_->Add(advertisement);
850 BluetoothApiAdvertisement*
851 BluetoothLowEnergyAdvertisementFunction::GetAdvertisement(
852 int advertisement_id) {
853 DCHECK(advertisements_manager_);
854 return advertisements_manager_->Get(extension_id(), advertisement_id);
857 void BluetoothLowEnergyAdvertisementFunction::RemoveAdvertisement(
858 int advertisement_id) {
859 DCHECK(advertisements_manager_);
860 advertisements_manager_->Remove(extension_id(), advertisement_id);
863 bool BluetoothLowEnergyAdvertisementFunction::RunAsync() {
864 Initialize();
865 return BluetoothLowEnergyExtensionFunction::RunAsync();
868 void BluetoothLowEnergyAdvertisementFunction::Initialize() {
869 advertisements_manager_ =
870 ApiResourceManager<BluetoothApiAdvertisement>::Get(browser_context());
873 static bool IsAutoLaunchedKioskApp(const ExtensionId& id) {
874 #if defined(OS_CHROMEOS)
875 chromeos::KioskAppManager::App app_info;
876 return chromeos::KioskAppManager::Get()->GetApp(id, &app_info) &&
877 app_info.was_auto_launched_with_zero_delay;
878 #else
879 return false;
880 #endif
883 static bool IsPeripheralFlagEnabled() {
884 return base::CommandLine::ForCurrentProcess()->HasSwitch(
885 switches::kEnableBLEAdvertising);
888 // RegisterAdvertisement:
890 bool BluetoothLowEnergyRegisterAdvertisementFunction::DoWork() {
891 DCHECK_CURRENTLY_ON(BrowserThread::UI);
893 // Check permissions in manifest.
894 if (!BluetoothManifestData::CheckPeripheralPermitted(extension())) {
895 error_ = kErrorPermissionDenied;
896 SendResponse(false);
897 return false;
900 // For this API to be available the app has to be either auto
901 // launched in Kiosk Mode or the enable-ble-advertisement-in-apps
902 // should be set.
903 if (!(IsAutoLaunchedKioskApp(extension()->id()) ||
904 IsPeripheralFlagEnabled())) {
905 error_ = kErrorPermissionDenied;
906 SendResponse(false);
907 return false;
910 BluetoothLowEnergyEventRouter* event_router =
911 GetEventRouter(browser_context());
913 // The adapter must be initialized at this point, but return an error instead
914 // of asserting.
915 if (!event_router->HasAdapter()) {
916 SetError(kErrorAdapterNotInitialized);
917 SendResponse(false);
918 return false;
921 scoped_ptr<apibtle::RegisterAdvertisement::Params> params(
922 apibtle::RegisterAdvertisement::Params::Create(*args_));
923 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
925 scoped_ptr<device::BluetoothAdvertisement::Data> advertisement_data(
926 new device::BluetoothAdvertisement::Data(
927 params->advertisement.type ==
928 apibtle::AdvertisementType::ADVERTISEMENT_TYPE_BROADCAST
929 ? device::BluetoothAdvertisement::AdvertisementType::
930 ADVERTISEMENT_TYPE_BROADCAST
931 : device::BluetoothAdvertisement::AdvertisementType::
932 ADVERTISEMENT_TYPE_PERIPHERAL));
934 advertisement_data->set_service_uuids(
935 params->advertisement.service_uuids.Pass());
936 advertisement_data->set_solicit_uuids(
937 params->advertisement.solicit_uuids.Pass());
938 if (params->advertisement.manufacturer_data) {
939 advertisement_data->set_manufacturer_data(
940 CreateManufacturerData(params->advertisement.manufacturer_data.get())
941 .Pass());
943 if (params->advertisement.service_data) {
944 advertisement_data->set_service_data(
945 CreateServiceData(params->advertisement.service_data.get()).Pass());
948 event_router->adapter()->RegisterAdvertisement(
949 advertisement_data.Pass(),
950 base::Bind(
951 &BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback,
952 this),
953 base::Bind(
954 &BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback,
955 this));
957 return true;
960 void BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback(
961 scoped_refptr<device::BluetoothAdvertisement> advertisement) {
962 results_ = apibtle::RegisterAdvertisement::Results::Create(AddAdvertisement(
963 new BluetoothApiAdvertisement(extension_id(), advertisement)));
964 SendResponse(true);
967 void BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback(
968 device::BluetoothAdvertisement::ErrorCode status) {
969 switch (status) {
970 case device::BluetoothAdvertisement::ErrorCode::
971 ERROR_ADVERTISEMENT_ALREADY_EXISTS:
972 SetError(kStatusAdvertisementAlreadyExists);
973 break;
974 case device::BluetoothAdvertisement::ErrorCode::
975 ERROR_ADVERTISEMENT_INVALID_LENGTH:
976 SetError(kErrorInvalidAdvertisementLength);
977 break;
978 default:
979 SetError(kErrorOperationFailed);
981 SendResponse(false);
984 // UnregisterAdvertisement:
986 bool BluetoothLowEnergyUnregisterAdvertisementFunction::DoWork() {
987 DCHECK_CURRENTLY_ON(BrowserThread::UI);
989 // Check permission in the manifest.
990 if (!BluetoothManifestData::CheckPeripheralPermitted(extension())) {
991 error_ = kErrorPermissionDenied;
992 SendResponse(false);
993 return false;
996 // For this API to be available the app has to be either auto
997 // launched in Kiosk Mode or the enable-ble-advertisement-in-apps
998 // should be set.
999 if (!(IsAutoLaunchedKioskApp(extension()->id()) ||
1000 IsPeripheralFlagEnabled())) {
1001 error_ = kErrorPermissionDenied;
1002 SendResponse(false);
1003 return false;
1006 BluetoothLowEnergyEventRouter* event_router =
1007 GetEventRouter(browser_context());
1009 // If we don't have an initialized adapter, unregistering is a no-op.
1010 if (!event_router->HasAdapter())
1011 return true;
1013 scoped_ptr<apibtle::UnregisterAdvertisement::Params> params(
1014 apibtle::UnregisterAdvertisement::Params::Create(*args_));
1015 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1017 BluetoothApiAdvertisement* advertisement =
1018 GetAdvertisement(params->advertisement_id);
1019 if (!advertisement) {
1020 error_ = kStatusAdvertisementDoesNotExist;
1021 SendResponse(false);
1022 return false;
1025 advertisement->advertisement()->Unregister(
1026 base::Bind(
1027 &BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback,
1028 this, params->advertisement_id),
1029 base::Bind(
1030 &BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback,
1031 this, params->advertisement_id));
1033 return true;
1036 void BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback(
1037 int advertisement_id) {
1038 RemoveAdvertisement(advertisement_id);
1039 SendResponse(true);
1042 void BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback(
1043 int advertisement_id,
1044 device::BluetoothAdvertisement::ErrorCode status) {
1045 RemoveAdvertisement(advertisement_id);
1046 switch (status) {
1047 case device::BluetoothAdvertisement::ErrorCode::
1048 ERROR_ADVERTISEMENT_DOES_NOT_EXIST:
1049 SetError(kStatusAdvertisementDoesNotExist);
1050 break;
1051 default:
1052 SetError(kErrorOperationFailed);
1054 SendResponse(false);
1057 } // namespace api
1058 } // namespace extensions