• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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