bluetooth_device_chromeos.cc revision 010d83a9304c5a91596085d917d248abff47903a
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_pairing_chromeos.h"
22#include "device/bluetooth/bluetooth_profile_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      ui_task_runner_(ui_task_runner),
132      socket_thread_(socket_thread),
133      weak_ptr_factory_(this) {
134  DBusThreadManager::Get()->GetBluetoothGattServiceClient()->AddObserver(this);
135
136  // Add all known GATT services.
137  const std::vector<dbus::ObjectPath> gatt_services =
138      DBusThreadManager::Get()->GetBluetoothGattServiceClient()->GetServices();
139  for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin();
140       it != gatt_services.end(); ++it) {
141    GattServiceAdded(*it);
142  }
143}
144
145BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
146  DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
147      RemoveObserver(this);
148
149  // Copy the GATT services list here and clear the original so that when we
150  // send GattServiceRemoved(), GetGattServices() returns no services.
151  GattServiceMap gatt_services = gatt_services_;
152  gatt_services_.clear();
153  for (GattServiceMap::iterator iter = gatt_services.begin();
154       iter != gatt_services.end(); ++iter) {
155    FOR_EACH_OBSERVER(BluetoothDevice::Observer, observers_,
156                      GattServiceRemoved(this, iter->second));
157    delete iter->second;
158  }
159}
160
161void BluetoothDeviceChromeOS::AddObserver(
162    device::BluetoothDevice::Observer* observer) {
163  DCHECK(observer);
164  observers_.AddObserver(observer);
165}
166
167void BluetoothDeviceChromeOS::RemoveObserver(
168    device::BluetoothDevice::Observer* observer) {
169  DCHECK(observer);
170  observers_.RemoveObserver(observer);
171}
172
173uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
174  BluetoothDeviceClient::Properties* properties =
175      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
176          GetProperties(object_path_);
177  DCHECK(properties);
178
179  return properties->bluetooth_class.value();
180}
181
182std::string BluetoothDeviceChromeOS::GetDeviceName() const {
183  BluetoothDeviceClient::Properties* properties =
184      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
185          GetProperties(object_path_);
186  DCHECK(properties);
187
188  return properties->alias.value();
189}
190
191std::string BluetoothDeviceChromeOS::GetAddress() const {
192  BluetoothDeviceClient::Properties* properties =
193      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
194          GetProperties(object_path_);
195  DCHECK(properties);
196
197  return properties->address.value();
198}
199
200BluetoothDevice::VendorIDSource
201BluetoothDeviceChromeOS::GetVendorIDSource() const {
202  VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN;
203  ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL);
204  return vendor_id_source;
205}
206
207uint16 BluetoothDeviceChromeOS::GetVendorID() const {
208  uint16 vendor_id  = 0;
209  ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
210  return vendor_id;
211}
212
213uint16 BluetoothDeviceChromeOS::GetProductID() const {
214  uint16 product_id  = 0;
215  ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
216  return product_id;
217}
218
219uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
220  uint16 device_id  = 0;
221  ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
222  return device_id;
223}
224
225int BluetoothDeviceChromeOS::GetRSSI() const {
226  NOTIMPLEMENTED();
227  return kUnknownPower;
228}
229
230int BluetoothDeviceChromeOS::GetCurrentHostTransmitPower() const {
231  NOTIMPLEMENTED();
232  return kUnknownPower;
233}
234
235int BluetoothDeviceChromeOS::GetMaximumHostTransmitPower() const {
236  NOTIMPLEMENTED();
237  return kUnknownPower;
238}
239
240bool BluetoothDeviceChromeOS::IsPaired() const {
241  BluetoothDeviceClient::Properties* properties =
242      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
243          GetProperties(object_path_);
244  DCHECK(properties);
245
246  // Trusted devices are devices that don't support pairing but that the
247  // user has explicitly connected; it makes no sense for UI purposes to
248  // treat them differently from each other.
249  return properties->paired.value() || properties->trusted.value();
250}
251
252bool BluetoothDeviceChromeOS::IsConnected() const {
253  BluetoothDeviceClient::Properties* properties =
254      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
255          GetProperties(object_path_);
256  DCHECK(properties);
257
258  return properties->connected.value();
259}
260
261bool BluetoothDeviceChromeOS::IsConnectable() const {
262  BluetoothInputClient::Properties* input_properties =
263      DBusThreadManager::Get()->GetBluetoothInputClient()->
264          GetProperties(object_path_);
265  // GetProperties returns NULL when the device does not implement the given
266  // interface. Non HID devices are normally connectable.
267  if (!input_properties)
268    return true;
269
270  return input_properties->reconnect_mode.value() != "device";
271}
272
273bool BluetoothDeviceChromeOS::IsConnecting() const {
274  return num_connecting_calls_ > 0;
275}
276
277BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const {
278  BluetoothDeviceClient::Properties* properties =
279      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
280          GetProperties(object_path_);
281  DCHECK(properties);
282
283  std::vector<device::BluetoothUUID> uuids;
284  const std::vector<std::string> &dbus_uuids = properties->uuids.value();
285  for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin();
286       iter != dbus_uuids.end(); ++iter) {
287    device::BluetoothUUID uuid(*iter);
288    DCHECK(uuid.IsValid());
289    uuids.push_back(uuid);
290  }
291  return uuids;
292}
293
294bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
295  return pairing_.get() && pairing_->ExpectingPinCode();
296}
297
298bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
299  return pairing_.get() && pairing_->ExpectingPasskey();
300}
301
302bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
303  return pairing_.get() && pairing_->ExpectingConfirmation();
304}
305
306void BluetoothDeviceChromeOS::Connect(
307    BluetoothDevice::PairingDelegate* pairing_delegate,
308    const base::Closure& callback,
309    const ConnectErrorCallback& error_callback) {
310  if (num_connecting_calls_++ == 0)
311    adapter_->NotifyDeviceChanged(this);
312
313  VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_
314          << " in progress";
315
316  if (IsPaired() || !pairing_delegate || !IsPairable()) {
317    // No need to pair, or unable to, skip straight to connection.
318    ConnectInternal(false, callback, error_callback);
319  } else {
320    // Initiate high-security connection with pairing.
321    BeginPairing(pairing_delegate);
322
323    DBusThreadManager::Get()->GetBluetoothDeviceClient()->
324        Pair(object_path_,
325             base::Bind(&BluetoothDeviceChromeOS::OnPair,
326                        weak_ptr_factory_.GetWeakPtr(),
327                        callback, error_callback),
328             base::Bind(&BluetoothDeviceChromeOS::OnPairError,
329                        weak_ptr_factory_.GetWeakPtr(),
330                        error_callback));
331  }
332}
333
334void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
335  if (!pairing_.get())
336    return;
337
338  pairing_->SetPinCode(pincode);
339}
340
341void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
342  if (!pairing_.get())
343    return;
344
345  pairing_->SetPasskey(passkey);
346}
347
348void BluetoothDeviceChromeOS::ConfirmPairing() {
349  if (!pairing_.get())
350    return;
351
352  pairing_->ConfirmPairing();
353}
354
355void BluetoothDeviceChromeOS::RejectPairing() {
356  if (!pairing_.get())
357    return;
358
359  pairing_->RejectPairing();
360}
361
362void BluetoothDeviceChromeOS::CancelPairing() {
363  bool canceled = false;
364
365  // If there is a callback in progress that we can reply to then use that
366  // to cancel the current pairing request.
367  if (pairing_.get() && pairing_->CancelPairing())
368    canceled = true;
369
370  // If not we have to send an explicit CancelPairing() to the device instead.
371  if (!canceled) {
372    VLOG(1) << object_path_.value() << ": No pairing context or callback. "
373            << "Sending explicit cancel";
374    DBusThreadManager::Get()->GetBluetoothDeviceClient()->
375        CancelPairing(
376            object_path_,
377            base::Bind(&base::DoNothing),
378            base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
379                       weak_ptr_factory_.GetWeakPtr()));
380  }
381
382  // Since there is no callback to this method it's possible that the pairing
383  // delegate is going to be freed before things complete (indeed it's
384  // documented that this is the method you should call while freeing the
385  // pairing delegate), so clear our the context holding on to it.
386  EndPairing();
387}
388
389void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
390                                         const ErrorCallback& error_callback) {
391  VLOG(1) << object_path_.value() << ": Disconnecting";
392  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
393      Disconnect(
394          object_path_,
395          base::Bind(&BluetoothDeviceChromeOS::OnDisconnect,
396                     weak_ptr_factory_.GetWeakPtr(),
397                     callback),
398          base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError,
399                     weak_ptr_factory_.GetWeakPtr(),
400                     error_callback));
401}
402
403void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
404  VLOG(1) << object_path_.value() << ": Removing device";
405  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
406      RemoveDevice(
407          adapter_->object_path_,
408          object_path_,
409          base::Bind(&base::DoNothing),
410          base::Bind(&BluetoothDeviceChromeOS::OnForgetError,
411                     weak_ptr_factory_.GetWeakPtr(),
412                     error_callback));
413}
414
415void BluetoothDeviceChromeOS::ConnectToProfile(
416    device::BluetoothProfile* profile,
417    const base::Closure& callback,
418    const ConnectToProfileErrorCallback& error_callback) {
419  BluetoothProfileChromeOS* profile_chromeos =
420      static_cast<BluetoothProfileChromeOS*>(profile);
421  VLOG(1) << object_path_.value() << ": Connecting profile: "
422          << profile_chromeos->uuid().canonical_value();
423  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
424      ConnectProfile(
425          object_path_,
426          profile_chromeos->uuid().canonical_value(),
427          base::Bind(
428              &BluetoothDeviceChromeOS::OnConnectProfile,
429              weak_ptr_factory_.GetWeakPtr(),
430              profile,
431              callback),
432          base::Bind(
433              &BluetoothDeviceChromeOS::OnConnectProfileError,
434              weak_ptr_factory_.GetWeakPtr(),
435              profile,
436              error_callback));
437}
438
439void BluetoothDeviceChromeOS::ConnectToService(
440    const BluetoothUUID& uuid,
441    const ConnectToServiceCallback& callback,
442    const ConnectToServiceErrorCallback& error_callback) {
443  // TODO(keybuk): implement
444  NOTIMPLEMENTED();
445}
446
447void BluetoothDeviceChromeOS::SetOutOfBandPairingData(
448    const device::BluetoothOutOfBandPairingData& data,
449    const base::Closure& callback,
450    const ErrorCallback& error_callback) {
451  // TODO(keybuk): implement
452  error_callback.Run();
453}
454
455void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
456    const base::Closure& callback,
457    const ErrorCallback& error_callback) {
458  // TODO(keybuk): implement
459  error_callback.Run();
460}
461
462BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
463    BluetoothDevice::PairingDelegate* pairing_delegate) {
464  pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
465  return pairing_.get();
466}
467
468void BluetoothDeviceChromeOS::EndPairing() {
469  pairing_.reset();
470}
471
472BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
473  return pairing_.get();
474}
475
476void BluetoothDeviceChromeOS::GattServiceAdded(
477    const dbus::ObjectPath& object_path) {
478  if (GetGattService(object_path.value())) {
479    VLOG(1) << "Remote GATT service already exists: " << object_path.value();
480    return;
481  }
482
483  BluetoothGattServiceClient::Properties* properties =
484      DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
485          GetProperties(object_path);
486  DCHECK(properties);
487  if (properties->device.value() != object_path_) {
488    VLOG(2) << "Remote GATT service does not belong to this device.";
489    return;
490  }
491
492  VLOG(1) << "Adding new remote GATT service for device: " << GetAddress();
493
494  BluetoothRemoteGattServiceChromeOS* service =
495      new BluetoothRemoteGattServiceChromeOS(this, object_path);
496  gatt_services_[service->GetIdentifier()] = service;
497  DCHECK(service->object_path() == object_path);
498  DCHECK(service->GetUUID().IsValid());
499
500  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
501                    GattServiceAdded(this, service));
502}
503
504void BluetoothDeviceChromeOS::GattServiceRemoved(
505    const dbus::ObjectPath& object_path) {
506  GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
507  if (iter == gatt_services_.end()) {
508    VLOG(2) << "Unknown GATT service removed: " << object_path.value();
509    return;
510  }
511
512  VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
513
514  BluetoothRemoteGattServiceChromeOS* service =
515      static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
516  DCHECK(service->object_path() == object_path);
517  gatt_services_.erase(iter);
518  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
519                    GattServiceRemoved(this, service));
520  delete service;
521}
522
523void BluetoothDeviceChromeOS::ConnectInternal(
524    bool after_pairing,
525    const base::Closure& callback,
526    const ConnectErrorCallback& error_callback) {
527  VLOG(1) << object_path_.value() << ": Connecting";
528  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
529      Connect(
530          object_path_,
531          base::Bind(&BluetoothDeviceChromeOS::OnConnect,
532                     weak_ptr_factory_.GetWeakPtr(),
533                     after_pairing,
534                     callback),
535          base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
536                     weak_ptr_factory_.GetWeakPtr(),
537                     after_pairing,
538                     error_callback));
539}
540
541void BluetoothDeviceChromeOS::OnConnect(bool after_pairing,
542                                        const base::Closure& callback) {
543  if (--num_connecting_calls_ == 0)
544    adapter_->NotifyDeviceChanged(this);
545
546  DCHECK(num_connecting_calls_ >= 0);
547  VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
548        << " still in progress";
549
550  SetTrusted();
551
552  if (after_pairing)
553    UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
554                              UMA_PAIRING_RESULT_SUCCESS,
555                              UMA_PAIRING_RESULT_COUNT);
556
557  callback.Run();
558}
559
560void BluetoothDeviceChromeOS::OnConnectError(
561    bool after_pairing,
562    const ConnectErrorCallback& error_callback,
563    const std::string& error_name,
564    const std::string& error_message) {
565  if (--num_connecting_calls_ == 0)
566    adapter_->NotifyDeviceChanged(this);
567
568  DCHECK(num_connecting_calls_ >= 0);
569  LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
570               << error_name << ": " << error_message;
571  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
572          << " still in progress";
573
574  // Determine the error code from error_name.
575  ConnectErrorCode error_code = ERROR_UNKNOWN;
576  if (error_name == bluetooth_device::kErrorFailed) {
577    error_code = ERROR_FAILED;
578  } else if (error_name == bluetooth_device::kErrorInProgress) {
579    error_code = ERROR_INPROGRESS;
580  } else if (error_name == bluetooth_device::kErrorNotSupported) {
581    error_code = ERROR_UNSUPPORTED_DEVICE;
582  }
583
584  if (after_pairing)
585    RecordPairingResult(error_code);
586  error_callback.Run(error_code);
587}
588
589void BluetoothDeviceChromeOS::OnPair(
590    const base::Closure& callback,
591    const ConnectErrorCallback& error_callback) {
592  VLOG(1) << object_path_.value() << ": Paired";
593
594  EndPairing();
595
596  ConnectInternal(true, callback, error_callback);
597}
598
599void BluetoothDeviceChromeOS::OnPairError(
600    const ConnectErrorCallback& error_callback,
601    const std::string& error_name,
602    const std::string& error_message) {
603  if (--num_connecting_calls_ == 0)
604    adapter_->NotifyDeviceChanged(this);
605
606  DCHECK(num_connecting_calls_ >= 0);
607  LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
608               << error_name << ": " << error_message;
609  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
610          << " still in progress";
611
612  EndPairing();
613
614  // Determine the error code from error_name.
615  ConnectErrorCode error_code = ERROR_UNKNOWN;
616  if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
617    error_code = ERROR_FAILED;
618  } else if (error_name == bluetooth_device::kErrorFailed) {
619    error_code = ERROR_FAILED;
620  } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
621    error_code = ERROR_AUTH_FAILED;
622  } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
623    error_code = ERROR_AUTH_CANCELED;
624  } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
625    error_code = ERROR_AUTH_REJECTED;
626  } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
627    error_code = ERROR_AUTH_TIMEOUT;
628  }
629
630  RecordPairingResult(error_code);
631  error_callback.Run(error_code);
632}
633
634void BluetoothDeviceChromeOS::OnCancelPairingError(
635    const std::string& error_name,
636    const std::string& error_message) {
637  LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
638               << error_name << ": " << error_message;
639}
640
641void BluetoothDeviceChromeOS::SetTrusted() {
642  // Unconditionally send the property change, rather than checking the value
643  // first; there's no harm in doing this and it solves any race conditions
644  // with the property becoming true or false and this call happening before
645  // we get the D-Bus signal about the earlier change.
646  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
647      GetProperties(object_path_)->trusted.Set(
648          true,
649          base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
650                     weak_ptr_factory_.GetWeakPtr()));
651}
652
653void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
654  LOG_IF(WARNING, !success) << object_path_.value()
655                            << ": Failed to set device as trusted";
656}
657
658void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
659  VLOG(1) << object_path_.value() << ": Disconnected";
660  callback.Run();
661}
662
663void BluetoothDeviceChromeOS::OnDisconnectError(
664    const ErrorCallback& error_callback,
665    const std::string& error_name,
666    const std::string& error_message) {
667  LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
668               << error_name << ": " << error_message;
669  error_callback.Run();
670}
671
672void BluetoothDeviceChromeOS::OnForgetError(
673    const ErrorCallback& error_callback,
674    const std::string& error_name,
675    const std::string& error_message) {
676  LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
677               << error_name << ": " << error_message;
678  error_callback.Run();
679}
680
681void BluetoothDeviceChromeOS::OnConnectProfile(
682    device::BluetoothProfile* profile,
683    const base::Closure& callback) {
684  BluetoothProfileChromeOS* profile_chromeos =
685      static_cast<BluetoothProfileChromeOS*>(profile);
686  VLOG(1) << object_path_.value() << ": Profile connected: "
687          << profile_chromeos->uuid().canonical_value();
688  callback.Run();
689}
690
691void BluetoothDeviceChromeOS::OnConnectProfileError(
692    device::BluetoothProfile* profile,
693    const ConnectToProfileErrorCallback& error_callback,
694    const std::string& error_name,
695    const std::string& error_message) {
696  BluetoothProfileChromeOS* profile_chromeos =
697      static_cast<BluetoothProfileChromeOS*>(profile);
698  VLOG(1) << object_path_.value() << ": Profile connection failed: "
699          << profile_chromeos->uuid().canonical_value() << ": "
700          << error_name << ": " << error_message;
701  error_callback.Run(error_message);
702}
703
704}  // namespace chromeos
705