bluetooth_device_chromeos.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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
30using device::BluetoothDevice;
31using device::BluetoothSocket;
32using device::BluetoothUUID;
33
34namespace {
35
36// Histogram enumerations for pairing results.
37enum 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
52void 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
86void 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
121namespace chromeos {
122
123BluetoothDeviceChromeOS::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
146BluetoothDeviceChromeOS::~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
162void BluetoothDeviceChromeOS::AddObserver(
163    device::BluetoothDevice::Observer* observer) {
164  DCHECK(observer);
165  observers_.AddObserver(observer);
166}
167
168void BluetoothDeviceChromeOS::RemoveObserver(
169    device::BluetoothDevice::Observer* observer) {
170  DCHECK(observer);
171  observers_.RemoveObserver(observer);
172}
173
174uint32 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
183std::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
192std::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
201BluetoothDevice::VendorIDSource
202BluetoothDeviceChromeOS::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
208uint16 BluetoothDeviceChromeOS::GetVendorID() const {
209  uint16 vendor_id  = 0;
210  ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
211  return vendor_id;
212}
213
214uint16 BluetoothDeviceChromeOS::GetProductID() const {
215  uint16 product_id  = 0;
216  ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
217  return product_id;
218}
219
220uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
221  uint16 device_id  = 0;
222  ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
223  return device_id;
224}
225
226int 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
241int 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
252int 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
262bool 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
274bool 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
283bool 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
295bool BluetoothDeviceChromeOS::IsConnecting() const {
296  return num_connecting_calls_ > 0;
297}
298
299BluetoothDeviceChromeOS::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
316bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
317  return pairing_.get() && pairing_->ExpectingPinCode();
318}
319
320bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
321  return pairing_.get() && pairing_->ExpectingPasskey();
322}
323
324bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
325  return pairing_.get() && pairing_->ExpectingConfirmation();
326}
327
328void 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
356void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
357  if (!pairing_.get())
358    return;
359
360  pairing_->SetPinCode(pincode);
361}
362
363void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
364  if (!pairing_.get())
365    return;
366
367  pairing_->SetPasskey(passkey);
368}
369
370void BluetoothDeviceChromeOS::ConfirmPairing() {
371  if (!pairing_.get())
372    return;
373
374  pairing_->ConfirmPairing();
375}
376
377void BluetoothDeviceChromeOS::RejectPairing() {
378  if (!pairing_.get())
379    return;
380
381  pairing_->RejectPairing();
382}
383
384void 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
411void 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
425void 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
437void 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
454void 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
466void 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
479BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
480    BluetoothDevice::PairingDelegate* pairing_delegate) {
481  pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
482  return pairing_.get();
483}
484
485void BluetoothDeviceChromeOS::EndPairing() {
486  pairing_.reset();
487}
488
489BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
490  return pairing_.get();
491}
492
493void 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(this, object_path);
513  gatt_services_[service->GetIdentifier()] = service;
514  DCHECK(service->object_path() == object_path);
515  DCHECK(service->GetUUID().IsValid());
516
517  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
518                    GattServiceAdded(this, service));
519}
520
521void BluetoothDeviceChromeOS::GattServiceRemoved(
522    const dbus::ObjectPath& object_path) {
523  GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
524  if (iter == gatt_services_.end()) {
525    VLOG(2) << "Unknown GATT service removed: " << object_path.value();
526    return;
527  }
528
529  VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
530
531  BluetoothRemoteGattServiceChromeOS* service =
532      static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
533  DCHECK(service->object_path() == object_path);
534  gatt_services_.erase(iter);
535  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
536                    GattServiceRemoved(this, service));
537  delete service;
538}
539
540void BluetoothDeviceChromeOS::ConnectInternal(
541    bool after_pairing,
542    const base::Closure& callback,
543    const ConnectErrorCallback& error_callback) {
544  VLOG(1) << object_path_.value() << ": Connecting";
545  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
546      Connect(
547          object_path_,
548          base::Bind(&BluetoothDeviceChromeOS::OnConnect,
549                     weak_ptr_factory_.GetWeakPtr(),
550                     after_pairing,
551                     callback),
552          base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
553                     weak_ptr_factory_.GetWeakPtr(),
554                     after_pairing,
555                     error_callback));
556}
557
558void BluetoothDeviceChromeOS::OnConnect(bool after_pairing,
559                                        const base::Closure& callback) {
560  if (--num_connecting_calls_ == 0)
561    adapter_->NotifyDeviceChanged(this);
562
563  DCHECK(num_connecting_calls_ >= 0);
564  VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
565        << " still in progress";
566
567  SetTrusted();
568
569  if (after_pairing)
570    UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
571                              UMA_PAIRING_RESULT_SUCCESS,
572                              UMA_PAIRING_RESULT_COUNT);
573
574  callback.Run();
575}
576
577void BluetoothDeviceChromeOS::OnCreateGattConnection(
578    const GattConnectionCallback& callback) {
579  scoped_ptr<device::BluetoothGattConnection> conn(
580      new BluetoothGattConnectionChromeOS(
581          adapter_, GetAddress(), object_path_));
582  callback.Run(conn.Pass());
583}
584
585void BluetoothDeviceChromeOS::OnConnectError(
586    bool after_pairing,
587    const ConnectErrorCallback& error_callback,
588    const std::string& error_name,
589    const std::string& error_message) {
590  if (--num_connecting_calls_ == 0)
591    adapter_->NotifyDeviceChanged(this);
592
593  DCHECK(num_connecting_calls_ >= 0);
594  LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
595               << error_name << ": " << error_message;
596  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
597          << " still in progress";
598
599  // Determine the error code from error_name.
600  ConnectErrorCode error_code = ERROR_UNKNOWN;
601  if (error_name == bluetooth_device::kErrorFailed) {
602    error_code = ERROR_FAILED;
603  } else if (error_name == bluetooth_device::kErrorInProgress) {
604    error_code = ERROR_INPROGRESS;
605  } else if (error_name == bluetooth_device::kErrorNotSupported) {
606    error_code = ERROR_UNSUPPORTED_DEVICE;
607  }
608
609  if (after_pairing)
610    RecordPairingResult(error_code);
611  error_callback.Run(error_code);
612}
613
614void BluetoothDeviceChromeOS::OnPair(
615    const base::Closure& callback,
616    const ConnectErrorCallback& error_callback) {
617  VLOG(1) << object_path_.value() << ": Paired";
618
619  EndPairing();
620
621  ConnectInternal(true, callback, error_callback);
622}
623
624void BluetoothDeviceChromeOS::OnPairError(
625    const ConnectErrorCallback& error_callback,
626    const std::string& error_name,
627    const std::string& error_message) {
628  if (--num_connecting_calls_ == 0)
629    adapter_->NotifyDeviceChanged(this);
630
631  DCHECK(num_connecting_calls_ >= 0);
632  LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
633               << error_name << ": " << error_message;
634  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
635          << " still in progress";
636
637  EndPairing();
638
639  // Determine the error code from error_name.
640  ConnectErrorCode error_code = ERROR_UNKNOWN;
641  if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
642    error_code = ERROR_FAILED;
643  } else if (error_name == bluetooth_device::kErrorFailed) {
644    error_code = ERROR_FAILED;
645  } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
646    error_code = ERROR_AUTH_FAILED;
647  } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
648    error_code = ERROR_AUTH_CANCELED;
649  } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
650    error_code = ERROR_AUTH_REJECTED;
651  } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
652    error_code = ERROR_AUTH_TIMEOUT;
653  }
654
655  RecordPairingResult(error_code);
656  error_callback.Run(error_code);
657}
658
659void BluetoothDeviceChromeOS::OnCancelPairingError(
660    const std::string& error_name,
661    const std::string& error_message) {
662  LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
663               << error_name << ": " << error_message;
664}
665
666void BluetoothDeviceChromeOS::SetTrusted() {
667  // Unconditionally send the property change, rather than checking the value
668  // first; there's no harm in doing this and it solves any race conditions
669  // with the property becoming true or false and this call happening before
670  // we get the D-Bus signal about the earlier change.
671  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
672      GetProperties(object_path_)->trusted.Set(
673          true,
674          base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
675                     weak_ptr_factory_.GetWeakPtr()));
676}
677
678void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
679  LOG_IF(WARNING, !success) << object_path_.value()
680                            << ": Failed to set device as trusted";
681}
682
683void BluetoothDeviceChromeOS::OnStartConnectionMonitor(
684    const base::Closure& callback) {
685  connection_monitor_started_ = true;
686  callback.Run();
687}
688
689void BluetoothDeviceChromeOS::OnStartConnectionMonitorError(
690    const ErrorCallback& error_callback,
691    const std::string& error_name,
692    const std::string& error_message) {
693  LOG(WARNING) << object_path_.value()
694               << ": Failed to start connection monitor: " << error_name << ": "
695               << error_message;
696  error_callback.Run();
697}
698
699void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
700  VLOG(1) << object_path_.value() << ": Disconnected";
701  callback.Run();
702}
703
704void BluetoothDeviceChromeOS::OnDisconnectError(
705    const ErrorCallback& error_callback,
706    const std::string& error_name,
707    const std::string& error_message) {
708  LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
709               << error_name << ": " << error_message;
710  error_callback.Run();
711}
712
713void BluetoothDeviceChromeOS::OnForgetError(
714    const ErrorCallback& error_callback,
715    const std::string& error_name,
716    const std::string& error_message) {
717  LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
718               << error_name << ": " << error_message;
719  error_callback.Run();
720}
721
722}  // namespace chromeos
723