summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chromeos/dbus/fake_bluetooth_agent_manager_client.cc7
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.cc336
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.h120
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.cc328
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.h63
-rw-r--r--device/bluetooth/bluetooth_profile_chromeos_unittest.cc4
6 files changed, 501 insertions, 357 deletions
diff --git a/chromeos/dbus/fake_bluetooth_agent_manager_client.cc b/chromeos/dbus/fake_bluetooth_agent_manager_client.cc
index 2672ad5..b2bdf96 100644
--- a/chromeos/dbus/fake_bluetooth_agent_manager_client.cc
+++ b/chromeos/dbus/fake_bluetooth_agent_manager_client.cc
@@ -45,8 +45,11 @@ void FakeBluetoothAgentManagerClient::UnregisterAgent(
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "UnregisterAgent: " << agent_path.value();
- if (service_provider_ != NULL) {
- error_callback.Run(bluetooth_agent_manager::kErrorInvalidArguments,
+ if (service_provider_ == NULL) {
+ error_callback.Run(bluetooth_agent_manager::kErrorDoesNotExist,
+ "No agent registered");
+ } else if (service_provider_->object_path_ != agent_path) {
+ error_callback.Run(bluetooth_agent_manager::kErrorDoesNotExist,
"Agent still registered");
} else {
callback.Run();
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index 0d962b9..3344392 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -11,15 +11,45 @@
#include "base/metrics/histogram.h"
#include "base/sys_info.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 "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothAdapter;
using device::BluetoothDevice;
+namespace {
+
+// The agent path is relatively meaningless since BlueZ only permits one to
+// exist per D-Bus connection, it just has to be unique within Chromium.
+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 accordingly.
+ UMA_PAIRING_METHOD_COUNT
+};
+
+void OnUnregisterAgentError(const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << "Failed to unregister pairing agent: "
+ << error_name << ": " << error_message;
+}
+
+} // namespace
+
namespace chromeos {
BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
@@ -35,12 +65,35 @@ BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
SetAdapter(object_paths[0]);
}
+
+ // Register the pairing agent.
+ dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
+ agent_.reset(BluetoothAgentServiceProvider::Create(
+ system_bus, dbus::ObjectPath(kAgentPath), this));
+ DCHECK(agent_.get());
+
+ VLOG(1) << "Registering pairing agent";
+ DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
+ RegisterAgent(
+ dbus::ObjectPath(kAgentPath),
+ bluetooth_agent_manager::kKeyboardDisplayCapability,
+ base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
+ weak_ptr_factory_.GetWeakPtr()));
}
BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
+
+ VLOG(1) << "Unregistering pairing agent";
+ DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
+ UnregisterAgent(
+ dbus::ObjectPath(kAgentPath),
+ base::Bind(&base::DoNothing),
+ base::Bind(&OnUnregisterAgentError));
}
void BluetoothAdapterChromeOS::AddObserver(
@@ -315,6 +368,267 @@ void BluetoothAdapterChromeOS::InputPropertyChanged(
NotifyDeviceChanged(device_chromeos);
}
+void BluetoothAdapterChromeOS::Release() {
+ DCHECK(agent_.get());
+ VLOG(1) << "Release";
+
+ // Called after we unregister the pairing agent, e.g. when changing I/O
+ // capabilities. Nothing much to be done right now.
+}
+
+void BluetoothAdapterChromeOS::RequestPinCode(
+ const dbus::ObjectPath& device_path,
+ const PinCodeCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestPinCode";
+
+ BluetoothDeviceChromeOS* device_chromeos;
+ PairingContext* pairing_context;
+ if (!GetDeviceAndPairingContext(device_path,
+ &device_chromeos, &pairing_context)) {
+ callback.Run(REJECTED, "");
+ return;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(pairing_context->pincode_callback_.is_null());
+ pairing_context->pincode_callback_ = callback;
+ pairing_context->pairing_delegate_->RequestPinCode(device_chromeos);
+ pairing_context->pairing_delegate_used_ = true;
+}
+
+void BluetoothAdapterChromeOS::DisplayPinCode(
+ const dbus::ObjectPath& device_path,
+ const std::string& pincode) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
+
+ BluetoothDeviceChromeOS* device_chromeos;
+ PairingContext* pairing_context;
+ if (!GetDeviceAndPairingContext(device_path,
+ &device_chromeos, &pairing_context))
+ return;
+
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ pairing_context->pairing_delegate_->DisplayPinCode(device_chromeos, pincode);
+ pairing_context->pairing_delegate_used_ = true;
+}
+
+void BluetoothAdapterChromeOS::RequestPasskey(
+ const dbus::ObjectPath& device_path,
+ const PasskeyCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestPasskey";
+
+ BluetoothDeviceChromeOS* device_chromeos;
+ PairingContext* pairing_context;
+ if (!GetDeviceAndPairingContext(device_path,
+ &device_chromeos, &pairing_context)) {
+ callback.Run(REJECTED, 0);
+ return;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(pairing_context->passkey_callback_.is_null());
+ pairing_context->passkey_callback_ = callback;
+ pairing_context->pairing_delegate_->RequestPasskey(device_chromeos);
+ pairing_context->pairing_delegate_used_ = true;
+}
+
+void BluetoothAdapterChromeOS::DisplayPasskey(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ uint16 entered) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
+ << " (" << entered << " entered)";
+
+ BluetoothDeviceChromeOS* device_chromeos;
+ PairingContext* pairing_context;
+ if (!GetDeviceAndPairingContext(device_path,
+ &device_chromeos, &pairing_context))
+ return;
+
+ if (entered == 0)
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ if (entered == 0)
+ pairing_context->pairing_delegate_->DisplayPasskey(device_chromeos,
+ passkey);
+
+ pairing_context->pairing_delegate_->KeysEntered(device_chromeos, entered);
+ pairing_context->pairing_delegate_used_ = true;
+}
+
+void BluetoothAdapterChromeOS::RequestConfirmation(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
+
+ BluetoothDeviceChromeOS* device_chromeos;
+ PairingContext* pairing_context;
+ if (!GetDeviceAndPairingContext(device_path,
+ &device_chromeos, &pairing_context)) {
+ callback.Run(REJECTED);
+ return;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(pairing_context->confirmation_callback_.is_null());
+ pairing_context->confirmation_callback_ = callback;
+ pairing_context->pairing_delegate_->ConfirmPasskey(device_chromeos, passkey);
+ pairing_context->pairing_delegate_used_ = true;
+}
+
+void BluetoothAdapterChromeOS::RequestAuthorization(
+ const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestAuthorization";
+
+ // TODO(keybuk): implement
+ callback.Run(CANCELLED);
+}
+
+void BluetoothAdapterChromeOS::AuthorizeService(
+ const dbus::ObjectPath& device_path,
+ const std::string& uuid,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
+
+ // TODO(keybuk): implement
+ callback.Run(CANCELLED);
+}
+
+void BluetoothAdapterChromeOS::Cancel() {
+ DCHECK(agent_.get());
+ VLOG(1) << "Cancel";
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::ExpectingPinCode() const {
+ return !pincode_callback_.is_null();
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::ExpectingPasskey() const {
+ return !passkey_callback_.is_null();
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::ExpectingConfirmation() const {
+ return !confirmation_callback_.is_null();
+}
+
+void BluetoothAdapterChromeOS::PairingContext::SetPinCode(
+ const std::string& pincode) {
+ if (pincode_callback_.is_null())
+ return;
+
+ pincode_callback_.Run(SUCCESS, pincode);
+ pincode_callback_.Reset();
+}
+
+void BluetoothAdapterChromeOS::PairingContext::SetPasskey(uint32 passkey) {
+ if (passkey_callback_.is_null())
+ return;
+
+ passkey_callback_.Run(SUCCESS, passkey);
+ passkey_callback_.Reset();
+}
+
+void BluetoothAdapterChromeOS::PairingContext::ConfirmPairing() {
+ if (confirmation_callback_.is_null())
+ return;
+
+ confirmation_callback_.Run(SUCCESS);
+ confirmation_callback_.Reset();
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::RejectPairing() {
+ return RunPairingCallbacks(REJECTED);
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::CancelPairing() {
+ return RunPairingCallbacks(CANCELLED);
+}
+
+BluetoothAdapterChromeOS::PairingContext::PairingContext(
+ BluetoothDevice::PairingDelegate* pairing_delegate)
+ : pairing_delegate_(pairing_delegate),
+ pairing_delegate_used_(false) {
+ VLOG(1) << "Created PairingContext";
+}
+
+BluetoothAdapterChromeOS::PairingContext::~PairingContext() {
+ VLOG(1) << "Destroying PairingContext";
+
+ if (!pairing_delegate_used_)
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_NONE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(pincode_callback_.is_null());
+ DCHECK(passkey_callback_.is_null());
+ DCHECK(confirmation_callback_.is_null());
+
+ pairing_delegate_->DismissDisplayOrConfirm();
+ pairing_delegate_ = NULL;
+}
+
+bool BluetoothAdapterChromeOS::PairingContext::RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::Status status) {
+ pairing_delegate_used_ = true;
+
+ 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 BluetoothAdapterChromeOS::OnRegisterAgent() {
+ VLOG(1) << "Pairing agent registered";
+}
+
+void BluetoothAdapterChromeOS::OnRegisterAgentError(
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << ": Failed to register pairing agent: "
+ << error_name << ": " << error_message;
+
+ agent_.reset();
+}
+
BluetoothDeviceChromeOS*
BluetoothAdapterChromeOS::GetDeviceWithPath(
const dbus::ObjectPath& object_path) {
@@ -329,6 +643,28 @@ BluetoothAdapterChromeOS::GetDeviceWithPath(
return NULL;
}
+bool BluetoothAdapterChromeOS::GetDeviceAndPairingContext(
+ const dbus::ObjectPath& object_path,
+ BluetoothDeviceChromeOS** device_chromeos,
+ PairingContext** pairing_context)
+{
+ *device_chromeos = GetDeviceWithPath(object_path);
+ if (!device_chromeos) {
+ LOG(WARNING) << "Pairing Agent request for unknown device: "
+ << object_path.value();
+ return false;
+ }
+
+ *pairing_context = (*device_chromeos)->pairing_context_.get();
+ if (*pairing_context)
+ return true;
+
+ // TODO(keybuk): this is the point we need a default pairing delegate, create
+ // a PairingContext with that passed in, set it as the context on the device
+ // and return true.
+ return false;
+}
+
void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
DCHECK(!IsPresent());
object_path_ = object_path;
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
index b400ed3..926ba86 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.h
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -9,10 +9,12 @@
#include "base/memory/weak_ptr.h"
#include "chromeos/dbus/bluetooth_adapter_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 "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_device.h"
namespace device {
@@ -31,7 +33,8 @@ class BluetoothAdapterChromeOS
: public device::BluetoothAdapter,
private chromeos::BluetoothAdapterClient::Observer,
private chromeos::BluetoothDeviceClient::Observer,
- private chromeos::BluetoothInputClient::Observer {
+ private chromeos::BluetoothInputClient::Observer,
+ private chromeos::BluetoothAgentServiceProvider::Delegate {
public:
// BluetoothAdapter override
virtual void AddObserver(
@@ -94,11 +97,122 @@ class BluetoothAdapterChromeOS
virtual void InputPropertyChanged(const dbus::ObjectPath& object_path,
const std::string& property_name) OVERRIDE;
+ // BluetoothAgentServiceProvider::Delegate override.
+ virtual void Release() OVERRIDE;
+ virtual void RequestPinCode(const dbus::ObjectPath& device_path,
+ const PinCodeCallback& callback) OVERRIDE;
+ virtual void DisplayPinCode(const dbus::ObjectPath& device_path,
+ const std::string& pincode) OVERRIDE;
+ virtual void RequestPasskey(const dbus::ObjectPath& device_path,
+ const PasskeyCallback& callback) OVERRIDE;
+ virtual void DisplayPasskey(const dbus::ObjectPath& device_path,
+ uint32 passkey, uint16 entered) OVERRIDE;
+ virtual void RequestConfirmation(const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ const ConfirmationCallback& callback)
+ OVERRIDE;
+ virtual void RequestAuthorization(const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback)
+ OVERRIDE;
+ virtual void AuthorizeService(const dbus::ObjectPath& device_path,
+ const std::string& uuid,
+ const ConfirmationCallback& callback) OVERRIDE;
+ virtual void Cancel() OVERRIDE;
+
+ // PairingContext is an API between BluetoothAdapterChromeOS and
+ // BluetoothDeviceChromeOS for a single pairing attempt, wrapping the
+ // callbacks of the underlying BluetoothAgentServiceProvider object.
+ class PairingContext {
+ public:
+ ~PairingContext();
+
+ // Indicates whether the device is currently pairing and expecting a
+ // PIN Code to be returned.
+ bool ExpectingPinCode() const;
+
+ // Indicates whether the device is currently pairing and expecting a
+ // Passkey to be returned.
+ bool ExpectingPasskey() const;
+
+ // Indicates whether the device is currently pairing and expecting
+ // confirmation of a displayed passkey.
+ bool ExpectingConfirmation() const;
+
+ // Sends the PIN code |pincode| to the remote device during pairing.
+ //
+ // PIN Codes are generally required for Bluetooth 2.0 and earlier devices
+ // for which there is no automatic pairing or special handling.
+ void SetPinCode(const std::string& pincode);
+
+ // Sends the Passkey |passkey| to the remote device during pairing.
+ //
+ // Passkeys are generally required for Bluetooth 2.1 and later devices
+ // which cannot provide input or display on their own, and don't accept
+ // passkey-less pairing, and are a numeric in the range 0-999999.
+ void SetPasskey(uint32 passkey);
+
+ // Confirms to the remote device during pairing that a passkey provided by
+ // the ConfirmPasskey() delegate call is displayed on both devices.
+ void ConfirmPairing();
+
+ // Rejects a pairing or connection request from a remote device, returns
+ // false if there was no way to reject the pairing.
+ bool RejectPairing();
+
+ // Cancels a pairing or connection attempt to a remote device, returns
+ // false if there was no way to cancel the pairing.
+ bool CancelPairing();
+
+ private:
+ friend class BluetoothAdapterChromeOS;
+ friend class BluetoothDeviceChromeOS;
+
+ explicit PairingContext(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate_);
+
+ // Internal method to response to the relevant callback for a RejectPairing
+ // or CancelPairing call.
+ bool RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::Status status);
+
+ // UI Pairing Delegate to make method calls on, this must live as long as
+ // the object capturing the PairingContext.
+ device::BluetoothDevice::PairingDelegate* pairing_delegate_;
+
+ // Flag to indicate whether any pairing delegate method has been called
+ // during pairing. Used to determine whether we need to log the
+ // "no pairing interaction" metric.
+ bool pairing_delegate_used_;
+
+ // During pairing these callbacks are set to those provided by method calls
+ // made on the BluetoothAdapterChromeOS instance by its respective
+ // BluetoothAgentServiceProvider instance, and are called by our own
+ // method calls such as SetPinCode() and SetPasskey().
+ PinCodeCallback pincode_callback_;
+ PasskeyCallback passkey_callback_;
+ ConfirmationCallback confirmation_callback_;
+ };
+
+ // Called by dbus:: on completion of the D-Bus method call to register the
+ // pairing agent.
+ void OnRegisterAgent();
+ void OnRegisterAgentError(const std::string& error_name,
+ const std::string& error_message);
+
// Internal method used to locate the device object by object path
// (the devices map and BluetoothDevice methods are by address)
BluetoothDeviceChromeOS* GetDeviceWithPath(
const dbus::ObjectPath& object_path);
+ // Internal method to obtain the ChromeOS BluetoothDevice object, returned in
+ // |device_chromeos| and associated PairingContext, returned in
+ // |pairing_context| for the device with path |object_path|.
+ // Returns true on success, false if device doesn't exist or there is no
+ // pairing context for it.
+ bool GetDeviceAndPairingContext(const dbus::ObjectPath& object_path,
+ BluetoothDeviceChromeOS** device_chromeos,
+ PairingContext** pairing_context);
+
// Set the tracked adapter to the one in |object_path|, this object will
// subsequently operate on that adapter until it is removed.
void SetAdapter(const dbus::ObjectPath& object_path);
@@ -148,6 +262,10 @@ class BluetoothAdapterChromeOS
// List of observers interested in event notifications from us.
ObserverList<device::BluetoothAdapter::Observer> observers_;
+ // Instance of the D-Bus agent object used for pairing, initialized with
+ // our own class as its delegate.
+ scoped_ptr<BluetoothAgentServiceProvider> agent_;
+
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<BluetoothAdapterChromeOS> weak_ptr_factory_;
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc
index 76e2097..74f3c8a 100644
--- a/device/bluetooth/bluetooth_device_chromeos.cc
+++ b/device/bluetooth/bluetooth_device_chromeos.cc
@@ -9,8 +9,6 @@
#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"
@@ -24,24 +22,6 @@ 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,
@@ -133,8 +113,6 @@ BluetoothDeviceChromeOS::BluetoothDeviceChromeOS(
: adapter_(adapter),
object_path_(object_path),
num_connecting_calls_(0),
- pairing_delegate_(NULL),
- pairing_delegate_used_(false),
weak_ptr_factory_(this) {
}
@@ -248,15 +226,15 @@ void BluetoothDeviceChromeOS::ProvidesServiceWithName(
}
bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
- return !pincode_callback_.is_null();
+ return pairing_context_.get() && pairing_context_->ExpectingPinCode();
}
bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
- return !passkey_callback_.is_null();
+ return pairing_context_.get() && pairing_context_->ExpectingPasskey();
}
bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
- return !confirmation_callback_.is_null();
+ return pairing_context_.get() && pairing_context_->ExpectingConfirmation();
}
void BluetoothDeviceChromeOS::Connect(
@@ -274,66 +252,55 @@ void BluetoothDeviceChromeOS::Connect(
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));
+ DCHECK(!pairing_context_);
+ pairing_context_.reset(
+ new BluetoothAdapterChromeOS::PairingContext(pairing_delegate));
+
+ 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::SetPinCode(const std::string& pincode) {
- if (!agent_.get() || pincode_callback_.is_null())
+ if (!pairing_context_.get())
return;
- pincode_callback_.Run(SUCCESS, pincode);
- pincode_callback_.Reset();
+ pairing_context_->SetPinCode(pincode);
}
void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
- if (!agent_.get() || passkey_callback_.is_null())
+ if (!pairing_context_.get())
return;
- passkey_callback_.Run(SUCCESS, passkey);
- passkey_callback_.Reset();
+ pairing_context_->SetPasskey(passkey);
}
void BluetoothDeviceChromeOS::ConfirmPairing() {
- if (!agent_.get() || confirmation_callback_.is_null())
+ if (!pairing_context_.get())
return;
- confirmation_callback_.Run(SUCCESS);
- confirmation_callback_.Reset();
+ pairing_context_->ConfirmPairing();
}
void BluetoothDeviceChromeOS::RejectPairing() {
- RunPairingCallbacks(REJECTED);
+ if (!pairing_context_.get())
+ return;
+
+ pairing_context_->RejectPairing();
}
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)) {
+ if (!pairing_context_.get() || !pairing_context_->CancelPairing()) {
+ VLOG(1) << object_path_.value() << ": No pairing context or callback. "
+ << "Sending explicit cancel";
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
CancelPairing(
object_path_,
@@ -342,8 +309,9 @@ void BluetoothDeviceChromeOS::CancelPairing() {
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();
+ // delegate is going to be freed before things complete, so clear out the
+ // context holding it.
+ pairing_context_.reset();
}
}
@@ -419,134 +387,6 @@ void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
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,
@@ -613,55 +453,13 @@ void BluetoothDeviceChromeOS::OnConnectError(
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();
+ pairing_context_.reset();
+
SetTrusted();
ConnectInternal(true, callback, error_callback);
}
@@ -679,7 +477,7 @@ void BluetoothDeviceChromeOS::OnPairError(
VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
<< " still in progress";
- UnregisterAgent();
+ pairing_context_.reset();
// Determine the error code from error_name.
ConnectErrorCode error_code = ERROR_UNKNOWN;
@@ -725,38 +523,6 @@ void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
<< ": 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();
@@ -780,32 +546,6 @@ void BluetoothDeviceChromeOS::OnForgetError(
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) {
diff --git a/device/bluetooth/bluetooth_device_chromeos.h b/device/bluetooth/bluetooth_device_chromeos.h
index fef7cfd..e2f2997 100644
--- a/device/bluetooth/bluetooth_device_chromeos.h
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -9,20 +9,17 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "chromeos/dbus/bluetooth_agent_service_provider.h"
#include "chromeos/dbus/bluetooth_device_client.h"
#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
#include "device/bluetooth/bluetooth_device.h"
namespace chromeos {
-class BluetoothAdapterChromeOS;
-
// The BluetoothDeviceChromeOS class implements BluetoothDevice for the
// Chrome OS platform.
class BluetoothDeviceChromeOS
- : public device::BluetoothDevice,
- private chromeos::BluetoothAgentServiceProvider::Delegate {
+ : public device::BluetoothDevice {
public:
// BluetoothDevice override
virtual uint32 GetBluetoothClass() const OVERRIDE;
@@ -83,28 +80,6 @@ class BluetoothDeviceChromeOS
const dbus::ObjectPath& object_path);
virtual ~BluetoothDeviceChromeOS();
- // BluetoothAgentServiceProvider::Delegate override.
- virtual void Release() OVERRIDE;
- virtual void RequestPinCode(const dbus::ObjectPath& device_path,
- const PinCodeCallback& callback) OVERRIDE;
- virtual void DisplayPinCode(const dbus::ObjectPath& device_path,
- const std::string& pincode) OVERRIDE;
- virtual void RequestPasskey(const dbus::ObjectPath& device_path,
- const PasskeyCallback& callback) OVERRIDE;
- virtual void DisplayPasskey(const dbus::ObjectPath& device_path,
- uint32 passkey, uint16 entered) OVERRIDE;
- virtual void RequestConfirmation(const dbus::ObjectPath& device_path,
- uint32 passkey,
- const ConfirmationCallback& callback)
- OVERRIDE;
- virtual void RequestAuthorization(const dbus::ObjectPath& device_path,
- const ConfirmationCallback& callback)
- OVERRIDE;
- virtual void AuthorizeService(const dbus::ObjectPath& device_path,
- const std::string& uuid,
- const ConfirmationCallback& callback) OVERRIDE;
- virtual void Cancel() OVERRIDE;
-
// Internal method to initiate a connection to this device, and methods called
// by dbus:: on completion of the D-Bus method call.
void ConnectInternal(bool after_pairing,
@@ -117,14 +92,6 @@ class BluetoothDeviceChromeOS
const std::string& error_name,
const std::string& error_message);
- // Called by dbus:: on completion of the D-Bus method call to register the
- // pairing agent.
- void OnRegisterAgent(const base::Closure& callback,
- const ConnectErrorCallback& error_callback);
- void OnRegisterAgentError(const ConnectErrorCallback& error_callback,
- const std::string& error_name,
- const std::string& error_message);
-
// Called by dbus:: on completion of the D-Bus method call to pair the device.
void OnPair(const base::Closure& callback,
const ConnectErrorCallback& error_callback);
@@ -145,13 +112,6 @@ class BluetoothDeviceChromeOS
void SetTrusted();
void OnSetTrusted(bool success);
- // Internal method to unregister the pairing agent and method called by dbus::
- // on failure of the D-Bus method call. No completion call as success is
- // ignored.
- void UnregisterAgent();
- void OnUnregisterAgentError(const std::string& error_name,
- const std::string& error_message);
-
// Called by dbus:: on completion of the D-Bus method call to disconnect the
// device.
void OnDisconnect(const base::Closure& callback);
@@ -166,10 +126,6 @@ class BluetoothDeviceChromeOS
const std::string& error_name,
const std::string& error_message);
- // Run any outstanding pairing callbacks passing |status| as the result of
- // pairing. Returns true if any callbacks were run, false if not.
- bool RunPairingCallbacks(Status status);
-
// Called by dbus:: on completion of the D-Bus method call to
// connect a peofile.
void OnConnectProfile(device::BluetoothProfile* profile,
@@ -196,20 +152,7 @@ class BluetoothDeviceChromeOS
// Passkeys. Generally it is the object that owns this one.
PairingDelegate* pairing_delegate_;
- // Flag to indicate whether a pairing delegate method has been called during
- // pairing.
- bool pairing_delegate_used_;
-
- // During pairing this is set to an instance of a D-Bus agent object
- // intialized with our own class as its delegate.
- scoped_ptr<BluetoothAgentServiceProvider> agent_;
-
- // During pairing these callbacks are set to those provided by method calls
- // made on us by |agent_| and are called by our own method calls such as
- // SetPinCode() and SetPasskey().
- PinCodeCallback pincode_callback_;
- PasskeyCallback passkey_callback_;
- ConfirmationCallback confirmation_callback_;
+ scoped_ptr<BluetoothAdapterChromeOS::PairingContext> pairing_context_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
diff --git a/device/bluetooth/bluetooth_profile_chromeos_unittest.cc b/device/bluetooth/bluetooth_profile_chromeos_unittest.cc
index dd7c945..da2f659 100644
--- a/device/bluetooth/bluetooth_profile_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_profile_chromeos_unittest.cc
@@ -4,6 +4,7 @@
#include "base/message_loop/message_loop.h"
#include "chromeos/dbus/fake_bluetooth_adapter_client.h"
+#include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
#include "chromeos/dbus/fake_bluetooth_device_client.h"
#include "chromeos/dbus/fake_bluetooth_input_client.h"
#include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
@@ -45,6 +46,9 @@ class BluetoothProfileChromeOSTest : public testing::Test {
fake_dbus_thread_manager->SetBluetoothProfileManagerClient(
scoped_ptr<BluetoothProfileManagerClient>(
fake_bluetooth_profile_manager_client_));
+ fake_dbus_thread_manager->SetBluetoothAgentManagerClient(
+ scoped_ptr<BluetoothAgentManagerClient>(
+ new FakeBluetoothAgentManagerClient));
fake_dbus_thread_manager->SetBluetoothAdapterClient(
scoped_ptr<BluetoothAdapterClient>(new FakeBluetoothAdapterClient));
fake_dbus_thread_manager->SetBluetoothDeviceClient(