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