| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/lazy_instance.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/memory/ref_counted.h" | |
| 15 #include "base/memory/scoped_vector.h" | |
| 16 #include "base/stl_util.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_pairing_delegate
.h" | |
| 19 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h" | |
| 20 #include "chrome/browser/extensions/api/bluetooth/bluetooth_private_api.h" | |
| 21 #include "chrome/common/extensions/api/bluetooth.h" | |
| 22 #include "chrome/common/extensions/api/bluetooth_private.h" | |
| 23 #include "content/public/browser/notification_details.h" | |
| 24 #include "content/public/browser/notification_source.h" | |
| 25 #include "device/bluetooth/bluetooth_adapter.h" | |
| 26 #include "device/bluetooth/bluetooth_adapter_factory.h" | |
| 27 #include "device/bluetooth/bluetooth_device.h" | |
| 28 #include "device/bluetooth/bluetooth_discovery_session.h" | |
| 29 #include "extensions/browser/event_router.h" | |
| 30 #include "extensions/browser/extension_host.h" | |
| 31 #include "extensions/browser/extension_registry.h" | |
| 32 #include "extensions/browser/notification_types.h" | |
| 33 | |
| 34 namespace extensions { | |
| 35 | |
| 36 namespace bluetooth = api::bluetooth; | |
| 37 namespace bt_private = api::bluetooth_private; | |
| 38 | |
| 39 BluetoothEventRouter::BluetoothEventRouter(content::BrowserContext* context) | |
| 40 : browser_context_(context), | |
| 41 adapter_(NULL), | |
| 42 num_event_listeners_(0), | |
| 43 extension_registry_observer_(this), | |
| 44 weak_ptr_factory_(this) { | |
| 45 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 46 DCHECK(browser_context_); | |
| 47 registrar_.Add(this, | |
| 48 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, | |
| 49 content::Source<content::BrowserContext>(browser_context_)); | |
| 50 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | |
| 51 } | |
| 52 | |
| 53 BluetoothEventRouter::~BluetoothEventRouter() { | |
| 54 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 55 if (adapter_.get()) { | |
| 56 adapter_->RemoveObserver(this); | |
| 57 adapter_ = NULL; | |
| 58 } | |
| 59 CleanUpAllExtensions(); | |
| 60 } | |
| 61 | |
| 62 bool BluetoothEventRouter::IsBluetoothSupported() const { | |
| 63 return adapter_.get() || | |
| 64 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); | |
| 65 } | |
| 66 | |
| 67 void BluetoothEventRouter::GetAdapter( | |
| 68 const device::BluetoothAdapterFactory::AdapterCallback& callback) { | |
| 69 if (adapter_.get()) { | |
| 70 callback.Run(scoped_refptr<device::BluetoothAdapter>(adapter_)); | |
| 71 return; | |
| 72 } | |
| 73 | |
| 74 device::BluetoothAdapterFactory::GetAdapter(callback); | |
| 75 } | |
| 76 | |
| 77 void BluetoothEventRouter::StartDiscoverySession( | |
| 78 device::BluetoothAdapter* adapter, | |
| 79 const std::string& extension_id, | |
| 80 const base::Closure& callback, | |
| 81 const base::Closure& error_callback) { | |
| 82 if (adapter != adapter_.get()) { | |
| 83 error_callback.Run(); | |
| 84 return; | |
| 85 } | |
| 86 DiscoverySessionMap::iterator iter = | |
| 87 discovery_session_map_.find(extension_id); | |
| 88 if (iter != discovery_session_map_.end() && iter->second->IsActive()) { | |
| 89 DVLOG(1) << "An active discovery session exists for extension."; | |
| 90 error_callback.Run(); | |
| 91 return; | |
| 92 } | |
| 93 adapter->StartDiscoverySession( | |
| 94 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession, | |
| 95 weak_ptr_factory_.GetWeakPtr(), | |
| 96 extension_id, | |
| 97 callback), | |
| 98 error_callback); | |
| 99 } | |
| 100 | |
| 101 void BluetoothEventRouter::StopDiscoverySession( | |
| 102 device::BluetoothAdapter* adapter, | |
| 103 const std::string& extension_id, | |
| 104 const base::Closure& callback, | |
| 105 const base::Closure& error_callback) { | |
| 106 if (adapter != adapter_.get()) { | |
| 107 error_callback.Run(); | |
| 108 return; | |
| 109 } | |
| 110 DiscoverySessionMap::iterator iter = | |
| 111 discovery_session_map_.find(extension_id); | |
| 112 if (iter == discovery_session_map_.end() || !iter->second->IsActive()) { | |
| 113 DVLOG(1) << "No active discovery session exists for extension."; | |
| 114 error_callback.Run(); | |
| 115 return; | |
| 116 } | |
| 117 device::BluetoothDiscoverySession* session = iter->second; | |
| 118 session->Stop(callback, error_callback); | |
| 119 } | |
| 120 | |
| 121 BluetoothApiPairingDelegate* BluetoothEventRouter::GetPairingDelegate( | |
| 122 const std::string& extension_id) { | |
| 123 return ContainsKey(pairing_delegate_map_, extension_id) | |
| 124 ? pairing_delegate_map_[extension_id] | |
| 125 : NULL; | |
| 126 } | |
| 127 | |
| 128 void BluetoothEventRouter::OnAdapterInitialized( | |
| 129 const base::Closure& callback, | |
| 130 scoped_refptr<device::BluetoothAdapter> adapter) { | |
| 131 if (!adapter_.get()) { | |
| 132 adapter_ = adapter; | |
| 133 adapter_->AddObserver(this); | |
| 134 } | |
| 135 | |
| 136 callback.Run(); | |
| 137 } | |
| 138 | |
| 139 void BluetoothEventRouter::MaybeReleaseAdapter() { | |
| 140 if (adapter_.get() && num_event_listeners_ == 0 && | |
| 141 pairing_delegate_map_.empty()) { | |
| 142 adapter_->RemoveObserver(this); | |
| 143 adapter_ = NULL; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void BluetoothEventRouter::AddPairingDelegate(const std::string& extension_id) { | |
| 148 if (!adapter_.get()) { | |
| 149 base::Closure self_callback = | |
| 150 base::Bind(&BluetoothEventRouter::AddPairingDelegate, | |
| 151 weak_ptr_factory_.GetWeakPtr(), | |
| 152 extension_id); | |
| 153 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized, | |
| 154 weak_ptr_factory_.GetWeakPtr(), | |
| 155 self_callback)); | |
| 156 return; | |
| 157 } | |
| 158 | |
| 159 if (!ContainsKey(pairing_delegate_map_, extension_id)) { | |
| 160 BluetoothApiPairingDelegate* delegate = | |
| 161 new BluetoothApiPairingDelegate(extension_id, browser_context_); | |
| 162 DCHECK(adapter_.get()); | |
| 163 adapter_->AddPairingDelegate( | |
| 164 delegate, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); | |
| 165 pairing_delegate_map_[extension_id] = delegate; | |
| 166 } else { | |
| 167 LOG(ERROR) << "Pairing delegate already exists for extension. " | |
| 168 << "There should be at most one onPairing listener."; | |
| 169 NOTREACHED(); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 void BluetoothEventRouter::RemovePairingDelegate( | |
| 174 const std::string& extension_id) { | |
| 175 if (ContainsKey(pairing_delegate_map_, extension_id)) { | |
| 176 BluetoothApiPairingDelegate* delegate = pairing_delegate_map_[extension_id]; | |
| 177 if (adapter_.get()) | |
| 178 adapter_->RemovePairingDelegate(delegate); | |
| 179 pairing_delegate_map_.erase(extension_id); | |
| 180 delete delegate; | |
| 181 MaybeReleaseAdapter(); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void BluetoothEventRouter::AdapterPresentChanged( | |
| 186 device::BluetoothAdapter* adapter, | |
| 187 bool present) { | |
| 188 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 189 if (adapter != adapter_.get()) { | |
| 190 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 191 return; | |
| 192 } | |
| 193 DispatchAdapterStateEvent(); | |
| 194 } | |
| 195 | |
| 196 void BluetoothEventRouter::AdapterPoweredChanged( | |
| 197 device::BluetoothAdapter* adapter, | |
| 198 bool has_power) { | |
| 199 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 200 if (adapter != adapter_.get()) { | |
| 201 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 202 return; | |
| 203 } | |
| 204 DispatchAdapterStateEvent(); | |
| 205 } | |
| 206 | |
| 207 void BluetoothEventRouter::AdapterDiscoveringChanged( | |
| 208 device::BluetoothAdapter* adapter, | |
| 209 bool discovering) { | |
| 210 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 211 if (adapter != adapter_.get()) { | |
| 212 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 213 return; | |
| 214 } | |
| 215 | |
| 216 if (!discovering) { | |
| 217 // If any discovery sessions are inactive, clean them up. | |
| 218 DiscoverySessionMap active_session_map; | |
| 219 for (DiscoverySessionMap::iterator iter = discovery_session_map_.begin(); | |
| 220 iter != discovery_session_map_.end(); | |
| 221 ++iter) { | |
| 222 device::BluetoothDiscoverySession* session = iter->second; | |
| 223 if (session->IsActive()) { | |
| 224 active_session_map[iter->first] = session; | |
| 225 continue; | |
| 226 } | |
| 227 delete session; | |
| 228 } | |
| 229 discovery_session_map_.swap(active_session_map); | |
| 230 MaybeReleaseAdapter(); | |
| 231 } | |
| 232 | |
| 233 DispatchAdapterStateEvent(); | |
| 234 } | |
| 235 | |
| 236 void BluetoothEventRouter::DeviceAdded(device::BluetoothAdapter* adapter, | |
| 237 device::BluetoothDevice* device) { | |
| 238 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 239 if (adapter != adapter_.get()) { | |
| 240 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 241 return; | |
| 242 } | |
| 243 | |
| 244 DispatchDeviceEvent(bluetooth::OnDeviceAdded::kEventName, device); | |
| 245 } | |
| 246 | |
| 247 void BluetoothEventRouter::DeviceChanged(device::BluetoothAdapter* adapter, | |
| 248 device::BluetoothDevice* device) { | |
| 249 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 250 if (adapter != adapter_.get()) { | |
| 251 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 252 return; | |
| 253 } | |
| 254 | |
| 255 DispatchDeviceEvent(bluetooth::OnDeviceChanged::kEventName, device); | |
| 256 } | |
| 257 | |
| 258 void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter* adapter, | |
| 259 device::BluetoothDevice* device) { | |
| 260 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 261 if (adapter != adapter_.get()) { | |
| 262 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress(); | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 DispatchDeviceEvent(bluetooth::OnDeviceRemoved::kEventName, device); | |
| 267 } | |
| 268 | |
| 269 void BluetoothEventRouter::OnListenerAdded() { | |
| 270 num_event_listeners_++; | |
| 271 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 272 if (!adapter_.get()) { | |
| 273 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized, | |
| 274 weak_ptr_factory_.GetWeakPtr(), | |
| 275 base::Bind(&base::DoNothing))); | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 void BluetoothEventRouter::OnListenerRemoved() { | |
| 280 if (num_event_listeners_ > 0) | |
| 281 num_event_listeners_--; | |
| 282 MaybeReleaseAdapter(); | |
| 283 } | |
| 284 | |
| 285 void BluetoothEventRouter::DispatchAdapterStateEvent() { | |
| 286 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 287 api::bluetooth::AdapterState state; | |
| 288 PopulateAdapterState(*adapter_.get(), &state); | |
| 289 | |
| 290 scoped_ptr<base::ListValue> args = | |
| 291 bluetooth::OnAdapterStateChanged::Create(state); | |
| 292 scoped_ptr<Event> event(new Event( | |
| 293 bluetooth::OnAdapterStateChanged::kEventName, | |
| 294 args.Pass())); | |
| 295 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); | |
| 296 } | |
| 297 | |
| 298 void BluetoothEventRouter::DispatchDeviceEvent( | |
| 299 const std::string& event_name, | |
| 300 device::BluetoothDevice* device) { | |
| 301 bluetooth::Device extension_device; | |
| 302 bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device); | |
| 303 | |
| 304 scoped_ptr<base::ListValue> args = | |
| 305 bluetooth::OnDeviceAdded::Create(extension_device); | |
| 306 scoped_ptr<Event> event(new Event(event_name, args.Pass())); | |
| 307 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); | |
| 308 } | |
| 309 | |
| 310 void BluetoothEventRouter::CleanUpForExtension( | |
| 311 const std::string& extension_id) { | |
| 312 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 313 RemovePairingDelegate(extension_id); | |
| 314 | |
| 315 // Remove any discovery session initiated by the extension. | |
| 316 DiscoverySessionMap::iterator session_iter = | |
| 317 discovery_session_map_.find(extension_id); | |
| 318 if (session_iter == discovery_session_map_.end()) | |
| 319 return; | |
| 320 delete session_iter->second; | |
| 321 discovery_session_map_.erase(session_iter); | |
| 322 } | |
| 323 | |
| 324 void BluetoothEventRouter::CleanUpAllExtensions() { | |
| 325 for (DiscoverySessionMap::iterator it = discovery_session_map_.begin(); | |
| 326 it != discovery_session_map_.end(); | |
| 327 ++it) { | |
| 328 delete it->second; | |
| 329 } | |
| 330 discovery_session_map_.clear(); | |
| 331 | |
| 332 PairingDelegateMap::iterator pairing_iter = pairing_delegate_map_.begin(); | |
| 333 while (pairing_iter != pairing_delegate_map_.end()) | |
| 334 RemovePairingDelegate(pairing_iter++->first); | |
| 335 } | |
| 336 | |
| 337 void BluetoothEventRouter::OnStartDiscoverySession( | |
| 338 const std::string& extension_id, | |
| 339 const base::Closure& callback, | |
| 340 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | |
| 341 // Clean up any existing session instance for the extension. | |
| 342 DiscoverySessionMap::iterator iter = | |
| 343 discovery_session_map_.find(extension_id); | |
| 344 if (iter != discovery_session_map_.end()) | |
| 345 delete iter->second; | |
| 346 discovery_session_map_[extension_id] = discovery_session.release(); | |
| 347 callback.Run(); | |
| 348 } | |
| 349 | |
| 350 void BluetoothEventRouter::Observe( | |
| 351 int type, | |
| 352 const content::NotificationSource& source, | |
| 353 const content::NotificationDetails& details) { | |
| 354 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 355 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, type); | |
| 356 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); | |
| 357 CleanUpForExtension(host->extension_id()); | |
| 358 } | |
| 359 | |
| 360 void BluetoothEventRouter::OnExtensionUnloaded( | |
| 361 content::BrowserContext* browser_context, | |
| 362 const Extension* extension, | |
| 363 UnloadedExtensionInfo::Reason reason) { | |
| 364 CleanUpForExtension(extension->id()); | |
| 365 } | |
| 366 | |
| 367 } // namespace extensions | |
| OLD | NEW |