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 16namespace bt_private = extensions::core_api::bluetooth_private; 17 18namespace extensions { 19 20static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothPrivateAPI> > 21 g_factory = LAZY_INSTANCE_INITIALIZER; 22 23// static 24BrowserContextKeyedAPIFactory<BluetoothPrivateAPI>* 25BluetoothPrivateAPI::GetFactoryInstance() { 26 return g_factory.Pointer(); 27} 28 29BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext* context) 30 : browser_context_(context) { 31 EventRouter::Get(browser_context_) 32 ->RegisterObserver(this, bt_private::OnPairing::kEventName); 33} 34 35BluetoothPrivateAPI::~BluetoothPrivateAPI() {} 36 37void BluetoothPrivateAPI::Shutdown() { 38 EventRouter::Get(browser_context_)->UnregisterObserver(this); 39} 40 41void 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 51void 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 61namespace core_api { 62 63namespace { 64 65const char kNameProperty[] = "name"; 66const char kPoweredProperty[] = "powered"; 67const char kDiscoverableProperty[] = "discoverable"; 68 69const char kSetAdapterPropertyError[] = "Error setting adapter properties: $1"; 70 71const char kDeviceNotFoundError[] = 72 "Given address is not a valid Bluetooth device."; 73 74const char kPairingNotEnabled[] = 75 "Pairing must be enabled to set a pairing response."; 76 77const char kInvalidPairingResponseOptions[] = 78 "Invalid pairing response options"; 79 80const 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. 85bool 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 117BluetoothPrivateSetAdapterStateFunction:: 118 BluetoothPrivateSetAdapterStateFunction() {} 119 120BluetoothPrivateSetAdapterStateFunction:: 121 ~BluetoothPrivateSetAdapterStateFunction() {} 122 123bool 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 169base::Closure 170BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback( 171 const std::string& property_name) { 172 return base::Bind( 173 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet, 174 this, 175 property_name); 176} 177 178base::Closure 179BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback( 180 const std::string& property_name) { 181 return base::Bind( 182 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError, 183 this, 184 property_name); 185} 186 187void 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 201void 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 212void 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 229BluetoothPrivateSetPairingResponseFunction:: 230 BluetoothPrivateSetPairingResponseFunction() {} 231 232BluetoothPrivateSetPairingResponseFunction:: 233 ~BluetoothPrivateSetPairingResponseFunction() {} 234 235bool 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