Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / bluetooth / bluetooth_event_router.cc
blob9302f7ce854fd71f0eb717fd5c39df87bf088886
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.
5 #include "extensions/browser/api/bluetooth/bluetooth_event_router.h"
7 #include <map>
8 #include <string>
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/stl_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_source.h"
19 #include "device/bluetooth/bluetooth_adapter.h"
20 #include "device/bluetooth/bluetooth_adapter_factory.h"
21 #include "device/bluetooth/bluetooth_device.h"
22 #include "device/bluetooth/bluetooth_discovery_session.h"
23 #include "extensions/browser/api/bluetooth/bluetooth_api_pairing_delegate.h"
24 #include "extensions/browser/api/bluetooth/bluetooth_api_utils.h"
25 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
26 #include "extensions/browser/event_router.h"
27 #include "extensions/browser/extension_host.h"
28 #include "extensions/browser/extension_registry.h"
29 #include "extensions/browser/notification_types.h"
30 #include "extensions/common/api/bluetooth.h"
31 #include "extensions/common/api/bluetooth_private.h"
33 namespace extensions {
35 namespace bluetooth = api::bluetooth;
36 namespace bt_private = api::bluetooth_private;
38 BluetoothEventRouter::BluetoothEventRouter(content::BrowserContext* context)
39 : browser_context_(context),
40 adapter_(NULL),
41 num_event_listeners_(0),
42 extension_registry_observer_(this),
43 weak_ptr_factory_(this) {
44 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
45 DCHECK(browser_context_);
46 registrar_.Add(this,
47 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
48 content::Source<content::BrowserContext>(browser_context_));
49 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
52 BluetoothEventRouter::~BluetoothEventRouter() {
53 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
54 if (adapter_.get()) {
55 adapter_->RemoveObserver(this);
56 adapter_ = NULL;
58 CleanUpAllExtensions();
61 bool BluetoothEventRouter::IsBluetoothSupported() const {
62 return adapter_.get() ||
63 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
66 void BluetoothEventRouter::GetAdapter(
67 const device::BluetoothAdapterFactory::AdapterCallback& callback) {
68 if (adapter_.get()) {
69 callback.Run(scoped_refptr<device::BluetoothAdapter>(adapter_));
70 return;
73 device::BluetoothAdapterFactory::GetAdapter(callback);
76 void BluetoothEventRouter::StartDiscoverySession(
77 device::BluetoothAdapter* adapter,
78 const std::string& extension_id,
79 const base::Closure& callback,
80 const base::Closure& error_callback) {
81 if (adapter != adapter_.get()) {
82 error_callback.Run();
83 return;
85 DiscoverySessionMap::iterator iter =
86 discovery_session_map_.find(extension_id);
87 if (iter != discovery_session_map_.end() && iter->second->IsActive()) {
88 DVLOG(1) << "An active discovery session exists for extension.";
89 error_callback.Run();
90 return;
93 // Check whether user pre set discovery filter by calling SetDiscoveryFilter
94 // before. If the user has set a discovery filter then start a filtered
95 // discovery session, otherwise start a regular session
96 PreSetFilterMap::iterator pre_set_iter =
97 pre_set_filter_map_.find(extension_id);
98 if (pre_set_iter != pre_set_filter_map_.end()) {
99 adapter->StartDiscoverySessionWithFilter(
100 scoped_ptr<device::BluetoothDiscoveryFilter>(pre_set_iter->second),
101 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession,
102 weak_ptr_factory_.GetWeakPtr(), extension_id, callback),
103 error_callback);
104 pre_set_filter_map_.erase(pre_set_iter);
105 return;
107 adapter->StartDiscoverySession(
108 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession,
109 weak_ptr_factory_.GetWeakPtr(), extension_id, callback),
110 error_callback);
113 void BluetoothEventRouter::StopDiscoverySession(
114 device::BluetoothAdapter* adapter,
115 const std::string& extension_id,
116 const base::Closure& callback,
117 const base::Closure& error_callback) {
118 if (adapter != adapter_.get()) {
119 error_callback.Run();
120 return;
122 DiscoverySessionMap::iterator iter =
123 discovery_session_map_.find(extension_id);
124 if (iter == discovery_session_map_.end() || !iter->second->IsActive()) {
125 DVLOG(1) << "No active discovery session exists for extension.";
126 error_callback.Run();
127 return;
129 device::BluetoothDiscoverySession* session = iter->second;
130 session->Stop(callback, error_callback);
133 void BluetoothEventRouter::SetDiscoveryFilter(
134 scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
135 device::BluetoothAdapter* adapter,
136 const std::string& extension_id,
137 const base::Closure& callback,
138 const base::Closure& error_callback) {
139 DVLOG(1) << "SetDiscoveryFilter";
140 if (adapter != adapter_.get()) {
141 error_callback.Run();
142 return;
145 DiscoverySessionMap::iterator iter =
146 discovery_session_map_.find(extension_id);
147 if (iter == discovery_session_map_.end() || !iter->second->IsActive()) {
148 DVLOG(1) << "No active discovery session exists for extension, so caching "
149 "filter for later use.";
150 pre_set_filter_map_[extension_id] = discovery_filter.release();
151 callback.Run();
152 return;
155 // extension is already running discovery, update it's discovery filter
156 iter->second->SetDiscoveryFilter(discovery_filter.Pass(), callback,
157 error_callback);
160 BluetoothApiPairingDelegate* BluetoothEventRouter::GetPairingDelegate(
161 const std::string& extension_id) {
162 return ContainsKey(pairing_delegate_map_, extension_id)
163 ? pairing_delegate_map_[extension_id]
164 : NULL;
167 void BluetoothEventRouter::OnAdapterInitialized(
168 const base::Closure& callback,
169 scoped_refptr<device::BluetoothAdapter> adapter) {
170 if (!adapter_.get()) {
171 adapter_ = adapter;
172 adapter_->AddObserver(this);
175 callback.Run();
178 void BluetoothEventRouter::MaybeReleaseAdapter() {
179 if (adapter_.get() && num_event_listeners_ == 0 &&
180 pairing_delegate_map_.empty()) {
181 adapter_->RemoveObserver(this);
182 adapter_ = NULL;
186 void BluetoothEventRouter::AddPairingDelegate(const std::string& extension_id) {
187 if (!adapter_.get()) {
188 base::Closure self_callback =
189 base::Bind(&BluetoothEventRouter::AddPairingDelegate,
190 weak_ptr_factory_.GetWeakPtr(),
191 extension_id);
192 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized,
193 weak_ptr_factory_.GetWeakPtr(),
194 self_callback));
195 return;
198 if (!ContainsKey(pairing_delegate_map_, extension_id)) {
199 BluetoothApiPairingDelegate* delegate =
200 new BluetoothApiPairingDelegate(extension_id, browser_context_);
201 DCHECK(adapter_.get());
202 adapter_->AddPairingDelegate(
203 delegate, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
204 pairing_delegate_map_[extension_id] = delegate;
205 } else {
206 LOG(ERROR) << "Pairing delegate already exists for extension. "
207 << "There should be at most one onPairing listener.";
208 NOTREACHED();
212 void BluetoothEventRouter::RemovePairingDelegate(
213 const std::string& extension_id) {
214 if (ContainsKey(pairing_delegate_map_, extension_id)) {
215 BluetoothApiPairingDelegate* delegate = pairing_delegate_map_[extension_id];
216 if (adapter_.get())
217 adapter_->RemovePairingDelegate(delegate);
218 pairing_delegate_map_.erase(extension_id);
219 delete delegate;
220 MaybeReleaseAdapter();
224 void BluetoothEventRouter::AdapterPresentChanged(
225 device::BluetoothAdapter* adapter,
226 bool present) {
227 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
228 if (adapter != adapter_.get()) {
229 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
230 return;
232 DispatchAdapterStateEvent();
235 void BluetoothEventRouter::AdapterPoweredChanged(
236 device::BluetoothAdapter* adapter,
237 bool has_power) {
238 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
239 if (adapter != adapter_.get()) {
240 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
241 return;
243 DispatchAdapterStateEvent();
246 void BluetoothEventRouter::AdapterDiscoveringChanged(
247 device::BluetoothAdapter* adapter,
248 bool discovering) {
249 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
250 if (adapter != adapter_.get()) {
251 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
252 return;
255 if (!discovering) {
256 // If any discovery sessions are inactive, clean them up.
257 DiscoverySessionMap active_session_map;
258 for (DiscoverySessionMap::iterator iter = discovery_session_map_.begin();
259 iter != discovery_session_map_.end();
260 ++iter) {
261 device::BluetoothDiscoverySession* session = iter->second;
262 if (session->IsActive()) {
263 active_session_map[iter->first] = session;
264 continue;
266 delete session;
268 discovery_session_map_.swap(active_session_map);
269 MaybeReleaseAdapter();
272 DispatchAdapterStateEvent();
275 void BluetoothEventRouter::DeviceAdded(device::BluetoothAdapter* adapter,
276 device::BluetoothDevice* device) {
277 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
278 if (adapter != adapter_.get()) {
279 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
280 return;
283 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_ADDED,
284 bluetooth::OnDeviceAdded::kEventName, device);
287 void BluetoothEventRouter::DeviceChanged(device::BluetoothAdapter* adapter,
288 device::BluetoothDevice* device) {
289 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
290 if (adapter != adapter_.get()) {
291 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
292 return;
295 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_CHANGED,
296 bluetooth::OnDeviceChanged::kEventName, device);
299 void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter* adapter,
300 device::BluetoothDevice* device) {
301 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
302 if (adapter != adapter_.get()) {
303 DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
304 return;
307 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_REMOVED,
308 bluetooth::OnDeviceRemoved::kEventName, device);
311 void BluetoothEventRouter::OnListenerAdded() {
312 num_event_listeners_++;
313 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
314 if (!adapter_.get()) {
315 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized,
316 weak_ptr_factory_.GetWeakPtr(),
317 base::Bind(&base::DoNothing)));
321 void BluetoothEventRouter::OnListenerRemoved() {
322 if (num_event_listeners_ > 0)
323 num_event_listeners_--;
324 MaybeReleaseAdapter();
327 void BluetoothEventRouter::DispatchAdapterStateEvent() {
328 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
329 api::bluetooth::AdapterState state;
330 PopulateAdapterState(*adapter_.get(), &state);
332 scoped_ptr<base::ListValue> args =
333 bluetooth::OnAdapterStateChanged::Create(state);
334 scoped_ptr<Event> event(
335 new Event(events::BLUETOOTH_ON_ADAPTER_STATE_CHANGED,
336 bluetooth::OnAdapterStateChanged::kEventName, args.Pass()));
337 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
340 void BluetoothEventRouter::DispatchDeviceEvent(
341 events::HistogramValue histogram_value,
342 const std::string& event_name,
343 device::BluetoothDevice* device) {
344 bluetooth::Device extension_device;
345 bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
347 scoped_ptr<base::ListValue> args =
348 bluetooth::OnDeviceAdded::Create(extension_device);
349 scoped_ptr<Event> event(new Event(histogram_value, event_name, args.Pass()));
350 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
353 void BluetoothEventRouter::CleanUpForExtension(
354 const std::string& extension_id) {
355 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
356 RemovePairingDelegate(extension_id);
358 PreSetFilterMap::iterator pre_set_iter =
359 pre_set_filter_map_.find(extension_id);
360 if (pre_set_iter != pre_set_filter_map_.end()) {
361 delete pre_set_iter->second;
362 pre_set_filter_map_.erase(pre_set_iter);
365 // Remove any discovery session initiated by the extension.
366 DiscoverySessionMap::iterator session_iter =
367 discovery_session_map_.find(extension_id);
368 if (session_iter == discovery_session_map_.end())
369 return;
370 delete session_iter->second;
371 discovery_session_map_.erase(session_iter);
374 void BluetoothEventRouter::CleanUpAllExtensions() {
375 for (auto& it : pre_set_filter_map_)
376 delete it.second;
378 pre_set_filter_map_.clear();
380 for (auto& it : discovery_session_map_)
381 delete it.second;
383 discovery_session_map_.clear();
385 PairingDelegateMap::iterator pairing_iter = pairing_delegate_map_.begin();
386 while (pairing_iter != pairing_delegate_map_.end())
387 RemovePairingDelegate(pairing_iter++->first);
390 void BluetoothEventRouter::OnStartDiscoverySession(
391 const std::string& extension_id,
392 const base::Closure& callback,
393 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
394 // Clean up any existing session instance for the extension.
395 DiscoverySessionMap::iterator iter =
396 discovery_session_map_.find(extension_id);
397 if (iter != discovery_session_map_.end())
398 delete iter->second;
399 discovery_session_map_[extension_id] = discovery_session.release();
400 callback.Run();
403 void BluetoothEventRouter::OnSetDiscoveryFilter(const std::string& extension_id,
404 const base::Closure& callback) {
405 DVLOG(1) << "Successfully set DiscoveryFilter.";
406 callback.Run();
409 void BluetoothEventRouter::Observe(
410 int type,
411 const content::NotificationSource& source,
412 const content::NotificationDetails& details) {
413 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
414 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, type);
415 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
416 CleanUpForExtension(host->extension_id());
419 void BluetoothEventRouter::OnExtensionUnloaded(
420 content::BrowserContext* browser_context,
421 const Extension* extension,
422 UnloadedExtensionInfo::Reason reason) {
423 CleanUpForExtension(extension->id());
426 } // namespace extensions