blob: 2b27d9da2c4bab7a00ae7d35bc8397d10de3e550 [file] [log] [blame]
// 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);
}
BluetoothDevice::ConnectErrorCode DBusErrorToConnectError(
const std::string& error_name) {
BluetoothDevice::ConnectErrorCode error_code = BluetoothDevice::ERROR_UNKNOWN;
if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
error_code = BluetoothDevice::ERROR_FAILED;
} else if (error_name == bluetooth_device::kErrorFailed) {
error_code = BluetoothDevice::ERROR_FAILED;
} else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
error_code = BluetoothDevice::ERROR_AUTH_FAILED;
} else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
error_code = BluetoothDevice::ERROR_AUTH_CANCELED;
} else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
error_code = BluetoothDevice::ERROR_AUTH_REJECTED;
} else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
error_code = BluetoothDevice::ERROR_AUTH_TIMEOUT;
}
return error_code;
}
} // 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::OnPairDuringConnect,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
base::Bind(&BluetoothDeviceChromeOS::OnPairDuringConnectError,
weak_ptr_factory_.GetWeakPtr(), error_callback));
}
}
void BluetoothDeviceChromeOS::Pair(
BluetoothDevice::PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
DCHECK(pairing_delegate);
BeginPairing(pairing_delegate);
bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair(
object_path_, base::Bind(&BluetoothDeviceChromeOS::OnPair,
weak_ptr_factory_.GetWeakPtr(), 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::OnPairDuringConnect(
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
VLOG(1) << object_path_.value() << ": Paired";
EndPairing();
ConnectInternal(true, callback, error_callback);
}
void BluetoothDeviceChromeOS::OnPairDuringConnectError(
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 = DBusErrorToConnectError(error_name);
RecordPairingResult(error_code);
error_callback.Run(error_code);
}
void BluetoothDeviceChromeOS::OnPair(const base::Closure& callback) {
VLOG(1) << object_path_.value() << ": Paired";
EndPairing();
callback.Run();
}
void BluetoothDeviceChromeOS::OnPairError(
const ConnectErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
LOG(WARNING) << object_path_.value()
<< ": Failed to pair device: " << error_name << ": "
<< error_message;
EndPairing();
ConnectErrorCode error_code = DBusErrorToConnectError(error_name);
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