bluetooth_device_chromeos.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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::ConnectToService( 437 const BluetoothUUID& uuid, 438 const ConnectToServiceCallback& callback, 439 const ConnectToServiceErrorCallback& error_callback) { 440 VLOG(1) << object_path_.value() << ": Connecting to service: " 441 << uuid.canonical_value(); 442 scoped_refptr<BluetoothSocketChromeOS> socket = 443 BluetoothSocketChromeOS::CreateBluetoothSocket( 444 ui_task_runner_, 445 socket_thread_, 446 NULL, 447 net::NetLog::Source()); 448 socket->Connect(this, uuid, 449 base::Bind(callback, socket), 450 error_callback); 451} 452 453void BluetoothDeviceChromeOS::CreateGattConnection( 454 const GattConnectionCallback& callback, 455 const ConnectErrorCallback& error_callback) { 456 // TODO(armansito): Implement. 457 error_callback.Run(ERROR_UNSUPPORTED_DEVICE); 458} 459 460void BluetoothDeviceChromeOS::StartConnectionMonitor( 461 const base::Closure& callback, 462 const ErrorCallback& error_callback) { 463 DBusThreadManager::Get()->GetBluetoothDeviceClient()->StartConnectionMonitor( 464 object_path_, 465 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitor, 466 weak_ptr_factory_.GetWeakPtr(), 467 callback), 468 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitorError, 469 weak_ptr_factory_.GetWeakPtr(), 470 error_callback)); 471} 472 473BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing( 474 BluetoothDevice::PairingDelegate* pairing_delegate) { 475 pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate)); 476 return pairing_.get(); 477} 478 479void BluetoothDeviceChromeOS::EndPairing() { 480 pairing_.reset(); 481} 482 483BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const { 484 return pairing_.get(); 485} 486 487void BluetoothDeviceChromeOS::GattServiceAdded( 488 const dbus::ObjectPath& object_path) { 489 if (GetGattService(object_path.value())) { 490 VLOG(1) << "Remote GATT service already exists: " << object_path.value(); 491 return; 492 } 493 494 BluetoothGattServiceClient::Properties* properties = 495 DBusThreadManager::Get()->GetBluetoothGattServiceClient()-> 496 GetProperties(object_path); 497 DCHECK(properties); 498 if (properties->device.value() != object_path_) { 499 VLOG(2) << "Remote GATT service does not belong to this device."; 500 return; 501 } 502 503 VLOG(1) << "Adding new remote GATT service for device: " << GetAddress(); 504 505 BluetoothRemoteGattServiceChromeOS* service = 506 new BluetoothRemoteGattServiceChromeOS(this, object_path); 507 gatt_services_[service->GetIdentifier()] = service; 508 DCHECK(service->object_path() == object_path); 509 DCHECK(service->GetUUID().IsValid()); 510 511 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_, 512 GattServiceAdded(this, service)); 513} 514 515void BluetoothDeviceChromeOS::GattServiceRemoved( 516 const dbus::ObjectPath& object_path) { 517 GattServiceMap::iterator iter = gatt_services_.find(object_path.value()); 518 if (iter == gatt_services_.end()) { 519 VLOG(2) << "Unknown GATT service removed: " << object_path.value(); 520 return; 521 } 522 523 VLOG(1) << "Removing remote GATT service from device: " << GetAddress(); 524 525 BluetoothRemoteGattServiceChromeOS* service = 526 static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second); 527 DCHECK(service->object_path() == object_path); 528 gatt_services_.erase(iter); 529 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_, 530 GattServiceRemoved(this, service)); 531 delete service; 532} 533 534void BluetoothDeviceChromeOS::ConnectInternal( 535 bool after_pairing, 536 const base::Closure& callback, 537 const ConnectErrorCallback& error_callback) { 538 VLOG(1) << object_path_.value() << ": Connecting"; 539 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 540 Connect( 541 object_path_, 542 base::Bind(&BluetoothDeviceChromeOS::OnConnect, 543 weak_ptr_factory_.GetWeakPtr(), 544 after_pairing, 545 callback), 546 base::Bind(&BluetoothDeviceChromeOS::OnConnectError, 547 weak_ptr_factory_.GetWeakPtr(), 548 after_pairing, 549 error_callback)); 550} 551 552void BluetoothDeviceChromeOS::OnConnect(bool after_pairing, 553 const base::Closure& callback) { 554 if (--num_connecting_calls_ == 0) 555 adapter_->NotifyDeviceChanged(this); 556 557 DCHECK(num_connecting_calls_ >= 0); 558 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_ 559 << " still in progress"; 560 561 SetTrusted(); 562 563 if (after_pairing) 564 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", 565 UMA_PAIRING_RESULT_SUCCESS, 566 UMA_PAIRING_RESULT_COUNT); 567 568 callback.Run(); 569} 570 571void BluetoothDeviceChromeOS::OnConnectError( 572 bool after_pairing, 573 const ConnectErrorCallback& error_callback, 574 const std::string& error_name, 575 const std::string& error_message) { 576 if (--num_connecting_calls_ == 0) 577 adapter_->NotifyDeviceChanged(this); 578 579 DCHECK(num_connecting_calls_ >= 0); 580 LOG(WARNING) << object_path_.value() << ": Failed to connect device: " 581 << error_name << ": " << error_message; 582 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ 583 << " still in progress"; 584 585 // Determine the error code from error_name. 586 ConnectErrorCode error_code = ERROR_UNKNOWN; 587 if (error_name == bluetooth_device::kErrorFailed) { 588 error_code = ERROR_FAILED; 589 } else if (error_name == bluetooth_device::kErrorInProgress) { 590 error_code = ERROR_INPROGRESS; 591 } else if (error_name == bluetooth_device::kErrorNotSupported) { 592 error_code = ERROR_UNSUPPORTED_DEVICE; 593 } 594 595 if (after_pairing) 596 RecordPairingResult(error_code); 597 error_callback.Run(error_code); 598} 599 600void BluetoothDeviceChromeOS::OnPair( 601 const base::Closure& callback, 602 const ConnectErrorCallback& error_callback) { 603 VLOG(1) << object_path_.value() << ": Paired"; 604 605 EndPairing(); 606 607 ConnectInternal(true, callback, error_callback); 608} 609 610void BluetoothDeviceChromeOS::OnPairError( 611 const ConnectErrorCallback& error_callback, 612 const std::string& error_name, 613 const std::string& error_message) { 614 if (--num_connecting_calls_ == 0) 615 adapter_->NotifyDeviceChanged(this); 616 617 DCHECK(num_connecting_calls_ >= 0); 618 LOG(WARNING) << object_path_.value() << ": Failed to pair device: " 619 << error_name << ": " << error_message; 620 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ 621 << " still in progress"; 622 623 EndPairing(); 624 625 // Determine the error code from error_name. 626 ConnectErrorCode error_code = ERROR_UNKNOWN; 627 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) { 628 error_code = ERROR_FAILED; 629 } else if (error_name == bluetooth_device::kErrorFailed) { 630 error_code = ERROR_FAILED; 631 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) { 632 error_code = ERROR_AUTH_FAILED; 633 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) { 634 error_code = ERROR_AUTH_CANCELED; 635 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) { 636 error_code = ERROR_AUTH_REJECTED; 637 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) { 638 error_code = ERROR_AUTH_TIMEOUT; 639 } 640 641 RecordPairingResult(error_code); 642 error_callback.Run(error_code); 643} 644 645void BluetoothDeviceChromeOS::OnCancelPairingError( 646 const std::string& error_name, 647 const std::string& error_message) { 648 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: " 649 << error_name << ": " << error_message; 650} 651 652void BluetoothDeviceChromeOS::SetTrusted() { 653 // Unconditionally send the property change, rather than checking the value 654 // first; there's no harm in doing this and it solves any race conditions 655 // with the property becoming true or false and this call happening before 656 // we get the D-Bus signal about the earlier change. 657 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 658 GetProperties(object_path_)->trusted.Set( 659 true, 660 base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, 661 weak_ptr_factory_.GetWeakPtr())); 662} 663 664void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { 665 LOG_IF(WARNING, !success) << object_path_.value() 666 << ": Failed to set device as trusted"; 667} 668 669void BluetoothDeviceChromeOS::OnStartConnectionMonitor( 670 const base::Closure& callback) { 671 connection_monitor_started_ = true; 672 callback.Run(); 673} 674 675void BluetoothDeviceChromeOS::OnStartConnectionMonitorError( 676 const ErrorCallback& error_callback, 677 const std::string& error_name, 678 const std::string& error_message) { 679 LOG(WARNING) << object_path_.value() 680 << ": Failed to start connection monitor: " << error_name << ": " 681 << error_message; 682 error_callback.Run(); 683} 684 685void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { 686 VLOG(1) << object_path_.value() << ": Disconnected"; 687 callback.Run(); 688} 689 690void BluetoothDeviceChromeOS::OnDisconnectError( 691 const ErrorCallback& error_callback, 692 const std::string& error_name, 693 const std::string& error_message) { 694 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: " 695 << error_name << ": " << error_message; 696 error_callback.Run(); 697} 698 699void BluetoothDeviceChromeOS::OnForgetError( 700 const ErrorCallback& error_callback, 701 const std::string& error_name, 702 const std::string& error_message) { 703 LOG(WARNING) << object_path_.value() << ": Failed to remove device: " 704 << error_name << ": " << error_message; 705 error_callback.Run(); 706} 707 708} // namespace chromeos 709