bluetooth_device_chromeos.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm// Copyright 2013 The Chromium Authors. All rights reserved. 266100609bb7fb01811e64318bec3018d0bc9abd5homeip.net!davidm// Use of this source code is governed by a BSD-style license that can be 3521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm// found in the LICENSE file. 4521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm 5521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_device_chromeos.h" 6521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm 7521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include <stdio.h> 8521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm 9521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "base/bind.h" 10521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "base/memory/scoped_ptr.h" 11521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "base/metrics/histogram.h" 12521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "base/strings/string_number_conversions.h" 13521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "base/strings/string_util.h" 14521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "chromeos/dbus/bluetooth_adapter_client.h" 15521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "chromeos/dbus/bluetooth_device_client.h" 16521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "chromeos/dbus/bluetooth_gatt_service_client.h" 17521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "chromeos/dbus/bluetooth_input_client.h" 18521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "chromeos/dbus/dbus_thread_manager.h" 19521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "dbus/bus.h" 20521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_adapter_chromeos.h" 21521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_gatt_connection_chromeos.h" 22521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_pairing_chromeos.h" 23521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h" 24521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_socket.h" 25521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_socket_chromeos.h" 26521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_socket_thread.h" 27521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm#include "device/bluetooth/bluetooth_uuid.h" 282319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris#include "third_party/cros_system_api/dbus/service_constants.h" 29521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm 30521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidmusing device::BluetoothDevice; 31521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidmusing device::BluetoothSocket; 32521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidmusing device::BluetoothUUID; 33521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm 34521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidmnamespace { 352319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris 362319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris// Histogram enumerations for pairing results. 37521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidmenum UMAPairingResult { 38521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_SUCCESS, 39521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_INPROGRESS, 40521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_FAILED, 41521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_AUTH_FAILED, 42521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_AUTH_CANCELED, 43521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_AUTH_REJECTED, 442319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris UMA_PAIRING_RESULT_AUTH_TIMEOUT, 452319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE, 46521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm UMA_PAIRING_RESULT_UNKNOWN_ERROR, 472319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris // NOTE: Add new pairing results immediately above this line. Make sure to 482319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris // update the enum list in tools/histogram/histograms.xml accordinly. 492319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris UMA_PAIRING_RESULT_COUNT 502319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris}; 512319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris 522319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferrisvoid ParseModalias(const dbus::ObjectPath& object_path, 532319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris BluetoothDevice::VendorIDSource* vendor_id_source, 542319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris uint16* vendor_id, 55521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm uint16* product_id, 562319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris uint16* device_id) { 572319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris chromeos::BluetoothDeviceClient::Properties* properties = 58521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm chromeos::DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 592319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris GetProperties(object_path); 60521e8ae52eb278c022fba51874a227ca0425b5a8hp.com!davidm DCHECK(properties); 612319e0f1aec9e1f716eff88987b0023c5b2f6c07Christopher Ferris 6266100609bb7fb01811e64318bec3018d0bc9abd5homeip.net!davidm std::string modalias = properties->modalias.value(); 6366100609bb7fb01811e64318bec3018d0bc9abd5homeip.net!davidm BluetoothDevice::VendorIDSource source_value; 6466100609bb7fb01811e64318bec3018d0bc9abd5homeip.net!davidm int vendor_value, product_value, device_value; 6566100609bb7fb01811e64318bec3018d0bc9abd5homeip.net!davidm 66 if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x", 67 &vendor_value, &product_value, &device_value) == 3) { 68 source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH; 69 } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x", 70 &vendor_value, &product_value, &device_value) == 3) { 71 source_value = BluetoothDevice::VENDOR_ID_USB; 72 } else { 73 return; 74 } 75 76 if (vendor_id_source != NULL) 77 *vendor_id_source = source_value; 78 if (vendor_id != NULL) 79 *vendor_id = vendor_value; 80 if (product_id != NULL) 81 *product_id = product_value; 82 if (device_id != NULL) 83 *device_id = device_value; 84} 85 86void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { 87 UMAPairingResult pairing_result; 88 switch (error_code) { 89 case BluetoothDevice::ERROR_INPROGRESS: 90 pairing_result = UMA_PAIRING_RESULT_INPROGRESS; 91 break; 92 case BluetoothDevice::ERROR_FAILED: 93 pairing_result = UMA_PAIRING_RESULT_FAILED; 94 break; 95 case BluetoothDevice::ERROR_AUTH_FAILED: 96 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED; 97 break; 98 case BluetoothDevice::ERROR_AUTH_CANCELED: 99 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED; 100 break; 101 case BluetoothDevice::ERROR_AUTH_REJECTED: 102 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED; 103 break; 104 case BluetoothDevice::ERROR_AUTH_TIMEOUT: 105 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT; 106 break; 107 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: 108 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE; 109 break; 110 default: 111 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR; 112 } 113 114 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", 115 pairing_result, 116 UMA_PAIRING_RESULT_COUNT); 117} 118 119} // namespace 120 121namespace chromeos { 122 123BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( 124 BluetoothAdapterChromeOS* adapter, 125 const dbus::ObjectPath& object_path, 126 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, 127 scoped_refptr<device::BluetoothSocketThread> socket_thread) 128 : adapter_(adapter), 129 object_path_(object_path), 130 num_connecting_calls_(0), 131 connection_monitor_started_(false), 132 ui_task_runner_(ui_task_runner), 133 socket_thread_(socket_thread), 134 weak_ptr_factory_(this) { 135 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->AddObserver(this); 136 137 // Add all known GATT services. 138 const std::vector<dbus::ObjectPath> gatt_services = 139 DBusThreadManager::Get()->GetBluetoothGattServiceClient()->GetServices(); 140 for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin(); 141 it != gatt_services.end(); ++it) { 142 GattServiceAdded(*it); 143 } 144} 145 146BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { 147 DBusThreadManager::Get()->GetBluetoothGattServiceClient()-> 148 RemoveObserver(this); 149 150 // Copy the GATT services list here and clear the original so that when we 151 // send GattServiceRemoved(), GetGattServices() returns no services. 152 GattServiceMap gatt_services = gatt_services_; 153 gatt_services_.clear(); 154 for (GattServiceMap::iterator iter = gatt_services.begin(); 155 iter != gatt_services.end(); ++iter) { 156 FOR_EACH_OBSERVER(BluetoothDevice::Observer, observers_, 157 GattServiceRemoved(this, iter->second)); 158 delete iter->second; 159 } 160} 161 162void BluetoothDeviceChromeOS::AddObserver( 163 device::BluetoothDevice::Observer* observer) { 164 DCHECK(observer); 165 observers_.AddObserver(observer); 166} 167 168void BluetoothDeviceChromeOS::RemoveObserver( 169 device::BluetoothDevice::Observer* observer) { 170 DCHECK(observer); 171 observers_.RemoveObserver(observer); 172} 173 174uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const { 175 BluetoothDeviceClient::Properties* properties = 176 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 177 GetProperties(object_path_); 178 DCHECK(properties); 179 180 return properties->bluetooth_class.value(); 181} 182 183std::string BluetoothDeviceChromeOS::GetDeviceName() const { 184 BluetoothDeviceClient::Properties* properties = 185 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 186 GetProperties(object_path_); 187 DCHECK(properties); 188 189 return properties->alias.value(); 190} 191 192std::string BluetoothDeviceChromeOS::GetAddress() const { 193 BluetoothDeviceClient::Properties* properties = 194 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 195 GetProperties(object_path_); 196 DCHECK(properties); 197 198 return CanonicalizeAddress(properties->address.value()); 199} 200 201BluetoothDevice::VendorIDSource 202BluetoothDeviceChromeOS::GetVendorIDSource() const { 203 VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN; 204 ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL); 205 return vendor_id_source; 206} 207 208uint16 BluetoothDeviceChromeOS::GetVendorID() const { 209 uint16 vendor_id = 0; 210 ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL); 211 return vendor_id; 212} 213 214uint16 BluetoothDeviceChromeOS::GetProductID() const { 215 uint16 product_id = 0; 216 ParseModalias(object_path_, NULL, NULL, &product_id, NULL); 217 return product_id; 218} 219 220uint16 BluetoothDeviceChromeOS::GetDeviceID() const { 221 uint16 device_id = 0; 222 ParseModalias(object_path_, NULL, NULL, NULL, &device_id); 223 return device_id; 224} 225 226int BluetoothDeviceChromeOS::GetRSSI() const { 227 BluetoothDeviceClient::Properties* properties = 228 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties( 229 object_path_); 230 DCHECK(properties); 231 232 if (!IsConnected()) { 233 NOTIMPLEMENTED(); 234 return kUnknownPower; 235 } 236 237 return connection_monitor_started_ ? properties->connection_rssi.value() 238 : kUnknownPower; 239} 240 241int BluetoothDeviceChromeOS::GetCurrentHostTransmitPower() const { 242 BluetoothDeviceClient::Properties* properties = 243 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties( 244 object_path_); 245 DCHECK(properties); 246 247 return IsConnected() && connection_monitor_started_ 248 ? properties->connection_tx_power.value() 249 : kUnknownPower; 250} 251 252int BluetoothDeviceChromeOS::GetMaximumHostTransmitPower() const { 253 BluetoothDeviceClient::Properties* properties = 254 DBusThreadManager::Get()->GetBluetoothDeviceClient()->GetProperties( 255 object_path_); 256 DCHECK(properties); 257 258 return IsConnected() ? properties->connection_tx_power_max.value() 259 : kUnknownPower; 260} 261 262bool BluetoothDeviceChromeOS::IsPaired() const { 263 BluetoothDeviceClient::Properties* properties = 264 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 265 GetProperties(object_path_); 266 DCHECK(properties); 267 268 // Trusted devices are devices that don't support pairing but that the 269 // user has explicitly connected; it makes no sense for UI purposes to 270 // treat them differently from each other. 271 return properties->paired.value() || properties->trusted.value(); 272} 273 274bool BluetoothDeviceChromeOS::IsConnected() const { 275 BluetoothDeviceClient::Properties* properties = 276 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 277 GetProperties(object_path_); 278 DCHECK(properties); 279 280 return properties->connected.value(); 281} 282 283bool BluetoothDeviceChromeOS::IsConnectable() const { 284 BluetoothInputClient::Properties* input_properties = 285 DBusThreadManager::Get()->GetBluetoothInputClient()-> 286 GetProperties(object_path_); 287 // GetProperties returns NULL when the device does not implement the given 288 // interface. Non HID devices are normally connectable. 289 if (!input_properties) 290 return true; 291 292 return input_properties->reconnect_mode.value() != "device"; 293} 294 295bool BluetoothDeviceChromeOS::IsConnecting() const { 296 return num_connecting_calls_ > 0; 297} 298 299BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const { 300 BluetoothDeviceClient::Properties* properties = 301 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 302 GetProperties(object_path_); 303 DCHECK(properties); 304 305 std::vector<device::BluetoothUUID> uuids; 306 const std::vector<std::string> &dbus_uuids = properties->uuids.value(); 307 for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin(); 308 iter != dbus_uuids.end(); ++iter) { 309 device::BluetoothUUID uuid(*iter); 310 DCHECK(uuid.IsValid()); 311 uuids.push_back(uuid); 312 } 313 return uuids; 314} 315 316bool BluetoothDeviceChromeOS::ExpectingPinCode() const { 317 return pairing_.get() && pairing_->ExpectingPinCode(); 318} 319 320bool BluetoothDeviceChromeOS::ExpectingPasskey() const { 321 return pairing_.get() && pairing_->ExpectingPasskey(); 322} 323 324bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { 325 return pairing_.get() && pairing_->ExpectingConfirmation(); 326} 327 328void BluetoothDeviceChromeOS::Connect( 329 BluetoothDevice::PairingDelegate* pairing_delegate, 330 const base::Closure& callback, 331 const ConnectErrorCallback& error_callback) { 332 if (num_connecting_calls_++ == 0) 333 adapter_->NotifyDeviceChanged(this); 334 335 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ 336 << " in progress"; 337 338 if (IsPaired() || !pairing_delegate || !IsPairable()) { 339 // No need to pair, or unable to, skip straight to connection. 340 ConnectInternal(false, callback, error_callback); 341 } else { 342 // Initiate high-security connection with pairing. 343 BeginPairing(pairing_delegate); 344 345 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 346 Pair(object_path_, 347 base::Bind(&BluetoothDeviceChromeOS::OnPair, 348 weak_ptr_factory_.GetWeakPtr(), 349 callback, error_callback), 350 base::Bind(&BluetoothDeviceChromeOS::OnPairError, 351 weak_ptr_factory_.GetWeakPtr(), 352 error_callback)); 353 } 354} 355 356void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { 357 if (!pairing_.get()) 358 return; 359 360 pairing_->SetPinCode(pincode); 361} 362 363void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { 364 if (!pairing_.get()) 365 return; 366 367 pairing_->SetPasskey(passkey); 368} 369 370void BluetoothDeviceChromeOS::ConfirmPairing() { 371 if (!pairing_.get()) 372 return; 373 374 pairing_->ConfirmPairing(); 375} 376 377void BluetoothDeviceChromeOS::RejectPairing() { 378 if (!pairing_.get()) 379 return; 380 381 pairing_->RejectPairing(); 382} 383 384void BluetoothDeviceChromeOS::CancelPairing() { 385 bool canceled = false; 386 387 // If there is a callback in progress that we can reply to then use that 388 // to cancel the current pairing request. 389 if (pairing_.get() && pairing_->CancelPairing()) 390 canceled = true; 391 392 // If not we have to send an explicit CancelPairing() to the device instead. 393 if (!canceled) { 394 VLOG(1) << object_path_.value() << ": No pairing context or callback. " 395 << "Sending explicit cancel"; 396 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 397 CancelPairing( 398 object_path_, 399 base::Bind(&base::DoNothing), 400 base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError, 401 weak_ptr_factory_.GetWeakPtr())); 402 } 403 404 // Since there is no callback to this method it's possible that the pairing 405 // delegate is going to be freed before things complete (indeed it's 406 // documented that this is the method you should call while freeing the 407 // pairing delegate), so clear our the context holding on to it. 408 EndPairing(); 409} 410 411void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, 412 const ErrorCallback& error_callback) { 413 VLOG(1) << object_path_.value() << ": Disconnecting"; 414 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 415 Disconnect( 416 object_path_, 417 base::Bind(&BluetoothDeviceChromeOS::OnDisconnect, 418 weak_ptr_factory_.GetWeakPtr(), 419 callback), 420 base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError, 421 weak_ptr_factory_.GetWeakPtr(), 422 error_callback)); 423} 424 425void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { 426 VLOG(1) << object_path_.value() << ": Removing device"; 427 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 428 RemoveDevice( 429 adapter_->object_path(), 430 object_path_, 431 base::Bind(&base::DoNothing), 432 base::Bind(&BluetoothDeviceChromeOS::OnForgetError, 433 weak_ptr_factory_.GetWeakPtr(), 434 error_callback)); 435} 436 437void BluetoothDeviceChromeOS::ConnectToService( 438 const BluetoothUUID& uuid, 439 const ConnectToServiceCallback& callback, 440 const ConnectToServiceErrorCallback& error_callback) { 441 VLOG(1) << object_path_.value() << ": Connecting to service: " 442 << uuid.canonical_value(); 443 scoped_refptr<BluetoothSocketChromeOS> socket = 444 BluetoothSocketChromeOS::CreateBluetoothSocket( 445 ui_task_runner_, 446 socket_thread_, 447 NULL, 448 net::NetLog::Source()); 449 socket->Connect(this, uuid, 450 base::Bind(callback, socket), 451 error_callback); 452} 453 454void BluetoothDeviceChromeOS::CreateGattConnection( 455 const GattConnectionCallback& callback, 456 const ConnectErrorCallback& error_callback) { 457 // TODO(armansito): Until there is a way to create a reference counted GATT 458 // connection in bluetoothd, simply do a regular connect. 459 Connect(NULL, 460 base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection, 461 weak_ptr_factory_.GetWeakPtr(), 462 callback), 463 error_callback); 464} 465 466void BluetoothDeviceChromeOS::StartConnectionMonitor( 467 const base::Closure& callback, 468 const ErrorCallback& error_callback) { 469 DBusThreadManager::Get()->GetBluetoothDeviceClient()->StartConnectionMonitor( 470 object_path_, 471 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitor, 472 weak_ptr_factory_.GetWeakPtr(), 473 callback), 474 base::Bind(&BluetoothDeviceChromeOS::OnStartConnectionMonitorError, 475 weak_ptr_factory_.GetWeakPtr(), 476 error_callback)); 477} 478 479BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing( 480 BluetoothDevice::PairingDelegate* pairing_delegate) { 481 pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate)); 482 return pairing_.get(); 483} 484 485void BluetoothDeviceChromeOS::EndPairing() { 486 pairing_.reset(); 487} 488 489BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const { 490 return pairing_.get(); 491} 492 493void BluetoothDeviceChromeOS::GattServiceAdded( 494 const dbus::ObjectPath& object_path) { 495 if (GetGattService(object_path.value())) { 496 VLOG(1) << "Remote GATT service already exists: " << object_path.value(); 497 return; 498 } 499 500 BluetoothGattServiceClient::Properties* properties = 501 DBusThreadManager::Get()->GetBluetoothGattServiceClient()-> 502 GetProperties(object_path); 503 DCHECK(properties); 504 if (properties->device.value() != object_path_) { 505 VLOG(2) << "Remote GATT service does not belong to this device."; 506 return; 507 } 508 509 VLOG(1) << "Adding new remote GATT service for device: " << GetAddress(); 510 511 BluetoothRemoteGattServiceChromeOS* service = 512 new BluetoothRemoteGattServiceChromeOS(adapter_, this, object_path); 513 514 gatt_services_[service->GetIdentifier()] = service; 515 DCHECK(service->object_path() == object_path); 516 DCHECK(service->GetUUID().IsValid()); 517 518 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_, 519 GattServiceAdded(this, service)); 520} 521 522void BluetoothDeviceChromeOS::GattServiceRemoved( 523 const dbus::ObjectPath& object_path) { 524 GattServiceMap::iterator iter = gatt_services_.find(object_path.value()); 525 if (iter == gatt_services_.end()) { 526 VLOG(2) << "Unknown GATT service removed: " << object_path.value(); 527 return; 528 } 529 530 VLOG(1) << "Removing remote GATT service from device: " << GetAddress(); 531 532 BluetoothRemoteGattServiceChromeOS* service = 533 static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second); 534 DCHECK(service->object_path() == object_path); 535 gatt_services_.erase(iter); 536 FOR_EACH_OBSERVER(device::BluetoothDevice::Observer, observers_, 537 GattServiceRemoved(this, service)); 538 delete service; 539} 540 541void 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 559void 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 578void 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 586void 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 615void 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 625void 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 660void 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 667void 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 679void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { 680 LOG_IF(WARNING, !success) << object_path_.value() 681 << ": Failed to set device as trusted"; 682} 683 684void BluetoothDeviceChromeOS::OnStartConnectionMonitor( 685 const base::Closure& callback) { 686 connection_monitor_started_ = true; 687 callback.Run(); 688} 689 690void 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 700void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { 701 VLOG(1) << object_path_.value() << ": Disconnected"; 702 callback.Run(); 703} 704 705void 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 714void 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