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/common/extensions/api/bluetooth_low_energy.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "extensions/browser/event_router.h"
15 using content::BrowserContext
;
16 using content::BrowserThread
;
18 namespace apibtle
= extensions::api::bluetooth_low_energy
;
22 const char kErrorAdapterNotInitialized
[] =
23 "Could not initialize Bluetooth adapter.";
24 const char kErrorCharacteristicNotFoundFormat
[] =
25 "Characteristic with ID \"%s\" not found.";
26 const char kErrorDeviceNotFoundFormat
[] =
27 "Device with address \"%s\" not found.";
28 const char kErrorServiceNotFoundFormat
[] = "Service with ID \"%s\" not found.";
29 const char kErrorPlatformNotSupported
[] =
30 "This operation is not supported on the current platform";
32 extensions::BluetoothLowEnergyEventRouter
* GetEventRouter(
33 BrowserContext
* context
) {
34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
35 return extensions::BluetoothLowEnergyAPI::Get(context
)->event_router();
38 void DoWorkCallback(const base::Callback
<bool()>& callback
) {
39 DCHECK(!callback
.is_null());
43 // TODO(armansito): Remove this function once the described bug is fixed.
44 // (See crbug.com/368368).
46 // Converts an apibtle::Characteristic to a base::Value. This function is
47 // necessary, as json_schema_compiler::util::AddItemToList has no template
48 // specialization for user defined enums, which get treated as integers. This is
49 // because Characteristic contains a list of enum CharacteristicProperty.
50 scoped_ptr
<base::DictionaryValue
> CharacteristicToValue(
51 apibtle::Characteristic
* from
) {
52 // Copy the properties. Use Characteristic::ToValue to generate the result
53 // dictionary without the properties, to prevent json_schema_compiler from
55 std::vector
<apibtle::CharacteristicProperty
> properties
= from
->properties
;
56 from
->properties
.clear();
57 scoped_ptr
<base::DictionaryValue
> to
= from
->ToValue();
59 // Manually set each property.
60 scoped_ptr
<base::ListValue
> property_list(new base::ListValue());
61 for (std::vector
<apibtle::CharacteristicProperty
>::iterator iter
=
63 iter
!= properties
.end();
65 property_list
->Append(new base::StringValue(apibtle::ToString(*iter
)));
67 to
->Set("properties", property_list
.release());
74 namespace extensions
{
76 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<BluetoothLowEnergyAPI
> >
77 g_factory
= LAZY_INSTANCE_INITIALIZER
;
80 BrowserContextKeyedAPIFactory
<BluetoothLowEnergyAPI
>*
81 BluetoothLowEnergyAPI::GetFactoryInstance() {
82 return g_factory
.Pointer();
86 BluetoothLowEnergyAPI
* BluetoothLowEnergyAPI::Get(BrowserContext
* context
) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
88 return GetFactoryInstance()->Get(context
);
91 BluetoothLowEnergyAPI::BluetoothLowEnergyAPI(BrowserContext
* context
)
92 : event_router_(new BluetoothLowEnergyEventRouter(context
)),
93 browser_context_(context
) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
97 BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
100 void BluetoothLowEnergyAPI::Shutdown() {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
106 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
109 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
112 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
115 BluetoothLowEnergyEventRouter
* event_router
=
116 GetEventRouter(browser_context());
117 if (!event_router
->IsBluetoothSupported()) {
118 SetError(kErrorPlatformNotSupported
);
122 // It is safe to pass |this| here as ExtensionFunction is refcounted.
123 if (!event_router
->InitializeAdapterAndInvokeCallback(base::Bind(
125 base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork
, this)))) {
126 SetError(kErrorAdapterNotInitialized
);
133 bool BluetoothLowEnergyGetServiceFunction::DoWork() {
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
136 BluetoothLowEnergyEventRouter
* event_router
=
137 GetEventRouter(browser_context());
139 // The adapter must be initialized at this point, but return an error instead
141 if (!event_router
->HasAdapter()) {
142 SetError(kErrorAdapterNotInitialized
);
147 scoped_ptr
<apibtle::GetService::Params
> params(
148 apibtle::GetService::Params::Create(*args_
));
149 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
151 std::string service_id
= params
->service_id
;
153 apibtle::Service service
;
154 if (!event_router
->GetService(service_id
, &service
)) {
156 base::StringPrintf(kErrorServiceNotFoundFormat
, service_id
.c_str()));
161 results_
= apibtle::GetService::Results::Create(service
);
167 bool BluetoothLowEnergyGetServicesFunction::DoWork() {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
170 BluetoothLowEnergyEventRouter
* event_router
=
171 GetEventRouter(browser_context());
173 // The adapter must be initialized at this point, but return an error instead
175 if (!event_router
->HasAdapter()) {
176 SetError(kErrorAdapterNotInitialized
);
181 scoped_ptr
<apibtle::GetServices::Params
> params(
182 apibtle::GetServices::Params::Create(*args_
));
183 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
185 std::string device_address
= params
->device_address
;
187 BluetoothLowEnergyEventRouter::ServiceList service_list
;
188 if (!event_router
->GetServices(device_address
, &service_list
)) {
190 base::StringPrintf(kErrorDeviceNotFoundFormat
, device_address
.c_str()));
195 results_
= apibtle::GetServices::Results::Create(service_list
);
201 bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
204 BluetoothLowEnergyEventRouter
* event_router
=
205 GetEventRouter(browser_context());
207 // The adapter must be initialized at this point, but return an error instead
209 if (!event_router
->HasAdapter()) {
210 SetError(kErrorAdapterNotInitialized
);
215 scoped_ptr
<apibtle::GetCharacteristic::Params
> params(
216 apibtle::GetCharacteristic::Params::Create(*args_
));
217 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
219 std::string characteristic_id
= params
->characteristic_id
;
221 apibtle::Characteristic characteristic
;
222 if (!event_router
->GetCharacteristic(characteristic_id
, &characteristic
)) {
223 SetError(base::StringPrintf(kErrorCharacteristicNotFoundFormat
,
224 characteristic_id
.c_str()));
229 // Manually construct the result instead of using
230 // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
232 SetResult(CharacteristicToValue(&characteristic
).release());
238 bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
241 BluetoothLowEnergyEventRouter
* event_router
=
242 GetEventRouter(browser_context());
244 // The adapter must be initialized at this point, but return an error instead
246 if (!event_router
->HasAdapter()) {
247 SetError(kErrorAdapterNotInitialized
);
252 scoped_ptr
<apibtle::GetCharacteristics::Params
> params(
253 apibtle::GetCharacteristics::Params::Create(*args_
));
254 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
256 std::string service_id
= params
->service_id
;
258 BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list
;
259 if (!event_router
->GetCharacteristics(service_id
, &characteristic_list
)) {
261 base::StringPrintf(kErrorServiceNotFoundFormat
, service_id
.c_str()));
267 // Manually construct the result instead of using
268 // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
270 scoped_ptr
<base::ListValue
> result(new base::ListValue());
271 for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter
=
272 characteristic_list
.begin();
273 iter
!= characteristic_list
.end();
275 result
->Append(CharacteristicToValue(iter
->get()).release());
277 SetResult(result
.release());
283 bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() {
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
286 BluetoothLowEnergyEventRouter
* event_router
=
287 GetEventRouter(browser_context());
289 // The adapter must be initialized at this point, but return an error instead
291 if (!event_router
->HasAdapter()) {
292 SetError(kErrorAdapterNotInitialized
);
297 scoped_ptr
<apibtle::GetIncludedServices::Params
> params(
298 apibtle::GetIncludedServices::Params::Create(*args_
));
299 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
301 std::string service_id
= params
->service_id
;
303 BluetoothLowEnergyEventRouter::ServiceList service_list
;
304 if (!event_router
->GetIncludedServices(service_id
, &service_list
)) {
306 base::StringPrintf(kErrorServiceNotFoundFormat
, service_id
.c_str()));
311 results_
= apibtle::GetIncludedServices::Results::Create(service_list
);
317 bool BluetoothLowEnergyGetDescriptorFunction::DoWork() {
318 // TODO(armansito): Implement.
319 SetError("Call not supported.");
324 bool BluetoothLowEnergyGetDescriptorsFunction::DoWork() {
325 // TODO(armansito): Implement.
326 SetError("Call not supported.");
331 bool BluetoothLowEnergyReadCharacteristicValueFunction::DoWork() {
332 // TODO(armansito): Implement.
333 SetError("Call not supported.");
338 bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
339 // TODO(armansito): Implement.
340 SetError("Call not supported.");
345 bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
346 // TODO(armansito): Implement.
347 SetError("Call not supported.");
352 bool BluetoothLowEnergyWriteDescriptorValueFunction::DoWork() {
353 // TODO(armansito): Implement.
354 SetError("Call not supported.");
360 } // namespace extensions