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