diff options
Diffstat (limited to 'device/bluetooth/bluetooth_device_chromeos.cc')
-rw-r--r-- | device/bluetooth/bluetooth_device_chromeos.cc | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc new file mode 100644 index 0000000..89c5572 --- /dev/null +++ b/device/bluetooth/bluetooth_device_chromeos.cc @@ -0,0 +1,734 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/bluetooth/bluetooth_device_chromeos.h" + +#include <stdio.h> + +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "dbus/bus.h" +#include "device/bluetooth/bluetooth_adapter_chromeos.h" +#include "device/bluetooth/bluetooth_gatt_connection_chromeos.h" +#include "device/bluetooth/bluetooth_pairing_chromeos.h" +#include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h" +#include "device/bluetooth/bluetooth_socket.h" +#include "device/bluetooth/bluetooth_socket_chromeos.h" +#include "device/bluetooth/bluetooth_socket_thread.h" +#include "device/bluetooth/bluetooth_uuid.h" +#include "device/bluetooth/dbus/bluetooth_adapter_client.h" +#include "device/bluetooth/dbus/bluetooth_device_client.h" +#include "device/bluetooth/dbus/bluetooth_gatt_service_client.h" +#include "device/bluetooth/dbus/bluetooth_input_client.h" +#include "device/bluetooth/dbus/bluez_dbus_manager.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using device::BluetoothDevice; +using device::BluetoothSocket; +using device::BluetoothUUID; + +namespace { + +// Histogram enumerations for pairing results. +enum UMAPairingResult { + UMA_PAIRING_RESULT_SUCCESS, + UMA_PAIRING_RESULT_INPROGRESS, + UMA_PAIRING_RESULT_FAILED, + UMA_PAIRING_RESULT_AUTH_FAILED, + UMA_PAIRING_RESULT_AUTH_CANCELED, + UMA_PAIRING_RESULT_AUTH_REJECTED, + UMA_PAIRING_RESULT_AUTH_TIMEOUT, + UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE, + UMA_PAIRING_RESULT_UNKNOWN_ERROR, + // NOTE: Add new pairing results immediately above this line. Make sure to + // update the enum list in tools/histogram/histograms.xml accordinly. + UMA_PAIRING_RESULT_COUNT +}; + +void ParseModalias(const dbus::ObjectPath& object_path, + BluetoothDevice::VendorIDSource* vendor_id_source, + uint16* vendor_id, + uint16* product_id, + uint16* device_id) { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path); + DCHECK(properties); + + std::string modalias = properties->modalias.value(); + BluetoothDevice::VendorIDSource source_value; + int vendor_value, product_value, device_value; + + if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x", + &vendor_value, &product_value, &device_value) == 3) { + source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH; + } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x", + &vendor_value, &product_value, &device_value) == 3) { + source_value = BluetoothDevice::VENDOR_ID_USB; + } else { + return; + } + + if (vendor_id_source != NULL) + *vendor_id_source = source_value; + if (vendor_id != NULL) + *vendor_id = vendor_value; + if (product_id != NULL) + *product_id = product_value; + if (device_id != NULL) + *device_id = device_value; +} + +void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { + UMAPairingResult pairing_result; + switch (error_code) { + case BluetoothDevice::ERROR_INPROGRESS: + pairing_result = UMA_PAIRING_RESULT_INPROGRESS; + break; + case BluetoothDevice::ERROR_FAILED: + pairing_result = UMA_PAIRING_RESULT_FAILED; + break; + case BluetoothDevice::ERROR_AUTH_FAILED: + pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED; + break; + case BluetoothDevice::ERROR_AUTH_CANCELED: + pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED; + break; + case BluetoothDevice::ERROR_AUTH_REJECTED: + pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED; + break; + case BluetoothDevice::ERROR_AUTH_TIMEOUT: + pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT; + break; + case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: + pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE; + break; + default: + pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR; + } + + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", + pairing_result, + UMA_PAIRING_RESULT_COUNT); +} + +} // namespace + +namespace chromeos { + +BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( + BluetoothAdapterChromeOS* adapter, + const dbus::ObjectPath& object_path, + scoped_refptr<base::SequencedTaskRunner> ui_task_runner, + scoped_refptr<device::BluetoothSocketThread> socket_thread) + : BluetoothDevice(adapter), + object_path_(object_path), + num_connecting_calls_(0), + connection_monitor_started_(false), + ui_task_runner_(ui_task_runner), + socket_thread_(socket_thread), + weak_ptr_factory_(this) { + bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver( + this); + + // Add all known GATT services. + const std::vector<dbus::ObjectPath> gatt_services = + bluez::BluezDBusManager::Get() + ->GetBluetoothGattServiceClient() + ->GetServices(); + for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin(); + it != gatt_services.end(); ++it) { + GattServiceAdded(*it); + } +} + +BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { + bluez::BluezDBusManager::Get() + ->GetBluetoothGattServiceClient() + ->RemoveObserver(this); + + // Copy the GATT services list here and clear the original so that when we + // send GattServiceRemoved(), GetGattServices() returns no services. + GattServiceMap gatt_services = gatt_services_; + gatt_services_.clear(); + for (GattServiceMap::iterator iter = gatt_services.begin(); + iter != gatt_services.end(); ++iter) { + DCHECK(adapter_); + adapter()->NotifyGattServiceRemoved( + static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second)); + delete iter->second; + } +} + +uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + return properties->bluetooth_class.value(); +} + +std::string BluetoothDeviceChromeOS::GetDeviceName() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + return properties->alias.value(); +} + +void BluetoothDeviceChromeOS::CreateGattConnectionImpl() { + // ChromeOS implementation does not use the default CreateGattConnection + // implementation. + NOTIMPLEMENTED(); +} + +void BluetoothDeviceChromeOS::DisconnectGatt() { + // ChromeOS implementation does not use the default CreateGattConnection + // implementation. + NOTIMPLEMENTED(); +} + +std::string BluetoothDeviceChromeOS::GetAddress() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + return CanonicalizeAddress(properties->address.value()); +} + +BluetoothDevice::VendorIDSource +BluetoothDeviceChromeOS::GetVendorIDSource() const { + VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN; + ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL); + return vendor_id_source; +} + +uint16 BluetoothDeviceChromeOS::GetVendorID() const { + uint16 vendor_id = 0; + ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL); + return vendor_id; +} + +uint16 BluetoothDeviceChromeOS::GetProductID() const { + uint16 product_id = 0; + ParseModalias(object_path_, NULL, NULL, &product_id, NULL); + return product_id; +} + +uint16 BluetoothDeviceChromeOS::GetDeviceID() const { + uint16 device_id = 0; + ParseModalias(object_path_, NULL, NULL, NULL, &device_id); + return device_id; +} + +bool BluetoothDeviceChromeOS::IsPaired() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + // Trusted devices are devices that don't support pairing but that the + // user has explicitly connected; it makes no sense for UI purposes to + // treat them differently from each other. + return properties->paired.value() || properties->trusted.value(); +} + +bool BluetoothDeviceChromeOS::IsConnected() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + return properties->connected.value(); +} + +bool BluetoothDeviceChromeOS::IsGattConnected() const { + NOTIMPLEMENTED(); + return false; +} + +bool BluetoothDeviceChromeOS::IsConnectable() const { + bluez::BluetoothInputClient::Properties* input_properties = + bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->GetProperties( + object_path_); + // GetProperties returns NULL when the device does not implement the given + // interface. Non HID devices are normally connectable. + if (!input_properties) + return true; + + return input_properties->reconnect_mode.value() != "device"; +} + +bool BluetoothDeviceChromeOS::IsConnecting() const { + return num_connecting_calls_ > 0; +} + +BluetoothDeviceChromeOS::UUIDList BluetoothDeviceChromeOS::GetUUIDs() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + std::vector<device::BluetoothUUID> uuids; + const std::vector<std::string> &dbus_uuids = properties->uuids.value(); + for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin(); + iter != dbus_uuids.end(); ++iter) { + device::BluetoothUUID uuid(*iter); + DCHECK(uuid.IsValid()); + uuids.push_back(uuid); + } + return uuids; +} + +int16 BluetoothDeviceChromeOS::GetInquiryRSSI() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + if (!properties->rssi.is_valid()) + return kUnknownPower; + + return properties->rssi.value(); +} + +int16 BluetoothDeviceChromeOS::GetInquiryTxPower() const { + bluez::BluetoothDeviceClient::Properties* properties = + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( + object_path_); + DCHECK(properties); + + if (!properties->tx_power.is_valid()) + return kUnknownPower; + + return properties->tx_power.value(); +} + +bool BluetoothDeviceChromeOS::ExpectingPinCode() const { + return pairing_.get() && pairing_->ExpectingPinCode(); +} + +bool BluetoothDeviceChromeOS::ExpectingPasskey() const { + return pairing_.get() && pairing_->ExpectingPasskey(); +} + +bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { + return pairing_.get() && pairing_->ExpectingConfirmation(); +} + +void BluetoothDeviceChromeOS::GetConnectionInfo( + const ConnectionInfoCallback& callback) { + // DBus method call should gracefully return an error if the device is not + // currently connected. + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetConnInfo( + object_path_, base::Bind(&BluetoothDeviceChromeOS::OnGetConnInfo, + weak_ptr_factory_.GetWeakPtr(), callback), + base::Bind(&BluetoothDeviceChromeOS::OnGetConnInfoError, + weak_ptr_factory_.GetWeakPtr(), callback)); +} + +void BluetoothDeviceChromeOS::Connect( + BluetoothDevice::PairingDelegate* pairing_delegate, + const base::Closure& callback, + const ConnectErrorCallback& error_callback) { + if (num_connecting_calls_++ == 0) + adapter()->NotifyDeviceChanged(this); + + VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ + << " in progress"; + + if (IsPaired() || !pairing_delegate || !IsPairable()) { + // No need to pair, or unable to, skip straight to connection. + ConnectInternal(false, callback, error_callback); + } else { + // Initiate high-security connection with pairing. + BeginPairing(pairing_delegate); + + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair( + object_path_, + base::Bind(&BluetoothDeviceChromeOS::OnPair, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback), + base::Bind(&BluetoothDeviceChromeOS::OnPairError, + weak_ptr_factory_.GetWeakPtr(), error_callback)); + } +} + +void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { + if (!pairing_.get()) + return; + + pairing_->SetPinCode(pincode); +} + +void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { + if (!pairing_.get()) + return; + + pairing_->SetPasskey(passkey); +} + +void BluetoothDeviceChromeOS::ConfirmPairing() { + if (!pairing_.get()) + return; + + pairing_->ConfirmPairing(); +} + +void BluetoothDeviceChromeOS::RejectPairing() { + if (!pairing_.get()) + return; + + pairing_->RejectPairing(); +} + +void BluetoothDeviceChromeOS::CancelPairing() { + bool canceled = false; + + // If there is a callback in progress that we can reply to then use that + // to cancel the current pairing request. + if (pairing_.get() && pairing_->CancelPairing()) + canceled = true; + + // If not we have to send an explicit CancelPairing() to the device instead. + if (!canceled) { + VLOG(1) << object_path_.value() << ": No pairing context or callback. " + << "Sending explicit cancel"; + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->CancelPairing( + object_path_, base::Bind(&base::DoNothing), + base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError, + weak_ptr_factory_.GetWeakPtr())); + } + + // Since there is no callback to this method it's possible that the pairing + // delegate is going to be freed before things complete (indeed it's + // documented that this is the method you should call while freeing the + // pairing delegate), so clear our the context holding on to it. + EndPairing(); +} + +void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, + const ErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Disconnecting"; + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Disconnect( + object_path_, base::Bind(&BluetoothDeviceChromeOS::OnDisconnect, + weak_ptr_factory_.GetWeakPtr(), callback), + base::Bind(&BluetoothDeviceChromeOS::OnDisconnectError, + weak_ptr_factory_.GetWeakPtr(), error_callback)); +} + +void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Removing device"; + bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->RemoveDevice( + adapter()->object_path(), object_path_, base::Bind(&base::DoNothing), + base::Bind(&BluetoothDeviceChromeOS::OnForgetError, + weak_ptr_factory_.GetWeakPtr(), error_callback)); +} + +void BluetoothDeviceChromeOS::ConnectToService( + const BluetoothUUID& uuid, + const ConnectToServiceCallback& callback, + const ConnectToServiceErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Connecting to service: " + << uuid.canonical_value(); + scoped_refptr<BluetoothSocketChromeOS> socket = + BluetoothSocketChromeOS::CreateBluetoothSocket( + ui_task_runner_, socket_thread_); + socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_MEDIUM, + base::Bind(callback, socket), error_callback); +} + +void BluetoothDeviceChromeOS::ConnectToServiceInsecurely( + const BluetoothUUID& uuid, + const ConnectToServiceCallback& callback, + const ConnectToServiceErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Connecting insecurely to service: " + << uuid.canonical_value(); + scoped_refptr<BluetoothSocketChromeOS> socket = + BluetoothSocketChromeOS::CreateBluetoothSocket( + ui_task_runner_, socket_thread_); + socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_LOW, + base::Bind(callback, socket), error_callback); +} + +void BluetoothDeviceChromeOS::CreateGattConnection( + const GattConnectionCallback& callback, + const ConnectErrorCallback& error_callback) { + // TODO(sacomoto): Workaround to retrieve the connection for already connected + // devices. Currently, BluetoothGattConnection::Disconnect doesn't do + // anything, the unique underlying physical GATT connection is kept. This + // should be removed once the correct behavour is implemented and the GATT + // connections are reference counted (see todo below). + if (IsConnected()) { + OnCreateGattConnection(callback); + return; + } + + // TODO(armansito): Until there is a way to create a reference counted GATT + // connection in bluetoothd, simply do a regular connect. + Connect(NULL, + base::Bind(&BluetoothDeviceChromeOS::OnCreateGattConnection, + weak_ptr_factory_.GetWeakPtr(), + callback), + error_callback); +} + +BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing( + BluetoothDevice::PairingDelegate* pairing_delegate) { + pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate)); + return pairing_.get(); +} + +void BluetoothDeviceChromeOS::EndPairing() { + pairing_.reset(); +} + +BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const { + return pairing_.get(); +} + +BluetoothAdapterChromeOS* BluetoothDeviceChromeOS::adapter() const { + return static_cast<BluetoothAdapterChromeOS*>(adapter_); +} + +void BluetoothDeviceChromeOS::GattServiceAdded( + const dbus::ObjectPath& object_path) { + if (GetGattService(object_path.value())) { + VLOG(1) << "Remote GATT service already exists: " << object_path.value(); + return; + } + + bluez::BluetoothGattServiceClient::Properties* properties = + bluez::BluezDBusManager::Get() + ->GetBluetoothGattServiceClient() + ->GetProperties(object_path); + DCHECK(properties); + if (properties->device.value() != object_path_) { + VLOG(2) << "Remote GATT service does not belong to this device."; + return; + } + + VLOG(1) << "Adding new remote GATT service for device: " << GetAddress(); + + BluetoothRemoteGattServiceChromeOS* service = + new BluetoothRemoteGattServiceChromeOS(adapter(), this, object_path); + + gatt_services_[service->GetIdentifier()] = service; + DCHECK(service->object_path() == object_path); + DCHECK(service->GetUUID().IsValid()); + + DCHECK(adapter_); + adapter()->NotifyGattServiceAdded(service); +} + +void BluetoothDeviceChromeOS::GattServiceRemoved( + const dbus::ObjectPath& object_path) { + GattServiceMap::iterator iter = gatt_services_.find(object_path.value()); + if (iter == gatt_services_.end()) { + VLOG(3) << "Unknown GATT service removed: " << object_path.value(); + return; + } + + BluetoothRemoteGattServiceChromeOS* service = + static_cast<BluetoothRemoteGattServiceChromeOS*>(iter->second); + + VLOG(1) << "Removing remote GATT service with UUID: '" + << service->GetUUID().canonical_value() + << "' from device: " << GetAddress(); + + DCHECK(service->object_path() == object_path); + gatt_services_.erase(iter); + + DCHECK(adapter_); + adapter()->NotifyGattServiceRemoved(service); + + delete service; +} + +void BluetoothDeviceChromeOS::OnGetConnInfo( + const ConnectionInfoCallback& callback, + int16 rssi, + int16 transmit_power, + int16 max_transmit_power) { + callback.Run(ConnectionInfo(rssi, transmit_power, max_transmit_power)); +} + +void BluetoothDeviceChromeOS::OnGetConnInfoError( + const ConnectionInfoCallback& callback, + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << object_path_.value() + << ": Failed to get connection info: " << error_name << ": " + << error_message; + callback.Run(ConnectionInfo()); +} + +void BluetoothDeviceChromeOS::ConnectInternal( + bool after_pairing, + const base::Closure& callback, + const ConnectErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Connecting"; + bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Connect( + object_path_, + base::Bind(&BluetoothDeviceChromeOS::OnConnect, + weak_ptr_factory_.GetWeakPtr(), after_pairing, callback), + base::Bind(&BluetoothDeviceChromeOS::OnConnectError, + weak_ptr_factory_.GetWeakPtr(), after_pairing, + error_callback)); +} + +void BluetoothDeviceChromeOS::OnConnect(bool after_pairing, + const base::Closure& callback) { + if (--num_connecting_calls_ == 0) + adapter()->NotifyDeviceChanged(this); + + DCHECK(num_connecting_calls_ >= 0); + VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_ + << " still in progress"; + + SetTrusted(); + + if (after_pairing) + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", + UMA_PAIRING_RESULT_SUCCESS, + UMA_PAIRING_RESULT_COUNT); + + callback.Run(); +} + +void BluetoothDeviceChromeOS::OnCreateGattConnection( + const GattConnectionCallback& callback) { + scoped_ptr<device::BluetoothGattConnection> conn( + new BluetoothGattConnectionChromeOS( + adapter_, GetAddress(), object_path_)); + callback.Run(conn.Pass()); +} + +void BluetoothDeviceChromeOS::OnConnectError( + bool after_pairing, + const ConnectErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message) { + if (--num_connecting_calls_ == 0) + adapter()->NotifyDeviceChanged(this); + + DCHECK(num_connecting_calls_ >= 0); + LOG(WARNING) << object_path_.value() << ": Failed to connect device: " + << error_name << ": " << error_message; + VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ + << " still in progress"; + + // Determine the error code from error_name. + ConnectErrorCode error_code = ERROR_UNKNOWN; + if (error_name == bluetooth_device::kErrorFailed) { + error_code = ERROR_FAILED; + } else if (error_name == bluetooth_device::kErrorInProgress) { + error_code = ERROR_INPROGRESS; + } else if (error_name == bluetooth_device::kErrorNotSupported) { + error_code = ERROR_UNSUPPORTED_DEVICE; + } + + if (after_pairing) + RecordPairingResult(error_code); + error_callback.Run(error_code); +} + +void BluetoothDeviceChromeOS::OnPair( + const base::Closure& callback, + const ConnectErrorCallback& error_callback) { + VLOG(1) << object_path_.value() << ": Paired"; + + EndPairing(); + + ConnectInternal(true, callback, error_callback); +} + +void BluetoothDeviceChromeOS::OnPairError( + const ConnectErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message) { + if (--num_connecting_calls_ == 0) + adapter()->NotifyDeviceChanged(this); + + DCHECK(num_connecting_calls_ >= 0); + LOG(WARNING) << object_path_.value() << ": Failed to pair device: " + << error_name << ": " << error_message; + VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ + << " still in progress"; + + EndPairing(); + + // Determine the error code from error_name. + ConnectErrorCode error_code = ERROR_UNKNOWN; + if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) { + error_code = ERROR_FAILED; + } else if (error_name == bluetooth_device::kErrorFailed) { + error_code = ERROR_FAILED; + } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) { + error_code = ERROR_AUTH_FAILED; + } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) { + error_code = ERROR_AUTH_CANCELED; + } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) { + error_code = ERROR_AUTH_REJECTED; + } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) { + error_code = ERROR_AUTH_TIMEOUT; + } + + RecordPairingResult(error_code); + error_callback.Run(error_code); +} + +void BluetoothDeviceChromeOS::OnCancelPairingError( + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: " + << error_name << ": " << error_message; +} + +void BluetoothDeviceChromeOS::SetTrusted() { + // Unconditionally send the property change, rather than checking the value + // first; there's no harm in doing this and it solves any race conditions + // with the property becoming true or false and this call happening before + // we get the D-Bus signal about the earlier change. + bluez::BluezDBusManager::Get() + ->GetBluetoothDeviceClient() + ->GetProperties(object_path_) + ->trusted.Set(true, base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, + weak_ptr_factory_.GetWeakPtr())); +} + +void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { + LOG_IF(WARNING, !success) << object_path_.value() + << ": Failed to set device as trusted"; +} + +void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { + VLOG(1) << object_path_.value() << ": Disconnected"; + callback.Run(); +} + +void BluetoothDeviceChromeOS::OnDisconnectError( + const ErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: " + << error_name << ": " << error_message; + error_callback.Run(); +} + +void BluetoothDeviceChromeOS::OnForgetError( + const ErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << object_path_.value() << ": Failed to remove device: " + << error_name << ": " << error_message; + error_callback.Run(); +} + +} // namespace chromeos |