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/bluetooth_low_energy_event_router.h"
11 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.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"
16 using content::BrowserContext;
17 using content::BrowserThread;
19 namespace apibtle = extensions::api::bluetooth_low_energy;
23 const char kErrorAdapterNotInitialized[] =
24 "Could not initialize Bluetooth adapter.";
25 const char kErrorCharacteristicNotFoundFormat[] =
26 "Characteristic with ID \"%s\" not found.";
27 const char kErrorDeviceNotFoundFormat[] =
28 "Device with address \"%s\" not found.";
29 const char kErrorReadCharacteristicValueFailedFormat[] =
30 "Failed to read value of characteristic with ID \"%s\".";
31 const char kErrorServiceNotFoundFormat[] = "Service with ID \"%s\" not found.";
32 const char kErrorPlatformNotSupported[] =
33 "This operation is not supported on the current platform";
35 extensions::BluetoothLowEnergyEventRouter* GetEventRouter(
36 BrowserContext* context) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
38 return extensions::BluetoothLowEnergyAPI::Get(context)->event_router();
41 void DoWorkCallback(const base::Callback<bool()>& callback) {
42 DCHECK(!callback.is_null());
48 namespace extensions {
50 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI> >
51 g_factory = LAZY_INSTANCE_INITIALIZER;
54 BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>*
55 BluetoothLowEnergyAPI::GetFactoryInstance() {
56 return g_factory.Pointer();
60 BluetoothLowEnergyAPI* BluetoothLowEnergyAPI::Get(BrowserContext* context) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
62 return GetFactoryInstance()->Get(context);
65 BluetoothLowEnergyAPI::BluetoothLowEnergyAPI(BrowserContext* context)
66 : event_router_(new BluetoothLowEnergyEventRouter(context)),
67 browser_context_(context) {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
71 BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
74 void BluetoothLowEnergyAPI::Shutdown() {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
83 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
86 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 BluetoothLowEnergyEventRouter* event_router =
90 GetEventRouter(browser_context());
91 if (!event_router->IsBluetoothSupported()) {
92 SetError(kErrorPlatformNotSupported);
96 // It is safe to pass |this| here as ExtensionFunction is refcounted.
97 if (!event_router->InitializeAdapterAndInvokeCallback(base::Bind(
99 base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork, this)))) {
100 SetError(kErrorAdapterNotInitialized);
107 bool BluetoothLowEnergyGetServiceFunction::DoWork() {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110 BluetoothLowEnergyEventRouter* event_router =
111 GetEventRouter(browser_context());
113 // The adapter must be initialized at this point, but return an error instead
115 if (!event_router->HasAdapter()) {
116 SetError(kErrorAdapterNotInitialized);
121 scoped_ptr<apibtle::GetService::Params> params(
122 apibtle::GetService::Params::Create(*args_));
123 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
125 std::string service_id = params->service_id;
127 apibtle::Service service;
128 if (!event_router->GetService(service_id, &service)) {
130 base::StringPrintf(kErrorServiceNotFoundFormat, service_id.c_str()));
135 results_ = apibtle::GetService::Results::Create(service);
141 bool BluetoothLowEnergyGetServicesFunction::DoWork() {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 BluetoothLowEnergyEventRouter* event_router =
145 GetEventRouter(browser_context());
147 // The adapter must be initialized at this point, but return an error instead
149 if (!event_router->HasAdapter()) {
150 SetError(kErrorAdapterNotInitialized);
155 scoped_ptr<apibtle::GetServices::Params> params(
156 apibtle::GetServices::Params::Create(*args_));
157 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
159 std::string device_address = params->device_address;
161 BluetoothLowEnergyEventRouter::ServiceList service_list;
162 if (!event_router->GetServices(device_address, &service_list)) {
164 base::StringPrintf(kErrorDeviceNotFoundFormat, device_address.c_str()));
169 results_ = apibtle::GetServices::Results::Create(service_list);
175 bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178 BluetoothLowEnergyEventRouter* event_router =
179 GetEventRouter(browser_context());
181 // The adapter must be initialized at this point, but return an error instead
183 if (!event_router->HasAdapter()) {
184 SetError(kErrorAdapterNotInitialized);
189 scoped_ptr<apibtle::GetCharacteristic::Params> params(
190 apibtle::GetCharacteristic::Params::Create(*args_));
191 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
193 std::string characteristic_id = params->characteristic_id;
195 apibtle::Characteristic characteristic;
196 if (!event_router->GetCharacteristic(characteristic_id, &characteristic)) {
197 SetError(base::StringPrintf(kErrorCharacteristicNotFoundFormat,
198 characteristic_id.c_str()));
203 // Manually construct the result instead of using
204 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
206 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
212 bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215 BluetoothLowEnergyEventRouter* event_router =
216 GetEventRouter(browser_context());
218 // The adapter must be initialized at this point, but return an error instead
220 if (!event_router->HasAdapter()) {
221 SetError(kErrorAdapterNotInitialized);
226 scoped_ptr<apibtle::GetCharacteristics::Params> params(
227 apibtle::GetCharacteristics::Params::Create(*args_));
228 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
230 std::string service_id = params->service_id;
232 BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list;
233 if (!event_router->GetCharacteristics(service_id, &characteristic_list)) {
235 base::StringPrintf(kErrorServiceNotFoundFormat, service_id.c_str()));
241 // Manually construct the result instead of using
242 // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
244 scoped_ptr<base::ListValue> result(new base::ListValue());
245 for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter =
246 characteristic_list.begin();
247 iter != characteristic_list.end();
249 result->Append(apibtle::CharacteristicToValue(iter->get()).release());
251 SetResult(result.release());
257 bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260 BluetoothLowEnergyEventRouter* event_router =
261 GetEventRouter(browser_context());
263 // The adapter must be initialized at this point, but return an error instead
265 if (!event_router->HasAdapter()) {
266 SetError(kErrorAdapterNotInitialized);
271 scoped_ptr<apibtle::GetIncludedServices::Params> params(
272 apibtle::GetIncludedServices::Params::Create(*args_));
273 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
275 std::string service_id = params->service_id;
277 BluetoothLowEnergyEventRouter::ServiceList service_list;
278 if (!event_router->GetIncludedServices(service_id, &service_list)) {
280 base::StringPrintf(kErrorServiceNotFoundFormat, service_id.c_str()));
285 results_ = apibtle::GetIncludedServices::Results::Create(service_list);
291 bool BluetoothLowEnergyGetDescriptorFunction::DoWork() {
292 // TODO(armansito): Implement.
293 SetError("Call not supported.");
298 bool BluetoothLowEnergyGetDescriptorsFunction::DoWork() {
299 // TODO(armansito): Implement.
300 SetError("Call not supported.");
305 bool BluetoothLowEnergyReadCharacteristicValueFunction::DoWork() {
306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 BluetoothLowEnergyEventRouter* event_router =
309 GetEventRouter(browser_context());
311 // The adapter must be initialized at this point, but return an error instead
313 if (!event_router->HasAdapter()) {
314 SetError(kErrorAdapterNotInitialized);
319 scoped_ptr<apibtle::ReadCharacteristicValue::Params> params(
320 apibtle::ReadCharacteristicValue::Params::Create(*args_));
321 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
323 instance_id_ = params->characteristic_id;
325 if (!event_router->ReadCharacteristicValue(
327 base::Bind(&BluetoothLowEnergyReadCharacteristicValueFunction::
331 &BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback,
333 SetError(base::StringPrintf(kErrorCharacteristicNotFoundFormat,
334 instance_id_.c_str()));
342 void BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback() {
343 // Obtain info on the characteristic and see whether or not the characteristic
345 apibtle::Characteristic characteristic;
346 if (!GetEventRouter(browser_context())
347 ->GetCharacteristic(instance_id_, &characteristic)) {
348 SetError(base::StringPrintf(kErrorCharacteristicNotFoundFormat,
349 instance_id_.c_str()));
354 // Manually construct the result instead of using
355 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
357 SetResult(apibtle::CharacteristicToValue(&characteristic).release());
361 void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback() {
362 SetError(base::StringPrintf(kErrorReadCharacteristicValueFailedFormat,
363 instance_id_.c_str()));
367 bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
368 // TODO(armansito): Implement.
369 SetError("Call not supported.");
374 bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
375 // TODO(armansito): Implement.
376 SetError("Call not supported.");
381 bool BluetoothLowEnergyWriteDescriptorValueFunction::DoWork() {
382 // TODO(armansito): Implement.
383 SetError("Call not supported.");
389 } // namespace extensions