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