1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/bluetooth/bluetooth_device_chromeos.h"
6
7 #include <stdio.h>
8
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "chromeos/dbus/bluetooth_adapter_client.h"
15 #include "chromeos/dbus/bluetooth_device_client.h"
16 #include "chromeos/dbus/bluetooth_gatt_service_client.h"
17 #include "chromeos/dbus/bluetooth_input_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "dbus/bus.h"
20 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
21 #include "device/bluetooth/bluetooth_gatt_connection_chromeos.h"
22 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
23 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
24 #include "device/bluetooth/bluetooth_socket.h"
25 #include "device/bluetooth/bluetooth_socket_chromeos.h"
26 #include "device/bluetooth/bluetooth_socket_thread.h"
27 #include "device/bluetooth/bluetooth_uuid.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
29
30 using device::BluetoothDevice;
31 using device::BluetoothSocket;
32 using device::BluetoothUUID;
33
34 namespace {
35
36 // Histogram enumerations for pairing results.
37 enum UMAPairingResult {
38 UMA_PAIRING_RESULT_SUCCESS,
39 UMA_PAIRING_RESULT_INPROGRESS,
40 UMA_PAIRING_RESULT_FAILED,
41 UMA_PAIRING_RESULT_AUTH_FAILED,
42 UMA_PAIRING_RESULT_AUTH_CANCELED,
43 UMA_PAIRING_RESULT_AUTH_REJECTED,
44 UMA_PAIRING_RESULT_AUTH_TIMEOUT,
45 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE,
46 UMA_PAIRING_RESULT_UNKNOWN_ERROR,
47 // NOTE: Add new pairing results immediately above this line. Make sure to
48 // update the enum list in tools/histogram/histograms.xml accordinly.
49 UMA_PAIRING_RESULT_COUNT
50 };
51
ParseModalias(const dbus::ObjectPath & object_path,BluetoothDevice::VendorIDSource * vendor_id_source,uint16 * vendor_id,uint16 * product_id,uint16 * device_id)52 void ParseModalias(const dbus::ObjectPath& object_path,
53 BluetoothDevice::VendorIDSource* vendor_id_source,
54 uint16* vendor_id,
55 uint16* product_id,
56 uint16* device_id) {
57 chromeos::BluetoothDeviceClient::Properties* properties =
58 chromeos::DBusThreadManager::Get()->GetBluetoothDeviceClient()->
59 GetProperties(object_path);
60 DCHECK(properties);
61
62 std::string modalias = properties->modalias.value();
63 BluetoothDevice::VendorIDSource source_value;
64 int vendor_value, product_value, device_value;
65
66 if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x",
67 &vendor_value, &product_value, &device_value) == 3) {
68 source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH;
69 } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x",
70 &vendor_value, &product_value, &device_value) == 3) {
71 source_value = BluetoothDevice::VENDOR_ID_USB;
72 } else {
73 return;
74 }
75
76 if (vendor_id_source != NULL)
77 *vendor_id_source = source_value;
78 if (vendor_id != NULL)
79 *vendor_id = vendor_value;
80 if (product_id != NULL)
81 *product_id = product_value;
82 if (device_id != NULL)
83 *device_id = device_value;
84 }
85
RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code)86 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) {
87 UMAPairingResult pairing_result;
88 switch (error_code) {
89 case BluetoothDevice::ERROR_INPROGRESS:
90 pairing_result = UMA_PAIRING_RESULT_INPROGRESS;
91 break;
92 case BluetoothDevice::ERROR_FAILED:
93 pairing_result = UMA_PAIRING_RESULT_FAILED;
94 break;
95 case BluetoothDevice::ERROR_AUTH_FAILED:
96 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED;
97 break;
98 case BluetoothDevice::ERROR_AUTH_CANCELED:
99 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED;
100 break;
101 case BluetoothDevice::ERROR_AUTH_REJECTED:
102 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED;
103 break;
104 case BluetoothDevice::ERROR_AUTH_TIMEOUT:
105 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT;
106 break;
107 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
108 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE;
109 break;
110 default:
111 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR;
112 }
113
114 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
115 pairing_result,
116 UMA_PAIRING_RESULT_COUNT);
117 }
118
119 } // namespace
120
121 namespace chromeos {
122
BluetoothDeviceChromeOS(BluetoothAdapterChromeOS * adapter,const dbus::ObjectPath & object_path,scoped_refptr<base::SequencedTaskRunner> ui_task_runner,scoped_refptr<device::BluetoothSocketThread> socket_thread)123 BluetoothDeviceChromeOS::BluetoothDeviceChromeOS(
124 BluetoothAdapterChromeOS* adapter,
125 const dbus::ObjectPath& object_path,
126 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
127 scoped_refptr<device::BluetoothSocketThread> socket_thread)
128 : adapter_(adapter),
129 object_path_(object_path),
130 num_connecting_calls_(0),
131 connection_monitor_started_(false),
132 ui_task_runner_(ui_task_runner),
133 socket_thread_(socket_thread),
134 weak_ptr_factory_(this) {
135 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->AddObserver(this);
136
137 // Add all known GATT services.
138 const std::vector<dbus::ObjectPath> gatt_services =
139 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->GetServices();
140 for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin();
141 it != gatt_services.end(); ++it) {
142 GattServiceAdded(*it);
143 }
144 }
145
~BluetoothDeviceChromeOS()146 BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
147 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
148 RemoveObserver(this);
149
150 // Copy the GATT services list here and clear the original so that when we
151 // send GattServiceRemoved(), GetGattServices() returns no services.
152 GattServiceMap gatt_services = gatt_services_;
153 gatt_services_.clear();
154 for (GattServiceMap::iterator iter = gatt_services.begin();
155 iter != gatt_services.end(); ++iter) {
156 FOR_EACH_OBSERVER(BluetoothDevice::Observer, observers_,
157 GattServiceRemoved(this, iter->second));
158 delete iter->second;
159 }
160 }
161
AddObserver(device::BluetoothDevice::Observer * observer)162 void BluetoothDeviceChromeOS::AddObserver(
163 device::BluetoothDevice::Observer* observer) {
164 DCHECK(observer);
165 observers_.AddObserver(observer);
166 }
167
RemoveObserver(device::BluetoothDevice::Observer * observer)168 void BluetoothDeviceChromeOS::RemoveObserver(
169 device::BluetoothDevice::Observer* observer) {
170 DCHECK(observer);
171 observers_.RemoveObserver(observer);
172 }
173
GetBluetoothClass() const174 uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
175 BluetoothDeviceClient::Properties* properties =
176 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
177 GetProperties(object_path_);
178 DCHECK(properties);
179
180 return properties->bluetooth_class.value();
181 }
182
GetDeviceName() const183 std::string BluetoothDeviceChromeOS::GetDeviceName() const {
184 BluetoothDeviceClient::Properties* properties =
185 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
186 GetProperties(object_path_);
187 DCHECK(properties);
188
189 return properties->alias.value();
190 }
191
GetAddress() const192 std::string BluetoothDeviceChromeOS::GetAddress() const {
193 BluetoothDeviceClient::Properties* properties =
194 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
195 GetProperties(object_path_);
196 DCHECK(properties);
197
198 return CanonicalizeAddress(properties->address.value());
199 }
200
201 BluetoothDevice::VendorIDSource
GetVendorIDSource() const202 BluetoothDeviceChromeOS::GetVendorIDSource() const {
203 VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN;
204 ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL);
205 return vendor_id_source;
206 }
207
GetVendorID() const208 uint16 BluetoothDeviceChromeOS::GetVendorID() const {
209 uint16 vendor_id = 0;
210 ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
211 return vendor_id;
212 }
213
GetProductID() const214 uint16 BluetoothDeviceChromeOS::GetProductID() const {
215 uint16 product_id = 0;
216 ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
217 return product_id;
218 }
219
GetDeviceID() const220 uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
221 uint16 device_id = 0;
222 ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
223 return device_id;
224 }
225
GetRSSI() const226 int BluetoothDeviceChromeOS::GetRSSI() const {
227 BluetoothDeviceClient::Properties* properties =
228 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
229 object_path_);
230 DCHECK(properties);
231
232 if (!IsConnected()) {
233 NOTIMPLEMENTED();
234 return kUnknownPower;
235 }
236
237 return connection_monitor_started_ ? properties->connection_rssi.value()
238 : kUnknownPower;
239 }
240
GetCurrentHostTransmitPower() const241 int BluetoothDeviceChromeOS::GetCurrentHostTransmitPower() const {
242 BluetoothDeviceClient::Properties* properties =
243 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
244 object_path_);
245 DCHECK(properties);
246
247 return IsConnected() && connection_monitor_started_
248 ? properties->connection_tx_power.value()
249 : kUnknownPower;
250 }
251
GetMaximumHostTransmitPower() const252 int BluetoothDeviceChromeOS::GetMaximumHostTransmitPower() const {
253 BluetoothDeviceClient::Properties* properties =
254 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
255 object_path_);
256 DCHECK(properties);
257
258 return IsConnected() ? properties->connection_tx_power_max.value()
259 : kUnknownPower;
260 }
261
IsPaired() const262 bool BluetoothDeviceChromeOS::IsPaired() const {
263 BluetoothDeviceClient::Properties* properties =
264 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
265 GetProperties(object_path_);
266 DCHECK(properties);
267
268 // Trusted devices are devices that don't support pairing but that the
269 // user has explicitly connected; it makes no sense for UI purposes to
270 // treat them differently from each other.
271 return properties->paired.value() || properties->trusted.value();
272 }
273
IsConnected() const274 bool BluetoothDeviceChromeOS::IsConnected() const {
275 BluetoothDeviceClient::Properties* properties =
276 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
277 GetProperties(object_path_);
278 DCHECK(properties);
279
280 return properties->connected.value();
281 }
282
IsConnectable() const283 bool BluetoothDeviceChromeOS::IsConnectable() const {
284 BluetoothInputClient::Properties* input_properties =
285 DBusThreadManager::Get()->GetBluetoothInputClient()->
286 GetProperties(object_path_);
287 // GetProperties returns NULL when the device does not implement the given
288 // interface. Non HID devices are normally connectable.
289 if (!input_properties)
290 return true;
291
292 return input_properties->reconnect_mode.value() != "device";
293 }
294
IsConnecting() const295 bool BluetoothDeviceChromeOS::IsConnecting() const {
296 return num_connecting_calls_ > 0;
297 }
298
GetUUIDs() const299 BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const {
300 BluetoothDeviceClient::Properties* properties =
301 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
302 GetProperties(object_path_);
303 DCHECK(properties);
304
305 std::vector<device::BluetoothUUID> uuids;
306 const std::vector<std::string> &dbus_uuids = properties->uuids.value();
307 for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin();
308 iter != dbus_uuids.end(); ++iter) {
309 device::BluetoothUUID uuid(*iter);
310 DCHECK(uuid.IsValid());
311 uuids.push_back(uuid);
312 }
313 return uuids;
314 }
315
ExpectingPinCode() const316 bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
317 return pairing_.get() && pairing_->ExpectingPinCode();
318 }
319
ExpectingPasskey() const320 bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
321 return pairing_.get() && pairing_->ExpectingPasskey();
322 }
323
ExpectingConfirmation() const324 bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
325 return pairing_.get() && pairing_->ExpectingConfirmation();
326 }
327
Connect(BluetoothDevice::PairingDelegate * pairing_delegate,const base::Closure & callback,const ConnectErrorCallback & error_callback)328 void BluetoothDeviceChromeOS::Connect(
329 BluetoothDevice::PairingDelegate* pairing_delegate,
330 const base::Closure& callback,
331 const ConnectErrorCallback& error_callback) {
332 if (num_connecting_calls_++ == 0)
333 adapter_->NotifyDeviceChanged(this);
334
335 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_
336 << " in progress";
337
338 if (IsPaired() || !pairing_delegate || !IsPairable()) {
339 // No need to pair, or unable to, skip straight to connection.
340 ConnectInternal(false, callback, error_callback);
341 } else {
342 // Initiate high-security connection with pairing.
343 BeginPairing(pairing_delegate);
344
345 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
346 Pair(object_path_,
347 base::Bind(&BluetoothDeviceChromeOS::OnPair,
348 weak_ptr_factory_.GetWeakPtr(),
349 callback, error_callback),
350 base::Bind(&BluetoothDeviceChromeOS::OnPairError,
351 weak_ptr_factory_.GetWeakPtr(),
352 error_callback));
353 }
354 }
355
SetPinCode(const std::string & pincode)356 void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
357 if (!pairing_.get())
358 return;
359
360 pairing_->SetPinCode(pincode);
361 }
362
SetPasskey(uint32 passkey)363 void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
364 if (!pairing_.get())
365 return;
366
367 pairing_->SetPasskey(passkey);
368 }
369
ConfirmPairing()370 void BluetoothDeviceChromeOS::ConfirmPairing() {
371 if (!pairing_.get())
372 return;
373
374 pairing_->ConfirmPairing();
375 }
376
RejectPairing()377 void BluetoothDeviceChromeOS::RejectPairing() {
378 if (!pairing_.get())
379 return;
380
381 pairing_->RejectPairing();
382 }
383
CancelPairing()384 void BluetoothDeviceChromeOS::CancelPairing() {
385 bool canceled = false;
386
387 // If there is a callback in progress that we can reply to then use that
388 // to cancel the current pairing request.
389 if (pairing_.get() && pairing_->CancelPairing())
390 canceled = true;
391
392 // If not we have to send an explicit CancelPairing() to the device instead.
393 if (!canceled) {
394 VLOG(1) << object_path_.value() << ": No pairing context or callback. "
395 << "Sending explicit cancel";
396 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
397 CancelPairing(
398 object_path_,
399 base::Bind(&base::DoNothing),
400 base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
401 weak_ptr_factory_.GetWeakPtr()));
402 }
403
404 // Since there is no callback to this method it's possible that the pairing
405 // delegate is going to be freed before things complete (indeed it's
406 // documented that this is the method you should call while freeing the
407 // pairing delegate), so clear our the context holding on to it.
408 EndPairing();
409 }
410
Disconnect(const base::Closure & callback,const ErrorCallback & error_callback)411 void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
412 const ErrorCallback& error_callback) {
413 VLOG(1) << object_path_.value() << ": Disconnecting";
414 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
415 Disconnect(
416 object_path_,
417 base::Bind(&BluetoothDeviceChromeOS::OnDisconnect,
418 weak_ptr_factory_.GetWeakPtr(),
419 callback),
420 base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError,
421 weak_ptr_factory_.GetWeakPtr(),
422 error_callback));
423 }
424
Forget(const ErrorCallback & error_callback)425 void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
426 VLOG(1) << object_path_.value() << ": Removing device";
427 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
428 RemoveDevice(
429 adapter_->object_path(),
430 object_path_,
431 base::Bind(&base::DoNothing),
432 base::Bind(&BluetoothDeviceChromeOS::OnForgetError,
433 weak_ptr_factory_.GetWeakPtr(),
434 error_callback));
435 }
436
ConnectToService(const BluetoothUUID & uuid,const ConnectToServiceCallback & callback,const ConnectToServiceErrorCallback & error_callback)437 void BluetoothDeviceChromeOS::ConnectToService(
438 const BluetoothUUID& uuid,
439 const ConnectToServiceCallback& callback,
440 const ConnectToServiceErrorCallback& error_callback) {
441 VLOG(1) << object_path_.value() << ": Connecting to service: "
442 << uuid.canonical_value();
443 scoped_refptr<BluetoothSocketChromeOS> socket =
444 BluetoothSocketChromeOS::CreateBluetoothSocket(
445 ui_task_runner_,
446 socket_thread_,
447 NULL,
448 net::NetLog::Source());
449 socket->Connect(this, uuid,
450 base::Bind(callback, socket),
451 error_callback);
452 }
453
CreateGattConnection(const GattConnectionCallback & callback,const ConnectErrorCallback & error_callback)454 void BluetoothDeviceChromeOS::CreateGattConnection(
455 const GattConnectionCallback& callback,
456 const ConnectErrorCallback& error_callback) {
457 // TODO(armansito): Until there is a way to create a reference counted GATT
458 // connection in bluetoothd, simply do a regular connect.
459 Connect(NULL,
460 base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection,
461 weak_ptr_factory_.GetWeakPtr(),
462 callback),
463 error_callback);
464 }
465
StartConnectionMonitor(const base::Closure & callback,const ErrorCallback & error_callback)466 void BluetoothDeviceChromeOS::StartConnectionMonitor(
467 const base::Closure& callback,
468 const ErrorCallback& error_callback) {
469 DBusThreadManager::Get()->GetBluetoothDeviceClient()->StartConnectionMonitor(
470 object_path_,
471 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitor,
472 weak_ptr_factory_.GetWeakPtr(),
473 callback),
474 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitorError,
475 weak_ptr_factory_.GetWeakPtr(),
476 error_callback));
477 }
478
BeginPairing(BluetoothDevice::PairingDelegate * pairing_delegate)479 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
480 BluetoothDevice::PairingDelegate* pairing_delegate) {
481 pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
482 return pairing_.get();
483 }
484
EndPairing()485 void BluetoothDeviceChromeOS::EndPairing() {
486 pairing_.reset();
487 }
488
GetPairing() const489 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
490 return pairing_.get();
491 }
492
GattServiceAdded(const dbus::ObjectPath & object_path)493 void BluetoothDeviceChromeOS::GattServiceAdded(
494 const dbus::ObjectPath& object_path) {
495 if (GetGattService(object_path.value())) {
496 VLOG(1) << "Remote GATT service already exists: " << object_path.value();
497 return;
498 }
499
500 BluetoothGattServiceClient::Properties* properties =
501 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
502 GetProperties(object_path);
503 DCHECK(properties);
504 if (properties->device.value() != object_path_) {
505 VLOG(2) << "Remote GATT service does not belong to this device.";
506 return;
507 }
508
509 VLOG(1) << "Adding new remote GATT service for device: " << GetAddress();
510
511 BluetoothRemoteGattServiceChromeOS* service =
512 new BluetoothRemoteGattServiceChromeOS(adapter_, this, object_path);
513
514 gatt_services_[service->GetIdentifier()] = service;
515 DCHECK(service->object_path() == object_path);
516 DCHECK(service->GetUUID().IsValid());
517
518 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
519 GattServiceAdded(this, service));
520 }
521
GattServiceRemoved(const dbus::ObjectPath & object_path)522 void BluetoothDeviceChromeOS::GattServiceRemoved(
523 const dbus::ObjectPath& object_path) {
524 GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
525 if (iter == gatt_services_.end()) {
526 VLOG(2) << "Unknown GATT service removed: " << object_path.value();
527 return;
528 }
529
530 VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
531
532 BluetoothRemoteGattServiceChromeOS* service =
533 static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
534 DCHECK(service->object_path() == object_path);
535 gatt_services_.erase(iter);
536 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
537 GattServiceRemoved(this, service));
538 delete service;
539 }
540
ConnectInternal(bool after_pairing,const base::Closure & callback,const ConnectErrorCallback & error_callback)541 void BluetoothDeviceChromeOS::ConnectInternal(
542 bool after_pairing,
543 const base::Closure& callback,
544 const ConnectErrorCallback& error_callback) {
545 VLOG(1) << object_path_.value() << ": Connecting";
546 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
547 Connect(
548 object_path_,
549 base::Bind(&BluetoothDeviceChromeOS::OnConnect,
550 weak_ptr_factory_.GetWeakPtr(),
551 after_pairing,
552 callback),
553 base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
554 weak_ptr_factory_.GetWeakPtr(),
555 after_pairing,
556 error_callback));
557 }
558
OnConnect(bool after_pairing,const base::Closure & callback)559 void BluetoothDeviceChromeOS::OnConnect(bool after_pairing,
560 const base::Closure& callback) {
561 if (--num_connecting_calls_ == 0)
562 adapter_->NotifyDeviceChanged(this);
563
564 DCHECK(num_connecting_calls_ >= 0);
565 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
566 << " still in progress";
567
568 SetTrusted();
569
570 if (after_pairing)
571 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
572 UMA_PAIRING_RESULT_SUCCESS,
573 UMA_PAIRING_RESULT_COUNT);
574
575 callback.Run();
576 }
577
OnCreateGattConnection(const GattConnectionCallback & callback)578 void BluetoothDeviceChromeOS::OnCreateGattConnection(
579 const GattConnectionCallback& callback) {
580 scoped_ptr<device::BluetoothGattConnection> conn(
581 new BluetoothGattConnectionChromeOS(
582 adapter_, GetAddress(), object_path_));
583 callback.Run(conn.Pass());
584 }
585
OnConnectError(bool after_pairing,const ConnectErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)586 void BluetoothDeviceChromeOS::OnConnectError(
587 bool after_pairing,
588 const ConnectErrorCallback& error_callback,
589 const std::string& error_name,
590 const std::string& error_message) {
591 if (--num_connecting_calls_ == 0)
592 adapter_->NotifyDeviceChanged(this);
593
594 DCHECK(num_connecting_calls_ >= 0);
595 LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
596 << error_name << ": " << error_message;
597 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
598 << " still in progress";
599
600 // Determine the error code from error_name.
601 ConnectErrorCode error_code = ERROR_UNKNOWN;
602 if (error_name == bluetooth_device::kErrorFailed) {
603 error_code = ERROR_FAILED;
604 } else if (error_name == bluetooth_device::kErrorInProgress) {
605 error_code = ERROR_INPROGRESS;
606 } else if (error_name == bluetooth_device::kErrorNotSupported) {
607 error_code = ERROR_UNSUPPORTED_DEVICE;
608 }
609
610 if (after_pairing)
611 RecordPairingResult(error_code);
612 error_callback.Run(error_code);
613 }
614
OnPair(const base::Closure & callback,const ConnectErrorCallback & error_callback)615 void BluetoothDeviceChromeOS::OnPair(
616 const base::Closure& callback,
617 const ConnectErrorCallback& error_callback) {
618 VLOG(1) << object_path_.value() << ": Paired";
619
620 EndPairing();
621
622 ConnectInternal(true, callback, error_callback);
623 }
624
OnPairError(const ConnectErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)625 void BluetoothDeviceChromeOS::OnPairError(
626 const ConnectErrorCallback& error_callback,
627 const std::string& error_name,
628 const std::string& error_message) {
629 if (--num_connecting_calls_ == 0)
630 adapter_->NotifyDeviceChanged(this);
631
632 DCHECK(num_connecting_calls_ >= 0);
633 LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
634 << error_name << ": " << error_message;
635 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
636 << " still in progress";
637
638 EndPairing();
639
640 // Determine the error code from error_name.
641 ConnectErrorCode error_code = ERROR_UNKNOWN;
642 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
643 error_code = ERROR_FAILED;
644 } else if (error_name == bluetooth_device::kErrorFailed) {
645 error_code = ERROR_FAILED;
646 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
647 error_code = ERROR_AUTH_FAILED;
648 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
649 error_code = ERROR_AUTH_CANCELED;
650 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
651 error_code = ERROR_AUTH_REJECTED;
652 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
653 error_code = ERROR_AUTH_TIMEOUT;
654 }
655
656 RecordPairingResult(error_code);
657 error_callback.Run(error_code);
658 }
659
OnCancelPairingError(const std::string & error_name,const std::string & error_message)660 void BluetoothDeviceChromeOS::OnCancelPairingError(
661 const std::string& error_name,
662 const std::string& error_message) {
663 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
664 << error_name << ": " << error_message;
665 }
666
SetTrusted()667 void BluetoothDeviceChromeOS::SetTrusted() {
668 // Unconditionally send the property change, rather than checking the value
669 // first; there's no harm in doing this and it solves any race conditions
670 // with the property becoming true or false and this call happening before
671 // we get the D-Bus signal about the earlier change.
672 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
673 GetProperties(object_path_)->trusted.Set(
674 true,
675 base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
676 weak_ptr_factory_.GetWeakPtr()));
677 }
678
OnSetTrusted(bool success)679 void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
680 LOG_IF(WARNING, !success) << object_path_.value()
681 << ": Failed to set device as trusted";
682 }
683
OnStartConnectionMonitor(const base::Closure & callback)684 void BluetoothDeviceChromeOS::OnStartConnectionMonitor(
685 const base::Closure& callback) {
686 connection_monitor_started_ = true;
687 callback.Run();
688 }
689
OnStartConnectionMonitorError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)690 void BluetoothDeviceChromeOS::OnStartConnectionMonitorError(
691 const ErrorCallback& error_callback,
692 const std::string& error_name,
693 const std::string& error_message) {
694 LOG(WARNING) << object_path_.value()
695 << ": Failed to start connection monitor: " << error_name << ": "
696 << error_message;
697 error_callback.Run();
698 }
699
OnDisconnect(const base::Closure & callback)700 void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
701 VLOG(1) << object_path_.value() << ": Disconnected";
702 callback.Run();
703 }
704
OnDisconnectError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)705 void BluetoothDeviceChromeOS::OnDisconnectError(
706 const ErrorCallback& error_callback,
707 const std::string& error_name,
708 const std::string& error_message) {
709 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
710 << error_name << ": " << error_message;
711 error_callback.Run();
712 }
713
OnForgetError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)714 void BluetoothDeviceChromeOS::OnForgetError(
715 const ErrorCallback& error_callback,
716 const std::string& error_name,
717 const std::string& error_message) {
718 LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
719 << error_name << ": " << error_message;
720 error_callback.Run();
721 }
722
723 } // namespace chromeos
724