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
= core_api::bluetooth
;
37 namespace bt_private
= core_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(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(bluetooth::OnDeviceChanged::kEventName
, device
);
298 void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter
* adapter
,
299 device::BluetoothDevice
* device
) {
300 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
301 if (adapter
!= adapter_
.get()) {
302 DVLOG(1) << "Ignoring event for adapter " << adapter
->GetAddress();
306 DispatchDeviceEvent(bluetooth::OnDeviceRemoved::kEventName
, device
);
309 void BluetoothEventRouter::OnListenerAdded() {
310 num_event_listeners_
++;
311 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
312 if (!adapter_
.get()) {
313 GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized
,
314 weak_ptr_factory_
.GetWeakPtr(),
315 base::Bind(&base::DoNothing
)));
319 void BluetoothEventRouter::OnListenerRemoved() {
320 if (num_event_listeners_
> 0)
321 num_event_listeners_
--;
322 MaybeReleaseAdapter();
325 void BluetoothEventRouter::DispatchAdapterStateEvent() {
326 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
327 core_api::bluetooth::AdapterState state
;
328 PopulateAdapterState(*adapter_
.get(), &state
);
330 scoped_ptr
<base::ListValue
> args
=
331 bluetooth::OnAdapterStateChanged::Create(state
);
332 scoped_ptr
<Event
> event(new Event(
333 bluetooth::OnAdapterStateChanged::kEventName
,
335 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
338 void BluetoothEventRouter::DispatchDeviceEvent(
339 const std::string
& event_name
,
340 device::BluetoothDevice
* device
) {
341 bluetooth::Device extension_device
;
342 bluetooth::BluetoothDeviceToApiDevice(*device
, &extension_device
);
344 scoped_ptr
<base::ListValue
> args
=
345 bluetooth::OnDeviceAdded::Create(extension_device
);
346 scoped_ptr
<Event
> event(new Event(event_name
, args
.Pass()));
347 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
350 void BluetoothEventRouter::CleanUpForExtension(
351 const std::string
& extension_id
) {
352 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
353 RemovePairingDelegate(extension_id
);
355 PreSetFilterMap::iterator pre_set_iter
=
356 pre_set_filter_map_
.find(extension_id
);
357 if (pre_set_iter
!= pre_set_filter_map_
.end()) {
358 delete pre_set_iter
->second
;
359 pre_set_filter_map_
.erase(pre_set_iter
);
362 // Remove any discovery session initiated by the extension.
363 DiscoverySessionMap::iterator session_iter
=
364 discovery_session_map_
.find(extension_id
);
365 if (session_iter
== discovery_session_map_
.end())
367 delete session_iter
->second
;
368 discovery_session_map_
.erase(session_iter
);
371 void BluetoothEventRouter::CleanUpAllExtensions() {
372 for (auto& it
: pre_set_filter_map_
)
375 pre_set_filter_map_
.clear();
377 for (auto& it
: discovery_session_map_
)
380 discovery_session_map_
.clear();
382 PairingDelegateMap::iterator pairing_iter
= pairing_delegate_map_
.begin();
383 while (pairing_iter
!= pairing_delegate_map_
.end())
384 RemovePairingDelegate(pairing_iter
++->first
);
387 void BluetoothEventRouter::OnStartDiscoverySession(
388 const std::string
& extension_id
,
389 const base::Closure
& callback
,
390 scoped_ptr
<device::BluetoothDiscoverySession
> discovery_session
) {
391 // Clean up any existing session instance for the extension.
392 DiscoverySessionMap::iterator iter
=
393 discovery_session_map_
.find(extension_id
);
394 if (iter
!= discovery_session_map_
.end())
396 discovery_session_map_
[extension_id
] = discovery_session
.release();
400 void BluetoothEventRouter::OnSetDiscoveryFilter(const std::string
& extension_id
,
401 const base::Closure
& callback
) {
402 DVLOG(1) << "Successfully set DiscoveryFilter.";
406 void BluetoothEventRouter::Observe(
408 const content::NotificationSource
& source
,
409 const content::NotificationDetails
& details
) {
410 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
411 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
, type
);
412 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
413 CleanUpForExtension(host
->extension_id());
416 void BluetoothEventRouter::OnExtensionUnloaded(
417 content::BrowserContext
* browser_context
,
418 const Extension
* extension
,
419 UnloadedExtensionInfo::Reason reason
) {
420 CleanUpForExtension(extension
->id());
423 } // namespace extensions