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 "device/bluetooth/bluetooth_discovery_session.h"
13 #include "extensions/browser/api/bluetooth/bluetooth_api.h"
14 #include "extensions/browser/api/bluetooth/bluetooth_event_router.h"
15 #include "extensions/common/api/bluetooth_private.h"
17 namespace bt_private
= extensions::api::bluetooth_private
;
18 namespace SetDiscoveryFilter
= bt_private::SetDiscoveryFilter
;
20 namespace extensions
{
22 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<BluetoothPrivateAPI
> >
23 g_factory
= LAZY_INSTANCE_INITIALIZER
;
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
)
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
)
59 BluetoothAPI::Get(browser_context_
)->event_router()->RemovePairingDelegate(
60 details
.extension_id
);
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
)
102 if (pincode
&& passkey
)
104 if (options
.response
!= bt_private::PAIRING_RESPONSE_CONFIRM
&&
105 (pincode
|| passkey
))
108 // Check the BluetoothDevice is in expecting the correct response.
109 if (!device
->ExpectingConfirmation() && !device
->ExpectingPinCode() &&
110 !device
->ExpectingPasskey())
112 if (pincode
&& !device
->ExpectingPinCode())
114 if (passkey
&& !device
->ExpectingPasskey())
116 if (options
.response
== bt_private::PAIRING_RESPONSE_CONFIRM
&& !pincode
&&
117 !passkey
&& !device
->ExpectingConfirmation())
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
);
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(
168 CreatePropertySetCallback(kDiscoverableProperty
),
169 CreatePropertyErrorCallback(kDiscoverableProperty
));
172 if (pending_properties_
.empty())
178 BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback(
179 const std::string
& property_name
) {
181 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet
,
187 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback(
188 const std::string
& property_name
) {
190 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError
,
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())
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())
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] = base::JoinString(failed_vector
, ", ");
231 std::string error
= base::ReplaceStringPlaceholders(kSetAdapterPropertyError
,
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
);
258 const std::string
& device_address
= options
.device
.address
;
259 device::BluetoothDevice
* device
= adapter
->GetDevice(device_address
);
261 SetError(kDeviceNotFoundError
);
266 if (!ValidatePairingResponseOptions(device
, options
)) {
267 SetError(kInvalidPairingResponseOptions
);
272 if (options
.pincode
.get()) {
273 device
->SetPinCode(*options
.pincode
.get());
274 } else if (options
.passkey
.get()) {
275 device
->SetPasskey(*options
.passkey
.get());
277 switch (options
.response
) {
278 case bt_private::PAIRING_RESPONSE_CONFIRM
:
279 device
->ConfirmPairing();
281 case bt_private::PAIRING_RESPONSE_REJECT
:
282 device
->RejectPairing();
284 case bt_private::PAIRING_RESPONSE_CANCEL
:
285 device
->CancelPairing();
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
);
311 SetError(kDeviceNotFoundError
);
316 if (!device
->IsConnected()) {
317 SetError(kDeviceNotConnectedError
);
323 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnSuccessCallback
,
325 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnErrorCallback
, this,
326 adapter
, params
->device_address
));
331 void BluetoothPrivateDisconnectAllFunction::OnSuccessCallback() {
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
341 device::BluetoothDevice
* device
= adapter
->GetDevice(device_address
);
342 if (device
&& !device
->IsConnected())
343 SetError(kDeviceNotConnectedError
);
345 SetError(kDisconnectError
);
350 void BluetoothPrivateSetDiscoveryFilterFunction::OnSuccessCallback() {
354 void BluetoothPrivateSetDiscoveryFilterFunction::OnErrorCallback() {
355 SetError(kSetDiscoveryFilterFailed
);
359 bool BluetoothPrivateSetDiscoveryFilterFunction::DoWork(
360 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
361 scoped_ptr
<SetDiscoveryFilter::Params
> params(
362 SetDiscoveryFilter::Params::Create(*args_
));
363 auto& df_param
= params
->discovery_filter
;
365 scoped_ptr
<device::BluetoothDiscoveryFilter
> discovery_filter
;
367 // If all filter fields are empty, we are clearing filter. If any field is
368 // set, then create proper filter.
369 if (df_param
.uuids
.get() || df_param
.rssi
.get() || df_param
.pathloss
.get() ||
370 df_param
.transport
!= bt_private::TransportType::TRANSPORT_TYPE_NONE
) {
373 switch (df_param
.transport
) {
374 case bt_private::TransportType::TRANSPORT_TYPE_LE
:
375 transport
= device::BluetoothDiscoveryFilter::Transport::TRANSPORT_LE
;
377 case bt_private::TransportType::TRANSPORT_TYPE_BREDR
:
379 device::BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC
;
381 default: // TRANSPORT_TYPE_NONE is included here
382 transport
= device::BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL
;
386 discovery_filter
.reset(new device::BluetoothDiscoveryFilter(transport
));
388 if (df_param
.uuids
.get()) {
389 std::vector
<device::BluetoothUUID
> uuids
;
390 if (df_param
.uuids
->as_string
.get()) {
391 discovery_filter
->AddUUID(
392 device::BluetoothUUID(*df_param
.uuids
->as_string
));
393 } else if (df_param
.uuids
->as_strings
.get()) {
394 for (const auto& iter
: *df_param
.uuids
->as_strings
) {
395 discovery_filter
->AddUUID(device::BluetoothUUID(iter
));
400 if (df_param
.rssi
.get())
401 discovery_filter
->SetRSSI(*df_param
.rssi
);
403 if (df_param
.pathloss
.get())
404 discovery_filter
->SetPathloss(*df_param
.pathloss
);
407 BluetoothAPI::Get(browser_context())->event_router()->SetDiscoveryFilter(
408 discovery_filter
.Pass(), adapter
.get(), extension_id(),
410 &BluetoothPrivateSetDiscoveryFilterFunction::OnSuccessCallback
,
413 &BluetoothPrivateSetDiscoveryFilterFunction::OnErrorCallback
,
420 } // namespace extensions