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"
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
),
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_
);
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
);
55 adapter_
->RemoveObserver(this);
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
) {
69 callback
.Run(scoped_refptr
<device::BluetoothAdapter
>(adapter_
));
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()) {
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.";
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
),
104 pre_set_filter_map_
.erase(pre_set_iter
);
107 adapter
->StartDiscoverySession(
108 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession
,
109 weak_ptr_factory_
.GetWeakPtr(), extension_id
, 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();
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();
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();
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();
155 // extension is already running discovery, update it's discovery filter
156 iter
->second
->SetDiscoveryFilter(discovery_filter
.Pass(), 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
]
167 void BluetoothEventRouter::OnAdapterInitialized(
168 const base::Closure
& callback
,
169 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
170 if (!adapter_
.get()) {
172 adapter_
->AddObserver(this);
178 void BluetoothEventRouter::MaybeReleaseAdapter() {
179 if (adapter_
.get() && num_event_listeners_
== 0 &&
180 pairing_delegate_map_
.empty()) {
181 adapter_
->RemoveObserver(this);
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(),
192 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized
,
193 weak_ptr_factory_
.GetWeakPtr(),
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
;
206 LOG(ERROR
) << "Pairing delegate already exists for extension. "
207 << "There should be at most one onPairing listener.";
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
];
217 adapter_
->RemovePairingDelegate(delegate
);
218 pairing_delegate_map_
.erase(extension_id
);
220 MaybeReleaseAdapter();
224 void BluetoothEventRouter::AdapterPresentChanged(
225 device::BluetoothAdapter
* adapter
,
227 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
228 if (adapter
!= adapter_
.get()) {
229 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
232 DispatchAdapterStateEvent();
235 void BluetoothEventRouter::AdapterPoweredChanged(
236 device::BluetoothAdapter
* adapter
,
238 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
239 if (adapter
!= adapter_
.get()) {
240 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
243 DispatchAdapterStateEvent();
246 void BluetoothEventRouter::AdapterDiscoveringChanged(
247 device::BluetoothAdapter
* adapter
,
249 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
250 if (adapter
!= adapter_
.get()) {
251 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
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();
261 device::BluetoothDiscoverySession
* session
= iter
->second
;
262 if (session
->IsActive()) {
263 active_session_map
[iter
->first
] = 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(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
278 if (adapter
!= adapter_
.get()) {
279 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
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(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
290 if (adapter
!= adapter_
.get()) {
291 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
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(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
302 if (adapter
!= adapter_
.get()) {
303 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
307 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_REMOVED
,
308 bluetooth::OnDeviceRemoved::kEventName
, device
);
311 void BluetoothEventRouter::OnListenerAdded() {
312 num_event_listeners_
++;
313 DCHECK(content::BrowserThread::CurrentlyOn(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(content::BrowserThread::CurrentlyOn(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(content::BrowserThread::CurrentlyOn(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())
370 delete session_iter
->second
;
371 discovery_session_map_
.erase(session_iter
);
374 void BluetoothEventRouter::CleanUpAllExtensions() {
375 for (auto& it
: pre_set_filter_map_
)
378 pre_set_filter_map_
.clear();
380 for (auto& it
: discovery_session_map_
)
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())
399 discovery_session_map_
[extension_id
] = discovery_session
.release();
403 void BluetoothEventRouter::OnSetDiscoveryFilter(const std::string
& extension_id
,
404 const base::Closure
& callback
) {
405 DVLOG(1) << "Successfully set DiscoveryFilter.";
409 void BluetoothEventRouter::Observe(
411 const content::NotificationSource
& source
,
412 const content::NotificationDetails
& details
) {
413 DCHECK(content::BrowserThread::CurrentlyOn(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