bluetooth_device_chromeos.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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::ConnectToProfile(
391    device::BluetoothProfile* profile,
392    const base::Closure& callback,
393    const ConnectToProfileErrorCallback& error_callback) {
394  BluetoothProfileChromeOS* profile_chromeos =
395      static_cast<BluetoothProfileChromeOS*>(profile);
396  VLOG(1) << object_path_.value() << ": Connecting profile: "
397          << profile_chromeos->uuid().canonical_value();
398  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
399      ConnectProfile(
400          object_path_,
401          profile_chromeos->uuid().canonical_value(),
402          base::Bind(
403              &BluetoothDeviceChromeOS::OnConnectProfile,
404              weak_ptr_factory_.GetWeakPtr(),
405              profile,
406              callback),
407          base::Bind(
408              &BluetoothDeviceChromeOS::OnConnectProfileError,
409              weak_ptr_factory_.GetWeakPtr(),
410              profile,
411              error_callback));
412}
413
414void BluetoothDeviceChromeOS::SetOutOfBandPairingData(
415    const device::BluetoothOutOfBandPairingData& data,
416    const base::Closure& callback,
417    const ErrorCallback& error_callback) {
418  // TODO(keybuk): implement
419  error_callback.Run();
420}
421
422void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
423    const base::Closure& callback,
424    const ErrorCallback& error_callback) {
425  // TODO(keybuk): implement
426  error_callback.Run();
427}
428
429BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
430    BluetoothDevice::PairingDelegate* pairing_delegate) {
431  pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
432  return pairing_.get();
433}
434
435void BluetoothDeviceChromeOS::EndPairing() {
436  pairing_.reset();
437}
438
439BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
440  return pairing_.get();
441}
442
443void BluetoothDeviceChromeOS::GattServiceAdded(
444    const dbus::ObjectPath& object_path) {
445  if (GetGattService(object_path.value())) {
446    VLOG(1) << "Remote GATT service already exists: " << object_path.value();
447    return;
448  }
449
450  BluetoothGattServiceClient::Properties* properties =
451      DBusThreadManager::Get()->GetBluetoothGattServiceClient()->
452          GetProperties(object_path);
453  DCHECK(properties);
454  if (properties->device.value() != object_path_) {
455    VLOG(2) << "Remote GATT service does not belong to this device.";
456    return;
457  }
458
459  VLOG(1) << "Adding new remote GATT service for device: " << GetAddress();
460
461  BluetoothRemoteGattServiceChromeOS* service =
462      new BluetoothRemoteGattServiceChromeOS(this, object_path);
463  gatt_services_[service->GetIdentifier()] = service;
464  DCHECK(service->object_path() == object_path);
465  DCHECK(service->GetUUID().IsValid());
466
467  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
468                    GattServiceAdded(this, service));
469}
470
471void BluetoothDeviceChromeOS::GattServiceRemoved(
472    const dbus::ObjectPath& object_path) {
473  GattServiceMap::iterator iter = gatt_services_.find(object_path.value());
474  if (iter == gatt_services_.end()) {
475    VLOG(2) << "Unknown GATT service removed: " << object_path.value();
476    return;
477  }
478
479  VLOG(1) << "Removing remote GATT service from device: " << GetAddress();
480
481  BluetoothRemoteGattServiceChromeOS* service =
482      static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second);
483  DCHECK(service->object_path() == object_path);
484  gatt_services_.erase(iter);
485  FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_,
486                    GattServiceRemoved(this, service));
487  delete service;
488}
489
490void BluetoothDeviceChromeOS::ConnectInternal(
491    bool after_pairing,
492    const base::Closure& callback,
493    const ConnectErrorCallback& error_callback) {
494  VLOG(1) << object_path_.value() << ": Connecting";
495  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
496      Connect(
497          object_path_,
498          base::Bind(&BluetoothDeviceChromeOS::OnConnect,
499                     weak_ptr_factory_.GetWeakPtr(),
500                     after_pairing,
501                     callback),
502          base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
503                     weak_ptr_factory_.GetWeakPtr(),
504                     after_pairing,
505                     error_callback));
506}
507
508void BluetoothDeviceChromeOS::OnConnect(bool after_pairing,
509                                        const base::Closure& callback) {
510  if (--num_connecting_calls_ == 0)
511    adapter_->NotifyDeviceChanged(this);
512
513  DCHECK(num_connecting_calls_ >= 0);
514  VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
515        << " still in progress";
516
517  SetTrusted();
518
519  if (after_pairing)
520    UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
521                              UMA_PAIRING_RESULT_SUCCESS,
522                              UMA_PAIRING_RESULT_COUNT);
523
524  callback.Run();
525}
526
527void BluetoothDeviceChromeOS::OnConnectError(
528    bool after_pairing,
529    const ConnectErrorCallback& error_callback,
530    const std::string& error_name,
531    const std::string& error_message) {
532  if (--num_connecting_calls_ == 0)
533    adapter_->NotifyDeviceChanged(this);
534
535  DCHECK(num_connecting_calls_ >= 0);
536  LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
537               << error_name << ": " << error_message;
538  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
539          << " still in progress";
540
541  // Determine the error code from error_name.
542  ConnectErrorCode error_code = ERROR_UNKNOWN;
543  if (error_name == bluetooth_device::kErrorFailed) {
544    error_code = ERROR_FAILED;
545  } else if (error_name == bluetooth_device::kErrorInProgress) {
546    error_code = ERROR_INPROGRESS;
547  } else if (error_name == bluetooth_device::kErrorNotSupported) {
548    error_code = ERROR_UNSUPPORTED_DEVICE;
549  }
550
551  if (after_pairing)
552    RecordPairingResult(error_code);
553  error_callback.Run(error_code);
554}
555
556void BluetoothDeviceChromeOS::OnPair(
557    const base::Closure& callback,
558    const ConnectErrorCallback& error_callback) {
559  VLOG(1) << object_path_.value() << ": Paired";
560
561  EndPairing();
562
563  ConnectInternal(true, callback, error_callback);
564}
565
566void BluetoothDeviceChromeOS::OnPairError(
567    const ConnectErrorCallback& error_callback,
568    const std::string& error_name,
569    const std::string& error_message) {
570  if (--num_connecting_calls_ == 0)
571    adapter_->NotifyDeviceChanged(this);
572
573  DCHECK(num_connecting_calls_ >= 0);
574  LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
575               << error_name << ": " << error_message;
576  VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
577          << " still in progress";
578
579  EndPairing();
580
581  // Determine the error code from error_name.
582  ConnectErrorCode error_code = ERROR_UNKNOWN;
583  if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
584    error_code = ERROR_FAILED;
585  } else if (error_name == bluetooth_device::kErrorFailed) {
586    error_code = ERROR_FAILED;
587  } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
588    error_code = ERROR_AUTH_FAILED;
589  } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
590    error_code = ERROR_AUTH_CANCELED;
591  } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
592    error_code = ERROR_AUTH_REJECTED;
593  } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
594    error_code = ERROR_AUTH_TIMEOUT;
595  }
596
597  RecordPairingResult(error_code);
598  error_callback.Run(error_code);
599}
600
601void BluetoothDeviceChromeOS::OnCancelPairingError(
602    const std::string& error_name,
603    const std::string& error_message) {
604  LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
605               << error_name << ": " << error_message;
606}
607
608void BluetoothDeviceChromeOS::SetTrusted() {
609  // Unconditionally send the property change, rather than checking the value
610  // first; there's no harm in doing this and it solves any race conditions
611  // with the property becoming true or false and this call happening before
612  // we get the D-Bus signal about the earlier change.
613  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
614      GetProperties(object_path_)->trusted.Set(
615          true,
616          base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
617                     weak_ptr_factory_.GetWeakPtr()));
618}
619
620void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
621  LOG_IF(WARNING, !success) << object_path_.value()
622                            << ": Failed to set device as trusted";
623}
624
625void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) {
626  VLOG(1) << object_path_.value() << ": Disconnected";
627  callback.Run();
628}
629
630void BluetoothDeviceChromeOS::OnDisconnectError(
631    const ErrorCallback& error_callback,
632    const std::string& error_name,
633    const std::string& error_message) {
634  LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
635               << error_name << ": " << error_message;
636  error_callback.Run();
637}
638
639void BluetoothDeviceChromeOS::OnForgetError(
640    const ErrorCallback& error_callback,
641    const std::string& error_name,
642    const std::string& error_message) {
643  LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
644               << error_name << ": " << error_message;
645  error_callback.Run();
646}
647
648void BluetoothDeviceChromeOS::OnConnectProfile(
649    device::BluetoothProfile* profile,
650    const base::Closure& callback) {
651  BluetoothProfileChromeOS* profile_chromeos =
652      static_cast<BluetoothProfileChromeOS*>(profile);
653  VLOG(1) << object_path_.value() << ": Profile connected: "
654          << profile_chromeos->uuid().canonical_value();
655  callback.Run();
656}
657
658void BluetoothDeviceChromeOS::OnConnectProfileError(
659    device::BluetoothProfile* profile,
660    const ConnectToProfileErrorCallback& error_callback,
661    const std::string& error_name,
662    const std::string& error_message) {
663  BluetoothProfileChromeOS* profile_chromeos =
664      static_cast<BluetoothProfileChromeOS*>(profile);
665  VLOG(1) << object_path_.value() << ": Profile connection failed: "
666          << profile_chromeos->uuid().canonical_value() << ": "
667          << error_name << ": " << error_message;
668  error_callback.Run(error_message);
669}
670
671}  // namespace chromeos
672