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 |