OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // NETWORK_ERROR Note: | 5 // NETWORK_ERROR Note: |
6 // When a device can't be found in the BluetoothAdapter, that generally | 6 // When a device can't be found in the BluetoothAdapter, that generally |
7 // indicates that it's gone out of range. We reject with a NetworkError in that | 7 // indicates that it's gone out of range. We reject with a NetworkError in that |
8 // case. | 8 // case. |
9 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-conne ctgatt | 9 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-conne ctgatt |
10 | 10 |
11 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" | 11 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
12 | 12 |
13 #include "base/bind.h" | |
14 #include "base/single_thread_task_runner.h" | |
13 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
16 #include "base/thread_task_runner_handle.h" | |
14 #include "content/browser/bad_message.h" | 17 #include "content/browser/bad_message.h" |
15 #include "content/browser/bluetooth/bluetooth_metrics.h" | 18 #include "content/browser/bluetooth/bluetooth_metrics.h" |
16 #include "content/browser/frame_host/render_frame_host_impl.h" | 19 #include "content/browser/frame_host/render_frame_host_impl.h" |
17 #include "content/common/bluetooth/bluetooth_messages.h" | 20 #include "content/common/bluetooth/bluetooth_messages.h" |
18 #include "device/bluetooth/bluetooth_adapter.h" | 21 #include "device/bluetooth/bluetooth_adapter.h" |
19 #include "device/bluetooth/bluetooth_adapter_factory.h" | 22 #include "device/bluetooth/bluetooth_adapter_factory.h" |
20 #include "device/bluetooth/bluetooth_device.h" | 23 #include "device/bluetooth/bluetooth_device.h" |
21 #include "device/bluetooth/bluetooth_discovery_session.h" | 24 #include "device/bluetooth/bluetooth_discovery_session.h" |
22 #include "device/bluetooth/bluetooth_gatt_characteristic.h" | 25 #include "device/bluetooth/bluetooth_gatt_characteristic.h" |
23 #include "device/bluetooth/bluetooth_gatt_service.h" | 26 #include "device/bluetooth/bluetooth_gatt_service.h" |
24 | 27 |
25 using blink::WebBluetoothError; | 28 using blink::WebBluetoothError; |
26 using device::BluetoothAdapter; | 29 using device::BluetoothAdapter; |
27 using device::BluetoothAdapterFactory; | 30 using device::BluetoothAdapterFactory; |
28 using device::BluetoothGattCharacteristic; | 31 using device::BluetoothGattCharacteristic; |
29 using device::BluetoothGattService; | 32 using device::BluetoothGattService; |
30 using device::BluetoothUUID; | 33 using device::BluetoothUUID; |
31 | 34 |
32 namespace content { | 35 namespace content { |
33 | 36 |
34 namespace { | 37 namespace { |
35 | 38 |
36 // TODO(ortuno): Once we have a chooser for scanning and the right | 39 // TODO(ortuno): Once we have a chooser for scanning, a way to control that |
37 // callback for discovered services we should delete these constants. | 40 // chooser from tests, and the right callback for discovered services we should |
41 // delete these constants. | |
38 // https://crbug.com/436280 and https://crbug.com/484504 | 42 // https://crbug.com/436280 and https://crbug.com/484504 |
39 const int kDelayTime = 5; // 5 seconds for scanning and discovering | 43 const int kDelayTime = 5; // 5 seconds for scanning and discovering |
40 const int kTestingDelayTime = 0; // No need to wait during tests | 44 const int kTestingDelayTime = 0; // No need to wait during tests |
41 | 45 |
42 // Defined at | 46 // Defined at |
43 // https://webbluetoothchrome.github.io/web-bluetooth/#dfn-matches-a-filter | 47 // https://webbluetoothchrome.github.io/web-bluetooth/#dfn-matches-a-filter |
44 bool MatchesFilter(const std::set<BluetoothUUID>& device_uuids, | 48 bool MatchesFilter(const std::set<BluetoothUUID>& device_uuids, |
45 const content::BluetoothScanFilter& filter) { | 49 const content::BluetoothScanFilter& filter) { |
46 if (filter.services.empty()) | 50 if (filter.services.empty()) |
47 return false; | 51 return false; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
130 return blink::WebBluetoothError::GATTNotPaired; | 134 return blink::WebBluetoothError::GATTNotPaired; |
131 case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED: | 135 case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED: |
132 RecordGATTOperationOutcome(operation, | 136 RecordGATTOperationOutcome(operation, |
133 UMAGATTOperationOutcome::NOT_SUPPORTED); | 137 UMAGATTOperationOutcome::NOT_SUPPORTED); |
134 return blink::WebBluetoothError::GATTNotSupported; | 138 return blink::WebBluetoothError::GATTNotSupported; |
135 } | 139 } |
136 NOTREACHED(); | 140 NOTREACHED(); |
137 return blink::WebBluetoothError::GATTUntranslatedErrorCode; | 141 return blink::WebBluetoothError::GATTUntranslatedErrorCode; |
138 } | 142 } |
139 | 143 |
144 void StopDiscoverySession( | |
145 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | |
146 // Nothing goes wrong if the discovery session fails to stop, and we don't | |
147 // need to wait for it before letting the user's script proceed, so we ignore | |
148 // the results here. | |
149 discovery_session->Stop(base::Bind(&base::DoNothing), | |
150 base::Bind(&base::DoNothing)); | |
151 } | |
152 | |
140 } // namespace | 153 } // namespace |
141 | 154 |
142 BluetoothDispatcherHost::BluetoothDispatcherHost(int render_process_id) | 155 BluetoothDispatcherHost::BluetoothDispatcherHost(int render_process_id) |
143 : BrowserMessageFilter(BluetoothMsgStart), | 156 : BrowserMessageFilter(BluetoothMsgStart), |
144 render_process_id_(render_process_id), | 157 render_process_id_(render_process_id), |
158 current_delay_time_(kDelayTime), | |
159 discovery_session_timer_( | |
160 FROM_HERE, | |
161 // TODO(jyasskin): Add a way for tests to control the dialog | |
162 // directly, and change this to a reasonable discovery timeout. | |
163 base::TimeDelta::FromSecondsD(current_delay_time_), | |
164 base::Bind(&BluetoothDispatcherHost::StopDeviceDiscovery, | |
165 // base::Timer guarantees it won't call back after its | |
166 // destructor starts. | |
167 base::Unretained(this)), | |
168 /*is_repeating=*/false), | |
145 weak_ptr_factory_(this) { | 169 weak_ptr_factory_(this) { |
146 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 170 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
147 current_delay_time_ = kDelayTime; | |
148 if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) | 171 if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) |
149 BluetoothAdapterFactory::GetAdapter( | 172 BluetoothAdapterFactory::GetAdapter( |
150 base::Bind(&BluetoothDispatcherHost::set_adapter, | 173 base::Bind(&BluetoothDispatcherHost::set_adapter, |
151 weak_ptr_factory_.GetWeakPtr())); | 174 weak_ptr_factory_.GetWeakPtr())); |
152 } | 175 } |
153 | 176 |
154 void BluetoothDispatcherHost::OnDestruct() const { | 177 void BluetoothDispatcherHost::OnDestruct() const { |
155 // See class comment: UI Thread Note. | 178 // See class comment: UI Thread Note. |
156 BrowserThread::DeleteOnUIThread::Destruct(this); | 179 BrowserThread::DeleteOnUIThread::Destruct(this); |
157 } | 180 } |
(...skipping 17 matching lines...) Expand all Loading... | |
175 IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) | 198 IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) |
176 IPC_MESSAGE_UNHANDLED(handled = false) | 199 IPC_MESSAGE_UNHANDLED(handled = false) |
177 IPC_END_MESSAGE_MAP() | 200 IPC_END_MESSAGE_MAP() |
178 return handled; | 201 return handled; |
179 } | 202 } |
180 | 203 |
181 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting( | 204 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting( |
182 scoped_refptr<device::BluetoothAdapter> mock_adapter) { | 205 scoped_refptr<device::BluetoothAdapter> mock_adapter) { |
183 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 206 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
184 current_delay_time_ = kTestingDelayTime; | 207 current_delay_time_ = kTestingDelayTime; |
208 // Reset the discovery session timer to use the new delay time. | |
209 discovery_session_timer_.Start( | |
210 FROM_HERE, base::TimeDelta::FromSecondsD(current_delay_time_), | |
211 base::Bind(&BluetoothDispatcherHost::StopDeviceDiscovery, | |
212 // base::Timer guarantees it won't call back after its | |
213 // destructor starts. | |
214 base::Unretained(this))); | |
185 set_adapter(mock_adapter.Pass()); | 215 set_adapter(mock_adapter.Pass()); |
186 } | 216 } |
187 | 217 |
188 BluetoothDispatcherHost::~BluetoothDispatcherHost() { | 218 BluetoothDispatcherHost::~BluetoothDispatcherHost() { |
189 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 219 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
190 // Clear adapter, releasing observer references. | 220 // Clear adapter, releasing observer references. |
191 set_adapter(scoped_refptr<device::BluetoothAdapter>()); | 221 set_adapter(scoped_refptr<device::BluetoothAdapter>()); |
192 } | 222 } |
193 | 223 |
194 // Stores information associated with an in-progress requestDevice call. This | 224 // Stores information associated with an in-progress requestDevice call. This |
195 // will include the state of the active chooser dialog in a future patch. | 225 // will include the state of the active chooser dialog in a future patch. |
196 struct BluetoothDispatcherHost::RequestDeviceSession { | 226 struct BluetoothDispatcherHost::RequestDeviceSession { |
197 RequestDeviceSession(const std::vector<BluetoothScanFilter>& filters, | 227 public: |
228 RequestDeviceSession(int thread_id, | |
229 int request_id, | |
230 const std::vector<BluetoothScanFilter>& filters, | |
198 const std::vector<BluetoothUUID>& optional_services) | 231 const std::vector<BluetoothUUID>& optional_services) |
199 : filters(filters), optional_services(optional_services) {} | 232 : thread_id(thread_id), |
233 request_id(request_id), | |
234 filters(filters), | |
235 optional_services(optional_services) {} | |
200 | 236 |
201 std::vector<BluetoothScanFilter> filters; | 237 void AddFilteredDevice(const device::BluetoothDevice& device) { |
202 std::vector<BluetoothUUID> optional_services; | 238 if (chooser && MatchesFilters(device, filters)) { |
239 chooser->AddDevice(device.GetIdentifier(), device.GetName()); | |
240 } | |
241 } | |
242 | |
243 const int thread_id; | |
244 const int request_id; | |
245 const std::vector<BluetoothScanFilter> filters; | |
246 const std::vector<BluetoothUUID> optional_services; | |
247 scoped_ptr<BluetoothChooser> chooser; | |
248 scoped_ptr<device::BluetoothDiscoverySession> discovery_session; | |
203 }; | 249 }; |
204 | 250 |
205 void BluetoothDispatcherHost::set_adapter( | 251 void BluetoothDispatcherHost::set_adapter( |
206 scoped_refptr<device::BluetoothAdapter> adapter) { | 252 scoped_refptr<device::BluetoothAdapter> adapter) { |
207 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
208 if (adapter_.get()) | 254 if (adapter_.get()) |
209 adapter_->RemoveObserver(this); | 255 adapter_->RemoveObserver(this); |
210 adapter_ = adapter; | 256 adapter_ = adapter; |
211 if (adapter_.get()) | 257 if (adapter_.get()) |
212 adapter_->AddObserver(this); | 258 adapter_->AddObserver(this); |
213 } | 259 } |
214 | 260 |
261 void BluetoothDispatcherHost::StopDeviceDiscovery() { | |
262 for (IDMap<RequestDeviceSession, IDMapOwnPointer>::iterator iter( | |
263 &request_device_sessions_); | |
264 !iter.IsAtEnd(); iter.Advance()) { | |
265 RequestDeviceSession* session = iter.GetCurrentValue(); | |
266 if (session->discovery_session) { | |
267 StopDiscoverySession(session->discovery_session.Pass()); | |
268 } | |
269 if (session->chooser) { | |
270 session->chooser->ShowDiscoveryState( | |
271 BluetoothChooser::DiscoveryState::IDLE); | |
272 } | |
273 } | |
274 } | |
275 | |
276 void BluetoothDispatcherHost::AdapterPoweredChanged( | |
277 device::BluetoothAdapter* adapter, | |
278 bool powered) { | |
279 const BluetoothChooser::AdapterPresence presence = | |
280 powered ? BluetoothChooser::AdapterPresence::POWERED_ON | |
281 : BluetoothChooser::AdapterPresence::POWERED_OFF; | |
282 for (IDMap<RequestDeviceSession, IDMapOwnPointer>::iterator iter( | |
283 &request_device_sessions_); | |
284 !iter.IsAtEnd(); iter.Advance()) { | |
285 RequestDeviceSession* session = iter.GetCurrentValue(); | |
286 if (session->chooser) | |
287 session->chooser->SetAdapterPresence(presence); | |
288 } | |
289 } | |
290 | |
291 void BluetoothDispatcherHost::DeviceAdded(device::BluetoothAdapter* adapter, | |
292 device::BluetoothDevice* device) { | |
293 VLOG(1) << "Adding device to all choosers: " << device->GetIdentifier(); | |
294 for (IDMap<RequestDeviceSession, IDMapOwnPointer>::iterator iter( | |
295 &request_device_sessions_); | |
296 !iter.IsAtEnd(); iter.Advance()) { | |
297 RequestDeviceSession* session = iter.GetCurrentValue(); | |
298 session->AddFilteredDevice(*device); | |
299 } | |
300 } | |
301 | |
215 static scoped_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( | 302 static scoped_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( |
216 const std::vector<BluetoothScanFilter>& filters) { | 303 const std::vector<BluetoothScanFilter>& filters) { |
217 std::set<BluetoothUUID> services; | 304 std::set<BluetoothUUID> services; |
218 for (const BluetoothScanFilter& filter : filters) { | 305 for (const BluetoothScanFilter& filter : filters) { |
219 services.insert(filter.services.begin(), filter.services.end()); | 306 services.insert(filter.services.begin(), filter.services.end()); |
220 } | 307 } |
221 scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter( | 308 scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter( |
222 new device::BluetoothDiscoveryFilter( | 309 new device::BluetoothDiscoveryFilter( |
223 device::BluetoothDiscoveryFilter::TRANSPORT_DUAL)); | 310 device::BluetoothDiscoveryFilter::TRANSPORT_DUAL)); |
224 for (const BluetoothUUID& service : services) { | 311 for (const BluetoothUUID& service : services) { |
(...skipping 30 matching lines...) Expand all Loading... | |
255 if (!render_frame_host) { | 342 if (!render_frame_host) { |
256 DLOG(WARNING) | 343 DLOG(WARNING) |
257 << "Got a requestDevice IPC without a matching RenderFrameHost: " | 344 << "Got a requestDevice IPC without a matching RenderFrameHost: " |
258 << render_process_id_ << ", " << frame_routing_id; | 345 << render_process_id_ << ", " << frame_routing_id; |
259 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_RENDER_FRAME); | 346 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_RENDER_FRAME); |
260 Send(new BluetoothMsg_RequestDeviceError( | 347 Send(new BluetoothMsg_RequestDeviceError( |
261 thread_id, request_id, WebBluetoothError::RequestDeviceWithoutFrame)); | 348 thread_id, request_id, WebBluetoothError::RequestDeviceWithoutFrame)); |
262 return; | 349 return; |
263 } | 350 } |
264 | 351 |
265 // TODO(scheib): Device selection UI: crbug.com/436280 | 352 if (!adapter_) { |
266 // TODO(scheib): Utilize BluetoothAdapter::Observer::DeviceAdded/Removed. | |
267 if (adapter_.get()) { | |
268 if (!request_device_sessions_ | |
269 .insert(std::make_pair( | |
270 std::make_pair(thread_id, request_id), | |
271 RequestDeviceSession(filters, optional_services))) | |
272 .second) { | |
273 LOG(ERROR) << "2 requestDevice() calls with the same thread_id (" | |
274 << thread_id << ") and request_id (" << request_id | |
275 << ") shouldn't arrive at the same BluetoothDispatcherHost."; | |
276 bad_message::ReceivedBadMessage( | |
277 this, bad_message::BDH_DUPLICATE_REQUEST_DEVICE_ID); | |
278 } | |
279 if (!adapter_->IsPresent()) { | |
280 VLOG(1) << "Bluetooth Adapter not present. Can't serve requestDevice."; | |
281 RecordRequestDeviceOutcome( | |
282 UMARequestDeviceOutcome::BLUETOOTH_ADAPTER_NOT_PRESENT); | |
283 Send(new BluetoothMsg_RequestDeviceError( | |
284 thread_id, request_id, WebBluetoothError::NoBluetoothAdapter)); | |
285 request_device_sessions_.erase(std::make_pair(thread_id, request_id)); | |
286 return; | |
287 } | |
288 // TODO(jyasskin): Once the dialog is available, the dialog should check for | |
289 // the status of the adapter, i.e. check IsPowered() and | |
290 // BluetoothAdapter::Observer::PoweredChanged, and inform the user. But | |
291 // until the dialog is available we log/histogram the status and return | |
292 // with a message. | |
293 // https://crbug.com/517237 | |
294 if (!adapter_->IsPowered()) { | |
295 RecordRequestDeviceOutcome( | |
296 UMARequestDeviceOutcome::BLUETOOTH_ADAPTER_OFF); | |
297 Send(new BluetoothMsg_RequestDeviceError( | |
298 thread_id, request_id, WebBluetoothError::BluetoothAdapterOff)); | |
299 request_device_sessions_.erase(std::make_pair(thread_id, request_id)); | |
300 return; | |
301 } | |
302 adapter_->StartDiscoverySessionWithFilter( | |
303 ComputeScanFilter(filters), | |
304 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStarted, | |
305 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), | |
306 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStartedError, | |
307 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); | |
308 } else { | |
309 VLOG(1) << "No BluetoothAdapter. Can't serve requestDevice."; | 353 VLOG(1) << "No BluetoothAdapter. Can't serve requestDevice."; |
310 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_BLUETOOTH_ADAPTER); | 354 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_BLUETOOTH_ADAPTER); |
311 Send(new BluetoothMsg_RequestDeviceError( | 355 Send(new BluetoothMsg_RequestDeviceError( |
312 thread_id, request_id, WebBluetoothError::NoBluetoothAdapter)); | 356 thread_id, request_id, WebBluetoothError::NoBluetoothAdapter)); |
357 return; | |
313 } | 358 } |
314 return; | 359 |
360 if (!adapter_->IsPresent()) { | |
361 VLOG(1) << "Bluetooth Adapter not present. Can't serve requestDevice."; | |
362 RecordRequestDeviceOutcome( | |
363 UMARequestDeviceOutcome::BLUETOOTH_ADAPTER_NOT_PRESENT); | |
364 Send(new BluetoothMsg_RequestDeviceError( | |
365 thread_id, request_id, WebBluetoothError::NoBluetoothAdapter)); | |
366 return; | |
367 } | |
368 | |
369 // Create storage for the information that backs the chooser, and show the | |
370 // chooser. | |
371 RequestDeviceSession* const session = new RequestDeviceSession( | |
372 thread_id, request_id, filters, optional_services); | |
373 int chooser_id = request_device_sessions_.Add(session); | |
374 | |
375 session->chooser = render_frame_host->RunBluetoothChooser( | |
jam
2015/08/25 15:49:21
instead of going through RenderFrameHost->RenderFr
Jeffrey Yasskin
2015/08/25 17:13:13
Thanks; I didn't realize that route existed.
| |
376 this, chooser_id, render_frame_host->GetLastCommittedURL().GetOrigin()); | |
377 if (!session->chooser) { | |
378 LOG(ERROR) << "No Bluetooth chooser implementation."; | |
379 RecordRequestDeviceOutcome( | |
380 UMARequestDeviceOutcome::NO_BLUETOOTH_CHOOSER_IMPLEMENTATION); | |
381 Send(new BluetoothMsg_RequestDeviceError( | |
382 thread_id, request_id, WebBluetoothError::NoBluetoothChooser)); | |
383 request_device_sessions_.Remove(chooser_id); | |
384 return; | |
385 } | |
386 | |
387 // Populate the initial list of devices. | |
388 VLOG(1) << "Populating devices in chooser " << chooser_id; | |
389 for (const device::BluetoothDevice* device : adapter_->GetDevices()) { | |
390 VLOG(1) << "\t" << device->GetIdentifier(); | |
391 session->AddFilteredDevice(*device); | |
392 } | |
393 | |
394 if (!session->chooser) { | |
395 // If the dialog's closing, no need to do any of the rest of this. | |
396 return; | |
397 } | |
398 | |
399 if (!adapter_->IsPowered()) { | |
400 session->chooser->SetAdapterPresence( | |
401 BluetoothChooser::AdapterPresence::POWERED_OFF); | |
402 return; | |
403 } | |
404 | |
405 // Redundant with the chooser's default; just to be clear: | |
406 session->chooser->ShowDiscoveryState( | |
407 BluetoothChooser::DiscoveryState::DISCOVERING); | |
408 adapter_->StartDiscoverySessionWithFilter( | |
409 ComputeScanFilter(filters), | |
410 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStarted, | |
411 weak_ptr_factory_.GetWeakPtr(), chooser_id), | |
412 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStartedError, | |
413 weak_ptr_factory_.GetWeakPtr(), chooser_id)); | |
315 } | 414 } |
316 | 415 |
317 void BluetoothDispatcherHost::OnConnectGATT( | 416 void BluetoothDispatcherHost::OnConnectGATT( |
318 int thread_id, | 417 int thread_id, |
319 int request_id, | 418 int request_id, |
320 const std::string& device_instance_id) { | 419 const std::string& device_instance_id) { |
321 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 420 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
322 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); | 421 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); |
323 const base::TimeTicks start_time = base::TimeTicks::Now(); | 422 const base::TimeTicks start_time = base::TimeTicks::Now(); |
324 | 423 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
557 return; | 656 return; |
558 } | 657 } |
559 characteristic->WriteRemoteCharacteristic( | 658 characteristic->WriteRemoteCharacteristic( |
560 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, | 659 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, |
561 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), | 660 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), |
562 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, | 661 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, |
563 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); | 662 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); |
564 } | 663 } |
565 | 664 |
566 void BluetoothDispatcherHost::OnDiscoverySessionStarted( | 665 void BluetoothDispatcherHost::OnDiscoverySessionStarted( |
567 int thread_id, | 666 int chooser_id, |
568 int request_id, | |
569 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | 667 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { |
570 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 668 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
571 BrowserThread::PostDelayedTask( | 669 VLOG(1) << "Started discovery session for " << chooser_id; |
572 BrowserThread::UI, FROM_HERE, | 670 if (RequestDeviceSession* session = |
573 base::Bind(&BluetoothDispatcherHost::StopDiscoverySession, | 671 request_device_sessions_.Lookup(chooser_id)) { |
574 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id, | 672 session->discovery_session = discovery_session.Pass(); |
575 base::Passed(&discovery_session)), | 673 |
576 base::TimeDelta::FromSeconds(current_delay_time_)); | 674 // Arrange to stop discovery later. |
675 discovery_session_timer_.Reset(); | |
676 } else { | |
677 VLOG(1) << "Chooser " << chooser_id | |
678 << " was closed before the session finished starting. Stopping."; | |
679 StopDiscoverySession(discovery_session.Pass()); | |
680 } | |
577 } | 681 } |
578 | 682 |
579 void BluetoothDispatcherHost::OnDiscoverySessionStartedError(int thread_id, | 683 void BluetoothDispatcherHost::OnDiscoverySessionStartedError(int chooser_id) { |
580 int request_id) { | |
581 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 684 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
582 DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStartedError"; | 685 VLOG(1) << "Failed to start discovery session for " << chooser_id; |
583 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::DISCOVERY_START_FAILED); | 686 if (RequestDeviceSession* session = |
584 Send(new BluetoothMsg_RequestDeviceError( | 687 request_device_sessions_.Lookup(chooser_id)) { |
585 thread_id, request_id, WebBluetoothError::DiscoverySessionStartFailed)); | 688 if (session->chooser && !session->discovery_session) { |
586 request_device_sessions_.erase(std::make_pair(thread_id, request_id)); | 689 session->chooser->ShowDiscoveryState( |
690 BluetoothChooser::DiscoveryState::FAILED_TO_START); | |
691 } | |
692 } | |
693 // Ignore discovery session start errors when the dialog was already closed by | |
694 // the time they happen. | |
587 } | 695 } |
588 | 696 |
589 void BluetoothDispatcherHost::StopDiscoverySession( | 697 void BluetoothDispatcherHost::CloseDialog(int chooser_id, |
590 int thread_id, | 698 const base::Closure& callback) { |
591 int request_id, | 699 RequestDeviceSession* session = request_device_sessions_.Lookup(chooser_id); |
592 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | 700 DCHECK(session) << "Shouldn't close the dialog twice."; |
593 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 701 CHECK(session->chooser) << "Shouldn't close the dialog twice."; |
594 discovery_session->Stop( | 702 |
595 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStopped, | 703 // Synchronously ensure nothing else calls into the chooser after it has asked |
596 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), | 704 // to be closed. |
597 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStoppedError, | 705 session->chooser.reset(); |
598 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); | 706 |
707 // Yield to the event loop to make sure |callback| isn't called within a | |
708 // BluetoothDispatcherHost stack frame. | |
709 if (!base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback)) { | |
710 LOG(WARNING) << "No TaskRunner; not closing requestDevice dialog."; | |
711 } | |
599 } | 712 } |
600 | 713 |
601 void BluetoothDispatcherHost::OnDiscoverySessionStopped(int thread_id, | 714 void BluetoothDispatcherHost::DialogCancelled(int chooser_id) { |
602 int request_id) { | 715 CloseDialog(chooser_id, |
603 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 716 base::Bind(&BluetoothDispatcherHost::OnRequestDeviceCancelled, |
604 auto session = | 717 weak_ptr_factory_.GetWeakPtr(), chooser_id)); |
605 request_device_sessions_.find(std::make_pair(thread_id, request_id)); | |
606 CHECK(session != request_device_sessions_.end()); | |
607 BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); | |
608 for (device::BluetoothDevice* device : devices) { | |
609 VLOG(1) << "Device: " << device->GetName(); | |
610 VLOG(1) << "UUIDs: "; | |
611 for (BluetoothUUID uuid : device->GetUUIDs()) | |
612 VLOG(1) << "\t" << uuid.canonical_value(); | |
613 if (MatchesFilters(*device, session->second.filters)) { | |
614 content::BluetoothDevice device_ipc( | |
615 device->GetAddress(), // instance_id | |
616 device->GetName(), // name | |
617 device->GetBluetoothClass(), // device_class | |
618 device->GetVendorIDSource(), // vendor_id_source | |
619 device->GetVendorID(), // vendor_id | |
620 device->GetProductID(), // product_id | |
621 device->GetDeviceID(), // product_version | |
622 device->IsPaired(), // paired | |
623 content::BluetoothDevice::UUIDsFromBluetoothUUIDs( | |
624 device->GetUUIDs())); // uuids | |
625 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS); | |
626 Send(new BluetoothMsg_RequestDeviceSuccess(thread_id, request_id, | |
627 device_ipc)); | |
628 request_device_sessions_.erase(session); | |
629 return; | |
630 } | |
631 } | |
632 RecordRequestDeviceOutcome( | |
633 UMARequestDeviceOutcome::NO_MATCHING_DEVICES_FOUND); | |
634 Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id, | |
635 WebBluetoothError::NoDevicesFound)); | |
636 request_device_sessions_.erase(session); | |
637 } | 718 } |
638 | 719 |
639 void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id, | 720 void BluetoothDispatcherHost::DeviceSelected(int chooser_id, |
640 int request_id) { | 721 const std::string& device_id) { |
641 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 722 CloseDialog( |
642 DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStoppedError"; | 723 chooser_id, |
643 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::DISCOVERY_STOP_FAILED); | 724 base::Bind(&BluetoothDispatcherHost::OnRequestDeviceSelected, |
725 weak_ptr_factory_.GetWeakPtr(), chooser_id, device_id)); | |
726 } | |
727 | |
728 void BluetoothDispatcherHost::OnRequestDeviceCancelled(int chooser_id) { | |
729 RequestDeviceSession* session = request_device_sessions_.Lookup(chooser_id); | |
730 DCHECK(session) << "Session removed unexpectedly."; | |
731 RecordRequestDeviceOutcome( | |
732 UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_CANCELLED); | |
733 VLOG(1) << "Bluetooth chooser cancelled"; | |
644 Send(new BluetoothMsg_RequestDeviceError( | 734 Send(new BluetoothMsg_RequestDeviceError( |
645 thread_id, request_id, WebBluetoothError::DiscoverySessionStopFailed)); | 735 session->thread_id, session->request_id, |
646 request_device_sessions_.erase(std::make_pair(thread_id, request_id)); | 736 WebBluetoothError::ChooserCancelled)); |
737 request_device_sessions_.Remove(chooser_id); | |
738 } | |
739 | |
740 void BluetoothDispatcherHost::OnRequestDeviceSelected( | |
741 int chooser_id, | |
742 const std::string& device_id) { | |
743 RequestDeviceSession* session = request_device_sessions_.Lookup(chooser_id); | |
744 DCHECK(session) << "Session removed unexpectedly."; | |
745 | |
746 const device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); | |
747 const device::BluetoothDevice* const device = adapter_->GetDevice(device_id); | |
748 if (device == nullptr) { | |
749 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::CHOSEN_DEVICE_VANISHED); | |
750 Send(new BluetoothMsg_RequestDeviceError( | |
751 session->thread_id, session->request_id, | |
752 WebBluetoothError::ChosenDeviceVanished)); | |
753 request_device_sessions_.Remove(chooser_id); | |
754 return; | |
755 } | |
756 | |
757 VLOG(1) << "Device: " << device->GetName(); | |
758 VLOG(1) << "UUIDs: "; | |
759 for (BluetoothUUID uuid : device->GetUUIDs()) | |
760 VLOG(1) << "\t" << uuid.canonical_value(); | |
761 | |
762 content::BluetoothDevice device_ipc( | |
763 device->GetAddress(), // instance_id | |
764 device->GetName(), // name | |
765 device->GetBluetoothClass(), // device_class | |
766 device->GetVendorIDSource(), // vendor_id_source | |
767 device->GetVendorID(), // vendor_id | |
768 device->GetProductID(), // product_id | |
769 device->GetDeviceID(), // product_version | |
770 device->IsPaired(), // paired | |
771 content::BluetoothDevice::UUIDsFromBluetoothUUIDs( | |
772 device->GetUUIDs())); // uuids | |
773 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS); | |
774 Send(new BluetoothMsg_RequestDeviceSuccess(session->thread_id, | |
775 session->request_id, device_ipc)); | |
776 request_device_sessions_.Remove(chooser_id); | |
647 } | 777 } |
648 | 778 |
649 void BluetoothDispatcherHost::OnGATTConnectionCreated( | 779 void BluetoothDispatcherHost::OnGATTConnectionCreated( |
650 int thread_id, | 780 int thread_id, |
651 int request_id, | 781 int request_id, |
652 const std::string& device_instance_id, | 782 const std::string& device_instance_id, |
653 base::TimeTicks start_time, | 783 base::TimeTicks start_time, |
654 scoped_ptr<device::BluetoothGattConnection> connection) { | 784 scoped_ptr<device::BluetoothGattConnection> connection) { |
655 // TODO(ortuno): Save the BluetoothGattConnection so we can disconnect | 785 // TODO(ortuno): Save the BluetoothGattConnection so we can disconnect |
656 // from it. | 786 // from it. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 int thread_id, | 871 int thread_id, |
742 int request_id, | 872 int request_id, |
743 device::BluetoothGattService::GattErrorCode error_code) { | 873 device::BluetoothGattService::GattErrorCode error_code) { |
744 // TranslateGATTError calls RecordGATTOperationOutcome. | 874 // TranslateGATTError calls RecordGATTOperationOutcome. |
745 Send(new BluetoothMsg_WriteCharacteristicValueError( | 875 Send(new BluetoothMsg_WriteCharacteristicValueError( |
746 thread_id, request_id, | 876 thread_id, request_id, |
747 TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE))); | 877 TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE))); |
748 } | 878 } |
749 | 879 |
750 } // namespace content | 880 } // namespace content |
OLD | NEW |