blob: 76e20972ad9bcee5f44199122295f4a3aaab2b4c [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 "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chromeos/dbus/bluetooth_adapter_client.h"
#include "chromeos/dbus/bluetooth_agent_manager_client.h"
#include "chromeos/dbus/bluetooth_agent_service_provider.h"
#include "chromeos/dbus/bluetooth_device_client.h"
#include "chromeos/dbus/bluetooth_input_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "dbus/bus.h"
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
#include "device/bluetooth/bluetooth_profile_chromeos.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothDevice;
namespace {
// The agent path is relatively meaningless since BlueZ only supports one
// at time and will fail in an attempt to register another with "Already Exists"
// (which we fail in OnRegisterAgentError with ERROR_INPROGRESS).
const char kAgentPath[] = "/org/chromium/bluetooth_agent";
// Histogram enumerations for pairing methods.
enum UMAPairingMethod {
UMA_PAIRING_METHOD_NONE,
UMA_PAIRING_METHOD_REQUEST_PINCODE,
UMA_PAIRING_METHOD_REQUEST_PASSKEY,
UMA_PAIRING_METHOD_DISPLAY_PINCODE,
UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
// NOTE: Add new pairing methods immediately above this line. Make sure to
// update the enum list in tools/histogram/histograms.xml accordinly.
UMA_PAIRING_METHOD_COUNT
};
// 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,
uint16 *vendor_id,
uint16 *product_id,
uint16 *device_id) {
chromeos::BluetoothDeviceClient::Properties* properties =
chromeos::DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path);
DCHECK(properties);
std::string modalias = properties->modalias.value();
if (StartsWithASCII(modalias, "usb:", false) && modalias.length() == 19) {
// usb:vXXXXpXXXXdXXXX
if (modalias[4] == 'v' && vendor_id != NULL) {
uint64 component = 0;
base::HexStringToUInt64(modalias.substr(5, 4), &component);
*vendor_id = component;
}
if (modalias[9] == 'p' && product_id != NULL) {
uint64 component = 0;
base::HexStringToUInt64(modalias.substr(10, 4), &component);
*product_id = component;
}
if (modalias[14] == 'd' && device_id != NULL) {
uint64 component = 0;
base::HexStringToUInt64(modalias.substr(15, 4), &component);
*device_id = component;
}
}
}
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)
: adapter_(adapter),
object_path_(object_path),
num_connecting_calls_(0),
pairing_delegate_(NULL),
pairing_delegate_used_(false),
weak_ptr_factory_(this) {
}
BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
}
uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_);
DCHECK(properties);
return properties->bluetooth_class.value();
}
std::string BluetoothDeviceChromeOS::GetDeviceName() const {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_);
DCHECK(properties);
return properties->alias.value();
}
std::string BluetoothDeviceChromeOS::GetAddress() const {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_);
DCHECK(properties);
return properties->address.value();
}
uint16 BluetoothDeviceChromeOS::GetVendorID() const {
uint16 vendor_id = 0;
ParseModalias(object_path_, &vendor_id, NULL, NULL);
return vendor_id;
}
uint16 BluetoothDeviceChromeOS::GetProductID() const {
uint16 product_id = 0;
ParseModalias(object_path_, NULL, &product_id, NULL);
return product_id;
}
uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
uint16 device_id = 0;
ParseModalias(object_path_, NULL, NULL, &device_id);
return device_id;
}
bool BluetoothDeviceChromeOS::IsPaired() const {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::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 {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_);
DCHECK(properties);
return properties->connected.value();
}
bool BluetoothDeviceChromeOS::IsConnectable() const {
BluetoothInputClient::Properties* input_properties =
DBusThreadManager::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::ServiceList BluetoothDeviceChromeOS::GetServices()
const {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_);
DCHECK(properties);
return properties->uuids.value();
}
void BluetoothDeviceChromeOS::GetServiceRecords(
const ServiceRecordsCallback& callback,
const ErrorCallback& error_callback) {
// TODO(keybuk): not implemented; remove
error_callback.Run();
}
void BluetoothDeviceChromeOS::ProvidesServiceWithName(
const std::string& name,
const ProvidesServiceCallback& callback) {
// TODO(keybuk): not implemented; remove
callback.Run(false);
}
bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
return !pincode_callback_.is_null();
}
bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
return !passkey_callback_.is_null();
}
bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
return !confirmation_callback_.is_null();
}
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.
DCHECK(!pairing_delegate_);
DCHECK(agent_.get() == NULL);
pairing_delegate_ = pairing_delegate;
pairing_delegate_used_ = false;
// The agent path is relatively meaningless since BlueZ only supports
// one per application at a time.
dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
agent_.reset(BluetoothAgentServiceProvider::Create(
system_bus, dbus::ObjectPath(kAgentPath), this));
DCHECK(agent_.get());
VLOG(1) << object_path_.value() << ": Registering agent for pairing";
DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
RegisterAgent(
dbus::ObjectPath(kAgentPath),
bluetooth_agent_manager::kKeyboardDisplayCapability,
base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgent,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback),
base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgentError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
}
}
void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
if (!agent_.get() || pincode_callback_.is_null())
return;
pincode_callback_.Run(SUCCESS, pincode);
pincode_callback_.Reset();
}
void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
if (!agent_.get() || passkey_callback_.is_null())
return;
passkey_callback_.Run(SUCCESS, passkey);
passkey_callback_.Reset();
}
void BluetoothDeviceChromeOS::ConfirmPairing() {
if (!agent_.get() || confirmation_callback_.is_null())
return;
confirmation_callback_.Run(SUCCESS);
confirmation_callback_.Reset();
}
void BluetoothDeviceChromeOS::RejectPairing() {
RunPairingCallbacks(REJECTED);
}
void BluetoothDeviceChromeOS::CancelPairing() {
// If there wasn't a callback in progress that we can reply to then we
// have to send a CancelPairing() to the device instead.
if (!RunPairingCallbacks(CANCELLED)) {
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
CancelPairing(
object_path_,
base::Bind(&base::DoNothing),
base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
weak_ptr_factory_.GetWeakPtr()));
// Since there's no calback to this method, it's possible that the pairing
// delegate is going to be freed before things complete.
UnregisterAgent();
}
}
void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << object_path_.value() << ": Disconnecting";
DBusThreadManager::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";
DBusThreadManager::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 std::string& service_uuid,
const SocketCallback& callback) {
// TODO(keybuk): implement
callback.Run(scoped_refptr<device::BluetoothSocket>());
}
void BluetoothDeviceChromeOS::ConnectToProfile(
device::BluetoothProfile* profile,
const base::Closure& callback,
const ErrorCallback& error_callback) {
BluetoothProfileChromeOS* profile_chromeos =
static_cast<BluetoothProfileChromeOS*>(profile);
VLOG(1) << object_path_.value() << ": Connecting profile: "
<< profile_chromeos->uuid();
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
ConnectProfile(
object_path_,
profile_chromeos->uuid(),
base::Bind(
&BluetoothDeviceChromeOS::OnConnectProfile,
weak_ptr_factory_.GetWeakPtr(),
profile,
callback),
base::Bind(
&BluetoothDeviceChromeOS::OnConnectProfileError,
weak_ptr_factory_.GetWeakPtr(),
profile,
error_callback));
}
void BluetoothDeviceChromeOS::SetOutOfBandPairingData(
const device::BluetoothOutOfBandPairingData& data,
const base::Closure& callback,
const ErrorCallback& error_callback) {
// TODO(keybuk): implement
error_callback.Run();
}
void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
const base::Closure& callback,
const ErrorCallback& error_callback) {
// TODO(keybuk): implement
error_callback.Run();
}
void BluetoothDeviceChromeOS::Release() {
DCHECK(agent_.get());
DCHECK(pairing_delegate_);
VLOG(1) << object_path_.value() << ": Release";
pincode_callback_.Reset();
passkey_callback_.Reset();
confirmation_callback_.Reset();
UnregisterAgent();
}
void BluetoothDeviceChromeOS::RequestPinCode(
const dbus::ObjectPath& device_path,
const PinCodeCallback& callback) {
DCHECK(agent_.get());
DCHECK(device_path == object_path_);
VLOG(1) << object_path_.value() << ": RequestPinCode";
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_REQUEST_PINCODE,
UMA_PAIRING_METHOD_COUNT);
DCHECK(pairing_delegate_);
DCHECK(pincode_callback_.is_null());
pincode_callback_ = callback;
pairing_delegate_->RequestPinCode(this);
pairing_delegate_used_ = true;
}
void BluetoothDeviceChromeOS::DisplayPinCode(
const dbus::ObjectPath& device_path,
const std::string& pincode) {
DCHECK(agent_.get());
DCHECK(device_path == object_path_);
VLOG(1) << object_path_.value() << ": DisplayPinCode: " << pincode;
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_DISPLAY_PINCODE,
UMA_PAIRING_METHOD_COUNT);
DCHECK(pairing_delegate_);
pairing_delegate_->DisplayPinCode(this, pincode);
pairing_delegate_used_ = true;
}
void BluetoothDeviceChromeOS::RequestPasskey(
const dbus::ObjectPath& device_path,
const PasskeyCallback& callback) {
DCHECK(agent_.get());
DCHECK(device_path == object_path_);
VLOG(1) << object_path_.value() << ": RequestPasskey";
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_REQUEST_PASSKEY,
UMA_PAIRING_METHOD_COUNT);
DCHECK(pairing_delegate_);
DCHECK(passkey_callback_.is_null());
passkey_callback_ = callback;
pairing_delegate_->RequestPasskey(this);
pairing_delegate_used_ = true;
}
void BluetoothDeviceChromeOS::DisplayPasskey(
const dbus::ObjectPath& device_path,
uint32 passkey,
uint16 entered) {
DCHECK(agent_.get());
DCHECK(device_path == object_path_);
VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey
<< " (" << entered << " entered)";
if (entered == 0)
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
UMA_PAIRING_METHOD_COUNT);
DCHECK(pairing_delegate_);
if (entered == 0)
pairing_delegate_->DisplayPasskey(this, passkey);
pairing_delegate_->KeysEntered(this, entered);
pairing_delegate_used_ = true;
}
void BluetoothDeviceChromeOS::RequestConfirmation(
const dbus::ObjectPath& device_path,
uint32 passkey,
const ConfirmationCallback& callback) {
DCHECK(agent_.get());
DCHECK(device_path == object_path_);
VLOG(1) << object_path_.value() << ": RequestConfirmation: " << passkey;
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
UMA_PAIRING_METHOD_COUNT);
DCHECK(pairing_delegate_);
DCHECK(confirmation_callback_.is_null());
confirmation_callback_ = callback;
pairing_delegate_->ConfirmPasskey(this, passkey);
pairing_delegate_used_ = true;
}
void BluetoothDeviceChromeOS::RequestAuthorization(
const dbus::ObjectPath& device_path,
const ConfirmationCallback& callback) {
// TODO(keybuk): implement
callback.Run(CANCELLED);
}
void BluetoothDeviceChromeOS::AuthorizeService(
const dbus::ObjectPath& device_path,
const std::string& uuid,
const ConfirmationCallback& callback) {
// TODO(keybuk): implement
callback.Run(CANCELLED);
}
void BluetoothDeviceChromeOS::Cancel() {
DCHECK(agent_.get());
VLOG(1) << object_path_.value() << ": Cancel";
DCHECK(pairing_delegate_);
pairing_delegate_->DismissDisplayOrConfirm();
}
void BluetoothDeviceChromeOS::ConnectInternal(
bool after_pairing,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
VLOG(1) << object_path_.value() << ": Connecting";
DBusThreadManager::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::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::OnRegisterAgent(
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
VLOG(1) << object_path_.value() << ": Agent registered, now pairing";
DBusThreadManager::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::OnRegisterAgentError(
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 register agent: "
<< error_name << ": " << error_message;
VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
<< " still in progress";
UnregisterAgent();
// Determine the error code from error_name.
ConnectErrorCode error_code = ERROR_UNKNOWN;
if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
error_code = ERROR_INPROGRESS;
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";
if (!pairing_delegate_used_)
UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
UMA_PAIRING_METHOD_NONE,
UMA_PAIRING_METHOD_COUNT);
UnregisterAgent();
SetTrusted();
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";
UnregisterAgent();
// 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.
DBusThreadManager::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::UnregisterAgent() {
if (!agent_.get())
return;
DCHECK(pairing_delegate_);
DCHECK(pincode_callback_.is_null());
DCHECK(passkey_callback_.is_null());
DCHECK(confirmation_callback_.is_null());
pairing_delegate_->DismissDisplayOrConfirm();
pairing_delegate_ = NULL;
agent_.reset();
// Clean up after ourselves.
VLOG(1) << object_path_.value() << ": Unregistering pairing agent";
DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
UnregisterAgent(
dbus::ObjectPath(kAgentPath),
base::Bind(&base::DoNothing),
base::Bind(&BluetoothDeviceChromeOS::OnUnregisterAgentError,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothDeviceChromeOS::OnUnregisterAgentError(
const std::string& error_name,
const std::string& error_message) {
LOG(WARNING) << object_path_.value() << ": Failed to unregister agent: "
<< error_name << ": " << error_message;
}
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();
}
bool BluetoothDeviceChromeOS::RunPairingCallbacks(Status status) {
if (!agent_.get())
return false;
bool callback_run = false;
if (!pincode_callback_.is_null()) {
pincode_callback_.Run(status, "");
pincode_callback_.Reset();
callback_run = true;
}
if (!passkey_callback_.is_null()) {
passkey_callback_.Run(status, 0);
passkey_callback_.Reset();
callback_run = true;
}
if (!confirmation_callback_.is_null()) {
confirmation_callback_.Run(status);
confirmation_callback_.Reset();
callback_run = true;
}
return callback_run;
}
void BluetoothDeviceChromeOS::OnConnectProfile(
device::BluetoothProfile* profile,
const base::Closure& callback) {
BluetoothProfileChromeOS* profile_chromeos =
static_cast<BluetoothProfileChromeOS*>(profile);
VLOG(1) << object_path_.value() << ": Profile connected: "
<< profile_chromeos->uuid();
callback.Run();
}
void BluetoothDeviceChromeOS::OnConnectProfileError(
device::BluetoothProfile* profile,
const ErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
BluetoothProfileChromeOS* profile_chromeos =
static_cast<BluetoothProfileChromeOS*>(profile);
VLOG(1) << object_path_.value() << ": Profile connection failed: "
<< profile_chromeos->uuid() << ": "
<< error_name << ": " << error_message;
error_callback.Run();
}
} // namespace chromeos