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

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: Use a callback function with an enum instead of an observer. 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"
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698