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 |