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