• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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