bluetooth_device_chromeos.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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 <map> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/command_line.h" 13#include "base/logging.h" 14#include "base/memory/scoped_vector.h" 15#include "base/memory/weak_ptr.h" 16#include "base/string16.h" 17#include "base/string_util.h" 18#include "base/values.h" 19#include "chromeos/dbus/bluetooth_adapter_client.h" 20#include "chromeos/dbus/bluetooth_agent_service_provider.h" 21#include "chromeos/dbus/bluetooth_device_client.h" 22#include "chromeos/dbus/bluetooth_input_client.h" 23#include "chromeos/dbus/bluetooth_out_of_band_client.h" 24#include "chromeos/dbus/dbus_thread_manager.h" 25#include "chromeos/dbus/introspectable_client.h" 26#include "dbus/bus.h" 27#include "dbus/object_path.h" 28#include "device/bluetooth/bluetooth_adapter_chromeos.h" 29#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h" 30#include "device/bluetooth/bluetooth_service_record.h" 31#include "device/bluetooth/bluetooth_service_record_chromeos.h" 32#include "device/bluetooth/bluetooth_socket_chromeos.h" 33#include "device/bluetooth/bluetooth_utils.h" 34#include "third_party/cros_system_api/dbus/service_constants.h" 35 36using device::BluetoothDevice; 37using device::BluetoothOutOfBandPairingData; 38using device::BluetoothServiceRecord; 39using device::BluetoothSocket; 40 41namespace { 42 43void DoNothingServiceRecordList(const BluetoothDevice::ServiceRecordList&) {} 44 45} // namespace 46 47namespace chromeos { 48 49BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( 50 BluetoothAdapterChromeOS* adapter) 51 : BluetoothDevice(), 52 adapter_(adapter), 53 pairing_delegate_(NULL), 54 connecting_applications_counter_(0), 55 connecting_calls_(0), 56 service_records_loaded_(false), 57 weak_ptr_factory_(this) { 58} 59 60BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { 61} 62 63bool BluetoothDeviceChromeOS::IsPaired() const { 64 return !object_path_.value().empty(); 65} 66 67const BluetoothDevice::ServiceList& 68BluetoothDeviceChromeOS::GetServices() const { 69 return service_uuids_; 70} 71 72void BluetoothDeviceChromeOS::GetServiceRecords( 73 const ServiceRecordsCallback& callback, 74 const ErrorCallback& error_callback) { 75 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 76 DiscoverServices( 77 object_path_, 78 "", // empty pattern to browse all services 79 base::Bind(&BluetoothDeviceChromeOS::CollectServiceRecordsCallback, 80 weak_ptr_factory_.GetWeakPtr(), 81 callback, 82 base::Bind( 83 &BluetoothDeviceChromeOS::OnGetServiceRecordsError, 84 weak_ptr_factory_.GetWeakPtr(), 85 callback, 86 error_callback))); 87} 88 89void BluetoothDeviceChromeOS::ProvidesServiceWithName( 90 const std::string& name, 91 const ProvidesServiceCallback& callback) { 92 GetServiceRecords( 93 base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameCallback, 94 weak_ptr_factory_.GetWeakPtr(), 95 name, 96 callback), 97 base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback, 98 weak_ptr_factory_.GetWeakPtr(), 99 callback)); 100} 101 102bool BluetoothDeviceChromeOS::ExpectingPinCode() const { 103 return !pincode_callback_.is_null(); 104} 105 106bool BluetoothDeviceChromeOS::ExpectingPasskey() const { 107 return !passkey_callback_.is_null(); 108} 109 110bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { 111 return !confirmation_callback_.is_null(); 112} 113 114void BluetoothDeviceChromeOS::Connect( 115 PairingDelegate* pairing_delegate, 116 const base::Closure& callback, 117 const ConnectErrorCallback& error_callback) { 118 // This is safe because Connect() and its callbacks are called in the same 119 // thread. 120 connecting_calls_++; 121 connecting_ = !!connecting_calls_; 122 // Set the decrement to be issued when either callback is called. 123 base::Closure wrapped_callback = base::Bind( 124 &BluetoothDeviceChromeOS::OnConnectCallbackCalled, 125 weak_ptr_factory_.GetWeakPtr(), 126 callback); 127 ConnectErrorCallback wrapped_error_callback = base::Bind( 128 &BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled, 129 weak_ptr_factory_.GetWeakPtr(), 130 error_callback); 131 132 if (IsPaired() || IsBonded() || IsConnected()) { 133 // Connection to already paired or connected device. 134 ConnectApplications(wrapped_callback, wrapped_error_callback); 135 136 } else if (!pairing_delegate) { 137 // No pairing delegate supplied, initiate low-security connection only. 138 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 139 CreateDevice(adapter_->object_path_, 140 address_, 141 base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice, 142 weak_ptr_factory_.GetWeakPtr(), 143 wrapped_callback, 144 wrapped_error_callback), 145 base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError, 146 weak_ptr_factory_.GetWeakPtr(), 147 wrapped_error_callback)); 148 } else { 149 // Initiate high-security connection with pairing. 150 DCHECK(!pairing_delegate_); 151 pairing_delegate_ = pairing_delegate; 152 153 // The agent path is relatively meaningless, we use the device address 154 // to generate it as we only support one pairing attempt at a time for 155 // a given bluetooth device. 156 DCHECK(agent_.get() == NULL); 157 158 std::string agent_path_basename; 159 ReplaceChars(address_, ":", "_", &agent_path_basename); 160 dbus::ObjectPath agent_path("/org/chromium/bluetooth_agent/" + 161 agent_path_basename); 162 163 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); 164 if (system_bus) { 165 agent_.reset(BluetoothAgentServiceProvider::Create(system_bus, 166 agent_path, 167 this)); 168 } else { 169 agent_.reset(NULL); 170 } 171 172 VLOG(1) << "Pairing: " << address_; 173 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 174 CreatePairedDevice( 175 adapter_->object_path_, 176 address_, 177 agent_path, 178 bluetooth_agent::kDisplayYesNoCapability, 179 base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice, 180 weak_ptr_factory_.GetWeakPtr(), 181 wrapped_callback, 182 wrapped_error_callback), 183 base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError, 184 weak_ptr_factory_.GetWeakPtr(), 185 wrapped_error_callback)); 186 } 187} 188 189void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { 190 if (!agent_.get() || pincode_callback_.is_null()) 191 return; 192 193 pincode_callback_.Run(SUCCESS, pincode); 194 pincode_callback_.Reset(); 195} 196 197void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { 198 if (!agent_.get() || passkey_callback_.is_null()) 199 return; 200 201 passkey_callback_.Run(SUCCESS, passkey); 202 passkey_callback_.Reset(); 203} 204 205void BluetoothDeviceChromeOS::ConfirmPairing() { 206 if (!agent_.get() || confirmation_callback_.is_null()) 207 return; 208 209 confirmation_callback_.Run(SUCCESS); 210 confirmation_callback_.Reset(); 211} 212 213void BluetoothDeviceChromeOS::RejectPairing() { 214 if (!agent_.get()) 215 return; 216 217 if (!pincode_callback_.is_null()) { 218 pincode_callback_.Run(REJECTED, ""); 219 pincode_callback_.Reset(); 220 } 221 if (!passkey_callback_.is_null()) { 222 passkey_callback_.Run(REJECTED, 0); 223 passkey_callback_.Reset(); 224 } 225 if (!confirmation_callback_.is_null()) { 226 confirmation_callback_.Run(REJECTED); 227 confirmation_callback_.Reset(); 228 } 229} 230 231void BluetoothDeviceChromeOS::CancelPairing() { 232 bool have_callback = false; 233 if (agent_.get()) { 234 if (!pincode_callback_.is_null()) { 235 pincode_callback_.Run(CANCELLED, ""); 236 pincode_callback_.Reset(); 237 have_callback = true; 238 } 239 if (!passkey_callback_.is_null()) { 240 passkey_callback_.Run(CANCELLED, 0); 241 passkey_callback_.Reset(); 242 have_callback = true; 243 } 244 if (!confirmation_callback_.is_null()) { 245 confirmation_callback_.Run(CANCELLED); 246 confirmation_callback_.Reset(); 247 have_callback = true; 248 } 249 } 250 251 if (!have_callback) { 252 // User cancels the pairing process. 253 DBusThreadManager::Get()->GetBluetoothAdapterClient()->CancelDeviceCreation( 254 adapter_->object_path_, 255 address_, 256 base::Bind(&BluetoothDeviceChromeOS::OnCancelDeviceCreation, 257 weak_ptr_factory_.GetWeakPtr())); 258 259 pairing_delegate_ = NULL; 260 agent_.reset(); 261 } 262} 263 264void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, 265 const ErrorCallback& error_callback) { 266 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 267 Disconnect(object_path_, 268 base::Bind(&BluetoothDeviceChromeOS::DisconnectCallback, 269 weak_ptr_factory_.GetWeakPtr(), 270 callback, 271 error_callback)); 272 273} 274 275void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { 276 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 277 RemoveDevice(adapter_->object_path_, 278 object_path_, 279 base::Bind(&BluetoothDeviceChromeOS::ForgetCallback, 280 weak_ptr_factory_.GetWeakPtr(), 281 error_callback)); 282} 283 284void BluetoothDeviceChromeOS::ConnectToService(const std::string& service_uuid, 285 const SocketCallback& callback) { 286 GetServiceRecords( 287 base::Bind(&BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback, 288 weak_ptr_factory_.GetWeakPtr(), 289 service_uuid, 290 callback), 291 base::Bind( 292 &BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback, 293 weak_ptr_factory_.GetWeakPtr(), 294 callback)); 295} 296 297void BluetoothDeviceChromeOS::SetOutOfBandPairingData( 298 const BluetoothOutOfBandPairingData& data, 299 const base::Closure& callback, 300 const ErrorCallback& error_callback) { 301 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> 302 AddRemoteData( 303 object_path_, 304 address(), 305 data, 306 base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback, 307 weak_ptr_factory_.GetWeakPtr(), 308 callback, 309 error_callback)); 310} 311 312void BluetoothDeviceChromeOS::ClearOutOfBandPairingData( 313 const base::Closure& callback, 314 const ErrorCallback& error_callback) { 315 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> 316 RemoveRemoteData( 317 object_path_, 318 address(), 319 base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback, 320 weak_ptr_factory_.GetWeakPtr(), 321 callback, 322 error_callback)); 323} 324 325void BluetoothDeviceChromeOS::SetObjectPath( 326 const dbus::ObjectPath& object_path) { 327 DCHECK(object_path_ == dbus::ObjectPath("")); 328 object_path_ = object_path; 329} 330 331void BluetoothDeviceChromeOS::RemoveObjectPath() { 332 DCHECK(object_path_ != dbus::ObjectPath("")); 333 object_path_ = dbus::ObjectPath(""); 334} 335 336void BluetoothDeviceChromeOS::Update( 337 const BluetoothDeviceClient::Properties* properties, 338 bool update_state) { 339 std::string address = properties->address.value(); 340 std::string name = properties->name.value(); 341 uint32 bluetooth_class = properties->bluetooth_class.value(); 342 const std::vector<std::string>& uuids = properties->uuids.value(); 343 344 if (!address.empty()) 345 address_ = address; 346 if (!name.empty()) 347 name_ = name; 348 if (bluetooth_class) 349 bluetooth_class_ = bluetooth_class; 350 if (!uuids.empty()) { 351 service_uuids_.clear(); 352 service_uuids_.assign(uuids.begin(), uuids.end()); 353 } 354 355 if (update_state) { 356 // When the device reconnects and we don't have any service records for it, 357 // try to update the cache or fail silently. 358 if (!service_records_loaded_ && !connected_ && 359 properties->connected.value()) 360 GetServiceRecords(base::Bind(&DoNothingServiceRecordList), 361 base::Bind(&base::DoNothing)); 362 363 // BlueZ uses paired to mean link keys exchanged, whereas the Bluetooth 364 // spec refers to this as bonded. Use the spec name for our interface. 365 bonded_ = properties->paired.value(); 366 connected_ = properties->connected.value(); 367 } 368} 369 370void BluetoothDeviceChromeOS::OnCreateDevice( 371 const base::Closure& callback, 372 const ConnectErrorCallback& error_callback, 373 const dbus::ObjectPath& device_path) { 374 VLOG(1) << "Connection successful: " << device_path.value(); 375 if (object_path_.value().empty()) { 376 object_path_ = device_path; 377 } else { 378 LOG_IF(WARNING, object_path_ != device_path) 379 << "Conflicting device paths for objects, result gave: " 380 << device_path.value() << " but signal gave: " 381 << object_path_.value(); 382 } 383 384 // Mark the device trusted so it can connect to us automatically, and 385 // we can connect after rebooting. This information is part of the 386 // pairing information of the device, and is unique to the combination 387 // of our bluetooth address and the device's bluetooth address. A 388 // different host needs a new pairing, so it's not useful to sync. 389 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 390 GetProperties(object_path_)->trusted.Set( 391 true, 392 base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, 393 weak_ptr_factory_.GetWeakPtr())); 394 395 // In parallel with the |trusted| property change, call GetServiceRecords to 396 // retrieve the SDP from the device and then, either on success or failure, 397 // call ConnectApplications. 398 GetServiceRecords( 399 base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecords, 400 weak_ptr_factory_.GetWeakPtr(), 401 callback, 402 error_callback), 403 base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError, 404 weak_ptr_factory_.GetWeakPtr(), 405 callback, 406 error_callback)); 407} 408 409void BluetoothDeviceChromeOS::OnCreateDeviceError( 410 const ConnectErrorCallback& error_callback, 411 const std::string& error_name, 412 const std::string& error_message) { 413 // The default |error_code| is an unknown error. 414 ConnectErrorCode error_code = ERROR_UNKNOWN; 415 416 // Report any error in the log, even if we know the possible source of it. 417 LOG(WARNING) << "Connection failed (on CreatePairedDevice): " 418 << "\"" << name_ << "\" (" << address_ << "): " 419 << error_name << ": \"" << error_message << "\""; 420 421 // Determines the right error code from error_name, assuming the error name 422 // comes from CreatePairedDevice bluez function. 423 if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) { 424 error_code = ERROR_FAILED; 425 } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) { 426 error_code = ERROR_AUTH_FAILED; 427 } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) { 428 error_code = ERROR_AUTH_REJECTED; 429 } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) { 430 error_code = ERROR_AUTH_TIMEOUT; 431 } 432 error_callback.Run(error_code); 433} 434 435void BluetoothDeviceChromeOS::CollectServiceRecordsCallback( 436 const ServiceRecordsCallback& callback, 437 const ErrorCallback& error_callback, 438 const dbus::ObjectPath& device_path, 439 const BluetoothDeviceClient::ServiceMap& service_map, 440 bool success) { 441 if (!success) { 442 error_callback.Run(); 443 return; 444 } 445 446 // Update the cache. No other thread is executing a GetServiceRecords 447 // callback, so it is safe to delete the previous objects here. 448 service_records_.clear(); 449 // TODO(deymo): Perhaps don't update the cache if the new SDP information is 450 // empty and we had something before. Some devices only answer this 451 // information while paired, and this callback could be called in any order if 452 // several calls to GetServiceRecords are made while initial pairing with the 453 // device. This requires more investigation. 454 for (BluetoothDeviceClient::ServiceMap::const_iterator i = 455 service_map.begin(); i != service_map.end(); ++i) { 456 service_records_.push_back( 457 new BluetoothServiceRecordChromeOS(address(), i->second)); 458 } 459 service_records_loaded_ = true; 460 461 callback.Run(service_records_); 462} 463 464void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { 465 LOG_IF(WARNING, !success) << "Failed to set device as trusted: " << address_; 466} 467 468void BluetoothDeviceChromeOS::OnInitialGetServiceRecords( 469 const base::Closure& callback, 470 const ConnectErrorCallback& error_callback, 471 const ServiceRecordList& list) { 472 // Connect application-layer protocols. 473 ConnectApplications(callback, error_callback); 474} 475 476void BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError( 477 const base::Closure& callback, 478 const ConnectErrorCallback& error_callback) { 479 // Ignore the error retrieving the service records and continue. 480 LOG(WARNING) << "Error retrieving SDP for " << address_ << " after pairing."; 481 // Connect application-layer protocols. 482 ConnectApplications(callback, error_callback); 483} 484 485void BluetoothDeviceChromeOS::OnGetServiceRecordsError( 486 const ServiceRecordsCallback& callback, 487 const ErrorCallback& error_callback) { 488 if (service_records_loaded_) { 489 callback.Run(service_records_); 490 } else { 491 error_callback.Run(); 492 } 493} 494 495void BluetoothDeviceChromeOS::OnConnectCallbackCalled( 496 const base::Closure& callback) { 497 // Update the connecting status. 498 connecting_calls_--; 499 connecting_ = !!connecting_calls_; 500 callback.Run(); 501} 502 503void BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled( 504 const ConnectErrorCallback& error_callback, 505 enum ConnectErrorCode error_code) { 506 // Update the connecting status. 507 connecting_calls_--; 508 connecting_ = !!connecting_calls_; 509 error_callback.Run(error_code); 510} 511 512void BluetoothDeviceChromeOS::ConnectApplications( 513 const base::Closure& callback, 514 const ConnectErrorCallback& error_callback) { 515 // Introspect the device object to determine supported applications. 516 DBusThreadManager::Get()->GetIntrospectableClient()-> 517 Introspect(bluetooth_device::kBluetoothDeviceServiceName, 518 object_path_, 519 base::Bind(&BluetoothDeviceChromeOS::OnIntrospect, 520 weak_ptr_factory_.GetWeakPtr(), 521 callback, 522 error_callback)); 523} 524 525void BluetoothDeviceChromeOS::OnIntrospect( 526 const base::Closure& callback, 527 const ConnectErrorCallback& error_callback, 528 const std::string& service_name, 529 const dbus::ObjectPath& device_path, 530 const std::string& xml_data, 531 bool success) { 532 if (!success) { 533 LOG(WARNING) << "Failed to determine supported applications: " << address_; 534 error_callback.Run(ERROR_UNKNOWN); 535 return; 536 } 537 538 // The introspection data for the device object may list one or more 539 // additional D-Bus interfaces that BlueZ supports for this particular 540 // device. Send appropraite Connect calls for each of those interfaces 541 // to connect all of the application protocols for this device. 542 std::vector<std::string> interfaces = 543 IntrospectableClient::GetInterfacesFromIntrospectResult(xml_data); 544 545 DCHECK_EQ(0, connecting_applications_counter_); 546 connecting_applications_counter_ = 0; 547 for (std::vector<std::string>::iterator iter = interfaces.begin(); 548 iter != interfaces.end(); ++iter) { 549 if (*iter == bluetooth_input::kBluetoothInputInterface) { 550 connecting_applications_counter_++; 551 // Supports Input interface. 552 DBusThreadManager::Get()->GetBluetoothInputClient()-> 553 Connect(object_path_, 554 base::Bind(&BluetoothDeviceChromeOS::OnConnect, 555 weak_ptr_factory_.GetWeakPtr(), 556 callback, 557 *iter), 558 base::Bind(&BluetoothDeviceChromeOS::OnConnectError, 559 weak_ptr_factory_.GetWeakPtr(), 560 error_callback, *iter)); 561 } 562 } 563 564 // If OnConnect has been called for every call to Connect above, then this 565 // will decrement the counter to -1. In that case, call the callback 566 // directly as it has not been called by any of the OnConnect callbacks. 567 // This is safe because OnIntrospect and OnConnect run on the same thread. 568 connecting_applications_counter_--; 569 if (connecting_applications_counter_ == -1) 570 callback.Run(); 571} 572 573void BluetoothDeviceChromeOS::OnConnect(const base::Closure& callback, 574 const std::string& interface_name, 575 const dbus::ObjectPath& device_path) { 576 VLOG(1) << "Application connection successful: " << device_path.value() 577 << ": " << interface_name; 578 579 connecting_applications_counter_--; 580 // |callback| should only be called once, meaning it cannot be called before 581 // all requests have been started. The extra decrement after all requests 582 // have been started, and the check for -1 instead of 0 below, insure only a 583 // single call to |callback| will occur (provided OnConnect and OnIntrospect 584 // run on the same thread, which is true). 585 if (connecting_applications_counter_ == -1) { 586 connecting_applications_counter_ = 0; 587 callback.Run(); 588 } 589} 590 591void BluetoothDeviceChromeOS::OnConnectError( 592 const ConnectErrorCallback& error_callback, 593 const std::string& interface_name, 594 const dbus::ObjectPath& device_path, 595 const std::string& error_name, 596 const std::string& error_message) { 597 // The default |error_code| is an unknown error. 598 ConnectErrorCode error_code = ERROR_UNKNOWN; 599 600 // Report any error in the log, even if we know the possible source of it. 601 LOG(WARNING) << "Connection failed (on Connect): " 602 << interface_name << ": " 603 << "\"" << name_ << "\" (" << address_ << "): " 604 << error_name << ": \"" << error_message << "\""; 605 606 // Determines the right error code from error_name, assuming the error name 607 // comes from Connect bluez function. 608 if (error_name == bluetooth_adapter::kErrorFailed) { 609 error_code = ERROR_FAILED; 610 } else if (error_name == bluetooth_adapter::kErrorInProgress) { 611 error_code = ERROR_INPROGRESS; 612 } else if (error_name == bluetooth_adapter::kErrorNotSupported) { 613 error_code = ERROR_UNSUPPORTED_DEVICE; 614 } 615 616 error_callback.Run(error_code); 617} 618 619void BluetoothDeviceChromeOS::DisconnectCallback( 620 const base::Closure& callback, 621 const ErrorCallback& error_callback, 622 const dbus::ObjectPath& device_path, 623 bool success) { 624 DCHECK(device_path == object_path_); 625 if (success) { 626 VLOG(1) << "Disconnection successful: " << address_; 627 callback.Run(); 628 } else { 629 if (connected_) { 630 LOG(WARNING) << "Disconnection failed: " << address_; 631 error_callback.Run(); 632 } else { 633 VLOG(1) << "Disconnection failed on a already disconnected device: " 634 << address_; 635 callback.Run(); 636 } 637 } 638} 639 640void BluetoothDeviceChromeOS::ForgetCallback( 641 const ErrorCallback& error_callback, 642 const dbus::ObjectPath& adapter_path, 643 bool success) { 644 // It's quite normal that this path never gets called on success; we use a 645 // weak pointer, and bluetoothd might send the DeviceRemoved signal before 646 // the method reply, in which case this object is deleted and the 647 // callback never takes place. Therefore don't do anything here for the 648 // success case. 649 if (!success) { 650 LOG(WARNING) << "Forget failed: " << address_; 651 error_callback.Run(); 652 } 653} 654 655void BluetoothDeviceChromeOS::OnCancelDeviceCreation( 656 const dbus::ObjectPath& adapter_path, 657 bool success) { 658 if (!success) 659 LOG(WARNING) << "CancelDeviceCreation failed: " << address_; 660} 661 662void BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback( 663 const ProvidesServiceCallback& callback) { 664 callback.Run(false); 665} 666 667void BluetoothDeviceChromeOS::SearchServicesForNameCallback( 668 const std::string& name, 669 const ProvidesServiceCallback& callback, 670 const ServiceRecordList& list) { 671 for (ServiceRecordList::const_iterator i = list.begin(); 672 i != list.end(); ++i) { 673 if ((*i)->name() == name) { 674 callback.Run(true); 675 return; 676 } 677 } 678 callback.Run(false); 679} 680 681void BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback( 682 const SocketCallback& callback) { 683 callback.Run(NULL); 684} 685 686void BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback( 687 const std::string& service_uuid, 688 const SocketCallback& callback, 689 const ServiceRecordList& list) { 690 for (ServiceRecordList::const_iterator i = list.begin(); 691 i != list.end(); ++i) { 692 if ((*i)->uuid() == service_uuid) { 693 // If multiple service records are found, use the first one that works. 694 scoped_refptr<BluetoothSocket> socket( 695 BluetoothSocketChromeOS::CreateBluetoothSocket(**i)); 696 if (socket.get() != NULL) { 697 callback.Run(socket); 698 return; 699 } 700 } 701 } 702 callback.Run(NULL); 703} 704 705void BluetoothDeviceChromeOS::OnRemoteDataCallback( 706 const base::Closure& callback, 707 const ErrorCallback& error_callback, 708 bool success) { 709 if (success) 710 callback.Run(); 711 else 712 error_callback.Run(); 713} 714 715void BluetoothDeviceChromeOS::DisconnectRequested( 716 const dbus::ObjectPath& object_path) { 717 DCHECK(object_path == object_path_); 718} 719 720void BluetoothDeviceChromeOS::Release() { 721 DCHECK(agent_.get()); 722 VLOG(1) << "Release: " << address_; 723 724 DCHECK(pairing_delegate_); 725 pairing_delegate_->DismissDisplayOrConfirm(); 726 pairing_delegate_ = NULL; 727 728 pincode_callback_.Reset(); 729 passkey_callback_.Reset(); 730 confirmation_callback_.Reset(); 731 732 agent_.reset(); 733} 734 735void BluetoothDeviceChromeOS::RequestPinCode( 736 const dbus::ObjectPath& device_path, 737 const PinCodeCallback& callback) { 738 DCHECK(agent_.get()); 739 VLOG(1) << "RequestPinCode: " << device_path.value(); 740 741 DCHECK(pairing_delegate_); 742 DCHECK(pincode_callback_.is_null()); 743 pincode_callback_ = callback; 744 pairing_delegate_->RequestPinCode(this); 745} 746 747void BluetoothDeviceChromeOS::RequestPasskey( 748 const dbus::ObjectPath& device_path, 749 const PasskeyCallback& callback) { 750 DCHECK(agent_.get()); 751 DCHECK(device_path == object_path_); 752 VLOG(1) << "RequestPasskey: " << device_path.value(); 753 754 DCHECK(pairing_delegate_); 755 DCHECK(passkey_callback_.is_null()); 756 passkey_callback_ = callback; 757 pairing_delegate_->RequestPasskey(this); 758} 759 760void BluetoothDeviceChromeOS::DisplayPinCode( 761 const dbus::ObjectPath& device_path, 762 const std::string& pincode) { 763 DCHECK(agent_.get()); 764 DCHECK(device_path == object_path_); 765 VLOG(1) << "DisplayPinCode: " << device_path.value() << " " << pincode; 766 767 DCHECK(pairing_delegate_); 768 pairing_delegate_->DisplayPinCode(this, pincode); 769} 770 771void BluetoothDeviceChromeOS::DisplayPasskey( 772 const dbus::ObjectPath& device_path, 773 uint32 passkey) { 774 DCHECK(agent_.get()); 775 DCHECK(device_path == object_path_); 776 VLOG(1) << "DisplayPasskey: " << device_path.value() << " " << passkey; 777 778 DCHECK(pairing_delegate_); 779 pairing_delegate_->DisplayPasskey(this, passkey); 780} 781 782void BluetoothDeviceChromeOS::RequestConfirmation( 783 const dbus::ObjectPath& device_path, 784 uint32 passkey, 785 const ConfirmationCallback& callback) { 786 DCHECK(agent_.get()); 787 DCHECK(device_path == object_path_); 788 VLOG(1) << "RequestConfirmation: " << device_path.value() << " " << passkey; 789 790 DCHECK(pairing_delegate_); 791 DCHECK(confirmation_callback_.is_null()); 792 confirmation_callback_ = callback; 793 pairing_delegate_->ConfirmPasskey(this, passkey); 794} 795 796void BluetoothDeviceChromeOS::Authorize(const dbus::ObjectPath& device_path, 797 const std::string& uuid, 798 const ConfirmationCallback& callback) { 799 DCHECK(agent_.get()); 800 DCHECK(device_path == object_path_); 801 LOG(WARNING) << "Rejected authorization for service: " << uuid 802 << " requested from device: " << device_path.value(); 803 callback.Run(REJECTED); 804} 805 806void BluetoothDeviceChromeOS::ConfirmModeChange( 807 Mode mode, 808 const ConfirmationCallback& callback) { 809 DCHECK(agent_.get()); 810 LOG(WARNING) << "Rejected adapter-level mode change: " << mode 811 << " made on agent for device: " << address_; 812 callback.Run(REJECTED); 813} 814 815void BluetoothDeviceChromeOS::Cancel() { 816 DCHECK(agent_.get()); 817 VLOG(1) << "Cancel: " << address_; 818 819 DCHECK(pairing_delegate_); 820 pairing_delegate_->DismissDisplayOrConfirm(); 821} 822 823 824// static 825BluetoothDeviceChromeOS* BluetoothDeviceChromeOS::Create( 826 BluetoothAdapterChromeOS* adapter) { 827 return new BluetoothDeviceChromeOS(adapter); 828} 829 830} // namespace chromeos 831