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