Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / bluetooth / bluetooth_private_api.cc
blob27cc1242df848c2dba01cf35b5a8c34d1134bedb
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 "extensions/browser/api/bluetooth/bluetooth_private_api.h"
7 #include "base/callback.h"
8 #include "base/lazy_instance.h"
9 #include "base/strings/string_util.h"
10 #include "device/bluetooth/bluetooth_adapter.h"
11 #include "device/bluetooth/bluetooth_adapter_factory.h"
12 #include "extensions/browser/api/bluetooth/bluetooth_api.h"
13 #include "extensions/browser/api/bluetooth/bluetooth_event_router.h"
14 #include "extensions/common/api/bluetooth_private.h"
16 namespace bt_private = extensions::core_api::bluetooth_private;
17 namespace SetDiscoveryFilter =
18 extensions::core_api::bluetooth_private::SetDiscoveryFilter;
20 namespace extensions {
22 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothPrivateAPI> >
23 g_factory = LAZY_INSTANCE_INITIALIZER;
25 // static
26 BrowserContextKeyedAPIFactory<BluetoothPrivateAPI>*
27 BluetoothPrivateAPI::GetFactoryInstance() {
28 return g_factory.Pointer();
31 BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext* context)
32 : browser_context_(context) {
33 EventRouter::Get(browser_context_)
34 ->RegisterObserver(this, bt_private::OnPairing::kEventName);
37 BluetoothPrivateAPI::~BluetoothPrivateAPI() {}
39 void BluetoothPrivateAPI::Shutdown() {
40 EventRouter::Get(browser_context_)->UnregisterObserver(this);
43 void BluetoothPrivateAPI::OnListenerAdded(const EventListenerInfo& details) {
44 // This function can be called multiple times for the same JS listener, for
45 // example, once for the addListener call and again if it is a lazy listener.
46 if (!details.browser_context)
47 return;
49 BluetoothAPI::Get(browser_context_)->event_router()->AddPairingDelegate(
50 details.extension_id);
53 void BluetoothPrivateAPI::OnListenerRemoved(const EventListenerInfo& details) {
54 // This function can be called multiple times for the same JS listener, for
55 // example, once for the addListener call and again if it is a lazy listener.
56 if (!details.browser_context)
57 return;
59 BluetoothAPI::Get(browser_context_)->event_router()->RemovePairingDelegate(
60 details.extension_id);
63 namespace core_api {
65 namespace {
67 const char kNameProperty[] = "name";
68 const char kPoweredProperty[] = "powered";
69 const char kDiscoverableProperty[] = "discoverable";
71 const char kSetAdapterPropertyError[] = "Error setting adapter properties: $1";
73 const char kDeviceNotFoundError[] =
74 "Given address is not a valid Bluetooth device.";
76 const char kDeviceNotConnectedError[] = "Device is not connected";
78 const char kPairingNotEnabled[] =
79 "Pairing must be enabled to set a pairing response.";
81 const char kInvalidPairingResponseOptions[] =
82 "Invalid pairing response options";
84 const char kAdapterNotPresent[] =
85 "Could not find a Bluetooth adapter.";
87 const char kDisconnectError[] = "Failed to disconnect device";
89 const char kSetDiscoveryFilterFailed[] = "Failed to set discovery filter";
91 // Returns true if the pairing response options passed into the
92 // setPairingResponse function are valid.
93 bool ValidatePairingResponseOptions(
94 const device::BluetoothDevice* device,
95 const bt_private::SetPairingResponseOptions& options) {
96 bool response = options.response != bt_private::PAIRING_RESPONSE_NONE;
97 bool pincode = options.pincode.get() != NULL;
98 bool passkey = options.passkey.get() != NULL;
100 if (!response && !pincode && !passkey)
101 return false;
102 if (pincode && passkey)
103 return false;
104 if (options.response != bt_private::PAIRING_RESPONSE_CONFIRM &&
105 (pincode || passkey))
106 return false;
108 // Check the BluetoothDevice is in expecting the correct response.
109 if (!device->ExpectingConfirmation() && !device->ExpectingPinCode() &&
110 !device->ExpectingPasskey())
111 return false;
112 if (pincode && !device->ExpectingPinCode())
113 return false;
114 if (passkey && !device->ExpectingPasskey())
115 return false;
116 if (options.response == bt_private::PAIRING_RESPONSE_CONFIRM && !pincode &&
117 !passkey && !device->ExpectingConfirmation())
118 return false;
120 return true;
123 } // namespace
125 BluetoothPrivateSetAdapterStateFunction::
126 BluetoothPrivateSetAdapterStateFunction() {}
128 BluetoothPrivateSetAdapterStateFunction::
129 ~BluetoothPrivateSetAdapterStateFunction() {}
131 bool BluetoothPrivateSetAdapterStateFunction::DoWork(
132 scoped_refptr<device::BluetoothAdapter> adapter) {
133 scoped_ptr<bt_private::SetAdapterState::Params> params(
134 bt_private::SetAdapterState::Params::Create(*args_));
135 EXTENSION_FUNCTION_VALIDATE(params.get());
137 if (!adapter->IsPresent()) {
138 SetError(kAdapterNotPresent);
139 SendResponse(false);
140 return true;
143 const bt_private::NewAdapterState& new_state = params->adapter_state;
145 // These properties are not owned.
146 std::string* name = new_state.name.get();
147 bool* powered = new_state.powered.get();
148 bool* discoverable = new_state.discoverable.get();
150 if (name && adapter->GetName() != *name) {
151 pending_properties_.insert(kNameProperty);
152 adapter->SetName(*name,
153 CreatePropertySetCallback(kNameProperty),
154 CreatePropertyErrorCallback(kNameProperty));
157 if (powered && adapter->IsPowered() != *powered) {
158 pending_properties_.insert(kPoweredProperty);
159 adapter->SetPowered(*powered,
160 CreatePropertySetCallback(kPoweredProperty),
161 CreatePropertyErrorCallback(kPoweredProperty));
164 if (discoverable && adapter->IsDiscoverable() != *discoverable) {
165 pending_properties_.insert(kDiscoverableProperty);
166 adapter->SetDiscoverable(
167 *discoverable,
168 CreatePropertySetCallback(kDiscoverableProperty),
169 CreatePropertyErrorCallback(kDiscoverableProperty));
172 if (pending_properties_.empty())
173 SendResponse(true);
174 return true;
177 base::Closure
178 BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback(
179 const std::string& property_name) {
180 return base::Bind(
181 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet,
182 this,
183 property_name);
186 base::Closure
187 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback(
188 const std::string& property_name) {
189 return base::Bind(
190 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError,
191 this,
192 property_name);
195 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet(
196 const std::string& property) {
197 DCHECK(pending_properties_.find(property) != pending_properties_.end());
198 DCHECK(failed_properties_.find(property) == failed_properties_.end());
200 pending_properties_.erase(property);
201 if (pending_properties_.empty()) {
202 if (failed_properties_.empty())
203 SendResponse(true);
204 else
205 SendError();
209 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError(
210 const std::string& property) {
211 DCHECK(pending_properties_.find(property) != pending_properties_.end());
212 DCHECK(failed_properties_.find(property) == failed_properties_.end());
214 pending_properties_.erase(property);
215 failed_properties_.insert(property);
216 if (pending_properties_.empty())
217 SendError();
220 void BluetoothPrivateSetAdapterStateFunction::SendError() {
221 DCHECK(pending_properties_.empty());
222 DCHECK(!failed_properties_.empty());
224 std::vector<std::string> failed_vector;
225 std::copy(failed_properties_.begin(),
226 failed_properties_.end(),
227 std::back_inserter(failed_vector));
229 std::vector<std::string> replacements(1);
230 replacements[0] = JoinString(failed_vector, ", ");
231 std::string error =
232 ReplaceStringPlaceholders(kSetAdapterPropertyError, replacements, NULL);
233 SetError(error);
234 SendResponse(false);
237 BluetoothPrivateSetPairingResponseFunction::
238 BluetoothPrivateSetPairingResponseFunction() {}
240 BluetoothPrivateSetPairingResponseFunction::
241 ~BluetoothPrivateSetPairingResponseFunction() {}
243 bool BluetoothPrivateSetPairingResponseFunction::DoWork(
244 scoped_refptr<device::BluetoothAdapter> adapter) {
245 scoped_ptr<bt_private::SetPairingResponse::Params> params(
246 bt_private::SetPairingResponse::Params::Create(*args_));
247 EXTENSION_FUNCTION_VALIDATE(params.get());
248 const bt_private::SetPairingResponseOptions& options = params->options;
250 BluetoothEventRouter* router =
251 BluetoothAPI::Get(browser_context())->event_router();
252 if (!router->GetPairingDelegate(extension_id())) {
253 SetError(kPairingNotEnabled);
254 SendResponse(false);
255 return true;
258 const std::string& device_address = options.device.address;
259 device::BluetoothDevice* device = adapter->GetDevice(device_address);
260 if (!device) {
261 SetError(kDeviceNotFoundError);
262 SendResponse(false);
263 return true;
266 if (!ValidatePairingResponseOptions(device, options)) {
267 SetError(kInvalidPairingResponseOptions);
268 SendResponse(false);
269 return true;
272 if (options.pincode.get()) {
273 device->SetPinCode(*options.pincode.get());
274 } else if (options.passkey.get()) {
275 device->SetPasskey(*options.passkey.get());
276 } else {
277 switch (options.response) {
278 case bt_private::PAIRING_RESPONSE_CONFIRM:
279 device->ConfirmPairing();
280 break;
281 case bt_private::PAIRING_RESPONSE_REJECT:
282 device->RejectPairing();
283 break;
284 case bt_private::PAIRING_RESPONSE_CANCEL:
285 device->CancelPairing();
286 break;
287 default:
288 NOTREACHED();
292 SendResponse(true);
293 return true;
296 BluetoothPrivateDisconnectAllFunction::BluetoothPrivateDisconnectAllFunction() {
299 BluetoothPrivateDisconnectAllFunction::
300 ~BluetoothPrivateDisconnectAllFunction() {
303 bool BluetoothPrivateDisconnectAllFunction::DoWork(
304 scoped_refptr<device::BluetoothAdapter> adapter) {
305 scoped_ptr<bt_private::DisconnectAll::Params> params(
306 bt_private::DisconnectAll::Params::Create(*args_));
307 EXTENSION_FUNCTION_VALIDATE(params.get());
309 device::BluetoothDevice* device = adapter->GetDevice(params->device_address);
310 if (!device) {
311 SetError(kDeviceNotFoundError);
312 SendResponse(false);
313 return true;
316 if (!device->IsConnected()) {
317 SetError(kDeviceNotConnectedError);
318 SendResponse(false);
319 return true;
322 device->Disconnect(
323 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnSuccessCallback,
324 this),
325 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnErrorCallback, this,
326 adapter, params->device_address));
328 return true;
331 void BluetoothPrivateDisconnectAllFunction::OnSuccessCallback() {
332 SendResponse(true);
335 void BluetoothPrivateDisconnectAllFunction::OnErrorCallback(
336 scoped_refptr<device::BluetoothAdapter> adapter,
337 const std::string& device_address) {
338 // The call to Disconnect may report an error if the device was disconnected
339 // due to an external reason. In this case, report "Not Connected" as the
340 // error.
341 device::BluetoothDevice* device = adapter->GetDevice(device_address);
342 if (device && !device->IsConnected())
343 SetError(kDeviceNotConnectedError);
344 else
345 SetError(kDisconnectError);
347 SendResponse(false);
350 bool BluetoothPrivateSetDiscoveryFilterFunction::DoWork(
351 scoped_refptr<device::BluetoothAdapter> adapter) {
352 scoped_ptr<SetDiscoveryFilter::Params> params(
353 SetDiscoveryFilter::Params::Create(*args_));
355 // TODO(jpawlowski): parse arguments, and call event router when method is
356 // implemented.
358 SetError(kSetDiscoveryFilterFailed);
359 SendResponse(false);
360 return true;
363 } // namespace core_api
365 } // namespace extensions