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"
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"
26 using content::BrowserContext
;
27 using content::BrowserThread
;
29 namespace apibtle
= extensions::api::bluetooth_low_energy
;
31 namespace extensions
{
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
) {
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
:
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
:
101 return kErrorOperationFailed
;
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());
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
;
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
;
145 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<BluetoothLowEnergyAPI
> >
146 g_factory
= LAZY_INSTANCE_INITIALIZER
;
149 BrowserContextKeyedAPIFactory
<BluetoothLowEnergyAPI
>*
150 BluetoothLowEnergyAPI::GetFactoryInstance() {
151 return g_factory
.Pointer();
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
);
174 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
177 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
180 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
181 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
183 if (!BluetoothManifestData::CheckLowEnergyPermitted(extension())) {
184 error_
= kErrorPermissionDenied
;
188 BluetoothLowEnergyEventRouter
* event_router
=
189 GetEventRouter(browser_context());
190 if (!event_router
->IsBluetoothSupported()) {
191 SetError(kErrorPlatformNotSupported
);
195 // It is safe to pass |this| here as ExtensionFunction is refcounted.
196 if (!event_router
->InitializeAdapterAndInvokeCallback(base::Bind(
198 base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork
, this)))) {
199 SetError(kErrorAdapterNotInitialized
);
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
214 if (!event_router
->HasAdapter()) {
215 SetError(kErrorAdapterNotInitialized
);
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();
227 persistent
= properties
->persistent
;
229 event_router
->Connect(
232 params
->device_address
,
233 base::Bind(&BluetoothLowEnergyConnectFunction::SuccessCallback
, this),
234 base::Bind(&BluetoothLowEnergyConnectFunction::ErrorCallback
, this));
239 void BluetoothLowEnergyConnectFunction::SuccessCallback() {
243 void BluetoothLowEnergyConnectFunction::ErrorCallback(
244 BluetoothLowEnergyEventRouter::Status status
) {
245 SetError(StatusToString(status
));
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
257 if (!event_router
->HasAdapter()) {
258 SetError(kErrorAdapterNotInitialized
);
263 scoped_ptr
<apibtle::Disconnect::Params
> params(
264 apibtle::Disconnect::Params::Create(*args_
));
265 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
267 event_router
->Disconnect(
269 params
->device_address
,
270 base::Bind(&BluetoothLowEnergyDisconnectFunction::SuccessCallback
, this),
271 base::Bind(&BluetoothLowEnergyDisconnectFunction::ErrorCallback
, this));
276 void BluetoothLowEnergyDisconnectFunction::SuccessCallback() {
280 void BluetoothLowEnergyDisconnectFunction::ErrorCallback(
281 BluetoothLowEnergyEventRouter::Status status
) {
282 SetError(StatusToString(status
));
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
294 if (!event_router
->HasAdapter()) {
295 SetError(kErrorAdapterNotInitialized
);
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
));
313 results_
= apibtle::GetService::Results::Create(service
);
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
327 if (!event_router
->HasAdapter()) {
328 SetError(kErrorAdapterNotInitialized
);
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
);
344 results_
= apibtle::GetServices::Results::Create(service_list
);
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
358 if (!event_router
->HasAdapter()) {
359 SetError(kErrorAdapterNotInitialized
);
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
));
378 // Manually construct the result instead of using
379 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
381 SetResult(apibtle::CharacteristicToValue(&characteristic
).release());
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
395 if (!event_router
->HasAdapter()) {
396 SetError(kErrorAdapterNotInitialized
);
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
));
415 // Manually construct the result instead of using
416 // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
418 scoped_ptr
<base::ListValue
> result(new base::ListValue());
419 for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter
=
420 characteristic_list
.begin();
421 iter
!= characteristic_list
.end();
423 result
->Append(apibtle::CharacteristicToValue(iter
->get()).release());
425 SetResult(result
.release());
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
439 if (!event_router
->HasAdapter()) {
440 SetError(kErrorAdapterNotInitialized
);
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
));
458 results_
= apibtle::GetIncludedServices::Results::Create(service_list
);
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
472 if (!event_router
->HasAdapter()) {
473 SetError(kErrorAdapterNotInitialized
);
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
));
491 // Manually construct the result instead of using
492 // apibtle::GetDescriptor::Result::Create as it doesn't convert lists of enums
494 SetResult(apibtle::DescriptorToValue(&descriptor
).release());
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
508 if (!event_router
->HasAdapter()) {
509 SetError(kErrorAdapterNotInitialized
);
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
));
527 // Manually construct the result instead of using
528 // apibtle::GetDescriptors::Result::Create as it doesn't convert lists of
530 scoped_ptr
<base::ListValue
> result(new base::ListValue());
531 for (BluetoothLowEnergyEventRouter::DescriptorList::iterator iter
=
532 descriptor_list
.begin();
533 iter
!= descriptor_list
.end();
535 result
->Append(apibtle::DescriptorToValue(iter
->get()).release());
537 SetResult(result
.release());
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
551 if (!event_router
->HasAdapter()) {
552 SetError(kErrorAdapterNotInitialized
);
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(
566 &BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback
,
569 &BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback
,
575 void BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback() {
576 // Obtain info on the characteristic and see whether or not the characteristic
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
));
588 // Manually construct the result instead of using
589 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
591 SetResult(apibtle::CharacteristicToValue(&characteristic
).release());
595 void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback(
596 BluetoothLowEnergyEventRouter::Status status
) {
597 SetError(StatusToString(status
));
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
609 if (!event_router
->HasAdapter()) {
610 SetError(kErrorAdapterNotInitialized
);
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(
622 params
->characteristic_id
,
625 &BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback
,
628 &BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback
,
634 void BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback() {
635 results_
= apibtle::WriteCharacteristicValue::Results::Create();
639 void BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback(
640 BluetoothLowEnergyEventRouter::Status status
) {
641 SetError(StatusToString(status
));
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
653 if (!event_router
->HasAdapter()) {
654 SetError(kErrorAdapterNotInitialized
);
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();
666 persistent
= properties
->persistent
;
668 event_router
->StartCharacteristicNotifications(
671 params
->characteristic_id
,
672 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
675 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
683 BluetoothLowEnergyStartCharacteristicNotificationsFunction::SuccessCallback() {
687 void BluetoothLowEnergyStartCharacteristicNotificationsFunction::ErrorCallback(
688 BluetoothLowEnergyEventRouter::Status status
) {
689 SetError(StatusToString(status
));
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
701 if (!event_router
->HasAdapter()) {
702 SetError(kErrorAdapterNotInitialized
);
707 scoped_ptr
<apibtle::StopCharacteristicNotifications::Params
> params(
708 apibtle::StopCharacteristicNotifications::Params::Create(*args_
));
709 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
711 event_router
->StopCharacteristicNotifications(
713 params
->characteristic_id
,
714 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
717 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
725 BluetoothLowEnergyStopCharacteristicNotificationsFunction::SuccessCallback() {
729 void BluetoothLowEnergyStopCharacteristicNotificationsFunction::ErrorCallback(
730 BluetoothLowEnergyEventRouter::Status status
) {
731 SetError(StatusToString(status
));
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
743 if (!event_router
->HasAdapter()) {
744 SetError(kErrorAdapterNotInitialized
);
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(
758 &BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback
,
760 base::Bind(&BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback
,
766 void BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback() {
767 // Obtain info on the descriptor and see whether or not the descriptor is
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
));
779 // Manually construct the result instead of using
780 // apibtle::GetDescriptor::Results::Create as it doesn't convert lists of
782 SetResult(apibtle::DescriptorToValue(&descriptor
).release());
786 void BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback(
787 BluetoothLowEnergyEventRouter::Status status
) {
788 SetError(StatusToString(status
));
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
800 if (!event_router
->HasAdapter()) {
801 SetError(kErrorAdapterNotInitialized
);
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(
813 params
->descriptor_id
,
816 &BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback
,
818 base::Bind(&BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback
,
824 void BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback() {
825 results_
= apibtle::WriteDescriptorValue::Results::Create();
829 void BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback(
830 BluetoothLowEnergyEventRouter::Status status
) {
831 SetError(StatusToString(status
));
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() {
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
;
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
;
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
903 if (!(IsAutoLaunchedKioskApp(extension()->id()) ||
904 IsPeripheralFlagEnabled())) {
905 error_
= kErrorPermissionDenied
;
910 BluetoothLowEnergyEventRouter
* event_router
=
911 GetEventRouter(browser_context());
913 // The adapter must be initialized at this point, but return an error instead
915 if (!event_router
->HasAdapter()) {
916 SetError(kErrorAdapterNotInitialized
);
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())
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(),
951 &BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback
,
954 &BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback
,
960 void BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback(
961 scoped_refptr
<device::BluetoothAdvertisement
> advertisement
) {
962 results_
= apibtle::RegisterAdvertisement::Results::Create(AddAdvertisement(
963 new BluetoothApiAdvertisement(extension_id(), advertisement
)));
967 void BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback(
968 device::BluetoothAdvertisement::ErrorCode status
) {
970 case device::BluetoothAdvertisement::ErrorCode::
971 ERROR_ADVERTISEMENT_ALREADY_EXISTS
:
972 SetError(kStatusAdvertisementAlreadyExists
);
974 case device::BluetoothAdvertisement::ErrorCode::
975 ERROR_ADVERTISEMENT_INVALID_LENGTH
:
976 SetError(kErrorInvalidAdvertisementLength
);
979 SetError(kErrorOperationFailed
);
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
;
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
999 if (!(IsAutoLaunchedKioskApp(extension()->id()) ||
1000 IsPeripheralFlagEnabled())) {
1001 error_
= kErrorPermissionDenied
;
1002 SendResponse(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())
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);
1025 advertisement
->advertisement()->Unregister(
1027 &BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback
,
1028 this, params
->advertisement_id
),
1030 &BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback
,
1031 this, params
->advertisement_id
));
1036 void BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback(
1037 int advertisement_id
) {
1038 RemoveAdvertisement(advertisement_id
);
1042 void BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback(
1043 int advertisement_id
,
1044 device::BluetoothAdvertisement::ErrorCode status
) {
1045 RemoveAdvertisement(advertisement_id
);
1047 case device::BluetoothAdvertisement::ErrorCode::
1048 ERROR_ADVERTISEMENT_DOES_NOT_EXIST
:
1049 SetError(kStatusAdvertisementDoesNotExist
);
1052 SetError(kErrorOperationFailed
);
1054 SendResponse(false);
1058 } // namespace extensions