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"
8 #include "base/lazy_instance.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
11 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
12 #include "chrome/common/extensions/api/bluetooth_low_energy.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "extensions/browser/event_router.h"
15 #include "extensions/common/permissions/permissions_data.h"
17 using content::BrowserContext;
18 using content::BrowserThread;
20 namespace apibtle = extensions::api::bluetooth_low_energy;
22 namespace extensions {
26 const char kErrorAdapterNotInitialized[] =
27 "Could not initialize Bluetooth adapter";
28 const char kErrorAlreadyConnected[] = "Already connected";
29 const char kErrorAlreadyNotifying[] = "Already notifying";
30 const char kErrorInProgress[] = "In progress";
31 const char kErrorNotConnected[] = "Not connected";
32 const char kErrorNotNotifying[] = "Not notifying";
33 const char kErrorNotFound[] = "Instance not found";
34 const char kErrorOperationFailed[] = "Operation failed";
35 const char kErrorPermissionDenied[] = "Permission denied";
36 const char kErrorPlatformNotSupported[] =
37 "This operation is not supported on the current platform";
39 // Returns the correct error string based on error status |status|. This is used
40 // to set the value of |chrome.runtime.lastError.message| and should not be
41 // passed |BluetoothLowEnergyEventRouter::kStatusSuccess|.
42 std::string StatusToString(BluetoothLowEnergyEventRouter::Status status) {
44 case BluetoothLowEnergyEventRouter::kStatusErrorPermissionDenied:
45 return kErrorPermissionDenied;
46 case BluetoothLowEnergyEventRouter::kStatusErrorNotFound:
47 return kErrorNotFound;
48 case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyConnected:
49 return kErrorAlreadyConnected;
50 case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyNotifying:
51 return kErrorAlreadyNotifying;
52 case BluetoothLowEnergyEventRouter::kStatusErrorNotConnected:
53 return kErrorNotConnected;
54 case BluetoothLowEnergyEventRouter::kStatusErrorNotNotifying:
55 return kErrorNotNotifying;
56 case BluetoothLowEnergyEventRouter::kStatusErrorInProgress:
57 return kErrorInProgress;
58 case BluetoothLowEnergyEventRouter::kStatusSuccess:
62 return kErrorOperationFailed;
67 extensions::BluetoothLowEnergyEventRouter* GetEventRouter(
68 BrowserContext* context) {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70 return extensions::BluetoothLowEnergyAPI::Get(context)->event_router();
73 void DoWorkCallback(const base::Callback<bool()>& callback) {
74 DCHECK(!callback.is_null());
81 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI> >
82 g_factory = LAZY_INSTANCE_INITIALIZER;
85 BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>*
86 BluetoothLowEnergyAPI::GetFactoryInstance() {
87 return g_factory.Pointer();
91 BluetoothLowEnergyAPI* BluetoothLowEnergyAPI::Get(BrowserContext* context) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 return GetFactoryInstance()->Get(context);
96 BluetoothLowEnergyAPI::BluetoothLowEnergyAPI(BrowserContext* context)
97 : event_router_(new BluetoothLowEnergyEventRouter(context)),
98 browser_context_(context) {
99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
102 BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
105 void BluetoothLowEnergyAPI::Shutdown() {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
114 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
117 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120 if (!BluetoothManifestData::CheckLowEnergyPermitted(extension())) {
121 error_ = kErrorPermissionDenied;
125 BluetoothLowEnergyEventRouter* event_router =
126 GetEventRouter(browser_context());
127 if (!event_router->IsBluetoothSupported()) {
128 SetError(kErrorPlatformNotSupported);
132 // It is safe to pass |this| here as ExtensionFunction is refcounted.
133 if (!event_router->InitializeAdapterAndInvokeCallback(base::Bind(
135 base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork, this)))) {
136 SetError(kErrorAdapterNotInitialized);
143 bool BluetoothLowEnergyConnectFunction::DoWork() {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
146 BluetoothLowEnergyEventRouter* event_router =
147 GetEventRouter(browser_context());
149 // The adapter must be initialized at this point, but return an error instead
151 if (!event_router->HasAdapter()) {
152 SetError(kErrorAdapterNotInitialized);
157 scoped_ptr<apibtle::Connect::Params> params(
158 apibtle::Connect::Params::Create(*args_));
159 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
161 bool persistent = false; // Not persistent by default.
162 apibtle::ConnectProperties* properties = params.get()->properties.get();
164 persistent = properties->persistent;
166 event_router->Connect(
169 params->device_address,
170 base::Bind(&BluetoothLowEnergyConnectFunction::SuccessCallback, this),
171 base::Bind(&BluetoothLowEnergyConnectFunction::ErrorCallback, this));
176 void BluetoothLowEnergyConnectFunction::SuccessCallback() {
180 void BluetoothLowEnergyConnectFunction::ErrorCallback(
181 BluetoothLowEnergyEventRouter::Status status) {
182 SetError(StatusToString(status));
186 bool BluetoothLowEnergyDisconnectFunction::DoWork() {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189 BluetoothLowEnergyEventRouter* event_router =
190 GetEventRouter(browser_context());
192 // The adapter must be initialized at this point, but return an error instead
194 if (!event_router->HasAdapter()) {
195 SetError(kErrorAdapterNotInitialized);
200 scoped_ptr<apibtle::Disconnect::Params> params(
201 apibtle::Disconnect::Params::Create(*args_));
202 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
204 event_router->Disconnect(
206 params->device_address,
207 base::Bind(&BluetoothLowEnergyDisconnectFunction::SuccessCallback, this),
208 base::Bind(&BluetoothLowEnergyDisconnectFunction::ErrorCallback, this));
213 void BluetoothLowEnergyDisconnectFunction::SuccessCallback() {
217 void BluetoothLowEnergyDisconnectFunction::ErrorCallback(
218 BluetoothLowEnergyEventRouter::Status status) {
219 SetError(StatusToString(status));
223 bool BluetoothLowEnergyGetServiceFunction::DoWork() {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 BluetoothLowEnergyEventRouter* event_router =
227 GetEventRouter(browser_context());
229 // The adapter must be initialized at this point, but return an error instead
231 if (!event_router->HasAdapter()) {
232 SetError(kErrorAdapterNotInitialized);
237 scoped_ptr<apibtle::GetService::Params> params(
238 apibtle::GetService::Params::Create(*args_));
239 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
241 apibtle::Service service;
242 BluetoothLowEnergyEventRouter::Status status =
243 event_router->GetService(params->service_id, &service);
244 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
245 SetError(StatusToString(status));
250 results_ = apibtle::GetService::Results::Create(service);
256 bool BluetoothLowEnergyGetServicesFunction::DoWork() {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
259 BluetoothLowEnergyEventRouter* event_router =
260 GetEventRouter(browser_context());
262 // The adapter must be initialized at this point, but return an error instead
264 if (!event_router->HasAdapter()) {
265 SetError(kErrorAdapterNotInitialized);
270 scoped_ptr<apibtle::GetServices::Params> params(
271 apibtle::GetServices::Params::Create(*args_));
272 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
274 BluetoothLowEnergyEventRouter::ServiceList service_list;
275 if (!event_router->GetServices(params->device_address, &service_list)) {
276 SetError(kErrorNotFound);
281 results_ = apibtle::GetServices::Results::Create(service_list);
287 bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290 BluetoothLowEnergyEventRouter* event_router =
291 GetEventRouter(browser_context());
293 // The adapter must be initialized at this point, but return an error instead
295 if (!event_router->HasAdapter()) {
296 SetError(kErrorAdapterNotInitialized);
301 scoped_ptr<apibtle::GetCharacteristic::Params> params(
302 apibtle::GetCharacteristic::Params::Create(*args_));
303 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
305 apibtle::Characteristic characteristic;
306 BluetoothLowEnergyEventRouter::Status status =
307 event_router->GetCharacteristic(
308 extension(), params->characteristic_id, &characteristic);
309 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
310 SetError(StatusToString(status));
315 // Manually construct the result instead of using
316 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
318 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
324 bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
327 BluetoothLowEnergyEventRouter* event_router =
328 GetEventRouter(browser_context());
330 // The adapter must be initialized at this point, but return an error instead
332 if (!event_router->HasAdapter()) {
333 SetError(kErrorAdapterNotInitialized);
338 scoped_ptr<apibtle::GetCharacteristics::Params> params(
339 apibtle::GetCharacteristics::Params::Create(*args_));
340 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
342 BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list;
343 BluetoothLowEnergyEventRouter::Status status =
344 event_router->GetCharacteristics(
345 extension(), params->service_id, &characteristic_list);
346 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
347 SetError(StatusToString(status));
352 // Manually construct the result instead of using
353 // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
355 scoped_ptr<base::ListValue> result(new base::ListValue());
356 for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter =
357 characteristic_list.begin();
358 iter != characteristic_list.end();
360 result->Append(apibtle::CharacteristicToValue(iter->get()).release());
362 SetResult(result.release());
368 bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() {
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
371 BluetoothLowEnergyEventRouter* event_router =
372 GetEventRouter(browser_context());
374 // The adapter must be initialized at this point, but return an error instead
376 if (!event_router->HasAdapter()) {
377 SetError(kErrorAdapterNotInitialized);
382 scoped_ptr<apibtle::GetIncludedServices::Params> params(
383 apibtle::GetIncludedServices::Params::Create(*args_));
384 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
386 BluetoothLowEnergyEventRouter::ServiceList service_list;
387 BluetoothLowEnergyEventRouter::Status status =
388 event_router->GetIncludedServices(params->service_id, &service_list);
389 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
390 SetError(StatusToString(status));
395 results_ = apibtle::GetIncludedServices::Results::Create(service_list);
401 bool BluetoothLowEnergyGetDescriptorFunction::DoWork() {
402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
404 BluetoothLowEnergyEventRouter* event_router =
405 GetEventRouter(browser_context());
407 // The adapter must be initialized at this point, but return an error instead
409 if (!event_router->HasAdapter()) {
410 SetError(kErrorAdapterNotInitialized);
415 scoped_ptr<apibtle::GetDescriptor::Params> params(
416 apibtle::GetDescriptor::Params::Create(*args_));
417 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
419 apibtle::Descriptor descriptor;
420 BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptor(
421 extension(), params->descriptor_id, &descriptor);
422 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
423 SetError(StatusToString(status));
428 // Manually construct the result instead of using
429 // apibtle::GetDescriptor::Result::Create as it doesn't convert lists of enums
431 SetResult(apibtle::DescriptorToValue(&descriptor).release());
437 bool BluetoothLowEnergyGetDescriptorsFunction::DoWork() {
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440 BluetoothLowEnergyEventRouter* event_router =
441 GetEventRouter(browser_context());
443 // The adapter must be initialized at this point, but return an error instead
445 if (!event_router->HasAdapter()) {
446 SetError(kErrorAdapterNotInitialized);
451 scoped_ptr<apibtle::GetDescriptors::Params> params(
452 apibtle::GetDescriptors::Params::Create(*args_));
453 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
455 BluetoothLowEnergyEventRouter::DescriptorList descriptor_list;
456 BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptors(
457 extension(), params->characteristic_id, &descriptor_list);
458 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
459 SetError(StatusToString(status));
464 // Manually construct the result instead of using
465 // apibtle::GetDescriptors::Result::Create as it doesn't convert lists of
467 scoped_ptr<base::ListValue> result(new base::ListValue());
468 for (BluetoothLowEnergyEventRouter::DescriptorList::iterator iter =
469 descriptor_list.begin();
470 iter != descriptor_list.end();
472 result->Append(apibtle::DescriptorToValue(iter->get()).release());
474 SetResult(result.release());
480 bool BluetoothLowEnergyReadCharacteristicValueFunction::DoWork() {
481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 BluetoothLowEnergyEventRouter* event_router =
484 GetEventRouter(browser_context());
486 // The adapter must be initialized at this point, but return an error instead
488 if (!event_router->HasAdapter()) {
489 SetError(kErrorAdapterNotInitialized);
494 scoped_ptr<apibtle::ReadCharacteristicValue::Params> params(
495 apibtle::ReadCharacteristicValue::Params::Create(*args_));
496 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
498 instance_id_ = params->characteristic_id;
499 event_router->ReadCharacteristicValue(
503 &BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback,
506 &BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback,
512 void BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback() {
513 // Obtain info on the characteristic and see whether or not the characteristic
515 apibtle::Characteristic characteristic;
516 BluetoothLowEnergyEventRouter::Status status =
517 GetEventRouter(browser_context())
518 ->GetCharacteristic(extension(), instance_id_, &characteristic);
519 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
520 SetError(StatusToString(status));
525 // Manually construct the result instead of using
526 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
528 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
532 void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback(
533 BluetoothLowEnergyEventRouter::Status status) {
534 SetError(StatusToString(status));
538 bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
541 BluetoothLowEnergyEventRouter* event_router =
542 GetEventRouter(browser_context());
544 // The adapter must be initialized at this point, but return an error instead
546 if (!event_router->HasAdapter()) {
547 SetError(kErrorAdapterNotInitialized);
552 scoped_ptr<apibtle::WriteCharacteristicValue::Params> params(
553 apibtle::WriteCharacteristicValue::Params::Create(*args_));
554 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
556 std::vector<uint8> value(params->value.begin(), params->value.end());
557 event_router->WriteCharacteristicValue(
559 params->characteristic_id,
562 &BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback,
565 &BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback,
571 void BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback() {
572 results_ = apibtle::WriteCharacteristicValue::Results::Create();
576 void BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback(
577 BluetoothLowEnergyEventRouter::Status status) {
578 SetError(StatusToString(status));
582 bool BluetoothLowEnergyStartCharacteristicNotificationsFunction::DoWork() {
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
585 BluetoothLowEnergyEventRouter* event_router =
586 GetEventRouter(browser_context());
588 // The adapter must be initialized at this point, but return an error instead
590 if (!event_router->HasAdapter()) {
591 SetError(kErrorAdapterNotInitialized);
596 scoped_ptr<apibtle::StartCharacteristicNotifications::Params> params(
597 apibtle::StartCharacteristicNotifications::Params::Create(*args_));
598 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
600 bool persistent = false; // Not persistent by default.
601 apibtle::NotificationProperties* properties = params.get()->properties.get();
603 persistent = properties->persistent;
605 event_router->StartCharacteristicNotifications(
608 params->characteristic_id,
609 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
612 base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
620 BluetoothLowEnergyStartCharacteristicNotificationsFunction::SuccessCallback() {
624 void BluetoothLowEnergyStartCharacteristicNotificationsFunction::ErrorCallback(
625 BluetoothLowEnergyEventRouter::Status status) {
626 SetError(StatusToString(status));
630 bool BluetoothLowEnergyStopCharacteristicNotificationsFunction::DoWork() {
631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
633 BluetoothLowEnergyEventRouter* event_router =
634 GetEventRouter(browser_context());
636 // The adapter must be initialized at this point, but return an error instead
638 if (!event_router->HasAdapter()) {
639 SetError(kErrorAdapterNotInitialized);
644 scoped_ptr<apibtle::StopCharacteristicNotifications::Params> params(
645 apibtle::StopCharacteristicNotifications::Params::Create(*args_));
646 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
648 event_router->StopCharacteristicNotifications(
650 params->characteristic_id,
651 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
654 base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
662 BluetoothLowEnergyStopCharacteristicNotificationsFunction::SuccessCallback() {
666 void BluetoothLowEnergyStopCharacteristicNotificationsFunction::ErrorCallback(
667 BluetoothLowEnergyEventRouter::Status status) {
668 SetError(StatusToString(status));
672 bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
673 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
675 BluetoothLowEnergyEventRouter* event_router =
676 GetEventRouter(browser_context());
678 // The adapter must be initialized at this point, but return an error instead
680 if (!event_router->HasAdapter()) {
681 SetError(kErrorAdapterNotInitialized);
686 scoped_ptr<apibtle::ReadDescriptorValue::Params> params(
687 apibtle::ReadDescriptorValue::Params::Create(*args_));
688 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
690 instance_id_ = params->descriptor_id;
691 event_router->ReadDescriptorValue(
695 &BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback,
697 base::Bind(&BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback,
703 void BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback() {
704 // Obtain info on the descriptor and see whether or not the descriptor is
706 apibtle::Descriptor descriptor;
707 BluetoothLowEnergyEventRouter::Status status =
708 GetEventRouter(browser_context())
709 ->GetDescriptor(extension(), instance_id_, &descriptor);
710 if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
711 SetError(StatusToString(status));
716 // Manually construct the result instead of using
717 // apibtle::GetDescriptor::Results::Create as it doesn't convert lists of
719 SetResult(apibtle::DescriptorToValue(&descriptor).release());
723 void BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback(
724 BluetoothLowEnergyEventRouter::Status status) {
725 SetError(StatusToString(status));
729 bool BluetoothLowEnergyWriteDescriptorValueFunction::DoWork() {
730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
732 BluetoothLowEnergyEventRouter* event_router =
733 GetEventRouter(browser_context());
735 // The adapter must be initialized at this point, but return an error instead
737 if (!event_router->HasAdapter()) {
738 SetError(kErrorAdapterNotInitialized);
743 scoped_ptr<apibtle::WriteDescriptorValue::Params> params(
744 apibtle::WriteDescriptorValue::Params::Create(*args_));
745 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
747 std::vector<uint8> value(params->value.begin(), params->value.end());
748 event_router->WriteDescriptorValue(
750 params->descriptor_id,
753 &BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback,
755 base::Bind(&BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback,
761 void BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback() {
762 results_ = apibtle::WriteDescriptorValue::Results::Create();
766 void BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback(
767 BluetoothLowEnergyEventRouter::Status status) {
768 SetError(StatusToString(status));
773 } // namespace extensions