OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 #include "content/browser/bluetooth/bluetooth_device_chooser_controller.h" | 5 #include "content/browser/bluetooth/bluetooth_device_chooser_controller.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 #include <unordered_set> | 9 #include <unordered_set> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/metrics/histogram_macros.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
15 #include "content/browser/bluetooth/bluetooth_blacklist.h" | 16 #include "content/browser/bluetooth/bluetooth_blacklist.h" |
16 #include "content/browser/bluetooth/bluetooth_metrics.h" | 17 #include "content/browser/bluetooth/bluetooth_metrics.h" |
17 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" | 18 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" |
18 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
19 #include "content/public/browser/content_browser_client.h" | 20 #include "content/public/browser/content_browser_client.h" |
20 #include "content/public/browser/render_frame_host.h" | 21 #include "content/public/browser/render_frame_host.h" |
21 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
22 #include "content/public/browser/web_contents_delegate.h" | 23 #include "content/public/browser/web_contents_delegate.h" |
(...skipping 24 matching lines...) Expand all Loading... |
47 | 48 |
48 namespace content { | 49 namespace content { |
49 | 50 |
50 bool BluetoothDeviceChooserController::use_test_scan_duration_ = false; | 51 bool BluetoothDeviceChooserController::use_test_scan_duration_ = false; |
51 | 52 |
52 namespace { | 53 namespace { |
53 constexpr size_t kMaxLengthForDeviceName = | 54 constexpr size_t kMaxLengthForDeviceName = |
54 29; // max length of device name in filter. | 55 29; // max length of device name in filter. |
55 | 56 |
56 // The duration of a Bluetooth Scan in seconds. | 57 // The duration of a Bluetooth Scan in seconds. |
57 constexpr int kScanDuration = 10; | 58 constexpr int kScanDuration = 60; |
58 constexpr int kTestScanDuration = 0; | 59 constexpr int kTestScanDuration = 0; |
59 | 60 |
60 void LogRequestDeviceOptions( | 61 void LogRequestDeviceOptions( |
61 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { | 62 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { |
62 VLOG(1) << "requestDevice called with the following filters: "; | 63 VLOG(1) << "requestDevice called with the following filters: "; |
63 int i = 0; | 64 int i = 0; |
64 for (const auto& filter : options->filters) { | 65 for (const auto& filter : options->filters) { |
65 VLOG(1) << "Filter #" << ++i; | 66 VLOG(1) << "Filter #" << ++i; |
66 if (!filter->name.is_null()) | 67 if (!filter->name.is_null()) |
67 VLOG(1) << "Name: " << filter->name; | 68 VLOG(1) << "Name: " << filter->name; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 return UMARequestDeviceOutcome::ADAPTER_OFF_HELP_LINK_PRESSED; | 191 return UMARequestDeviceOutcome::ADAPTER_OFF_HELP_LINK_PRESSED; |
191 case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP: | 192 case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP: |
192 return UMARequestDeviceOutcome::NEED_LOCATION_HELP_LINK_PRESSED; | 193 return UMARequestDeviceOutcome::NEED_LOCATION_HELP_LINK_PRESSED; |
193 case BluetoothChooser::Event::SELECTED: | 194 case BluetoothChooser::Event::SELECTED: |
194 // We can't know if we are going to send a success message yet because | 195 // We can't know if we are going to send a success message yet because |
195 // the device could have vanished. This event should be histogramed | 196 // the device could have vanished. This event should be histogramed |
196 // manually after checking if the device is still around. | 197 // manually after checking if the device is still around. |
197 NOTREACHED(); | 198 NOTREACHED(); |
198 return UMARequestDeviceOutcome::SUCCESS; | 199 return UMARequestDeviceOutcome::SUCCESS; |
199 case BluetoothChooser::Event::RESCAN: | 200 case BluetoothChooser::Event::RESCAN: |
200 // Rescanning doesn't result in a IPC message for the request being sent | 201 return UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_RESCAN; |
201 // so no need to histogram it. | |
202 NOTREACHED(); | |
203 return UMARequestDeviceOutcome::SUCCESS; | |
204 } | 202 } |
205 NOTREACHED(); | 203 NOTREACHED(); |
206 return UMARequestDeviceOutcome::SUCCESS; | 204 return UMARequestDeviceOutcome::SUCCESS; |
207 } | 205 } |
208 | 206 |
| 207 void RecordScanningDuration(const base::TimeDelta& duration) { |
| 208 UMA_HISTOGRAM_LONG_TIMES("Bluetooth.Web.RequestDevice.ScanningDuration", |
| 209 duration); |
| 210 } |
| 211 |
209 } // namespace | 212 } // namespace |
210 | 213 |
211 BluetoothDeviceChooserController::BluetoothDeviceChooserController( | 214 BluetoothDeviceChooserController::BluetoothDeviceChooserController( |
212 WebBluetoothServiceImpl* web_bluetooth_service, | 215 WebBluetoothServiceImpl* web_bluetooth_service, |
213 RenderFrameHost* render_frame_host, | 216 RenderFrameHost* render_frame_host, |
214 device::BluetoothAdapter* adapter) | 217 device::BluetoothAdapter* adapter) |
215 : adapter_(adapter), | 218 : adapter_(adapter), |
216 web_bluetooth_service_(web_bluetooth_service), | 219 web_bluetooth_service_(web_bluetooth_service), |
217 render_frame_host_(render_frame_host), | 220 render_frame_host_(render_frame_host), |
218 web_contents_(WebContents::FromRenderFrameHost(render_frame_host_)), | 221 web_contents_(WebContents::FromRenderFrameHost(render_frame_host_)), |
219 discovery_session_timer_( | 222 discovery_session_timer_( |
220 FROM_HERE, | 223 FROM_HERE, |
221 // TODO(jyasskin): Add a way for tests to control the dialog | 224 // TODO(jyasskin): Add a way for tests to control the dialog |
222 // directly, and change this to a reasonable discovery timeout. | 225 // directly, and change this to a reasonable discovery timeout. |
223 base::TimeDelta::FromSeconds( | 226 base::TimeDelta::FromSeconds( |
224 use_test_scan_duration_ ? kTestScanDuration : kScanDuration), | 227 use_test_scan_duration_ ? kTestScanDuration : kScanDuration), |
225 base::Bind(&BluetoothDeviceChooserController::StopDeviceDiscovery, | 228 base::Bind(&BluetoothDeviceChooserController::StopDeviceDiscovery, |
226 // base::Timer guarantees it won't call back after its | 229 // base::Timer guarantees it won't call back after its |
227 // destructor starts. | 230 // destructor starts. |
228 base::Unretained(this)), | 231 base::Unretained(this)), |
229 /*is_repeating=*/false), | 232 /*is_repeating=*/false), |
230 weak_ptr_factory_(this) { | 233 weak_ptr_factory_(this) { |
231 CHECK(adapter_); | 234 CHECK(adapter_); |
232 } | 235 } |
233 | 236 |
234 BluetoothDeviceChooserController::~BluetoothDeviceChooserController() { | 237 BluetoothDeviceChooserController::~BluetoothDeviceChooserController() { |
| 238 if (scanning_start_time_) { |
| 239 RecordScanningDuration(base::TimeTicks::Now() - |
| 240 scanning_start_time_.value()); |
| 241 } |
| 242 |
235 if (chooser_) { | 243 if (chooser_) { |
236 DCHECK(!error_callback_.is_null()); | 244 DCHECK(!error_callback_.is_null()); |
237 error_callback_.Run(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); | 245 error_callback_.Run(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); |
238 } | 246 } |
239 } | 247 } |
240 | 248 |
241 void BluetoothDeviceChooserController::GetDevice( | 249 void BluetoothDeviceChooserController::GetDevice( |
242 blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, | 250 blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, |
243 const SuccessCallback& success_callback, | 251 const SuccessCallback& success_callback, |
244 const ErrorCallback& error_callback) { | 252 const ErrorCallback& error_callback) { |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 | 440 |
433 void BluetoothDeviceChooserController::StartDeviceDiscovery() { | 441 void BluetoothDeviceChooserController::StartDeviceDiscovery() { |
434 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 442 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
435 | 443 |
436 if (discovery_session_.get() && discovery_session_->IsActive()) { | 444 if (discovery_session_.get() && discovery_session_->IsActive()) { |
437 // Already running; just increase the timeout. | 445 // Already running; just increase the timeout. |
438 discovery_session_timer_.Reset(); | 446 discovery_session_timer_.Reset(); |
439 return; | 447 return; |
440 } | 448 } |
441 | 449 |
| 450 scanning_start_time_ = base::TimeTicks::Now(); |
| 451 |
442 chooser_->ShowDiscoveryState(BluetoothChooser::DiscoveryState::DISCOVERING); | 452 chooser_->ShowDiscoveryState(BluetoothChooser::DiscoveryState::DISCOVERING); |
443 adapter_->StartDiscoverySessionWithFilter( | 453 adapter_->StartDiscoverySessionWithFilter( |
444 ComputeScanFilter(options_->filters), | 454 ComputeScanFilter(options_->filters), |
445 base::Bind( | 455 base::Bind( |
446 &BluetoothDeviceChooserController::OnStartDiscoverySessionSuccess, | 456 &BluetoothDeviceChooserController::OnStartDiscoverySessionSuccess, |
447 weak_ptr_factory_.GetWeakPtr()), | 457 weak_ptr_factory_.GetWeakPtr()), |
448 base::Bind( | 458 base::Bind( |
449 &BluetoothDeviceChooserController::OnStartDiscoverySessionFailed, | 459 &BluetoothDeviceChooserController::OnStartDiscoverySessionFailed, |
450 weak_ptr_factory_.GetWeakPtr())); | 460 weak_ptr_factory_.GetWeakPtr())); |
451 } | 461 } |
452 | 462 |
453 void BluetoothDeviceChooserController::StopDeviceDiscovery() { | 463 void BluetoothDeviceChooserController::StopDeviceDiscovery() { |
454 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 464 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 465 |
| 466 if (scanning_start_time_) { |
| 467 RecordScanningDuration(base::TimeTicks::Now() - |
| 468 scanning_start_time_.value()); |
| 469 scanning_start_time_.reset(); |
| 470 } |
| 471 |
455 StopDiscoverySession(std::move(discovery_session_)); | 472 StopDiscoverySession(std::move(discovery_session_)); |
456 if (chooser_) { | 473 if (chooser_) { |
457 chooser_->ShowDiscoveryState(BluetoothChooser::DiscoveryState::IDLE); | 474 chooser_->ShowDiscoveryState(BluetoothChooser::DiscoveryState::IDLE); |
458 } | 475 } |
459 } | 476 } |
460 | 477 |
461 void BluetoothDeviceChooserController::OnStartDiscoverySessionSuccess( | 478 void BluetoothDeviceChooserController::OnStartDiscoverySessionSuccess( |
462 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { | 479 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { |
463 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 480 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
464 VLOG(1) << "Started discovery session."; | 481 VLOG(1) << "Started discovery session."; |
(...skipping 14 matching lines...) Expand all Loading... |
479 | 496 |
480 void BluetoothDeviceChooserController::OnBluetoothChooserEvent( | 497 void BluetoothDeviceChooserController::OnBluetoothChooserEvent( |
481 BluetoothChooser::Event event, | 498 BluetoothChooser::Event event, |
482 const std::string& device_address) { | 499 const std::string& device_address) { |
483 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 500 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
484 // Shouldn't recieve an event from a closed chooser. | 501 // Shouldn't recieve an event from a closed chooser. |
485 DCHECK(chooser_.get()); | 502 DCHECK(chooser_.get()); |
486 | 503 |
487 switch (event) { | 504 switch (event) { |
488 case BluetoothChooser::Event::RESCAN: | 505 case BluetoothChooser::Event::RESCAN: |
| 506 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); |
489 PopulateConnectedDevices(); | 507 PopulateConnectedDevices(); |
490 DCHECK(chooser_); | 508 DCHECK(chooser_); |
491 StartDeviceDiscovery(); | 509 StartDeviceDiscovery(); |
492 // No need to close the chooser so we return. | 510 // No need to close the chooser so we return. |
493 return; | 511 return; |
494 case BluetoothChooser::Event::DENIED_PERMISSION: | 512 case BluetoothChooser::Event::DENIED_PERMISSION: |
495 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); | 513 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); |
496 PostErrorCallback(blink::mojom::WebBluetoothResult:: | 514 PostErrorCallback(blink::mojom::WebBluetoothResult:: |
497 CHOOSER_NOT_SHOWN_USER_DENIED_PERMISSION_TO_SCAN); | 515 CHOOSER_NOT_SHOWN_USER_DENIED_PERMISSION_TO_SCAN); |
498 break; | 516 break; |
(...skipping 10 matching lines...) Expand all Loading... |
509 VLOG(1) << "Adapter Off Help link pressed."; | 527 VLOG(1) << "Adapter Off Help link pressed."; |
510 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); | 528 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); |
511 PostErrorCallback(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); | 529 PostErrorCallback(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); |
512 break; | 530 break; |
513 case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP: | 531 case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP: |
514 VLOG(1) << "Need Location Help link pressed."; | 532 VLOG(1) << "Need Location Help link pressed."; |
515 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); | 533 RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event)); |
516 PostErrorCallback(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); | 534 PostErrorCallback(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED); |
517 break; | 535 break; |
518 case BluetoothChooser::Event::SELECTED: | 536 case BluetoothChooser::Event::SELECTED: |
| 537 // RecordRequestDeviceOutcome is called in the callback, because the |
| 538 // device may have vanished. |
519 PostSuccessCallback(device_address); | 539 PostSuccessCallback(device_address); |
520 break; | 540 break; |
521 } | 541 } |
522 // Close chooser. | 542 // Close chooser. |
523 chooser_.reset(); | 543 chooser_.reset(); |
524 } | 544 } |
525 | 545 |
526 void BluetoothDeviceChooserController::PostSuccessCallback( | 546 void BluetoothDeviceChooserController::PostSuccessCallback( |
527 const std::string& device_address) { | 547 const std::string& device_address) { |
528 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( | 548 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( |
529 FROM_HERE, | 549 FROM_HERE, |
530 base::Bind(success_callback_, base::Passed(std::move(options_)), | 550 base::Bind(success_callback_, base::Passed(std::move(options_)), |
531 device_address))) { | 551 device_address))) { |
532 LOG(WARNING) << "No TaskRunner."; | 552 LOG(WARNING) << "No TaskRunner."; |
533 } | 553 } |
534 } | 554 } |
535 | 555 |
536 void BluetoothDeviceChooserController::PostErrorCallback( | 556 void BluetoothDeviceChooserController::PostErrorCallback( |
537 blink::mojom::WebBluetoothResult error) { | 557 blink::mojom::WebBluetoothResult error) { |
538 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( | 558 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( |
539 FROM_HERE, base::Bind(error_callback_, error))) { | 559 FROM_HERE, base::Bind(error_callback_, error))) { |
540 LOG(WARNING) << "No TaskRunner."; | 560 LOG(WARNING) << "No TaskRunner."; |
541 } | 561 } |
542 } | 562 } |
543 | 563 |
544 } // namespace content | 564 } // namespace content |
OLD | NEW |