Home | History | Annotate | Download | only in bluetooth
      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 
     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 
     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 
    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 
    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     DCHECK(adapter_);
    157     adapter_->NotifyGattServiceRemoved(
    158         static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second));
    159     delete iter->second;
    160   }
    161 }
    162 
    163 uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
    164   BluetoothDeviceClient::Properties* properties =
    165       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    166           GetProperties(object_path_);
    167   DCHECK(properties);
    168 
    169   return properties->bluetooth_class.value();
    170 }
    171 
    172 std::string BluetoothDeviceChromeOS::GetDeviceName() const {
    173   BluetoothDeviceClient::Properties* properties =
    174       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    175           GetProperties(object_path_);
    176   DCHECK(properties);
    177 
    178   return properties->alias.value();
    179 }
    180 
    181 std::string BluetoothDeviceChromeOS::GetAddress() const {
    182   BluetoothDeviceClient::Properties* properties =
    183       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    184           GetProperties(object_path_);
    185   DCHECK(properties);
    186 
    187   return CanonicalizeAddress(properties->address.value());
    188 }
    189 
    190 BluetoothDevice::VendorIDSource
    191 BluetoothDeviceChromeOS::GetVendorIDSource() const {
    192   VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN;
    193   ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL);
    194   return vendor_id_source;
    195 }
    196 
    197 uint16 BluetoothDeviceChromeOS::GetVendorID() const {
    198   uint16 vendor_id  = 0;
    199   ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
    200   return vendor_id;
    201 }
    202 
    203 uint16 BluetoothDeviceChromeOS::GetProductID() const {
    204   uint16 product_id  = 0;
    205   ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
    206   return product_id;
    207 }
    208 
    209 uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
    210   uint16 device_id  = 0;
    211   ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
    212   return device_id;
    213 }
    214 
    215 int BluetoothDeviceChromeOS::GetRSSI() const {
    216   BluetoothDeviceClient::Properties* properties =
    217       DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
    218           object_path_);
    219   DCHECK(properties);
    220 
    221   if (!IsConnected()) {
    222     NOTIMPLEMENTED();
    223     return kUnknownPower;
    224   }
    225 
    226   return connection_monitor_started_ ? properties->connection_rssi.value()
    227                                      : kUnknownPower;
    228 }
    229 
    230 int BluetoothDeviceChromeOS::GetCurrentHostTransmitPower() const {
    231   BluetoothDeviceClient::Properties* properties =
    232       DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
    233           object_path_);
    234   DCHECK(properties);
    235 
    236   return IsConnected() && connection_monitor_started_
    237              ? properties->connection_tx_power.value()
    238              : kUnknownPower;
    239 }
    240 
    241 int BluetoothDeviceChromeOS::GetMaximumHostTransmitPower() const {
    242   BluetoothDeviceClient::Properties* properties =
    243       DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties(
    244           object_path_);
    245   DCHECK(properties);
    246 
    247   return IsConnected() ? properties->connection_tx_power_max.value()
    248                        : kUnknownPower;
    249 }
    250 
    251 bool BluetoothDeviceChromeOS::IsPaired() const {
    252   BluetoothDeviceClient::Properties* properties =
    253       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    254           GetProperties(object_path_);
    255   DCHECK(properties);
    256 
    257   // Trusted devices are devices that don't support pairing but that the
    258   // user has explicitly connected; it makes no sense for UI purposes to
    259   // treat them differently from each other.
    260   return properties->paired.value() || properties->trusted.value();
    261 }
    262 
    263 bool BluetoothDeviceChromeOS::IsConnected() const {
    264   BluetoothDeviceClient::Properties* properties =
    265       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    266           GetProperties(object_path_);
    267   DCHECK(properties);
    268 
    269   return properties->connected.value();
    270 }
    271 
    272 bool BluetoothDeviceChromeOS::IsConnectable() const {
    273   BluetoothInputClient::Properties* input_properties =
    274       DBusThreadManager::Get()->GetBluetoothInputClient()->
    275           GetProperties(object_path_);
    276   // GetProperties returns NULL when the device does not implement the given
    277   // interface. Non HID devices are normally connectable.
    278   if (!input_properties)
    279     return true;
    280 
    281   return input_properties->reconnect_mode.value() != "device";
    282 }
    283 
    284 bool BluetoothDeviceChromeOS::IsConnecting() const {
    285   return num_connecting_calls_ > 0;
    286 }
    287 
    288 BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const {
    289   BluetoothDeviceClient::Properties* properties =
    290       DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    291           GetProperties(object_path_);
    292   DCHECK(properties);
    293 
    294   std::vector<device::BluetoothUUID> uuids;
    295   const std::vector<std::string> &dbus_uuids = properties->uuids.value();
    296   for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin();
    297        iter != dbus_uuids.end(); ++iter) {
    298     device::BluetoothUUID uuid(*iter);
    299     DCHECK(uuid.IsValid());
    300     uuids.push_back(uuid);
    301   }
    302   return uuids;
    303 }
    304 
    305 bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
    306   return pairing_.get() && pairing_->ExpectingPinCode();
    307 }
    308 
    309 bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
    310   return pairing_.get() && pairing_->ExpectingPasskey();
    311 }
    312 
    313 bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
    314   return pairing_.get() && pairing_->ExpectingConfirmation();
    315 }
    316 
    317 void BluetoothDeviceChromeOS::Connect(
    318     BluetoothDevice::PairingDelegate* pairing_delegate,
    319     const base::Closure& callback,
    320     const ConnectErrorCallback& error_callback) {
    321   if (num_connecting_calls_++ == 0)
    322     adapter_->NotifyDeviceChanged(this);
    323 
    324   VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_
    325           << " in progress";
    326 
    327   if (IsPaired() || !pairing_delegate || !IsPairable()) {
    328     // No need to pair, or unable to, skip straight to connection.
    329     ConnectInternal(false, callback, error_callback);
    330   } else {
    331     // Initiate high-security connection with pairing.
    332     BeginPairing(pairing_delegate);
    333 
    334     DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    335         Pair(object_path_,
    336              base::Bind(&BluetoothDeviceChromeOS::OnPair,
    337                         weak_ptr_factory_.GetWeakPtr(),
    338                         callback, error_callback),
    339              base::Bind(&BluetoothDeviceChromeOS::OnPairError,
    340                         weak_ptr_factory_.GetWeakPtr(),
    341                         error_callback));
    342   }
    343 }
    344 
    345 void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
    346   if (!pairing_.get())
    347     return;
    348 
    349   pairing_->SetPinCode(pincode);
    350 }
    351 
    352 void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
    353   if (!pairing_.get())
    354     return;
    355 
    356   pairing_->SetPasskey(passkey);
    357 }
    358 
    359 void BluetoothDeviceChromeOS::ConfirmPairing() {
    360   if (!pairing_.get())
    361     return;
    362 
    363   pairing_->ConfirmPairing();
    364 }
    365 
    366 void BluetoothDeviceChromeOS::RejectPairing() {
    367   if (!pairing_.get())
    368     return;
    369 
    370   pairing_->RejectPairing();
    371 }
    372 
    373 void BluetoothDeviceChromeOS::CancelPairing() {
    374   bool canceled = false;
    375 
    376   // If there is a callback in progress that we can reply to then use that
    377   // to cancel the current pairing request.
    378   if (pairing_.get() && pairing_->CancelPairing())
    379     canceled = true;
    380 
    381   // If not we have to send an explicit CancelPairing() to the device instead.
    382   if (!canceled) {
    383     VLOG(1) << object_path_.value() << ": No pairing context or callback. "
    384             << "Sending explicit cancel";
    385     DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    386         CancelPairing(
    387             object_path_,
    388             base::Bind(&base::DoNothing),
    389             base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
    390                        weak_ptr_factory_.GetWeakPtr()));
    391   }
    392 
    393   // Since there is no callback to this method it's possible that the pairing
    394   // delegate is going to be freed before things complete (indeed it's
    395   // documented that this is the method you should call while freeing the
    396   // pairing delegate), so clear our the context holding on to it.
    397   EndPairing();
    398 }
    399 
    400 void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
    401                                          const ErrorCallback& error_callback) {
    402   VLOG(1) << object_path_.value() << ": Disconnecting";
    403   DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    404       Disconnect(
    405           object_path_,
    406           base::Bind(&BluetoothDeviceChromeOS::OnDisconnect,
    407                      weak_ptr_factory_.GetWeakPtr(),
    408                      callback),
    409           base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError,
    410                      weak_ptr_factory_.GetWeakPtr(),
    411                      error_callback));
    412 }
    413 
    414 void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
    415   VLOG(1) << object_path_.value() << ": Removing device";
    416   DBusThreadManager::Get()->GetBluetoothAdapterClient()->
    417       RemoveDevice(
    418           adapter_->object_path(),
    419           object_path_,
    420           base::Bind(&base::DoNothing),
    421           base::Bind(&BluetoothDeviceChromeOS::OnForgetError,
    422                      weak_ptr_factory_.GetWeakPtr(),
    423                      error_callback));
    424 }
    425 
    426 void BluetoothDeviceChromeOS::ConnectToService(
    427     const BluetoothUUID& uuid,
    428     const ConnectToServiceCallback& callback,
    429     const ConnectToServiceErrorCallback& error_callback) {
    430   VLOG(1) << object_path_.value() << ": Connecting to service: "
    431           << uuid.canonical_value();
    432   scoped_refptr<BluetoothSocketChromeOS> socket =
    433       BluetoothSocketChromeOS::CreateBluetoothSocket(
    434           ui_task_runner_, socket_thread_);
    435   socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_MEDIUM,
    436                   base::Bind(callback, socket), error_callback);
    437 }
    438 
    439 void BluetoothDeviceChromeOS::ConnectToServiceInsecurely(
    440     const BluetoothUUID& uuid,
    441     const ConnectToServiceCallback& callback,
    442     const ConnectToServiceErrorCallback& error_callback) {
    443   VLOG(1) << object_path_.value() << ": Connecting insecurely to service: "
    444           << uuid.canonical_value();
    445   scoped_refptr<BluetoothSocketChromeOS> socket =
    446       BluetoothSocketChromeOS::CreateBluetoothSocket(
    447           ui_task_runner_, socket_thread_);
    448   socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_LOW,
    449                   base::Bind(callback, socket), error_callback);
    450 }
    451 
    452 void BluetoothDeviceChromeOS::CreateGattConnection(
    453       const GattConnectionCallback& callback,
    454       const ConnectErrorCallback& error_callback) {
    455   // TODO(armansito): Until there is a way to create a reference counted GATT
    456   // connection in bluetoothd, simply do a regular connect.
    457   Connect(NULL,
    458           base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection,
    459                      weak_ptr_factory_.GetWeakPtr(),
    460                      callback),
    461           error_callback);
    462 }
    463 
    464 void BluetoothDeviceChromeOS::StartConnectionMonitor(
    465     const base::Closure& callback,
    466     const ErrorCallback& error_callback) {
    467   DBusThreadManager::Get()->GetBluetoothDeviceClient()->StartConnectionMonitor(
    468       object_path_,
    469       base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitor,
    470                  weak_ptr_factory_.GetWeakPtr(),
    471                  callback),
    472       base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitorError,
    473                  weak_ptr_factory_.GetWeakPtr(),
    474                  error_callback));
    475 }
    476 
    477 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
    478     BluetoothDevice::PairingDelegate* pairing_delegate) {
    479   pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
    480   return pairing_.get();
    481 }
    482 
    483 void BluetoothDeviceChromeOS::EndPairing() {
    484   pairing_.reset();
    485 }
    486 
    487 BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
    488   return pairing_.get();
    489 }
    490 
    491 void BluetoothDeviceChromeOS::GattServiceAdded(
    492     const dbus::ObjectPath& object_path) {
    493   if (GetGattService(object_path.value())) {
    494     VLOG(1) << "Remote GATT service already exists: " << object_path.value();
    495     return;
    496   }
    497 
    498   BluetoothGattServiceClient::Properties* properties =
    499       DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
    500           GetProperties(object_path);
    501   DCHECK(properties);
    502   if (properties->device.value() != object_path_) {
    503     VLOG(2) << "Remote GATT service does not belong to this device.";
    504     return;
    505   }
    506 
    507   VLOG(1) << "Adding new remote GATT service for device: " << GetAddress();
    508 
    509   BluetoothRemoteGattServiceChromeOS* service =
    510       new BluetoothRemoteGattServiceChromeOS(adapter_, this, object_path);
    511 
    512   gatt_services_[service->GetIdentifier()] = service;
    513   DCHECK(service->object_path() == object_path);
    514   DCHECK(service->GetUUID().IsValid());
    515 
    516   DCHECK(adapter_);
    517   adapter_->NotifyGattServiceAdded(service);
    518 }
    519 
    520 void BluetoothDeviceChromeOS::GattServiceRemoved(
    521     const dbus::ObjectPath& object_path) {
    522   GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
    523   if (iter == gatt_services_.end()) {
    524     VLOG(3) << "Unknown GATT service removed: " << object_path.value();
    525     return;
    526   }
    527 
    528   VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
    529 
    530   BluetoothRemoteGattServiceChromeOS* service =
    531       static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
    532   DCHECK(service->object_path() == object_path);
    533   gatt_services_.erase(iter);
    534 
    535   DCHECK(adapter_);
    536   adapter_->NotifyGattServiceRemoved(service);
    537 
    538   delete service;
    539 }
    540 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    679 void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
    680   LOG_IF(WARNING, !success) << object_path_.value()
    681                             << ": Failed to set device as trusted";
    682 }
    683 
    684 void BluetoothDeviceChromeOS::OnStartConnectionMonitor(
    685     const base::Closure& callback) {
    686   connection_monitor_started_ = true;
    687   callback.Run();
    688 }
    689 
    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 
    700 void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
    701   VLOG(1) << object_path_.value() << ": Disconnected";
    702   callback.Run();
    703 }
    704 
    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 
    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