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