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/memory/scoped_vector.h"
16 #include "base/stl_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "device/bluetooth/bluetooth_adapter.h"
21 #include "device/bluetooth/bluetooth_adapter_factory.h"
22 #include "device/bluetooth/bluetooth_device.h"
23 #include "device/bluetooth/bluetooth_discovery_session.h"
24 #include "extensions/browser/api/bluetooth/bluetooth_api_pairing_delegate.h"
25 #include "extensions/browser/api/bluetooth/bluetooth_api_utils.h"
26 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
27 #include "extensions/browser/event_router.h"
28 #include "extensions/browser/extension_host.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/browser/notification_types.h"
31 #include "extensions/common/api/bluetooth.h"
32 #include "extensions/common/api/bluetooth_private.h"
34 namespace extensions
{
36 namespace bluetooth
= api::bluetooth
;
37 namespace bt_private
= api::bluetooth_private
;
39 BluetoothEventRouter::BluetoothEventRouter(content::BrowserContext
* context
)
40 : browser_context_(context
),
42 num_event_listeners_(0),
43 extension_registry_observer_(this),
44 weak_ptr_factory_(this) {
45 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
46 DCHECK(browser_context_
);
48 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
49 content::Source
<content::BrowserContext
>(browser_context_
));
50 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
53 BluetoothEventRouter::~BluetoothEventRouter() {
54 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
56 adapter_
->RemoveObserver(this);
59 CleanUpAllExtensions();
62 bool BluetoothEventRouter::IsBluetoothSupported() const {
63 return adapter_
.get() ||
64 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
67 void BluetoothEventRouter::GetAdapter(
68 const device::BluetoothAdapterFactory::AdapterCallback
& callback
) {
70 callback
.Run(scoped_refptr
<device::BluetoothAdapter
>(adapter_
));
74 device::BluetoothAdapterFactory::GetAdapter(callback
);
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()) {
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.";
94 // Check whether user pre set discovery filter by calling SetDiscoveryFilter
95 // before. If the user has set a discovery filter then start a filtered
96 // discovery session, otherwise start a regular session
97 PreSetFilterMap::iterator pre_set_iter
=
98 pre_set_filter_map_
.find(extension_id
);
99 if (pre_set_iter
!= pre_set_filter_map_
.end()) {
100 adapter
->StartDiscoverySessionWithFilter(
101 scoped_ptr
<device::BluetoothDiscoveryFilter
>(pre_set_iter
->second
),
102 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession
,
103 weak_ptr_factory_
.GetWeakPtr(), extension_id
, callback
),
105 pre_set_filter_map_
.erase(pre_set_iter
);
108 adapter
->StartDiscoverySession(
109 base::Bind(&BluetoothEventRouter::OnStartDiscoverySession
,
110 weak_ptr_factory_
.GetWeakPtr(), extension_id
, callback
),
114 void BluetoothEventRouter::StopDiscoverySession(
115 device::BluetoothAdapter
* adapter
,
116 const std::string
& extension_id
,
117 const base::Closure
& callback
,
118 const base::Closure
& error_callback
) {
119 if (adapter
!= adapter_
.get()) {
120 error_callback
.Run();
123 DiscoverySessionMap::iterator iter
=
124 discovery_session_map_
.find(extension_id
);
125 if (iter
== discovery_session_map_
.end() || !iter
->second
->IsActive()) {
126 DVLOG(1) << "No active discovery session exists for extension.";
127 error_callback
.Run();
130 device::BluetoothDiscoverySession
* session
= iter
->second
;
131 session
->Stop(callback
, error_callback
);
134 void BluetoothEventRouter::SetDiscoveryFilter(
135 scoped_ptr
<device::BluetoothDiscoveryFilter
> discovery_filter
,
136 device::BluetoothAdapter
* adapter
,
137 const std::string
& extension_id
,
138 const base::Closure
& callback
,
139 const base::Closure
& error_callback
) {
140 DVLOG(1) << "SetDiscoveryFilter";
141 if (adapter
!= adapter_
.get()) {
142 error_callback
.Run();
146 DiscoverySessionMap::iterator iter
=
147 discovery_session_map_
.find(extension_id
);
148 if (iter
== discovery_session_map_
.end() || !iter
->second
->IsActive()) {
149 DVLOG(1) << "No active discovery session exists for extension, so caching "
150 "filter for later use.";
151 pre_set_filter_map_
[extension_id
] = discovery_filter
.release();
156 // extension is already running discovery, update it's discovery filter
157 iter
->second
->SetDiscoveryFilter(discovery_filter
.Pass(), callback
,
161 BluetoothApiPairingDelegate
* BluetoothEventRouter::GetPairingDelegate(
162 const std::string
& extension_id
) {
163 return ContainsKey(pairing_delegate_map_
, extension_id
)
164 ? pairing_delegate_map_
[extension_id
]
168 void BluetoothEventRouter::OnAdapterInitialized(
169 const base::Closure
& callback
,
170 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
171 if (!adapter_
.get()) {
173 adapter_
->AddObserver(this);
179 void BluetoothEventRouter::MaybeReleaseAdapter() {
180 if (adapter_
.get() && num_event_listeners_
== 0 &&
181 pairing_delegate_map_
.empty()) {
182 adapter_
->RemoveObserver(this);
187 void BluetoothEventRouter::AddPairingDelegate(const std::string
& extension_id
) {
188 if (!adapter_
.get()) {
189 base::Closure self_callback
=
190 base::Bind(&BluetoothEventRouter::AddPairingDelegate
,
191 weak_ptr_factory_
.GetWeakPtr(),
193 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized
,
194 weak_ptr_factory_
.GetWeakPtr(),
199 if (!ContainsKey(pairing_delegate_map_
, extension_id
)) {
200 BluetoothApiPairingDelegate
* delegate
=
201 new BluetoothApiPairingDelegate(extension_id
, browser_context_
);
202 DCHECK(adapter_
.get());
203 adapter_
->AddPairingDelegate(
204 delegate
, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
205 pairing_delegate_map_
[extension_id
] = delegate
;
207 LOG(ERROR
) << "Pairing delegate already exists for extension. "
208 << "There should be at most one onPairing listener.";
213 void BluetoothEventRouter::RemovePairingDelegate(
214 const std::string
& extension_id
) {
215 if (ContainsKey(pairing_delegate_map_
, extension_id
)) {
216 BluetoothApiPairingDelegate
* delegate
= pairing_delegate_map_
[extension_id
];
218 adapter_
->RemovePairingDelegate(delegate
);
219 pairing_delegate_map_
.erase(extension_id
);
221 MaybeReleaseAdapter();
225 void BluetoothEventRouter::AdapterPresentChanged(
226 device::BluetoothAdapter
* adapter
,
228 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
229 if (adapter
!= adapter_
.get()) {
230 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
233 DispatchAdapterStateEvent();
236 void BluetoothEventRouter::AdapterPoweredChanged(
237 device::BluetoothAdapter
* adapter
,
239 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
240 if (adapter
!= adapter_
.get()) {
241 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
244 DispatchAdapterStateEvent();
247 void BluetoothEventRouter::AdapterDiscoveringChanged(
248 device::BluetoothAdapter
* adapter
,
250 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
251 if (adapter
!= adapter_
.get()) {
252 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
257 // If any discovery sessions are inactive, clean them up.
258 DiscoverySessionMap active_session_map
;
259 for (DiscoverySessionMap::iterator iter
= discovery_session_map_
.begin();
260 iter
!= discovery_session_map_
.end();
262 device::BluetoothDiscoverySession
* session
= iter
->second
;
263 if (session
->IsActive()) {
264 active_session_map
[iter
->first
] = session
;
269 discovery_session_map_
.swap(active_session_map
);
270 MaybeReleaseAdapter();
273 DispatchAdapterStateEvent();
276 void BluetoothEventRouter::DeviceAdded(device::BluetoothAdapter
* adapter
,
277 device::BluetoothDevice
* device
) {
278 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
279 if (adapter
!= adapter_
.get()) {
280 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
284 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_ADDED
,
285 bluetooth::OnDeviceAdded::kEventName
, device
);
288 void BluetoothEventRouter::DeviceChanged(device::BluetoothAdapter
* adapter
,
289 device::BluetoothDevice
* device
) {
290 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
291 if (adapter
!= adapter_
.get()) {
292 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
296 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_CHANGED
,
297 bluetooth::OnDeviceChanged::kEventName
, device
);
300 void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter
* adapter
,
301 device::BluetoothDevice
* device
) {
302 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
303 if (adapter
!= adapter_
.get()) {
304 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
308 DispatchDeviceEvent(events::BLUETOOTH_ON_DEVICE_REMOVED
,
309 bluetooth::OnDeviceRemoved::kEventName
, device
);
312 void BluetoothEventRouter::OnListenerAdded() {
313 num_event_listeners_
++;
314 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
315 if (!adapter_
.get()) {
316 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized
,
317 weak_ptr_factory_
.GetWeakPtr(),
318 base::Bind(&base::DoNothing
)));
322 void BluetoothEventRouter::OnListenerRemoved() {
323 if (num_event_listeners_
> 0)
324 num_event_listeners_
--;
325 MaybeReleaseAdapter();
328 void BluetoothEventRouter::DispatchAdapterStateEvent() {
329 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
330 api::bluetooth::AdapterState state
;
331 PopulateAdapterState(*adapter_
.get(), &state
);
333 scoped_ptr
<base::ListValue
> args
=
334 bluetooth::OnAdapterStateChanged::Create(state
);
335 scoped_ptr
<Event
> event(
336 new Event(events::BLUETOOTH_ON_ADAPTER_STATE_CHANGED
,
337 bluetooth::OnAdapterStateChanged::kEventName
, args
.Pass()));
338 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
341 void BluetoothEventRouter::DispatchDeviceEvent(
342 events::HistogramValue histogram_value
,
343 const std::string
& event_name
,
344 device::BluetoothDevice
* device
) {
345 bluetooth::Device extension_device
;
346 bluetooth::BluetoothDeviceToApiDevice(*device
, &extension_device
);
348 scoped_ptr
<base::ListValue
> args
=
349 bluetooth::OnDeviceAdded::Create(extension_device
);
350 scoped_ptr
<Event
> event(new Event(histogram_value
, event_name
, args
.Pass()));
351 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
354 void BluetoothEventRouter::CleanUpForExtension(
355 const std::string
& extension_id
) {
356 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
357 RemovePairingDelegate(extension_id
);
359 PreSetFilterMap::iterator pre_set_iter
=
360 pre_set_filter_map_
.find(extension_id
);
361 if (pre_set_iter
!= pre_set_filter_map_
.end()) {
362 delete pre_set_iter
->second
;
363 pre_set_filter_map_
.erase(pre_set_iter
);
366 // Remove any discovery session initiated by the extension.
367 DiscoverySessionMap::iterator session_iter
=
368 discovery_session_map_
.find(extension_id
);
369 if (session_iter
== discovery_session_map_
.end())
371 delete session_iter
->second
;
372 discovery_session_map_
.erase(session_iter
);
375 void BluetoothEventRouter::CleanUpAllExtensions() {
376 for (auto& it
: pre_set_filter_map_
)
379 pre_set_filter_map_
.clear();
381 for (auto& it
: discovery_session_map_
)
384 discovery_session_map_
.clear();
386 PairingDelegateMap::iterator pairing_iter
= pairing_delegate_map_
.begin();
387 while (pairing_iter
!= pairing_delegate_map_
.end())
388 RemovePairingDelegate(pairing_iter
++->first
);
391 void BluetoothEventRouter::OnStartDiscoverySession(
392 const std::string
& extension_id
,
393 const base::Closure
& callback
,
394 scoped_ptr
<device::BluetoothDiscoverySession
> discovery_session
) {
395 // Clean up any existing session instance for the extension.
396 DiscoverySessionMap::iterator iter
=
397 discovery_session_map_
.find(extension_id
);
398 if (iter
!= discovery_session_map_
.end())
400 discovery_session_map_
[extension_id
] = discovery_session
.release();
404 void BluetoothEventRouter::OnSetDiscoveryFilter(const std::string
& extension_id
,
405 const base::Closure
& callback
) {
406 DVLOG(1) << "Successfully set DiscoveryFilter.";
410 void BluetoothEventRouter::Observe(
412 const content::NotificationSource
& source
,
413 const content::NotificationDetails
& details
) {
414 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
415 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
, type
);
416 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
417 CleanUpForExtension(host
->extension_id());
420 void BluetoothEventRouter::OnExtensionUnloaded(
421 content::BrowserContext
* browser_context
,
422 const Extension
* extension
,
423 UnloadedExtensionInfo::Reason reason
) {
424 CleanUpForExtension(extension
->id());
427 } // namespace extensions