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