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>* 25 BluetoothPrivateAPI::GetFactoryInstance() { 26 return g_factory.Pointer(); 27 } 28 29 BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext* context) 30 : browser_context_(context) { 31 EventRouter::Get(browser_context_) 32 ->RegisterObserver(this, bt_private::OnPairing::kEventName); 33 } 34 35 BluetoothPrivateAPI::~BluetoothPrivateAPI() {} 36 37 void BluetoothPrivateAPI::Shutdown() { 38 EventRouter::Get(browser_context_)->UnregisterObserver(this); 39 } 40 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 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. 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:: 118 BluetoothPrivateSetAdapterStateFunction() {} 119 120 BluetoothPrivateSetAdapterStateFunction:: 121 ~BluetoothPrivateSetAdapterStateFunction() {} 122 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 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 179 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback( 180 const std::string& property_name) { 181 return base::Bind( 182 &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError, 183 this, 184 property_name); 185 } 186 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 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 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:: 230 BluetoothPrivateSetPairingResponseFunction() {} 231 232 BluetoothPrivateSetPairingResponseFunction:: 233 ~BluetoothPrivateSetPairingResponseFunction() {} 234 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