Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(241)

Side by Side Diff: content/browser/bluetooth/bluetooth_dispatcher_host.cc

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

Powered by Google App Engine
This is Rietveld 408576698