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.
4
5 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
6
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"
15
16 namespace bt_private = extensions::core_api::bluetooth_private;
17
18 namespace extensions {
19
20 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothPrivateAPI> >
21 g_factory = LAZY_INSTANCE_INITIALIZER;
22
23 // static
24 BrowserContextKeyedAPIFactory<BluetoothPrivateAPI>*
GetFactoryInstance()25 BluetoothPrivateAPI::GetFactoryInstance() {
26 return g_factory.Pointer();
27 }
28
BluetoothPrivateAPI(content::BrowserContext * context)29 BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext* context)
30 : browser_context_(context) {
31 EventRouter::Get(browser_context_)
32 ->RegisterObserver(this, bt_private::OnPairing::kEventName);
33 }
34
~BluetoothPrivateAPI()35 BluetoothPrivateAPI::~BluetoothPrivateAPI() {}
36
Shutdown()37 void BluetoothPrivateAPI::Shutdown() {
38 EventRouter::Get(browser_context_)->UnregisterObserver(this);
39 }
40
OnListenerAdded(const EventListenerInfo & details)41 void BluetoothPrivateAPI::OnListenerAdded(const EventListenerInfo& details) {
42 // This function can be called multiple times for the same JS listener, for
43 // example, once for the addListener call and again if it is a lazy listener.
44 if (!details.browser_context)
45 return;
46
47 BluetoothAPI::Get(browser_context_)->event_router()->AddPairingDelegate(
48 details.extension_id);
49 }
50
OnListenerRemoved(const EventListenerInfo & details)51 void BluetoothPrivateAPI::OnListenerRemoved(const EventListenerInfo& details) {
52 // This function can be called multiple times for the same JS listener, for
53 // example, once for the addListener call and again if it is a lazy listener.
54 if (!details.browser_context)
55 return;
56
57 BluetoothAPI::Get(browser_context_)->event_router()->RemovePairingDelegate(
58 details.extension_id);
59 }
60
61 namespace core_api {
62
63 namespace {
64
65 const char kNameProperty[] = "name";
66 const char kPoweredProperty[] = "powered";
67 const char kDiscoverableProperty[] = "discoverable";
68
69 const char kSetAdapterPropertyError[] = "Error setting adapter properties: $1";
70
71 const char kDeviceNotFoundError[] =
72 "Given address is not a valid Bluetooth device.";
73
74 const char kPairingNotEnabled[] =
75 "Pairing must be enabled to set a pairing response.";
76
77 const char kInvalidPairingResponseOptions[] =
78 "Invalid pairing response options";
79
80 const char kAdapterNotPresent[] =
81 "Could not find a Bluetooth adapter.";
82
83 // Returns true if the pairing response options passed into the
84 // setPairingResponse function are valid.
ValidatePairingResponseOptions(const device::BluetoothDevice * device,const bt_private::SetPairingResponseOptions & options)85 bool ValidatePairingResponseOptions(
86 const device::BluetoothDevice* device,
87 const bt_private::SetPairingResponseOptions& options) {
88 bool response = options.response != bt_private::PAIRING_RESPONSE_NONE;
89 bool pincode = options.pincode.get() != NULL;
90 bool passkey = options.passkey.get() != NULL;
91
92 if (!response && !pincode && !passkey)
93 return false;
94 if (pincode && passkey)
95 return false;
96 if (options.response != bt_private::PAIRING_RESPONSE_CONFIRM &&
97 (pincode || passkey))
98 return false;
99
100 // Check the BluetoothDevice is in expecting the correct response.
101 if (!device->ExpectingConfirmation() && !device->ExpectingPinCode() &&
102 !device->ExpectingPasskey())
103 return false;
104 if (pincode && !device->ExpectingPinCode())
105 return false;
106 if (passkey && !device->ExpectingPasskey())
107 return false;
108 if (options.response == bt_private::PAIRING_RESPONSE_CONFIRM && !pincode &&
109 !passkey && !device->ExpectingConfirmation())
110 return false;
111
112 return true;
113 }
114
115 } // namespace
116
117 BluetoothPrivateSetAdapterStateFunction::
BluetoothPrivateSetAdapterStateFunction()118 BluetoothPrivateSetAdapterStateFunction() {}
119
120 BluetoothPrivateSetAdapterStateFunction::
~BluetoothPrivateSetAdapterStateFunction()121 ~BluetoothPrivateSetAdapterStateFunction() {}
122
DoWork(scoped_refptr<device::BluetoothAdapter> adapter)123 bool BluetoothPrivateSetAdapterStateFunction::DoWork(
124 scoped_refptr<device::BluetoothAdapter> adapter) {
125 scoped_ptr<bt_private::SetAdapterState::Params> params(
126 bt_private::SetAdapterState::Params::Create(*args_));
127 EXTENSION_FUNCTION_VALIDATE(params.get());
128
129 if (!adapter->IsPresent()) {
130 SetError(kAdapterNotPresent);
131 SendResponse(false);
132 return true;
133 }
134
135 const bt_private::NewAdapterState& new_state = params->adapter_state;
136
137 // These properties are not owned.
138 std::string* name = new_state.name.get();
139 bool* powered = new_state.powered.get();
140 bool* discoverable = new_state.discoverable.get();
141
142 if (name && adapter->GetName() != *name) {
143 pending_properties_.insert(kNameProperty);
144 adapter->SetName(*name,
145 CreatePropertySetCallback(kNameProperty),
146 CreatePropertyErrorCallback(kNameProperty));
147 }
148
149 if (powered && adapter->IsPowered() != *powered) {
150 pending_properties_.insert(kPoweredProperty);
151 adapter->SetPowered(*powered,
152 CreatePropertySetCallback(kPoweredProperty),
153 CreatePropertyErrorCallback(kPoweredProperty));
154 }
155
156 if (discoverable && adapter->IsDiscoverable() != *discoverable) {
157 pending_properties_.insert(kDiscoverableProperty);
158 adapter->SetDiscoverable(
159 *discoverable,
160 CreatePropertySetCallback(kDiscoverableProperty),
161 CreatePropertyErrorCallback(kDiscoverableProperty));
162 }
163
164 if (pending_properties_.empty())
165 SendResponse(true);
166 return true;
167 }
168
169 base::Closure
CreatePropertySetCallback(const std::string & property_name)170 BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback(
171 const std::string& property_name) {
172 return base::Bind(
173 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet,
174 this,
175 property_name);
176 }
177
178 base::Closure
CreatePropertyErrorCallback(const std::string & property_name)179 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback(
180 const std::string& property_name) {
181 return base::Bind(
182 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError,
183 this,
184 property_name);
185 }
186
OnAdapterPropertySet(const std::string & property)187 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet(
188 const std::string& property) {
189 DCHECK(pending_properties_.find(property) != pending_properties_.end());
190 DCHECK(failed_properties_.find(property) == failed_properties_.end());
191
192 pending_properties_.erase(property);
193 if (pending_properties_.empty()) {
194 if (failed_properties_.empty())
195 SendResponse(true);
196 else
197 SendError();
198 }
199 }
200
OnAdapterPropertyError(const std::string & property)201 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError(
202 const std::string& property) {
203 DCHECK(pending_properties_.find(property) != pending_properties_.end());
204 DCHECK(failed_properties_.find(property) == failed_properties_.end());
205
206 pending_properties_.erase(property);
207 failed_properties_.insert(property);
208 if (pending_properties_.empty())
209 SendError();
210 }
211
SendError()212 void BluetoothPrivateSetAdapterStateFunction::SendError() {
213 DCHECK(pending_properties_.empty());
214 DCHECK(!failed_properties_.empty());
215
216 std::vector<std::string> failed_vector;
217 std::copy(failed_properties_.begin(),
218 failed_properties_.end(),
219 std::back_inserter(failed_vector));
220
221 std::vector<std::string> replacements(1);
222 replacements[0] = JoinString(failed_vector, ", ");
223 std::string error =
224 ReplaceStringPlaceholders(kSetAdapterPropertyError, replacements, NULL);
225 SetError(error);
226 SendResponse(false);
227 }
228
229 BluetoothPrivateSetPairingResponseFunction::
BluetoothPrivateSetPairingResponseFunction()230 BluetoothPrivateSetPairingResponseFunction() {}
231
232 BluetoothPrivateSetPairingResponseFunction::
~BluetoothPrivateSetPairingResponseFunction()233 ~BluetoothPrivateSetPairingResponseFunction() {}
234
DoWork(scoped_refptr<device::BluetoothAdapter> adapter)235 bool BluetoothPrivateSetPairingResponseFunction::DoWork(
236 scoped_refptr<device::BluetoothAdapter> adapter) {
237 scoped_ptr<bt_private::SetPairingResponse::Params> params(
238 bt_private::SetPairingResponse::Params::Create(*args_));
239 EXTENSION_FUNCTION_VALIDATE(params.get());
240 const bt_private::SetPairingResponseOptions& options = params->options;
241
242 BluetoothEventRouter* router =
243 BluetoothAPI::Get(browser_context())->event_router();
244 if (!router->GetPairingDelegate(extension_id())) {
245 SetError(kPairingNotEnabled);
246 SendResponse(false);
247 return true;
248 }
249
250 const std::string& device_address = options.device.address;
251 device::BluetoothDevice* device = adapter->GetDevice(device_address);
252 if (!device) {
253 SetError(kDeviceNotFoundError);
254 SendResponse(false);
255 return true;
256 }
257
258 if (!ValidatePairingResponseOptions(device, options)) {
259 SetError(kInvalidPairingResponseOptions);
260 SendResponse(false);
261 return true;
262 }
263
264 if (options.pincode.get()) {
265 device->SetPinCode(*options.pincode.get());
266 } else if (options.passkey.get()) {
267 device->SetPasskey(*options.passkey.get());
268 } else {
269 switch (options.response) {
270 case bt_private::PAIRING_RESPONSE_CONFIRM:
271 device->ConfirmPairing();
272 break;
273 case bt_private::PAIRING_RESPONSE_REJECT:
274 device->RejectPairing();
275 break;
276 case bt_private::PAIRING_RESPONSE_CANCEL:
277 device->CancelPairing();
278 break;
279 default:
280 NOTREACHED();
281 }
282 }
283
284 SendResponse(true);
285 return true;
286 }
287
288 } // namespace core_api
289
290 } // namespace extensions
291