| 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 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 29; // max length of device name in filter. | 55 29; // max length of device name in filter. |
| 56 | 56 |
| 57 // The duration of a Bluetooth Scan in seconds. | 57 // The duration of a Bluetooth Scan in seconds. |
| 58 constexpr int kScanDuration = 60; | 58 constexpr int kScanDuration = 60; |
| 59 constexpr int kTestScanDuration = 0; | 59 constexpr int kTestScanDuration = 0; |
| 60 | 60 |
| 61 void LogRequestDeviceOptions( | 61 void LogRequestDeviceOptions( |
| 62 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { | 62 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { |
| 63 VLOG(1) << "requestDevice called with the following filters: "; | 63 VLOG(1) << "requestDevice called with the following filters: "; |
| 64 int i = 0; | 64 int i = 0; |
| 65 VLOG(1) << "acceptAllDevices: " << options->accept_all_devices; |
| 66 |
| 67 if (options->filters.is_null()) |
| 68 return; |
| 69 |
| 65 for (const auto& filter : options->filters) { | 70 for (const auto& filter : options->filters) { |
| 66 VLOG(1) << "Filter #" << ++i; | 71 VLOG(1) << "Filter #" << ++i; |
| 67 if (!filter->name.is_null()) | 72 if (!filter->name.is_null()) |
| 68 VLOG(1) << "Name: " << filter->name; | 73 VLOG(1) << "Name: " << filter->name; |
| 69 | 74 |
| 70 if (!filter->name_prefix.is_null()) | 75 if (!filter->name_prefix.is_null()) |
| 71 VLOG(1) << "Name Prefix: " << filter->name_prefix; | 76 VLOG(1) << "Name Prefix: " << filter->name_prefix; |
| 72 | 77 |
| 73 if (!filter->services.is_null()) { | 78 if (!filter->services.is_null()) { |
| 74 VLOG(1) << "Services: "; | 79 VLOG(1) << "Services: "; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 95 return true; | 100 return true; |
| 96 if (!filter->name_prefix.is_null() && | 101 if (!filter->name_prefix.is_null() && |
| 97 filter->name_prefix.size() > kMaxLengthForDeviceName) | 102 filter->name_prefix.size() > kMaxLengthForDeviceName) |
| 98 return true; | 103 return true; |
| 99 | 104 |
| 100 return false; | 105 return false; |
| 101 } | 106 } |
| 102 | 107 |
| 103 bool HasEmptyOrInvalidFilter( | 108 bool HasEmptyOrInvalidFilter( |
| 104 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { | 109 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { |
| 110 if (filters.is_null()) { |
| 111 return true; |
| 112 } |
| 113 |
| 105 return filters.empty() | 114 return filters.empty() |
| 106 ? true | 115 ? true |
| 107 : filters.end() != std::find_if(filters.begin(), filters.end(), | 116 : filters.end() != std::find_if(filters.begin(), filters.end(), |
| 108 IsEmptyOrInvalidFilter); | 117 IsEmptyOrInvalidFilter); |
| 109 } | 118 } |
| 110 | 119 |
| 120 bool IsOptionsInvalid( |
| 121 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { |
| 122 if (options->accept_all_devices) { |
| 123 return !options->filters.is_null(); |
| 124 } else { |
| 125 return HasEmptyOrInvalidFilter(options->filters); |
| 126 } |
| 127 } |
| 128 |
| 111 bool MatchesFilter(const std::string* device_name, | 129 bool MatchesFilter(const std::string* device_name, |
| 112 const UUIDSet& device_uuids, | 130 const UUIDSet& device_uuids, |
| 113 const blink::mojom::WebBluetoothScanFilterPtr& filter) { | 131 const blink::mojom::WebBluetoothScanFilterPtr& filter) { |
| 114 if (!filter->name.is_null()) { | 132 if (!filter->name.is_null()) { |
| 115 if (device_name == nullptr) | 133 if (device_name == nullptr) |
| 116 return false; | 134 return false; |
| 117 if (filter->name != *device_name) | 135 if (filter->name != *device_name) |
| 118 return false; | 136 return false; |
| 119 } | 137 } |
| 120 | 138 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 146 if (MatchesFilter(device_name, device_uuids, filter)) { | 164 if (MatchesFilter(device_name, device_uuids, filter)) { |
| 147 return true; | 165 return true; |
| 148 } | 166 } |
| 149 } | 167 } |
| 150 return false; | 168 return false; |
| 151 } | 169 } |
| 152 | 170 |
| 153 std::unique_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( | 171 std::unique_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( |
| 154 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { | 172 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { |
| 155 std::unordered_set<BluetoothUUID, device::BluetoothUUIDHash> services; | 173 std::unordered_set<BluetoothUUID, device::BluetoothUUIDHash> services; |
| 156 for (const auto& filter : filters) { | 174 if (!filters.is_null()) { |
| 157 for (const base::Optional<BluetoothUUID>& service : filter->services) { | 175 for (const auto& filter : filters) { |
| 158 services.insert(service.value()); | 176 for (const base::Optional<BluetoothUUID>& service : filter->services) { |
| 177 services.insert(service.value()); |
| 178 } |
| 159 } | 179 } |
| 160 } | 180 } |
| 181 |
| 161 // There isn't much support for GATT over BR/EDR from neither platforms nor | 182 // There isn't much support for GATT over BR/EDR from neither platforms nor |
| 162 // devices so performing a Dual scan will find devices that the API is not | 183 // devices so performing a Dual scan will find devices that the API is not |
| 163 // able to interact with. To avoid wasting power and confusing users with | 184 // able to interact with. To avoid wasting power and confusing users with |
| 164 // devices they are not able to interact with, we only perform an LE Scan. | 185 // devices they are not able to interact with, we only perform an LE Scan. |
| 165 auto discovery_filter = base::MakeUnique<device::BluetoothDiscoveryFilter>( | 186 auto discovery_filter = base::MakeUnique<device::BluetoothDiscoveryFilter>( |
| 166 device::BLUETOOTH_TRANSPORT_LE); | 187 device::BLUETOOTH_TRANSPORT_LE); |
| 167 for (const BluetoothUUID& service : services) { | 188 for (const BluetoothUUID& service : services) { |
| 168 discovery_filter->AddUUID(service); | 189 discovery_filter->AddUUID(service); |
| 169 } | 190 } |
| 170 return discovery_filter; | 191 return discovery_filter; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 const ErrorCallback& error_callback) { | 273 const ErrorCallback& error_callback) { |
| 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 274 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 254 | 275 |
| 255 // GetDevice should only be called once. | 276 // GetDevice should only be called once. |
| 256 DCHECK(success_callback_.is_null()); | 277 DCHECK(success_callback_.is_null()); |
| 257 DCHECK(error_callback_.is_null()); | 278 DCHECK(error_callback_.is_null()); |
| 258 | 279 |
| 259 success_callback_ = success_callback; | 280 success_callback_ = success_callback; |
| 260 error_callback_ = error_callback; | 281 error_callback_ = error_callback; |
| 261 | 282 |
| 262 // The renderer should never send empty filters. | 283 // The renderer should never send invalid options. |
| 263 if (HasEmptyOrInvalidFilter(options->filters)) { | 284 if (IsOptionsInvalid(options)) { |
| 264 web_bluetooth_service_->CrashRendererAndClosePipe( | 285 web_bluetooth_service_->CrashRendererAndClosePipe( |
| 265 bad_message::BDH_EMPTY_OR_INVALID_FILTERS); | 286 bad_message::BDH_INVALID_OPTIONS); |
| 266 return; | 287 return; |
| 267 } | 288 } |
| 268 options_ = std::move(options); | 289 options_ = std::move(options); |
| 269 LogRequestDeviceOptions(options_); | 290 LogRequestDeviceOptions(options_); |
| 270 | 291 |
| 271 // Check blocklist to reject invalid filters and adjust optional_services. | 292 // Check blocklist to reject invalid filters and adjust optional_services. |
| 272 if (BluetoothBlocklist::Get().IsExcluded(options_->filters)) { | 293 if (!options_->filters.is_null() && |
| 294 BluetoothBlocklist::Get().IsExcluded(options_->filters)) { |
| 273 RecordRequestDeviceOutcome( | 295 RecordRequestDeviceOutcome( |
| 274 UMARequestDeviceOutcome::BLOCKLISTED_SERVICE_IN_FILTER); | 296 UMARequestDeviceOutcome::BLOCKLISTED_SERVICE_IN_FILTER); |
| 275 PostErrorCallback( | 297 PostErrorCallback( |
| 276 blink::mojom::WebBluetoothResult::REQUEST_DEVICE_WITH_BLOCKLISTED_UUID); | 298 blink::mojom::WebBluetoothResult::REQUEST_DEVICE_WITH_BLOCKLISTED_UUID); |
| 277 return; | 299 return; |
| 278 } | 300 } |
| 279 BluetoothBlocklist::Get().RemoveExcludedUUIDs(options_.get()); | 301 BluetoothBlocklist::Get().RemoveExcludedUUIDs(options_.get()); |
| 280 | 302 |
| 281 const url::Origin requesting_origin = | 303 const url::Origin requesting_origin = |
| 282 render_frame_host_->GetLastCommittedOrigin(); | 304 render_frame_host_->GetLastCommittedOrigin(); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 BluetoothChooser::AdapterPresence::POWERED_OFF); | 385 BluetoothChooser::AdapterPresence::POWERED_OFF); |
| 364 return; | 386 return; |
| 365 } | 387 } |
| 366 | 388 |
| 367 StartDeviceDiscovery(); | 389 StartDeviceDiscovery(); |
| 368 } | 390 } |
| 369 | 391 |
| 370 void BluetoothDeviceChooserController::AddFilteredDevice( | 392 void BluetoothDeviceChooserController::AddFilteredDevice( |
| 371 const device::BluetoothDevice& device) { | 393 const device::BluetoothDevice& device) { |
| 372 base::Optional<std::string> device_name = device.GetName(); | 394 base::Optional<std::string> device_name = device.GetName(); |
| 373 if (chooser_.get() && | 395 if (chooser_.get()) { |
| 374 MatchesFilters(device_name ? &device_name.value() : nullptr, | 396 if (options_->accept_all_devices || |
| 375 device.GetUUIDs(), options_->filters)) { | 397 MatchesFilters(device_name ? &device_name.value() : nullptr, |
| 376 base::Optional<int8_t> rssi = device.GetInquiryRSSI(); | 398 device.GetUUIDs(), options_->filters)) { |
| 377 chooser_->AddOrUpdateDevice( | 399 base::Optional<int8_t> rssi = device.GetInquiryRSSI(); |
| 378 device.GetAddress(), !!device.GetName() /* should_update_name */, | 400 chooser_->AddOrUpdateDevice( |
| 379 device.GetNameForDisplay(), device.IsGattConnected(), | 401 device.GetAddress(), !!device.GetName() /* should_update_name */, |
| 380 web_bluetooth_service_->IsDevicePaired(device.GetAddress()), | 402 device.GetNameForDisplay(), device.IsGattConnected(), |
| 381 rssi ? CalculateSignalStrengthLevel(rssi.value()) : -1); | 403 web_bluetooth_service_->IsDevicePaired(device.GetAddress()), |
| 404 rssi ? CalculateSignalStrengthLevel(rssi.value()) : -1); |
| 405 } |
| 382 } | 406 } |
| 383 } | 407 } |
| 384 | 408 |
| 385 void BluetoothDeviceChooserController::AdapterPoweredChanged(bool powered) { | 409 void BluetoothDeviceChooserController::AdapterPoweredChanged(bool powered) { |
| 386 if (!powered && discovery_session_.get()) { | 410 if (!powered && discovery_session_.get()) { |
| 387 StopDiscoverySession(std::move(discovery_session_)); | 411 StopDiscoverySession(std::move(discovery_session_)); |
| 388 } | 412 } |
| 389 | 413 |
| 390 if (chooser_.get()) { | 414 if (chooser_.get()) { |
| 391 chooser_->SetAdapterPresence( | 415 chooser_->SetAdapterPresence( |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 | 579 |
| 556 void BluetoothDeviceChooserController::PostErrorCallback( | 580 void BluetoothDeviceChooserController::PostErrorCallback( |
| 557 blink::mojom::WebBluetoothResult error) { | 581 blink::mojom::WebBluetoothResult error) { |
| 558 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( | 582 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 559 FROM_HERE, base::Bind(error_callback_, error))) { | 583 FROM_HERE, base::Bind(error_callback_, error))) { |
| 560 LOG(WARNING) << "No TaskRunner."; | 584 LOG(WARNING) << "No TaskRunner."; |
| 561 } | 585 } |
| 562 } | 586 } |
| 563 | 587 |
| 564 } // namespace content | 588 } // namespace content |
| OLD | NEW |