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 "base/bind.h" 8 #include "base/metrics/histogram.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_util.h" 11 #include "chromeos/dbus/bluetooth_adapter_client.h" 12 #include "chromeos/dbus/bluetooth_agent_manager_client.h" 13 #include "chromeos/dbus/bluetooth_agent_service_provider.h" 14 #include "chromeos/dbus/bluetooth_device_client.h" 15 #include "chromeos/dbus/bluetooth_input_client.h" 16 #include "chromeos/dbus/dbus_thread_manager.h" 17 #include "dbus/bus.h" 18 #include "device/bluetooth/bluetooth_adapter_chromeos.h" 19 #include "device/bluetooth/bluetooth_profile_chromeos.h" 20 #include "device/bluetooth/bluetooth_socket.h" 21 #include "third_party/cros_system_api/dbus/service_constants.h" 22 23 using device::BluetoothDevice; 24 25 namespace { 26 27 // The agent path is relatively meaningless since BlueZ only supports one 28 // at time and will fail in an attempt to register another with "Already Exists" 29 // (which we fail in OnRegisterAgentError with ERROR_INPROGRESS). 30 const char kAgentPath[] = "/org/chromium/bluetooth_agent"; 31 32 // Histogram enumerations for pairing methods. 33 enum UMAPairingMethod { 34 UMA_PAIRING_METHOD_NONE, 35 UMA_PAIRING_METHOD_REQUEST_PINCODE, 36 UMA_PAIRING_METHOD_REQUEST_PASSKEY, 37 UMA_PAIRING_METHOD_DISPLAY_PINCODE, 38 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, 39 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, 40 // NOTE: Add new pairing methods immediately above this line. Make sure to 41 // update the enum list in tools/histogram/histograms.xml accordinly. 42 UMA_PAIRING_METHOD_COUNT 43 }; 44 45 // Histogram enumerations for pairing results. 46 enum UMAPairingResult { 47 UMA_PAIRING_RESULT_SUCCESS, 48 UMA_PAIRING_RESULT_INPROGRESS, 49 UMA_PAIRING_RESULT_FAILED, 50 UMA_PAIRING_RESULT_AUTH_FAILED, 51 UMA_PAIRING_RESULT_AUTH_CANCELED, 52 UMA_PAIRING_RESULT_AUTH_REJECTED, 53 UMA_PAIRING_RESULT_AUTH_TIMEOUT, 54 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE, 55 UMA_PAIRING_RESULT_UNKNOWN_ERROR, 56 // NOTE: Add new pairing results immediately above this line. Make sure to 57 // update the enum list in tools/histogram/histograms.xml accordinly. 58 UMA_PAIRING_RESULT_COUNT 59 }; 60 61 void ParseModalias(const dbus::ObjectPath& object_path, 62 uint16 *vendor_id, 63 uint16 *product_id, 64 uint16 *device_id) { 65 chromeos::BluetoothDeviceClient::Properties* properties = 66 chromeos::DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 67 GetProperties(object_path); 68 DCHECK(properties); 69 70 std::string modalias = properties->modalias.value(); 71 if (StartsWithASCII(modalias, "usb:", false) && modalias.length() == 19) { 72 // usb:vXXXXpXXXXdXXXX 73 if (modalias[4] == 'v' && vendor_id != NULL) { 74 uint64 component = 0; 75 base::HexStringToUInt64(modalias.substr(5, 4), &component); 76 *vendor_id = component; 77 } 78 79 if (modalias[9] == 'p' && product_id != NULL) { 80 uint64 component = 0; 81 base::HexStringToUInt64(modalias.substr(10, 4), &component); 82 *product_id = component; 83 } 84 85 if (modalias[14] == 'd' && device_id != NULL) { 86 uint64 component = 0; 87 base::HexStringToUInt64(modalias.substr(15, 4), &component); 88 *device_id = component; 89 } 90 } 91 } 92 93 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { 94 UMAPairingResult pairing_result; 95 switch (error_code) { 96 case BluetoothDevice::ERROR_INPROGRESS: 97 pairing_result = UMA_PAIRING_RESULT_INPROGRESS; 98 break; 99 case BluetoothDevice::ERROR_FAILED: 100 pairing_result = UMA_PAIRING_RESULT_FAILED; 101 break; 102 case BluetoothDevice::ERROR_AUTH_FAILED: 103 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED; 104 break; 105 case BluetoothDevice::ERROR_AUTH_CANCELED: 106 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED; 107 break; 108 case BluetoothDevice::ERROR_AUTH_REJECTED: 109 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED; 110 break; 111 case BluetoothDevice::ERROR_AUTH_TIMEOUT: 112 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT; 113 break; 114 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: 115 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE; 116 break; 117 default: 118 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR; 119 } 120 121 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", 122 pairing_result, 123 UMA_PAIRING_RESULT_COUNT); 124 } 125 126 } // namespace 127 128 namespace chromeos { 129 130 BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( 131 BluetoothAdapterChromeOS* adapter, 132 const dbus::ObjectPath& object_path) 133 : adapter_(adapter), 134 object_path_(object_path), 135 num_connecting_calls_(0), 136 pairing_delegate_(NULL), 137 pairing_delegate_used_(false), 138 weak_ptr_factory_(this) { 139 } 140 141 BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { 142 } 143 144 uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const { 145 BluetoothDeviceClient::Properties* properties = 146 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 147 GetProperties(object_path_); 148 DCHECK(properties); 149 150 return properties->bluetooth_class.value(); 151 } 152 153 std::string BluetoothDeviceChromeOS::GetDeviceName() const { 154 BluetoothDeviceClient::Properties* properties = 155 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 156 GetProperties(object_path_); 157 DCHECK(properties); 158 159 return properties->alias.value(); 160 } 161 162 std::string BluetoothDeviceChromeOS::GetAddress() const { 163 BluetoothDeviceClient::Properties* properties = 164 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 165 GetProperties(object_path_); 166 DCHECK(properties); 167 168 return properties->address.value(); 169 } 170 171 uint16 BluetoothDeviceChromeOS::GetVendorID() const { 172 uint16 vendor_id = 0; 173 ParseModalias(object_path_, &vendor_id, NULL, NULL); 174 return vendor_id; 175 } 176 177 uint16 BluetoothDeviceChromeOS::GetProductID() const { 178 uint16 product_id = 0; 179 ParseModalias(object_path_, NULL, &product_id, NULL); 180 return product_id; 181 } 182 183 uint16 BluetoothDeviceChromeOS::GetDeviceID() const { 184 uint16 device_id = 0; 185 ParseModalias(object_path_, NULL, NULL, &device_id); 186 return device_id; 187 } 188 189 bool BluetoothDeviceChromeOS::IsPaired() const { 190 BluetoothDeviceClient::Properties* properties = 191 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 192 GetProperties(object_path_); 193 DCHECK(properties); 194 195 // Trusted devices are devices that don't support pairing but that the 196 // user has explicitly connected; it makes no sense for UI purposes to 197 // treat them differently from each other. 198 return properties->paired.value() || properties->trusted.value(); 199 } 200 201 bool BluetoothDeviceChromeOS::IsConnected() const { 202 BluetoothDeviceClient::Properties* properties = 203 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 204 GetProperties(object_path_); 205 DCHECK(properties); 206 207 return properties->connected.value(); 208 } 209 210 bool BluetoothDeviceChromeOS::IsConnectable() const { 211 BluetoothInputClient::Properties* input_properties = 212 DBusThreadManager::Get()->GetBluetoothInputClient()-> 213 GetProperties(object_path_); 214 // GetProperties returns NULL when the device does not implement the given 215 // interface. Non HID devices are normally connectable. 216 if (!input_properties) 217 return true; 218 219 return input_properties->reconnect_mode.value() != "device"; 220 } 221 222 bool BluetoothDeviceChromeOS::IsConnecting() const { 223 return num_connecting_calls_ > 0; 224 } 225 226 BluetoothDeviceChromeOS::ServiceList BluetoothDeviceChromeOS::GetServices() 227 const { 228 BluetoothDeviceClient::Properties* properties = 229 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 230 GetProperties(object_path_); 231 DCHECK(properties); 232 233 return properties->uuids.value(); 234 } 235 236 void BluetoothDeviceChromeOS::GetServiceRecords( 237 const ServiceRecordsCallback& callback, 238 const ErrorCallback& error_callback) { 239 // TODO(keybuk): not implemented; remove 240 error_callback.Run(); 241 } 242 243 void BluetoothDeviceChromeOS::ProvidesServiceWithName( 244 const std::string& name, 245 const ProvidesServiceCallback& callback) { 246 // TODO(keybuk): not implemented; remove 247 callback.Run(false); 248 } 249 250 bool BluetoothDeviceChromeOS::ExpectingPinCode() const { 251 return !pincode_callback_.is_null(); 252 } 253 254 bool BluetoothDeviceChromeOS::ExpectingPasskey() const { 255 return !passkey_callback_.is_null(); 256 } 257 258 bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { 259 return !confirmation_callback_.is_null(); 260 } 261 262 void BluetoothDeviceChromeOS::Connect( 263 BluetoothDevice::PairingDelegate* pairing_delegate, 264 const base::Closure& callback, 265 const ConnectErrorCallback& error_callback) { 266 if (num_connecting_calls_++ == 0) 267 adapter_->NotifyDeviceChanged(this); 268 269 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ 270 << " in progress"; 271 272 if (IsPaired() || !pairing_delegate || !IsPairable()) { 273 // No need to pair, or unable to, skip straight to connection. 274 ConnectInternal(false, callback, error_callback); 275 } else { 276 // Initiate high-security connection with pairing. 277 DCHECK(!pairing_delegate_); 278 DCHECK(agent_.get() == NULL); 279 280 pairing_delegate_ = pairing_delegate; 281 pairing_delegate_used_ = false; 282 283 // The agent path is relatively meaningless since BlueZ only supports 284 // one per application at a time. 285 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); 286 agent_.reset(BluetoothAgentServiceProvider::Create( 287 system_bus, dbus::ObjectPath(kAgentPath), this)); 288 DCHECK(agent_.get()); 289 290 VLOG(1) << object_path_.value() << ": Registering agent for pairing"; 291 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> 292 RegisterAgent( 293 dbus::ObjectPath(kAgentPath), 294 bluetooth_agent_manager::kKeyboardDisplayCapability, 295 base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgent, 296 weak_ptr_factory_.GetWeakPtr(), 297 callback, 298 error_callback), 299 base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgentError, 300 weak_ptr_factory_.GetWeakPtr(), 301 error_callback)); 302 } 303 } 304 305 void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { 306 if (!agent_.get() || pincode_callback_.is_null()) 307 return; 308 309 pincode_callback_.Run(SUCCESS, pincode); 310 pincode_callback_.Reset(); 311 } 312 313 void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { 314 if (!agent_.get() || passkey_callback_.is_null()) 315 return; 316 317 passkey_callback_.Run(SUCCESS, passkey); 318 passkey_callback_.Reset(); 319 } 320 321 void BluetoothDeviceChromeOS::ConfirmPairing() { 322 if (!agent_.get() || confirmation_callback_.is_null()) 323 return; 324 325 confirmation_callback_.Run(SUCCESS); 326 confirmation_callback_.Reset(); 327 } 328 329 void BluetoothDeviceChromeOS::RejectPairing() { 330 RunPairingCallbacks(REJECTED); 331 } 332 333 void BluetoothDeviceChromeOS::CancelPairing() { 334 // If there wasn't a callback in progress that we can reply to then we 335 // have to send a CancelPairing() to the device instead. 336 if (!RunPairingCallbacks(CANCELLED)) { 337 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 338 CancelPairing( 339 object_path_, 340 base::Bind(&base::DoNothing), 341 base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError, 342 weak_ptr_factory_.GetWeakPtr())); 343 344 // Since there's no calback to this method, it's possible that the pairing 345 // delegate is going to be freed before things complete. 346 UnregisterAgent(); 347 } 348 } 349 350 void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, 351 const ErrorCallback& error_callback) { 352 VLOG(1) << object_path_.value() << ": Disconnecting"; 353 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 354 Disconnect( 355 object_path_, 356 base::Bind(&BluetoothDeviceChromeOS::OnDisconnect, 357 weak_ptr_factory_.GetWeakPtr(), 358 callback), 359 base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError, 360 weak_ptr_factory_.GetWeakPtr(), 361 error_callback)); 362 } 363 364 void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { 365 VLOG(1) << object_path_.value() << ": Removing device"; 366 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 367 RemoveDevice( 368 adapter_->object_path_, 369 object_path_, 370 base::Bind(&base::DoNothing), 371 base::Bind(&BluetoothDeviceChromeOS::OnForgetError, 372 weak_ptr_factory_.GetWeakPtr(), 373 error_callback)); 374 } 375 376 void BluetoothDeviceChromeOS::ConnectToService( 377 const std::string& service_uuid, 378 const SocketCallback& callback) { 379 // TODO(keybuk): implement 380 callback.Run(scoped_refptr<device::BluetoothSocket>()); 381 } 382 383 void BluetoothDeviceChromeOS::ConnectToProfile( 384 device::BluetoothProfile* profile, 385 const base::Closure& callback, 386 const ErrorCallback& error_callback) { 387 BluetoothProfileChromeOS* profile_chromeos = 388 static_cast<BluetoothProfileChromeOS*>(profile); 389 VLOG(1) << object_path_.value() << ": Connecting profile: " 390 << profile_chromeos->uuid(); 391 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 392 ConnectProfile( 393 object_path_, 394 profile_chromeos->uuid(), 395 base::Bind( 396 &BluetoothDeviceChromeOS::OnConnectProfile, 397 weak_ptr_factory_.GetWeakPtr(), 398 profile, 399 callback), 400 base::Bind( 401 &BluetoothDeviceChromeOS::OnConnectProfileError, 402 weak_ptr_factory_.GetWeakPtr(), 403 profile, 404 error_callback)); 405 } 406 407 void BluetoothDeviceChromeOS::SetOutOfBandPairingData( 408 const device::BluetoothOutOfBandPairingData& data, 409 const base::Closure& callback, 410 const ErrorCallback& error_callback) { 411 // TODO(keybuk): implement 412 error_callback.Run(); 413 } 414 415 void BluetoothDeviceChromeOS::ClearOutOfBandPairingData( 416 const base::Closure& callback, 417 const ErrorCallback& error_callback) { 418 // TODO(keybuk): implement 419 error_callback.Run(); 420 } 421 422 423 void BluetoothDeviceChromeOS::Release() { 424 DCHECK(agent_.get()); 425 DCHECK(pairing_delegate_); 426 VLOG(1) << object_path_.value() << ": Release"; 427 428 pincode_callback_.Reset(); 429 passkey_callback_.Reset(); 430 confirmation_callback_.Reset(); 431 432 UnregisterAgent(); 433 } 434 435 void BluetoothDeviceChromeOS::RequestPinCode( 436 const dbus::ObjectPath& device_path, 437 const PinCodeCallback& callback) { 438 DCHECK(agent_.get()); 439 DCHECK(device_path == object_path_); 440 VLOG(1) << object_path_.value() << ": RequestPinCode"; 441 442 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 443 UMA_PAIRING_METHOD_REQUEST_PINCODE, 444 UMA_PAIRING_METHOD_COUNT); 445 446 DCHECK(pairing_delegate_); 447 DCHECK(pincode_callback_.is_null()); 448 pincode_callback_ = callback; 449 pairing_delegate_->RequestPinCode(this); 450 pairing_delegate_used_ = true; 451 } 452 453 void BluetoothDeviceChromeOS::DisplayPinCode( 454 const dbus::ObjectPath& device_path, 455 const std::string& pincode) { 456 DCHECK(agent_.get()); 457 DCHECK(device_path == object_path_); 458 VLOG(1) << object_path_.value() << ": DisplayPinCode: " << pincode; 459 460 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 461 UMA_PAIRING_METHOD_DISPLAY_PINCODE, 462 UMA_PAIRING_METHOD_COUNT); 463 464 DCHECK(pairing_delegate_); 465 pairing_delegate_->DisplayPinCode(this, pincode); 466 pairing_delegate_used_ = true; 467 } 468 469 void BluetoothDeviceChromeOS::RequestPasskey( 470 const dbus::ObjectPath& device_path, 471 const PasskeyCallback& callback) { 472 DCHECK(agent_.get()); 473 DCHECK(device_path == object_path_); 474 VLOG(1) << object_path_.value() << ": RequestPasskey"; 475 476 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 477 UMA_PAIRING_METHOD_REQUEST_PASSKEY, 478 UMA_PAIRING_METHOD_COUNT); 479 480 DCHECK(pairing_delegate_); 481 DCHECK(passkey_callback_.is_null()); 482 passkey_callback_ = callback; 483 pairing_delegate_->RequestPasskey(this); 484 pairing_delegate_used_ = true; 485 } 486 487 void BluetoothDeviceChromeOS::DisplayPasskey( 488 const dbus::ObjectPath& device_path, 489 uint32 passkey, 490 uint16 entered) { 491 DCHECK(agent_.get()); 492 DCHECK(device_path == object_path_); 493 VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey 494 << " (" << entered << " entered)"; 495 496 if (entered == 0) 497 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 498 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, 499 UMA_PAIRING_METHOD_COUNT); 500 501 DCHECK(pairing_delegate_); 502 if (entered == 0) 503 pairing_delegate_->DisplayPasskey(this, passkey); 504 pairing_delegate_->KeysEntered(this, entered); 505 pairing_delegate_used_ = true; 506 } 507 508 void BluetoothDeviceChromeOS::RequestConfirmation( 509 const dbus::ObjectPath& device_path, 510 uint32 passkey, 511 const ConfirmationCallback& callback) { 512 DCHECK(agent_.get()); 513 DCHECK(device_path == object_path_); 514 VLOG(1) << object_path_.value() << ": RequestConfirmation: " << passkey; 515 516 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 517 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, 518 UMA_PAIRING_METHOD_COUNT); 519 520 DCHECK(pairing_delegate_); 521 DCHECK(confirmation_callback_.is_null()); 522 confirmation_callback_ = callback; 523 pairing_delegate_->ConfirmPasskey(this, passkey); 524 pairing_delegate_used_ = true; 525 } 526 527 void BluetoothDeviceChromeOS::RequestAuthorization( 528 const dbus::ObjectPath& device_path, 529 const ConfirmationCallback& callback) { 530 // TODO(keybuk): implement 531 callback.Run(CANCELLED); 532 } 533 534 void BluetoothDeviceChromeOS::AuthorizeService( 535 const dbus::ObjectPath& device_path, 536 const std::string& uuid, 537 const ConfirmationCallback& callback) { 538 // TODO(keybuk): implement 539 callback.Run(CANCELLED); 540 } 541 542 void BluetoothDeviceChromeOS::Cancel() { 543 DCHECK(agent_.get()); 544 VLOG(1) << object_path_.value() << ": Cancel"; 545 546 DCHECK(pairing_delegate_); 547 pairing_delegate_->DismissDisplayOrConfirm(); 548 } 549 550 void BluetoothDeviceChromeOS::ConnectInternal( 551 bool after_pairing, 552 const base::Closure& callback, 553 const ConnectErrorCallback& error_callback) { 554 VLOG(1) << object_path_.value() << ": Connecting"; 555 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 556 Connect( 557 object_path_, 558 base::Bind(&BluetoothDeviceChromeOS::OnConnect, 559 weak_ptr_factory_.GetWeakPtr(), 560 after_pairing, 561 callback), 562 base::Bind(&BluetoothDeviceChromeOS::OnConnectError, 563 weak_ptr_factory_.GetWeakPtr(), 564 after_pairing, 565 error_callback)); 566 } 567 568 void BluetoothDeviceChromeOS::OnConnect(bool after_pairing, 569 const base::Closure& callback) { 570 if (--num_connecting_calls_ == 0) 571 adapter_->NotifyDeviceChanged(this); 572 573 DCHECK(num_connecting_calls_ >= 0); 574 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_ 575 << " still in progress"; 576 577 SetTrusted(); 578 579 if (after_pairing) 580 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", 581 UMA_PAIRING_RESULT_SUCCESS, 582 UMA_PAIRING_RESULT_COUNT); 583 584 callback.Run(); 585 } 586 587 void BluetoothDeviceChromeOS::OnConnectError( 588 bool after_pairing, 589 const ConnectErrorCallback& error_callback, 590 const std::string& error_name, 591 const std::string& error_message) { 592 if (--num_connecting_calls_ == 0) 593 adapter_->NotifyDeviceChanged(this); 594 595 DCHECK(num_connecting_calls_ >= 0); 596 LOG(WARNING) << object_path_.value() << ": Failed to connect device: " 597 << error_name << ": " << error_message; 598 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ 599 << " still in progress"; 600 601 // Determine the error code from error_name. 602 ConnectErrorCode error_code = ERROR_UNKNOWN; 603 if (error_name == bluetooth_device::kErrorFailed) { 604 error_code = ERROR_FAILED; 605 } else if (error_name == bluetooth_device::kErrorInProgress) { 606 error_code = ERROR_INPROGRESS; 607 } else if (error_name == bluetooth_device::kErrorNotSupported) { 608 error_code = ERROR_UNSUPPORTED_DEVICE; 609 } 610 611 if (after_pairing) 612 RecordPairingResult(error_code); 613 error_callback.Run(error_code); 614 } 615 616 void BluetoothDeviceChromeOS::OnRegisterAgent( 617 const base::Closure& callback, 618 const ConnectErrorCallback& error_callback) { 619 VLOG(1) << object_path_.value() << ": Agent registered, now pairing"; 620 621 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 622 Pair(object_path_, 623 base::Bind(&BluetoothDeviceChromeOS::OnPair, 624 weak_ptr_factory_.GetWeakPtr(), 625 callback, error_callback), 626 base::Bind(&BluetoothDeviceChromeOS::OnPairError, 627 weak_ptr_factory_.GetWeakPtr(), 628 error_callback)); 629 } 630 631 void BluetoothDeviceChromeOS::OnRegisterAgentError( 632 const ConnectErrorCallback& error_callback, 633 const std::string& error_name, 634 const std::string& error_message) { 635 if (--num_connecting_calls_ == 0) 636 adapter_->NotifyDeviceChanged(this); 637 638 DCHECK(num_connecting_calls_ >= 0); 639 LOG(WARNING) << object_path_.value() << ": Failed to register agent: " 640 << error_name << ": " << error_message; 641 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ 642 << " still in progress"; 643 644 UnregisterAgent(); 645 646 // Determine the error code from error_name. 647 ConnectErrorCode error_code = ERROR_UNKNOWN; 648 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists) 649 error_code = ERROR_INPROGRESS; 650 651 RecordPairingResult(error_code); 652 error_callback.Run(error_code); 653 } 654 655 void BluetoothDeviceChromeOS::OnPair( 656 const base::Closure& callback, 657 const ConnectErrorCallback& error_callback) { 658 VLOG(1) << object_path_.value() << ": Paired"; 659 660 if (!pairing_delegate_used_) 661 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", 662 UMA_PAIRING_METHOD_NONE, 663 UMA_PAIRING_METHOD_COUNT); 664 UnregisterAgent(); 665 SetTrusted(); 666 ConnectInternal(true, callback, error_callback); 667 } 668 669 void BluetoothDeviceChromeOS::OnPairError( 670 const ConnectErrorCallback& error_callback, 671 const std::string& error_name, 672 const std::string& error_message) { 673 if (--num_connecting_calls_ == 0) 674 adapter_->NotifyDeviceChanged(this); 675 676 DCHECK(num_connecting_calls_ >= 0); 677 LOG(WARNING) << object_path_.value() << ": Failed to pair device: " 678 << error_name << ": " << error_message; 679 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ 680 << " still in progress"; 681 682 UnregisterAgent(); 683 684 // Determine the error code from error_name. 685 ConnectErrorCode error_code = ERROR_UNKNOWN; 686 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) { 687 error_code = ERROR_FAILED; 688 } else if (error_name == bluetooth_device::kErrorFailed) { 689 error_code = ERROR_FAILED; 690 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) { 691 error_code = ERROR_AUTH_FAILED; 692 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) { 693 error_code = ERROR_AUTH_CANCELED; 694 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) { 695 error_code = ERROR_AUTH_REJECTED; 696 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) { 697 error_code = ERROR_AUTH_TIMEOUT; 698 } 699 700 RecordPairingResult(error_code); 701 error_callback.Run(error_code); 702 } 703 704 void BluetoothDeviceChromeOS::OnCancelPairingError( 705 const std::string& error_name, 706 const std::string& error_message) { 707 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: " 708 << error_name << ": " << error_message; 709 } 710 711 void BluetoothDeviceChromeOS::SetTrusted() { 712 // Unconditionally send the property change, rather than checking the value 713 // first; there's no harm in doing this and it solves any race conditions 714 // with the property becoming true or false and this call happening before 715 // we get the D-Bus signal about the earlier change. 716 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 717 GetProperties(object_path_)->trusted.Set( 718 true, 719 base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, 720 weak_ptr_factory_.GetWeakPtr())); 721 } 722 723 void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { 724 LOG_IF(WARNING, !success) << object_path_.value() 725 << ": Failed to set device as trusted"; 726 } 727 728 void BluetoothDeviceChromeOS::UnregisterAgent() { 729 if (!agent_.get()) 730 return; 731 732 DCHECK(pairing_delegate_); 733 734 DCHECK(pincode_callback_.is_null()); 735 DCHECK(passkey_callback_.is_null()); 736 DCHECK(confirmation_callback_.is_null()); 737 738 pairing_delegate_->DismissDisplayOrConfirm(); 739 pairing_delegate_ = NULL; 740 741 agent_.reset(); 742 743 // Clean up after ourselves. 744 VLOG(1) << object_path_.value() << ": Unregistering pairing agent"; 745 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> 746 UnregisterAgent( 747 dbus::ObjectPath(kAgentPath), 748 base::Bind(&base::DoNothing), 749 base::Bind(&BluetoothDeviceChromeOS::OnUnregisterAgentError, 750 weak_ptr_factory_.GetWeakPtr())); 751 } 752 753 void BluetoothDeviceChromeOS::OnUnregisterAgentError( 754 const std::string& error_name, 755 const std::string& error_message) { 756 LOG(WARNING) << object_path_.value() << ": Failed to unregister agent: " 757 << error_name << ": " << error_message; 758 } 759 760 void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { 761 VLOG(1) << object_path_.value() << ": Disconnected"; 762 callback.Run(); 763 } 764 765 void BluetoothDeviceChromeOS::OnDisconnectError( 766 const ErrorCallback& error_callback, 767 const std::string& error_name, 768 const std::string& error_message) { 769 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: " 770 << error_name << ": " << error_message; 771 error_callback.Run(); 772 } 773 774 void BluetoothDeviceChromeOS::OnForgetError( 775 const ErrorCallback& error_callback, 776 const std::string& error_name, 777 const std::string& error_message) { 778 LOG(WARNING) << object_path_.value() << ": Failed to remove device: " 779 << error_name << ": " << error_message; 780 error_callback.Run(); 781 } 782 783 bool BluetoothDeviceChromeOS::RunPairingCallbacks(Status status) { 784 if (!agent_.get()) 785 return false; 786 787 bool callback_run = false; 788 if (!pincode_callback_.is_null()) { 789 pincode_callback_.Run(status, ""); 790 pincode_callback_.Reset(); 791 callback_run = true; 792 } 793 794 if (!passkey_callback_.is_null()) { 795 passkey_callback_.Run(status, 0); 796 passkey_callback_.Reset(); 797 callback_run = true; 798 } 799 800 if (!confirmation_callback_.is_null()) { 801 confirmation_callback_.Run(status); 802 confirmation_callback_.Reset(); 803 callback_run = true; 804 } 805 806 return callback_run; 807 } 808 809 void BluetoothDeviceChromeOS::OnConnectProfile( 810 device::BluetoothProfile* profile, 811 const base::Closure& callback) { 812 BluetoothProfileChromeOS* profile_chromeos = 813 static_cast<BluetoothProfileChromeOS*>(profile); 814 VLOG(1) << object_path_.value() << ": Profile connected: " 815 << profile_chromeos->uuid(); 816 callback.Run(); 817 } 818 819 void BluetoothDeviceChromeOS::OnConnectProfileError( 820 device::BluetoothProfile* profile, 821 const ErrorCallback& error_callback, 822 const std::string& error_name, 823 const std::string& error_message) { 824 BluetoothProfileChromeOS* profile_chromeos = 825 static_cast<BluetoothProfileChromeOS*>(profile); 826 VLOG(1) << object_path_.value() << ": Profile connection failed: " 827 << profile_chromeos->uuid() << ": " 828 << error_name << ": " << error_message; 829 error_callback.Run(); 830 } 831 832 } // namespace chromeos 833