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