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
;
18 namespace extensions
{
20 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<BluetoothPrivateAPI
> >
21 g_factory
= LAZY_INSTANCE_INITIALIZER
;
24 BrowserContextKeyedAPIFactory
<BluetoothPrivateAPI
>*
25 BluetoothPrivateAPI::GetFactoryInstance() {
26 return g_factory
.Pointer();
29 BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext
* context
)
30 : browser_context_(context
) {
31 EventRouter::Get(browser_context_
)
32 ->RegisterObserver(this, bt_private::OnPairing::kEventName
);
35 BluetoothPrivateAPI::~BluetoothPrivateAPI() {}
37 void BluetoothPrivateAPI::Shutdown() {
38 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
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
)
47 BluetoothAPI::Get(browser_context_
)->event_router()->AddPairingDelegate(
48 details
.extension_id
);
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
)
57 BluetoothAPI::Get(browser_context_
)->event_router()->RemovePairingDelegate(
58 details
.extension_id
);
65 const char kNameProperty
[] = "name";
66 const char kPoweredProperty
[] = "powered";
67 const char kDiscoverableProperty
[] = "discoverable";
69 const char kSetAdapterPropertyError
[] = "Error setting adapter properties: $1";
71 const char kDeviceNotFoundError
[] =
72 "Given address is not a valid Bluetooth device.";
74 const char kDeviceNotConnectedError
[] = "Device is not connected";
76 const char kPairingNotEnabled
[] =
77 "Pairing must be enabled to set a pairing response.";
79 const char kInvalidPairingResponseOptions
[] =
80 "Invalid pairing response options";
82 const char kAdapterNotPresent
[] =
83 "Could not find a Bluetooth adapter.";
85 const char kDisconnectError
[] = "Failed to disconnect device";
87 // Returns true if the pairing response options passed into the
88 // setPairingResponse function are valid.
89 bool ValidatePairingResponseOptions(
90 const device::BluetoothDevice
* device
,
91 const bt_private::SetPairingResponseOptions
& options
) {
92 bool response
= options
.response
!= bt_private::PAIRING_RESPONSE_NONE
;
93 bool pincode
= options
.pincode
.get() != NULL
;
94 bool passkey
= options
.passkey
.get() != NULL
;
96 if (!response
&& !pincode
&& !passkey
)
98 if (pincode
&& passkey
)
100 if (options
.response
!= bt_private::PAIRING_RESPONSE_CONFIRM
&&
101 (pincode
|| passkey
))
104 // Check the BluetoothDevice is in expecting the correct response.
105 if (!device
->ExpectingConfirmation() && !device
->ExpectingPinCode() &&
106 !device
->ExpectingPasskey())
108 if (pincode
&& !device
->ExpectingPinCode())
110 if (passkey
&& !device
->ExpectingPasskey())
112 if (options
.response
== bt_private::PAIRING_RESPONSE_CONFIRM
&& !pincode
&&
113 !passkey
&& !device
->ExpectingConfirmation())
121 BluetoothPrivateSetAdapterStateFunction::
122 BluetoothPrivateSetAdapterStateFunction() {}
124 BluetoothPrivateSetAdapterStateFunction::
125 ~BluetoothPrivateSetAdapterStateFunction() {}
127 bool BluetoothPrivateSetAdapterStateFunction::DoWork(
128 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
129 scoped_ptr
<bt_private::SetAdapterState::Params
> params(
130 bt_private::SetAdapterState::Params::Create(*args_
));
131 EXTENSION_FUNCTION_VALIDATE(params
.get());
133 if (!adapter
->IsPresent()) {
134 SetError(kAdapterNotPresent
);
139 const bt_private::NewAdapterState
& new_state
= params
->adapter_state
;
141 // These properties are not owned.
142 std::string
* name
= new_state
.name
.get();
143 bool* powered
= new_state
.powered
.get();
144 bool* discoverable
= new_state
.discoverable
.get();
146 if (name
&& adapter
->GetName() != *name
) {
147 pending_properties_
.insert(kNameProperty
);
148 adapter
->SetName(*name
,
149 CreatePropertySetCallback(kNameProperty
),
150 CreatePropertyErrorCallback(kNameProperty
));
153 if (powered
&& adapter
->IsPowered() != *powered
) {
154 pending_properties_
.insert(kPoweredProperty
);
155 adapter
->SetPowered(*powered
,
156 CreatePropertySetCallback(kPoweredProperty
),
157 CreatePropertyErrorCallback(kPoweredProperty
));
160 if (discoverable
&& adapter
->IsDiscoverable() != *discoverable
) {
161 pending_properties_
.insert(kDiscoverableProperty
);
162 adapter
->SetDiscoverable(
164 CreatePropertySetCallback(kDiscoverableProperty
),
165 CreatePropertyErrorCallback(kDiscoverableProperty
));
168 if (pending_properties_
.empty())
174 BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback(
175 const std::string
& property_name
) {
177 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet
,
183 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback(
184 const std::string
& property_name
) {
186 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError
,
191 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet(
192 const std::string
& property
) {
193 DCHECK(pending_properties_
.find(property
) != pending_properties_
.end());
194 DCHECK(failed_properties_
.find(property
) == failed_properties_
.end());
196 pending_properties_
.erase(property
);
197 if (pending_properties_
.empty()) {
198 if (failed_properties_
.empty())
205 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError(
206 const std::string
& property
) {
207 DCHECK(pending_properties_
.find(property
) != pending_properties_
.end());
208 DCHECK(failed_properties_
.find(property
) == failed_properties_
.end());
210 pending_properties_
.erase(property
);
211 failed_properties_
.insert(property
);
212 if (pending_properties_
.empty())
216 void BluetoothPrivateSetAdapterStateFunction::SendError() {
217 DCHECK(pending_properties_
.empty());
218 DCHECK(!failed_properties_
.empty());
220 std::vector
<std::string
> failed_vector
;
221 std::copy(failed_properties_
.begin(),
222 failed_properties_
.end(),
223 std::back_inserter(failed_vector
));
225 std::vector
<std::string
> replacements(1);
226 replacements
[0] = JoinString(failed_vector
, ", ");
228 ReplaceStringPlaceholders(kSetAdapterPropertyError
, replacements
, NULL
);
233 BluetoothPrivateSetPairingResponseFunction::
234 BluetoothPrivateSetPairingResponseFunction() {}
236 BluetoothPrivateSetPairingResponseFunction::
237 ~BluetoothPrivateSetPairingResponseFunction() {}
239 bool BluetoothPrivateSetPairingResponseFunction::DoWork(
240 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
241 scoped_ptr
<bt_private::SetPairingResponse::Params
> params(
242 bt_private::SetPairingResponse::Params::Create(*args_
));
243 EXTENSION_FUNCTION_VALIDATE(params
.get());
244 const bt_private::SetPairingResponseOptions
& options
= params
->options
;
246 BluetoothEventRouter
* router
=
247 BluetoothAPI::Get(browser_context())->event_router();
248 if (!router
->GetPairingDelegate(extension_id())) {
249 SetError(kPairingNotEnabled
);
254 const std::string
& device_address
= options
.device
.address
;
255 device::BluetoothDevice
* device
= adapter
->GetDevice(device_address
);
257 SetError(kDeviceNotFoundError
);
262 if (!ValidatePairingResponseOptions(device
, options
)) {
263 SetError(kInvalidPairingResponseOptions
);
268 if (options
.pincode
.get()) {
269 device
->SetPinCode(*options
.pincode
.get());
270 } else if (options
.passkey
.get()) {
271 device
->SetPasskey(*options
.passkey
.get());
273 switch (options
.response
) {
274 case bt_private::PAIRING_RESPONSE_CONFIRM
:
275 device
->ConfirmPairing();
277 case bt_private::PAIRING_RESPONSE_REJECT
:
278 device
->RejectPairing();
280 case bt_private::PAIRING_RESPONSE_CANCEL
:
281 device
->CancelPairing();
292 BluetoothPrivateDisconnectAllFunction::BluetoothPrivateDisconnectAllFunction() {
295 BluetoothPrivateDisconnectAllFunction::
296 ~BluetoothPrivateDisconnectAllFunction() {
299 bool BluetoothPrivateDisconnectAllFunction::DoWork(
300 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
301 scoped_ptr
<bt_private::DisconnectAll::Params
> params(
302 bt_private::DisconnectAll::Params::Create(*args_
));
303 EXTENSION_FUNCTION_VALIDATE(params
.get());
305 device::BluetoothDevice
* device
= adapter
->GetDevice(params
->device_address
);
307 SetError(kDeviceNotFoundError
);
312 if (!device
->IsConnected()) {
313 SetError(kDeviceNotConnectedError
);
319 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnSuccessCallback
,
321 base::Bind(&BluetoothPrivateDisconnectAllFunction::OnErrorCallback
, this,
322 adapter
, params
->device_address
));
327 void BluetoothPrivateDisconnectAllFunction::OnSuccessCallback() {
331 void BluetoothPrivateDisconnectAllFunction::OnErrorCallback(
332 scoped_refptr
<device::BluetoothAdapter
> adapter
,
333 const std::string
& device_address
) {
334 // The call to Disconnect may report an error if the device was disconnected
335 // due to an external reason. In this case, report "Not Connected" as the
337 device::BluetoothDevice
* device
= adapter
->GetDevice(device_address
);
338 if (device
&& !device
->IsConnected())
339 SetError(kDeviceNotConnectedError
);
341 SetError(kDisconnectError
);
346 } // namespace core_api
348 } // namespace extensions