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