bluetooth_device_chromeos.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 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 <map>
8#include <string>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/command_line.h"
13#include "base/logging.h"
14#include "base/memory/scoped_vector.h"
15#include "base/memory/weak_ptr.h"
16#include "base/string16.h"
17#include "base/string_util.h"
18#include "base/values.h"
19#include "chromeos/dbus/bluetooth_adapter_client.h"
20#include "chromeos/dbus/bluetooth_agent_service_provider.h"
21#include "chromeos/dbus/bluetooth_device_client.h"
22#include "chromeos/dbus/bluetooth_input_client.h"
23#include "chromeos/dbus/bluetooth_out_of_band_client.h"
24#include "chromeos/dbus/dbus_thread_manager.h"
25#include "chromeos/dbus/introspectable_client.h"
26#include "dbus/bus.h"
27#include "dbus/object_path.h"
28#include "device/bluetooth/bluetooth_adapter_chromeos.h"
29#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
30#include "device/bluetooth/bluetooth_service_record.h"
31#include "device/bluetooth/bluetooth_service_record_chromeos.h"
32#include "device/bluetooth/bluetooth_socket_chromeos.h"
33#include "device/bluetooth/bluetooth_utils.h"
34#include "third_party/cros_system_api/dbus/service_constants.h"
35
36using device::BluetoothDevice;
37using device::BluetoothOutOfBandPairingData;
38using device::BluetoothServiceRecord;
39using device::BluetoothSocket;
40
41namespace {
42
43void DoNothingServiceRecordList(const BluetoothDevice::ServiceRecordList&) {}
44
45} // namespace
46
47namespace chromeos {
48
49BluetoothDeviceChromeOS::BluetoothDeviceChromeOS(
50    BluetoothAdapterChromeOS* adapter)
51    : BluetoothDevice(),
52      adapter_(adapter),
53      bluetooth_class_(0),
54      paired_(false),
55      trusted_(false),
56      connected_(false),
57      connectable_(true),
58      connecting_(false),
59      pairing_delegate_(NULL),
60      connecting_applications_counter_(0),
61      connecting_calls_(0),
62      service_records_loaded_(false),
63      weak_ptr_factory_(this) {
64}
65
66BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
67}
68
69uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
70  return bluetooth_class_;
71}
72
73std::string BluetoothDeviceChromeOS::GetDeviceName() const {
74  return name_;
75}
76
77std::string BluetoothDeviceChromeOS::GetAddress() const {
78  return address_;
79}
80
81uint16 BluetoothDeviceChromeOS::GetVendorID() const {
82  return 0;
83}
84
85uint16 BluetoothDeviceChromeOS::GetProductID() const {
86  return 0;
87}
88
89uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
90  return 0;
91}
92
93bool BluetoothDeviceChromeOS::IsPaired() const {
94  return paired_ || trusted_;
95}
96
97bool BluetoothDeviceChromeOS::IsConnected() const {
98  return connected_;
99}
100
101bool BluetoothDeviceChromeOS::IsConnectable() const {
102  return connectable_;
103}
104
105bool BluetoothDeviceChromeOS::IsConnecting() const {
106  return connecting_;
107}
108
109BluetoothDeviceChromeOS::ServiceList
110BluetoothDeviceChromeOS::GetServices() const {
111  return service_uuids_;
112}
113
114void BluetoothDeviceChromeOS::GetServiceRecords(
115    const ServiceRecordsCallback& callback,
116    const ErrorCallback& error_callback) {
117  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
118      DiscoverServices(
119          object_path_,
120          "",  // empty pattern to browse all services
121          base::Bind(&BluetoothDeviceChromeOS::CollectServiceRecordsCallback,
122                     weak_ptr_factory_.GetWeakPtr(),
123                     callback,
124                     base::Bind(
125                         &BluetoothDeviceChromeOS::OnGetServiceRecordsError,
126                         weak_ptr_factory_.GetWeakPtr(),
127                         callback,
128                         error_callback)));
129}
130
131void BluetoothDeviceChromeOS::ProvidesServiceWithName(
132    const std::string& name,
133    const ProvidesServiceCallback& callback) {
134  GetServiceRecords(
135      base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameCallback,
136                 weak_ptr_factory_.GetWeakPtr(),
137                 name,
138                 callback),
139      base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback,
140                 weak_ptr_factory_.GetWeakPtr(),
141                 callback));
142}
143
144bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
145  return !pincode_callback_.is_null();
146}
147
148bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
149  return !passkey_callback_.is_null();
150}
151
152bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
153  return !confirmation_callback_.is_null();
154}
155
156void BluetoothDeviceChromeOS::Connect(
157    PairingDelegate* pairing_delegate,
158    const base::Closure& callback,
159    const ConnectErrorCallback& error_callback) {
160  // This is safe because Connect() and its callbacks are called in the same
161  // thread.
162  connecting_calls_++;
163  if (!connecting_) {
164    connecting_ = true;
165    adapter_->NotifyDeviceChanged(this);
166  }
167  connecting_ = !!connecting_calls_;
168  // Set the decrement to be issued when either callback is called.
169  base::Closure wrapped_callback = base::Bind(
170      &BluetoothDeviceChromeOS::OnConnectCallbackCalled,
171      weak_ptr_factory_.GetWeakPtr(),
172      callback);
173  ConnectErrorCallback wrapped_error_callback = base::Bind(
174      &BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled,
175      weak_ptr_factory_.GetWeakPtr(),
176      error_callback);
177
178  if (IsPaired()) {
179    // Connection to already paired device.
180    ConnectApplications(wrapped_callback, wrapped_error_callback);
181
182  } else if (!pairing_delegate || !IsPairable()) {
183    // No pairing delegate supplied, or unpairable device; initiate
184    // low-security connection only.
185    DBusThreadManager::Get()->GetBluetoothAdapterClient()->
186        CreateDevice(adapter_->object_path_,
187                     address_,
188                     base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice,
189                                weak_ptr_factory_.GetWeakPtr(),
190                                wrapped_callback,
191                                wrapped_error_callback),
192                     base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError,
193                                weak_ptr_factory_.GetWeakPtr(),
194                                wrapped_error_callback));
195  } else {
196    // Initiate high-security connection with pairing.
197    DCHECK(!pairing_delegate_);
198    pairing_delegate_ = pairing_delegate;
199
200    // The agent path is relatively meaningless, we use the device address
201    // to generate it as we only support one pairing attempt at a time for
202    // a given bluetooth device.
203    DCHECK(agent_.get() == NULL);
204
205    std::string agent_path_basename;
206    ReplaceChars(address_, ":", "_", &agent_path_basename);
207    dbus::ObjectPath agent_path("/org/chromium/bluetooth_agent/" +
208                                agent_path_basename);
209
210    dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
211    if (system_bus) {
212      agent_.reset(BluetoothAgentServiceProvider::Create(system_bus,
213                                                         agent_path,
214                                                         this));
215    } else {
216      agent_.reset(NULL);
217    }
218
219    VLOG(1) << "Pairing: " << address_;
220    DBusThreadManager::Get()->GetBluetoothAdapterClient()->
221        CreatePairedDevice(
222            adapter_->object_path_,
223            address_,
224            agent_path,
225            bluetooth_agent::kDisplayYesNoCapability,
226            base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice,
227                       weak_ptr_factory_.GetWeakPtr(),
228                       wrapped_callback,
229                       wrapped_error_callback),
230            base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError,
231                       weak_ptr_factory_.GetWeakPtr(),
232                       wrapped_error_callback));
233  }
234}
235
236void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
237  if (!agent_.get() || pincode_callback_.is_null())
238    return;
239
240  pincode_callback_.Run(SUCCESS, pincode);
241  pincode_callback_.Reset();
242}
243
244void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
245  if (!agent_.get() || passkey_callback_.is_null())
246    return;
247
248  passkey_callback_.Run(SUCCESS, passkey);
249  passkey_callback_.Reset();
250}
251
252void BluetoothDeviceChromeOS::ConfirmPairing() {
253  if (!agent_.get() || confirmation_callback_.is_null())
254    return;
255
256  confirmation_callback_.Run(SUCCESS);
257  confirmation_callback_.Reset();
258}
259
260void BluetoothDeviceChromeOS::RejectPairing() {
261  if (!agent_.get())
262    return;
263
264  if (!pincode_callback_.is_null()) {
265    pincode_callback_.Run(REJECTED, "");
266    pincode_callback_.Reset();
267  }
268  if (!passkey_callback_.is_null()) {
269    passkey_callback_.Run(REJECTED, 0);
270    passkey_callback_.Reset();
271  }
272  if (!confirmation_callback_.is_null()) {
273    confirmation_callback_.Run(REJECTED);
274    confirmation_callback_.Reset();
275  }
276}
277
278void BluetoothDeviceChromeOS::CancelPairing() {
279  bool have_callback = false;
280  if (agent_.get()) {
281    if (!pincode_callback_.is_null()) {
282      pincode_callback_.Run(CANCELLED, "");
283      pincode_callback_.Reset();
284      have_callback = true;
285    }
286    if (!passkey_callback_.is_null()) {
287      passkey_callback_.Run(CANCELLED, 0);
288      passkey_callback_.Reset();
289      have_callback = true;
290    }
291    if (!confirmation_callback_.is_null()) {
292      confirmation_callback_.Run(CANCELLED);
293      confirmation_callback_.Reset();
294      have_callback = true;
295    }
296  }
297
298  if (!have_callback) {
299    // User cancels the pairing process.
300    DBusThreadManager::Get()->GetBluetoothAdapterClient()->CancelDeviceCreation(
301        adapter_->object_path_,
302        address_,
303        base::Bind(&BluetoothDeviceChromeOS::OnCancelDeviceCreation,
304                   weak_ptr_factory_.GetWeakPtr()));
305
306    pairing_delegate_ = NULL;
307    agent_.reset();
308  }
309}
310
311void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
312                                         const ErrorCallback& error_callback) {
313  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
314      Disconnect(object_path_,
315                 base::Bind(&BluetoothDeviceChromeOS::DisconnectCallback,
316                            weak_ptr_factory_.GetWeakPtr(),
317                            callback,
318                            error_callback));
319
320}
321
322void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
323  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
324      RemoveDevice(adapter_->object_path_,
325                   object_path_,
326                   base::Bind(&BluetoothDeviceChromeOS::ForgetCallback,
327                              weak_ptr_factory_.GetWeakPtr(),
328                              error_callback));
329}
330
331void BluetoothDeviceChromeOS::ConnectToService(const std::string& service_uuid,
332                                               const SocketCallback& callback) {
333  GetServiceRecords(
334      base::Bind(&BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback,
335                 weak_ptr_factory_.GetWeakPtr(),
336                 service_uuid,
337                 callback),
338      base::Bind(
339          &BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback,
340          weak_ptr_factory_.GetWeakPtr(),
341          callback));
342}
343
344void BluetoothDeviceChromeOS::ConnectToProfile(
345    device::BluetoothProfile* profile,
346    const base::Closure& callback,
347    const ErrorCallback& error_callback) {
348  // TODO(keybuk): implement
349}
350
351void BluetoothDeviceChromeOS::SetOutOfBandPairingData(
352    const BluetoothOutOfBandPairingData& data,
353    const base::Closure& callback,
354    const ErrorCallback& error_callback) {
355  DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
356      AddRemoteData(
357          object_path_,
358          address_,
359          data,
360          base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback,
361                     weak_ptr_factory_.GetWeakPtr(),
362                     callback,
363                     error_callback));
364}
365
366void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
367    const base::Closure& callback,
368    const ErrorCallback& error_callback) {
369  DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
370      RemoveRemoteData(
371          object_path_,
372          address_,
373          base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback,
374                     weak_ptr_factory_.GetWeakPtr(),
375                     callback,
376                     error_callback));
377}
378
379void BluetoothDeviceChromeOS::SetObjectPath(
380    const dbus::ObjectPath& object_path) {
381  DCHECK(object_path_ == dbus::ObjectPath(""));
382  object_path_ = object_path;
383}
384
385void BluetoothDeviceChromeOS::RemoveObjectPath() {
386  DCHECK(object_path_ != dbus::ObjectPath(""));
387  object_path_ = dbus::ObjectPath("");
388}
389
390void BluetoothDeviceChromeOS::Update(
391    const BluetoothDeviceClient::Properties* properties,
392    bool update_state) {
393  std::string address = properties->address.value();
394  std::string name = properties->name.value();
395  uint32 bluetooth_class = properties->bluetooth_class.value();
396  const std::vector<std::string>& uuids = properties->uuids.value();
397
398  if (!address.empty())
399    address_ = address;
400  if (!name.empty())
401    name_ = name;
402  if (bluetooth_class)
403    bluetooth_class_ = bluetooth_class;
404  if (!uuids.empty()) {
405    service_uuids_.clear();
406    service_uuids_.assign(uuids.begin(), uuids.end());
407  }
408
409  if (update_state) {
410    // When the device reconnects and we don't have any service records for it,
411    // try to update the cache or fail silently.
412    if (!service_records_loaded_ && !connected_ &&
413        properties->connected.value())
414      GetServiceRecords(base::Bind(&DoNothingServiceRecordList),
415                        base::Bind(&base::DoNothing));
416
417    paired_ = properties->paired.value();
418    trusted_ = properties->trusted.value();
419    connected_ = properties->connected.value();
420  }
421}
422
423void BluetoothDeviceChromeOS::OnCreateDevice(
424    const base::Closure& callback,
425    const ConnectErrorCallback& error_callback,
426    const dbus::ObjectPath& device_path) {
427  VLOG(1) << "Connection successful: " << device_path.value();
428  if (object_path_.value().empty()) {
429    object_path_ = device_path;
430  } else {
431    LOG_IF(WARNING, object_path_ != device_path)
432        << "Conflicting device paths for objects, result gave: "
433        << device_path.value() << " but signal gave: "
434        << object_path_.value();
435  }
436
437  SetTrusted();
438
439  // In parallel with the |trusted| property change, call GetServiceRecords to
440  // retrieve the SDP from the device and then, either on success or failure,
441  // call ConnectApplications.
442  GetServiceRecords(
443      base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecords,
444                 weak_ptr_factory_.GetWeakPtr(),
445                 callback,
446                 error_callback),
447      base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError,
448                 weak_ptr_factory_.GetWeakPtr(),
449                 callback,
450                 error_callback));
451}
452
453void BluetoothDeviceChromeOS::OnCreateDeviceError(
454    const ConnectErrorCallback& error_callback,
455    const std::string& error_name,
456    const std::string& error_message) {
457  // The default |error_code| is an unknown error.
458  ConnectErrorCode error_code = ERROR_UNKNOWN;
459
460  // Report any error in the log, even if we know the possible source of it.
461  LOG(WARNING) << "Connection failed (on CreatePairedDevice): "
462               << "\"" << name_ << "\" (" << address_ << "): "
463               << error_name << ": \"" << error_message << "\"";
464
465  // Determines the right error code from error_name, assuming the error name
466  // comes from CreatePairedDevice bluez function.
467  if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) {
468    error_code = ERROR_FAILED;
469  } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) {
470    error_code = ERROR_AUTH_FAILED;
471  } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) {
472    error_code = ERROR_AUTH_REJECTED;
473  } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) {
474    error_code = ERROR_AUTH_TIMEOUT;
475  }
476  error_callback.Run(error_code);
477}
478
479void BluetoothDeviceChromeOS::CollectServiceRecordsCallback(
480    const ServiceRecordsCallback& callback,
481    const ErrorCallback& error_callback,
482    const dbus::ObjectPath& device_path,
483    const BluetoothDeviceClient::ServiceMap& service_map,
484    bool success) {
485  if (!success) {
486    error_callback.Run();
487    return;
488  }
489
490  // Update the cache. No other thread is executing a GetServiceRecords
491  // callback, so it is safe to delete the previous objects here.
492  service_records_.clear();
493  // TODO(deymo): Perhaps don't update the cache if the new SDP information is
494  // empty and we had something before. Some devices only answer this
495  // information while paired, and this callback could be called in any order if
496  // several calls to GetServiceRecords are made while initial pairing with the
497  // device. This requires more investigation.
498  for (BluetoothDeviceClient::ServiceMap::const_iterator i =
499      service_map.begin(); i != service_map.end(); ++i) {
500    service_records_.push_back(
501        new BluetoothServiceRecordChromeOS(address_, i->second));
502  }
503  service_records_loaded_ = true;
504
505  callback.Run(service_records_);
506}
507
508void BluetoothDeviceChromeOS::SetTrusted() {
509  // Unconditionally send the property change, rather than checking the value
510  // first; there's no harm in doing this and it solves any race conditions
511  // with the property becoming true or false and this call happening before
512  // we get the D-Bus signal about the earlier change.
513  DBusThreadManager::Get()->GetBluetoothDeviceClient()->
514      GetProperties(object_path_)->trusted.Set(
515          true,
516          base::Bind(
517              &BluetoothDeviceChromeOS::OnSetTrusted,
518              weak_ptr_factory_.GetWeakPtr()));
519}
520
521void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
522  LOG_IF(WARNING, !success) << "Failed to set device as trusted: " << address_;
523}
524
525void BluetoothDeviceChromeOS::OnInitialGetServiceRecords(
526    const base::Closure& callback,
527    const ConnectErrorCallback& error_callback,
528    const ServiceRecordList& list) {
529  // Connect application-layer protocols.
530  ConnectApplications(callback, error_callback);
531}
532
533void BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError(
534    const base::Closure& callback,
535    const ConnectErrorCallback& error_callback) {
536  // Ignore the error retrieving the service records and continue.
537  LOG(WARNING) << "Error retrieving SDP for " << address_ << " after pairing.";
538  // Connect application-layer protocols.
539  ConnectApplications(callback, error_callback);
540}
541
542void BluetoothDeviceChromeOS::OnGetServiceRecordsError(
543    const ServiceRecordsCallback& callback,
544    const ErrorCallback& error_callback) {
545  if (service_records_loaded_) {
546    callback.Run(service_records_);
547  } else {
548    error_callback.Run();
549  }
550}
551
552void BluetoothDeviceChromeOS::OnConnectCallbackCalled(
553    const base::Closure& callback) {
554  // Update the connecting status.
555  bool prev_connecting = connecting_;
556  connecting_calls_--;
557  connecting_ = !!connecting_calls_;
558  callback.Run();
559  if (prev_connecting != connecting_) adapter_->NotifyDeviceChanged(this);
560}
561
562void BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled(
563    const ConnectErrorCallback& error_callback,
564    enum ConnectErrorCode error_code) {
565  // Update the connecting status.
566  bool prev_connecting = connecting_;
567  connecting_calls_--;
568  connecting_ = !!connecting_calls_;
569  error_callback.Run(error_code);
570  if (prev_connecting != connecting_) adapter_->NotifyDeviceChanged(this);
571}
572
573void BluetoothDeviceChromeOS::ConnectApplications(
574    const base::Closure& callback,
575    const ConnectErrorCallback& error_callback) {
576  // Introspect the device object to determine supported applications.
577  DBusThreadManager::Get()->GetIntrospectableClient()->
578      Introspect(bluetooth_device::kBluetoothDeviceServiceName,
579                 object_path_,
580                 base::Bind(&BluetoothDeviceChromeOS::OnIntrospect,
581                            weak_ptr_factory_.GetWeakPtr(),
582                            callback,
583                            error_callback));
584}
585
586void BluetoothDeviceChromeOS::OnIntrospect(
587    const base::Closure& callback,
588    const ConnectErrorCallback& error_callback,
589    const std::string& service_name,
590    const dbus::ObjectPath& device_path,
591    const std::string& xml_data,
592    bool success) {
593  if (!success) {
594    LOG(WARNING) << "Failed to determine supported applications: " << address_;
595    error_callback.Run(ERROR_UNKNOWN);
596    return;
597  }
598
599  // The introspection data for the device object may list one or more
600  // additional D-Bus interfaces that BlueZ supports for this particular
601  // device. Send appropraite Connect calls for each of those interfaces
602  // to connect all of the application protocols for this device.
603  std::vector<std::string> interfaces =
604      IntrospectableClient::GetInterfacesFromIntrospectResult(xml_data);
605
606  DCHECK_EQ(0, connecting_applications_counter_);
607  connecting_applications_counter_ = 0;
608  for (std::vector<std::string>::iterator iter = interfaces.begin();
609       iter != interfaces.end(); ++iter) {
610    if (*iter == bluetooth_input::kBluetoothInputInterface) {
611      connecting_applications_counter_++;
612      // Supports Input interface.
613      DBusThreadManager::Get()->GetBluetoothInputClient()->
614          Connect(object_path_,
615                  base::Bind(&BluetoothDeviceChromeOS::OnConnect,
616                             weak_ptr_factory_.GetWeakPtr(),
617                             callback,
618                             *iter),
619                  base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
620                             weak_ptr_factory_.GetWeakPtr(),
621                             error_callback, *iter));
622    }
623  }
624
625  // If OnConnect has been called for every call to Connect above, then this
626  // will decrement the counter to -1.  In that case, call the callback
627  // directly as it has not been called by any of the OnConnect callbacks.
628  // This is safe because OnIntrospect and OnConnect run on the same thread.
629  connecting_applications_counter_--;
630  if (connecting_applications_counter_ == -1)
631    callback.Run();
632}
633
634void BluetoothDeviceChromeOS::OnConnect(const base::Closure& callback,
635                                        const std::string& interface_name,
636                                        const dbus::ObjectPath& device_path) {
637  VLOG(1) << "Application connection successful: " << device_path.value()
638          << ": " << interface_name;
639
640  connecting_applications_counter_--;
641  // |callback| should only be called once, meaning it cannot be called before
642  // all requests have been started.  The extra decrement after all requests
643  // have been started, and the check for -1 instead of 0 below, insure only a
644  // single call to |callback| will occur (provided OnConnect and OnIntrospect
645  // run on the same thread, which is true).
646  if (connecting_applications_counter_ == -1) {
647    connecting_applications_counter_ = 0;
648    SetTrusted();
649    callback.Run();
650  }
651}
652
653void BluetoothDeviceChromeOS::OnConnectError(
654    const ConnectErrorCallback& error_callback,
655    const std::string& interface_name,
656    const dbus::ObjectPath& device_path,
657    const std::string& error_name,
658    const std::string& error_message) {
659  // The default |error_code| is an unknown error.
660  ConnectErrorCode error_code = ERROR_UNKNOWN;
661
662  // Report any error in the log, even if we know the possible source of it.
663  LOG(WARNING) << "Connection failed (on Connect): "
664               << interface_name << ": "
665               << "\"" << name_ << "\" (" << address_ << "): "
666               << error_name << ": \"" << error_message << "\"";
667
668  // Determines the right error code from error_name, assuming the error name
669  // comes from Connect bluez function.
670  if (error_name == bluetooth_adapter::kErrorFailed) {
671    error_code = ERROR_FAILED;
672  } else if (error_name == bluetooth_adapter::kErrorInProgress) {
673    error_code = ERROR_INPROGRESS;
674  } else if (error_name == bluetooth_adapter::kErrorNotSupported) {
675    error_code = ERROR_UNSUPPORTED_DEVICE;
676  }
677
678  error_callback.Run(error_code);
679}
680
681void BluetoothDeviceChromeOS::DisconnectCallback(
682    const base::Closure& callback,
683    const ErrorCallback& error_callback,
684    const dbus::ObjectPath& device_path,
685    bool success) {
686  DCHECK(device_path == object_path_);
687  if (success) {
688    VLOG(1) << "Disconnection successful: " << address_;
689    callback.Run();
690  } else {
691    if (connected_)  {
692      LOG(WARNING) << "Disconnection failed: " << address_;
693      error_callback.Run();
694    } else {
695      VLOG(1) << "Disconnection failed on a already disconnected device: "
696              << address_;
697      callback.Run();
698    }
699  }
700}
701
702void BluetoothDeviceChromeOS::ForgetCallback(
703    const ErrorCallback& error_callback,
704    const dbus::ObjectPath& adapter_path,
705    bool success) {
706  // It's quite normal that this path never gets called on success; we use a
707  // weak pointer, and bluetoothd might send the DeviceRemoved signal before
708  // the method reply, in which case this object is deleted and the
709  // callback never takes place. Therefore don't do anything here for the
710  // success case.
711  if (!success) {
712    LOG(WARNING) << "Forget failed: " << address_;
713    error_callback.Run();
714  }
715}
716
717void BluetoothDeviceChromeOS::OnCancelDeviceCreation(
718    const dbus::ObjectPath& adapter_path,
719    bool success) {
720  if (!success)
721    LOG(WARNING) << "CancelDeviceCreation failed: " << address_;
722}
723
724void BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback(
725    const ProvidesServiceCallback& callback) {
726  callback.Run(false);
727}
728
729void BluetoothDeviceChromeOS::SearchServicesForNameCallback(
730    const std::string& name,
731    const ProvidesServiceCallback& callback,
732    const ServiceRecordList& list) {
733  for (ServiceRecordList::const_iterator i = list.begin();
734      i != list.end(); ++i) {
735    if ((*i)->name() == name) {
736      callback.Run(true);
737      return;
738    }
739  }
740  callback.Run(false);
741}
742
743void BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback(
744    const SocketCallback& callback) {
745  callback.Run(NULL);
746}
747
748void BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback(
749    const std::string& service_uuid,
750    const SocketCallback& callback,
751    const ServiceRecordList& list) {
752  for (ServiceRecordList::const_iterator i = list.begin();
753      i != list.end(); ++i) {
754    if ((*i)->uuid() == service_uuid) {
755      // If multiple service records are found, use the first one that works.
756      scoped_refptr<BluetoothSocket> socket(
757          BluetoothSocketChromeOS::CreateBluetoothSocket(**i));
758      if (socket.get() != NULL) {
759        callback.Run(socket);
760        return;
761      }
762    }
763  }
764  callback.Run(NULL);
765}
766
767void BluetoothDeviceChromeOS::OnRemoteDataCallback(
768    const base::Closure& callback,
769    const ErrorCallback& error_callback,
770    bool success) {
771  if (success)
772    callback.Run();
773  else
774    error_callback.Run();
775}
776
777void BluetoothDeviceChromeOS::DisconnectRequested(
778    const dbus::ObjectPath& object_path) {
779  DCHECK(object_path == object_path_);
780}
781
782void BluetoothDeviceChromeOS::Release() {
783  DCHECK(agent_.get());
784  VLOG(1) << "Release: " << address_;
785
786  DCHECK(pairing_delegate_);
787  pairing_delegate_->DismissDisplayOrConfirm();
788  pairing_delegate_ = NULL;
789
790  pincode_callback_.Reset();
791  passkey_callback_.Reset();
792  confirmation_callback_.Reset();
793
794  agent_.reset();
795}
796
797void BluetoothDeviceChromeOS::RequestPinCode(
798    const dbus::ObjectPath& device_path,
799    const PinCodeCallback& callback) {
800  DCHECK(agent_.get());
801  VLOG(1) << "RequestPinCode: " << device_path.value();
802
803  DCHECK(pairing_delegate_);
804  DCHECK(pincode_callback_.is_null());
805  pincode_callback_ = callback;
806  pairing_delegate_->RequestPinCode(this);
807}
808
809void BluetoothDeviceChromeOS::RequestPasskey(
810    const dbus::ObjectPath& device_path,
811    const PasskeyCallback& callback) {
812  DCHECK(agent_.get());
813  DCHECK(device_path == object_path_);
814  VLOG(1) << "RequestPasskey: " << device_path.value();
815
816  DCHECK(pairing_delegate_);
817  DCHECK(passkey_callback_.is_null());
818  passkey_callback_ = callback;
819  pairing_delegate_->RequestPasskey(this);
820}
821
822void BluetoothDeviceChromeOS::DisplayPinCode(
823    const dbus::ObjectPath& device_path,
824    const std::string& pincode) {
825  DCHECK(agent_.get());
826  DCHECK(device_path == object_path_);
827  VLOG(1) << "DisplayPinCode: " << device_path.value() << " " << pincode;
828
829  DCHECK(pairing_delegate_);
830  pairing_delegate_->DisplayPinCode(this, pincode);
831}
832
833void BluetoothDeviceChromeOS::DisplayPasskey(
834    const dbus::ObjectPath& device_path,
835    uint32 passkey) {
836  DCHECK(agent_.get());
837  DCHECK(device_path == object_path_);
838  VLOG(1) << "DisplayPasskey: " << device_path.value() << " " << passkey;
839
840  DCHECK(pairing_delegate_);
841  pairing_delegate_->DisplayPasskey(this, passkey);
842}
843
844void BluetoothDeviceChromeOS::RequestConfirmation(
845    const dbus::ObjectPath& device_path,
846    uint32 passkey,
847    const ConfirmationCallback& callback) {
848  DCHECK(agent_.get());
849  DCHECK(device_path == object_path_);
850  VLOG(1) << "RequestConfirmation: " << device_path.value() << " " << passkey;
851
852  DCHECK(pairing_delegate_);
853  DCHECK(confirmation_callback_.is_null());
854  confirmation_callback_ = callback;
855  pairing_delegate_->ConfirmPasskey(this, passkey);
856}
857
858void BluetoothDeviceChromeOS::Authorize(const dbus::ObjectPath& device_path,
859                                        const std::string& uuid,
860                                        const ConfirmationCallback& callback) {
861  DCHECK(agent_.get());
862  DCHECK(device_path == object_path_);
863  LOG(WARNING) << "Rejected authorization for service: " << uuid
864               << " requested from device: " << device_path.value();
865  callback.Run(REJECTED);
866}
867
868void BluetoothDeviceChromeOS::ConfirmModeChange(
869    Mode mode,
870    const ConfirmationCallback& callback) {
871  DCHECK(agent_.get());
872  LOG(WARNING) << "Rejected adapter-level mode change: " << mode
873               << " made on agent for device: " << address_;
874  callback.Run(REJECTED);
875}
876
877void BluetoothDeviceChromeOS::Cancel() {
878  DCHECK(agent_.get());
879  VLOG(1) << "Cancel: " << address_;
880
881  DCHECK(pairing_delegate_);
882  pairing_delegate_->DismissDisplayOrConfirm();
883}
884
885
886// static
887BluetoothDeviceChromeOS* BluetoothDeviceChromeOS::Create(
888    BluetoothAdapterChromeOS* adapter) {
889  return new BluetoothDeviceChromeOS(adapter);
890}
891
892}  // namespace chromeos
893