Merge from Chromium at DEPS revision 257591
This commit was generated by merge_to_master.py.
Change-Id: I0010df2ec3fbb5d4947cd026de2feb150ce7a6b5
diff --git a/device/bluetooth/OWNERS b/device/bluetooth/OWNERS
index 5bdf96a..7bf8537 100644
--- a/device/bluetooth/OWNERS
+++ b/device/bluetooth/OWNERS
@@ -1,2 +1,2 @@
keybuk@chromium.org
-youngki@chromium.org
+armansito@chromium.org
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index c4012bd..2d70842 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -15,9 +15,9 @@
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../../net/net.gyp:net',
'../../third_party/libxml/libxml.gyp:libxml',
+ '../../ui/base/ui_base.gyp:ui_base',
'../../ui/gfx/gfx.gyp:gfx',
'../../ui/gfx/gfx.gyp:gfx_geometry',
- '../../ui/ui.gyp:ui',
'bluetooth_strings.gyp:device_bluetooth_strings',
],
'sources': [
@@ -39,6 +39,8 @@
'bluetooth_device_mac.mm',
'bluetooth_device_win.cc',
'bluetooth_device_win.h',
+ 'bluetooth_discovery_session.cc',
+ 'bluetooth_discovery_session.h',
'bluetooth_gatt_characteristic.cc',
'bluetooth_gatt_characteristic.h',
'bluetooth_gatt_descriptor.cc',
@@ -48,6 +50,8 @@
'bluetooth_init_win.cc',
'bluetooth_init_win.h',
'bluetooth_out_of_band_pairing_data.h',
+ 'bluetooth_pairing_chromeos.cc',
+ 'bluetooth_pairing_chromeos.h',
'bluetooth_profile.cc',
'bluetooth_profile.h',
'bluetooth_profile_chromeos.cc',
@@ -119,6 +123,8 @@
'test/mock_bluetooth_adapter.h',
'test/mock_bluetooth_device.cc',
'test/mock_bluetooth_device.h',
+ 'test/mock_bluetooth_discovery_session.cc',
+ 'test/mock_bluetooth_discovery_session.h',
'test/mock_bluetooth_profile.cc',
'test/mock_bluetooth_profile.h',
'test/mock_bluetooth_socket.cc',
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index 8cce6ec..ffa27ef 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -4,18 +4,31 @@
#include "device/bluetooth/bluetooth_adapter.h"
+#include "base/bind.h"
#include "base/stl_util.h"
#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
namespace device {
-BluetoothAdapter::BluetoothAdapter() {
+BluetoothAdapter::BluetoothAdapter()
+ : weak_ptr_factory_(this) {
}
BluetoothAdapter::~BluetoothAdapter() {
STLDeleteValues(&devices_);
}
+void BluetoothAdapter::StartDiscoverySession(
+ const DiscoverySessionCallback& callback,
+ const ErrorCallback& error_callback) {
+ AddDiscoverySession(
+ base::Bind(&BluetoothAdapter::OnStartDiscoverySession,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ error_callback);
+}
+
BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() {
ConstDeviceList const_devices =
const_cast<const BluetoothAdapter *>(this)->GetDevices();
@@ -52,4 +65,66 @@
return NULL;
}
+void BluetoothAdapter::AddPairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate,
+ PairingDelegatePriority priority) {
+ // Remove the delegate, if it already exists, before inserting to allow a
+ // change of priority.
+ RemovePairingDelegate(pairing_delegate);
+
+ // Find the first point with a lower priority, or the end of the list.
+ std::list<PairingDelegatePair>::iterator iter = pairing_delegates_.begin();
+ while (iter != pairing_delegates_.end() && iter->second >= priority)
+ ++iter;
+
+ pairing_delegates_.insert(iter, std::make_pair(pairing_delegate, priority));
+}
+
+void BluetoothAdapter::RemovePairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ for (std::list<PairingDelegatePair>::iterator iter =
+ pairing_delegates_.begin(); iter != pairing_delegates_.end(); ++iter) {
+ if (iter->first == pairing_delegate) {
+ RemovePairingDelegateInternal(pairing_delegate);
+ pairing_delegates_.erase(iter);
+ return;
+ }
+ }
+}
+
+BluetoothDevice::PairingDelegate* BluetoothAdapter::DefaultPairingDelegate() {
+ if (pairing_delegates_.empty())
+ return NULL;
+
+ return pairing_delegates_.front().first;
+}
+
+void BluetoothAdapter::OnStartDiscoverySession(
+ const DiscoverySessionCallback& callback) {
+ VLOG(1) << "Discovery session started!";
+ scoped_ptr<BluetoothDiscoverySession> discovery_session(
+ new BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter>(this)));
+ discovery_sessions_.insert(discovery_session.get());
+ callback.Run(discovery_session.Pass());
+}
+
+void BluetoothAdapter::MarkDiscoverySessionsAsInactive() {
+ // As sessions are marked as inactive they will notify the adapter that they
+ // have become inactive, upon which the adapter will remove them from
+ // |discovery_sessions_|. To avoid invalidating the iterator, make a copy
+ // here.
+ std::set<BluetoothDiscoverySession*> temp(discovery_sessions_);
+ for (std::set<BluetoothDiscoverySession*>::iterator
+ iter = temp.begin();
+ iter != temp.end(); ++iter) {
+ (*iter)->MarkAsInactive();
+ }
+}
+
+void BluetoothAdapter::DiscoverySessionBecameInactive(
+ BluetoothDiscoverySession* discovery_session) {
+ DCHECK(!discovery_session->IsActive());
+ discovery_sessions_.erase(discovery_session);
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h
index 24e9dcd..e713ff4 100644
--- a/device/bluetooth/bluetooth_adapter.h
+++ b/device/bluetooth/bluetooth_adapter.h
@@ -5,16 +5,20 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
+#include <list>
#include <map>
+#include <set>
#include <string>
-#include <vector>
+#include <utility>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_device.h"
namespace device {
-class BluetoothDevice;
+class BluetoothDiscoverySession;
struct BluetoothOutOfBandPairingData;
@@ -76,7 +80,7 @@
// The ErrorCallback is used for methods that can fail in which case it
// is called, in the success case the callback is simply not called.
- typedef base::Callback<void()> ErrorCallback;
+ typedef base::Closure ErrorCallback;
// The BluetoothOutOfBandPairingDataCallback is used to return
// BluetoothOutOfBandPairingData to the caller.
@@ -135,26 +139,27 @@
// Indicates whether the adapter is currently discovering new devices.
virtual bool IsDiscovering() const = 0;
- // Requests that the adapter begin discovering new devices, code must
- // always call this method if they require the adapter be in discovery
- // and should not make it conditional on the value of IsDiscovering()
- // as other adapter users may be making the same request. Code must also
- // call StopDiscovering() when done. On success |callback| will be called,
- // on failure |error_callback| will be called instead.
+ // Requests the adapter to start a new discovery session. On success, a new
+ // instance of BluetoothDiscoverySession will be returned to the caller via
+ // |callback| and the adapter will be discovering nearby Bluetooth devices.
+ // The returned BluetoothDiscoverySession is owned by the caller and it's the
+ // owner's responsibility to properly clean it up and stop the session when
+ // device discovery is no longer needed.
//
- // Since discovery may already be in progress when this method is called,
- // callers should retrieve the current set of discovered devices by calling
- // GetDevices() and checking for those with IsPaired() as false.
- virtual void StartDiscovering(const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Requests that an earlier call to StartDiscovering() be cancelled; the
- // adapter may not actually cease discovering devices if other callers
- // have called StartDiscovering() and not yet called this method. On
- // success |callback| will be called, on failure |error_callback| will be
- // called instead.
- virtual void StopDiscovering(const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ // If clients desire device discovery to run, they should always call this
+ // method and never make it conditional on the value of IsDiscovering(), as
+ // another client might cause discovery to stop unexpectedly. Hence, clients
+ // should always obtain a BluetoothDiscoverySession and call
+ // BluetoothDiscoverySession::Stop when done. When this method gets called,
+ // device discovery may actually be in progress. Clients can call GetDevices()
+ // and check for those with IsPaired() as false to obtain the list of devices
+ // that have been discovered so far. Otherwise, clients can be notified of all
+ // new and lost devices can by implementing the Observer methods "DeviceAdded"
+ // and "DeviceRemoved".
+ typedef base::Callback<void(scoped_ptr<BluetoothDiscoverySession>)>
+ DiscoverySessionCallback;
+ virtual void StartDiscoverySession(const DiscoverySessionCallback& callback,
+ const ErrorCallback& error_callback);
// Requests the list of devices from the adapter, all are returned
// including those currently connected and those paired. Use the
@@ -175,17 +180,118 @@
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) = 0;
+ // Possible priorities for AddPairingDelegate(), low is intended for
+ // permanent UI and high is intended for interactive UI or applications.
+ enum PairingDelegatePriority {
+ PAIRING_DELEGATE_PRIORITY_LOW,
+ PAIRING_DELEGATE_PRIORITY_HIGH
+ };
+
+ // Adds a default pairing delegate with priority |priority|, method calls
+ // will be made on |pairing_delegate| for incoming pairing requests if the
+ // priority is higher than any other registered, or for those of the same
+ // priority, the first registered.
+ //
+ // |pairing_delegate| must not be freed without first calling
+ // RemovePairingDelegate().
+ virtual void AddPairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate,
+ PairingDelegatePriority priority);
+
+ // Removes a previously added pairing delegate.
+ virtual void RemovePairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate);
+
+ // Returns the first registered pairing delegate with the highest priority,
+ // or NULL if no delegate is registered. Used to select the delegate for
+ // incoming pairing requests.
+ virtual BluetoothDevice::PairingDelegate* DefaultPairingDelegate();
+
protected:
friend class base::RefCounted<BluetoothAdapter>;
+ friend class BluetoothDiscoverySession;
BluetoothAdapter();
virtual ~BluetoothAdapter();
+ // Internal methods for initiating and terminating device discovery sessions.
+ // An implementation of BluetoothAdapter keeps an internal reference count to
+ // make sure that the underlying controller is constantly searching for nearby
+ // devices and retrieving information from them as long as there are clients
+ // who have requested discovery. These methods behave in the following way:
+ //
+ // On a call to AddDiscoverySession:
+ // - If there is a pending request to the subsystem, queue this request to
+ // execute once the pending requests are done.
+ // - If the count is 0, issue a request to the subsystem to start
+ // device discovery. On success, increment the count to 1.
+ // - If the count is greater than 0, increment the count and return
+ // success.
+ // As long as the count is non-zero, the underlying controller will be
+ // discovering for devices. This means that Chrome will restart device
+ // scan and inquiry sessions if they ever end, unless these sessions
+ // terminate due to an unexpected reason.
+ //
+ // On a call to RemoveDiscoverySession:
+ // - If there is a pending request to the subsystem, queue this request to
+ // execute once the pending requests are done.
+ // - If the count is 0, return failure, as there is no active discovery
+ // session.
+ // - If the count is 1, issue a request to the subsystem to stop device
+ // discovery and decrement the count to 0 on success.
+ // - If the count is greater than 1, decrement the count and return
+ // success.
+ //
+ // These methods invoke |callback| for success and |error_callback| for
+ // failures.
+ virtual void AddDiscoverySession(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+ virtual void RemoveDiscoverySession(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Called by RemovePairingDelegate() in order to perform any class-specific
+ // internal functionality necessary to remove the pairing delegate, such as
+ // cleaning up ongoing pairings using it.
+ virtual void RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) = 0;
+
+ // Success callback passed to AddDiscoverySession by StartDiscoverySession.
+ void OnStartDiscoverySession(const DiscoverySessionCallback& callback);
+
+ // Marks all known DiscoverySession instances as inactive. Called by
+ // BluetoothAdapter in the event that the adapter unexpectedly stops
+ // discovering. This should be called by all platform implementations.
+ void MarkDiscoverySessionsAsInactive();
+
+ // Removes |discovery_session| from |discovery_sessions_|, if its in there.
+ // Called by DiscoverySession when an instance is destroyed or becomes
+ // inactive.
+ void DiscoverySessionBecameInactive(
+ BluetoothDiscoverySession* discovery_session);
+
// Devices paired with, connected to, discovered by, or visible to the
// adapter. The key is the Bluetooth address of the device and the value
// is the BluetoothDevice object whose lifetime is managed by the
// adapter instance.
typedef std::map<const std::string, BluetoothDevice*> DevicesMap;
DevicesMap devices_;
+
+ // Default pairing delegates registered with the adapter.
+ typedef std::pair<BluetoothDevice::PairingDelegate*,
+ PairingDelegatePriority> PairingDelegatePair;
+ std::list<PairingDelegatePair> pairing_delegates_;
+
+ private:
+ // List of active DiscoverySession objects. This is used to notify sessions to
+ // become inactive in case of an unexpected change to the adapter discovery
+ // state. We keep raw pointers, with the invariant that a DiscoverySession
+ // will remove itself from this list when it gets destroyed or becomes
+ // inactive by calling DiscoverySessionBecameInactive(), hence no pointers to
+ // deallocated sessions are kept.
+ std::set<BluetoothDiscoverySession*> discovery_sessions_;
+
+ // 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<BluetoothAdapter> weak_ptr_factory_;
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index 0d962b9..820972e 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -11,23 +11,53 @@
#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 "device/bluetooth/bluetooth_pairing_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";
+
+void OnUnregisterAgentError(const std::string& error_name,
+ const std::string& error_message) {
+ // It's okay if the agent didn't exist, it means we never saw an adapter.
+ if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
+ return;
+
+ LOG(WARNING) << "Failed to unregister pairing agent: "
+ << error_name << ": " << error_message;
+}
+
+} // namespace
+
namespace chromeos {
BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
- : weak_ptr_factory_(this) {
+ : num_discovery_sessions_(0),
+ discovery_request_pending_(false),
+ weak_ptr_factory_(this) {
DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
+ // Register the pairing agent.
+ dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
+ agent_.reset(BluetoothAgentServiceProvider::Create(
+ system_bus, dbus::ObjectPath(kAgentPath), this));
+ DCHECK(agent_.get());
+
std::vector<dbus::ObjectPath> object_paths =
DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
@@ -41,6 +71,13 @@
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(
@@ -158,44 +195,28 @@
return properties->discovering.value();
}
-void BluetoothAdapterChromeOS::StartDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- // BlueZ counts discovery sessions, and permits multiple sessions for a
- // single connection, so issue a StartDiscovery() call for every use
- // within Chromium for the right behavior.
- DBusThreadManager::Get()->GetBluetoothAdapterClient()->
- StartDiscovery(
- object_path_,
- base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
- weak_ptr_factory_.GetWeakPtr(),
- callback),
- base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
- weak_ptr_factory_.GetWeakPtr(),
- error_callback));
-}
-
-void BluetoothAdapterChromeOS::StopDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- // Inform BlueZ to stop one of our open discovery sessions.
- DBusThreadManager::Get()->GetBluetoothAdapterClient()->
- StopDiscovery(
- object_path_,
- base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
- weak_ptr_factory_.GetWeakPtr(),
- callback),
- base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
- weak_ptr_factory_.GetWeakPtr(),
- error_callback));
-}
-
void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) {
error_callback.Run();
}
+void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ // Before removing a pairing delegate make sure that there aren't any devices
+ // currently using it; if there are, clear the pairing context which will
+ // make any responses no-ops.
+ for (DevicesMap::iterator iter = devices_.begin();
+ iter != devices_.end(); ++iter) {
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(iter->second);
+
+ BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
+ if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
+ device_chromeos->EndPairing();
+ }
+}
+
void BluetoothAdapterChromeOS::AdapterAdded(
const dbus::ObjectPath& object_path) {
// Set the adapter to the newly added adapter only if no adapter is present.
@@ -282,6 +303,12 @@
property_name == properties->uuids.name())
NotifyDeviceChanged(device_chromeos);
+ // When a device becomes paired, mark it as trusted so that the user does
+ // not need to approve every incoming connection
+ if (property_name == properties->paired.name() &&
+ properties->paired.value())
+ device_chromeos->SetTrusted();
+
// UMA connection counting
if (property_name == properties->connected.name()) {
int count = 0;
@@ -315,6 +342,157 @@
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";
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
+ callback.Run(REJECTED, "");
+ return;
+ }
+
+ pairing->RequestPinCode(callback);
+}
+
+void BluetoothAdapterChromeOS::DisplayPinCode(
+ const dbus::ObjectPath& device_path,
+ const std::string& pincode) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing)
+ return;
+
+ pairing->DisplayPinCode(pincode);
+}
+
+void BluetoothAdapterChromeOS::RequestPasskey(
+ const dbus::ObjectPath& device_path,
+ const PasskeyCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestPasskey";
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
+ callback.Run(REJECTED, 0);
+ return;
+ }
+
+ pairing->RequestPasskey(callback);
+}
+
+void BluetoothAdapterChromeOS::DisplayPasskey(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ uint16 entered) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
+ << " (" << entered << " entered)";
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing)
+ return;
+
+ if (entered == 0)
+ pairing->DisplayPasskey(passkey);
+
+ pairing->KeysEntered(entered);
+}
+
+void BluetoothAdapterChromeOS::RequestConfirmation(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
+ callback.Run(REJECTED);
+ return;
+ }
+
+ pairing->RequestConfirmation(passkey, callback);
+}
+
+void BluetoothAdapterChromeOS::RequestAuthorization(
+ const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ VLOG(1) << device_path.value() << ": RequestAuthorization";
+
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
+ callback.Run(REJECTED);
+ return;
+ }
+
+ pairing->RequestAuthorization(callback);
+}
+
+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";
+}
+
+void BluetoothAdapterChromeOS::OnRegisterAgent() {
+ VLOG(1) << "Pairing agent registered, requesting to be made default";
+
+ DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
+ RequestDefaultAgent(
+ dbus::ObjectPath(kAgentPath),
+ base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
+ weak_ptr_factory_.GetWeakPtr()));
+
+}
+
+void BluetoothAdapterChromeOS::OnRegisterAgentError(
+ const std::string& error_name,
+ const std::string& error_message) {
+ // Our agent being already registered isn't an error.
+ if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
+ return;
+
+ LOG(WARNING) << ": Failed to register pairing agent: "
+ << error_name << ": " << error_message;
+}
+
+void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
+ VLOG(1) << "Pairing agent now default";
+}
+
+void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << ": Failed to make pairing agent default: "
+ << error_name << ": " << error_message;
+}
+
BluetoothDeviceChromeOS*
BluetoothAdapterChromeOS::GetDeviceWithPath(
const dbus::ObjectPath& object_path) {
@@ -329,12 +507,45 @@
return NULL;
}
+BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
+ const dbus::ObjectPath& object_path)
+{
+ BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
+ if (!device_chromeos) {
+ LOG(WARNING) << "Pairing Agent request for unknown device: "
+ << object_path.value();
+ return NULL;
+ }
+
+ BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
+ if (pairing)
+ return pairing;
+
+ // The device doesn't have its own pairing context, so this is an incoming
+ // pairing request that should use our best default delegate (if we have one).
+ BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
+ if (!pairing_delegate)
+ return NULL;
+
+ return device_chromeos->BeginPairing(pairing_delegate);
+}
+
void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
DCHECK(!IsPresent());
object_path_ = object_path;
VLOG(1) << object_path_.value() << ": using adapter.";
+ 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()));
+
SetDefaultAdapterName();
BluetoothAdapterClient::Properties* properties =
@@ -424,6 +635,15 @@
void BluetoothAdapterChromeOS::DiscoveringChanged(
bool discovering) {
+ // If the adapter stopped discovery due to a reason other than a request by
+ // us, reset the count to 0.
+ VLOG(1) << "Discovering changed: " << discovering;
+ if (!discovering && !discovery_request_pending_
+ && num_discovery_sessions_ > 0) {
+ VLOG(1) << "Marking sessions as inactive.";
+ num_discovery_sessions_ = 0;
+ MarkDiscoverySessionsAsInactive();
+ }
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
AdapterDiscoveringChanged(this, discovering));
}
@@ -466,21 +686,144 @@
error_callback.Run();
}
+void BluetoothAdapterChromeOS::AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ VLOG(1) << __func__;
+ if (discovery_request_pending_) {
+ // The pending request is either to stop a previous session or to start a
+ // new one. Either way, queue this one.
+ DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
+ VLOG(1) << "Pending request to start/stop device discovery. Queueing "
+ << "request to start a new discovery session.";
+ discovery_request_queue_.push(std::make_pair(callback, error_callback));
+ return;
+ }
+
+ // The adapter is already discovering.
+ if (num_discovery_sessions_ > 0) {
+ DCHECK(IsDiscovering());
+ DCHECK(!discovery_request_pending_);
+ num_discovery_sessions_++;
+ callback.Run();
+ return;
+ }
+
+ // There are no active discovery sessions.
+ DCHECK(num_discovery_sessions_ == 0);
+
+ // This is the first request to start device discovery.
+ discovery_request_pending_ = true;
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StartDiscovery(
+ object_path_,
+ base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+void BluetoothAdapterChromeOS::RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ VLOG(1) << __func__;
+ // There are active sessions other than the one currently being removed.
+ if (num_discovery_sessions_ > 1) {
+ DCHECK(IsDiscovering());
+ DCHECK(!discovery_request_pending_);
+ num_discovery_sessions_--;
+ callback.Run();
+ return;
+ }
+
+ // If there is a pending request to BlueZ, then queue this request.
+ if (discovery_request_pending_) {
+ VLOG(1) << "Pending request to start/stop device discovery. Queueing "
+ << "request to stop discovery session.";
+ error_callback.Run();
+ return;
+ }
+
+ // There are no active sessions. Return error.
+ if (num_discovery_sessions_ == 0) {
+ // TODO(armansito): This should never happen once we have the
+ // DiscoverySession API. Replace this case with an assert once it's
+ // the deprecated methods have been removed. (See crbug.com/3445008).
+ VLOG(1) << "No active discovery sessions. Returning error.";
+ error_callback.Run();
+ return;
+ }
+
+ // There is exactly one active discovery session. Request BlueZ to stop
+ // discovery.
+ DCHECK(num_discovery_sessions_ == 1);
+ discovery_request_pending_ = true;
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StopDiscovery(
+ object_path_,
+ base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback));
+}
+
void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
+ // Report success on the original request and increment the count.
+ VLOG(1) << __func__;
+ DCHECK(discovery_request_pending_);
+ DCHECK(num_discovery_sessions_ == 0);
+ discovery_request_pending_ = false;
+ num_discovery_sessions_++;
callback.Run();
+
+ // Try to add a new discovery session for each queued request.
+ ProcessQueuedDiscoveryRequests();
}
void BluetoothAdapterChromeOS::OnStartDiscoveryError(
+ const base::Closure& callback,
const ErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
<< error_name << ": " << error_message;
- error_callback.Run();
+
+ // Failed to start discovery. This can only happen if the count is at 0.
+ DCHECK(num_discovery_sessions_ == 0);
+ DCHECK(discovery_request_pending_);
+ discovery_request_pending_ = false;
+
+ // Discovery request may fail if discovery was previously initiated by Chrome,
+ // but the session were invalidated due to the discovery state unexpectedly
+ // changing to false and then back to true. In this case, report success.
+ if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
+ VLOG(1) << "Discovery previously initiated. Reporting success.";
+ num_discovery_sessions_++;
+ callback.Run();
+ } else {
+ error_callback.Run();
+ }
+
+ // Try to add a new discovery session for each queued request.
+ ProcessQueuedDiscoveryRequests();
}
void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
+ // Report success on the original request and decrement the count.
+ VLOG(1) << __func__;
+ DCHECK(discovery_request_pending_);
+ DCHECK(num_discovery_sessions_ == 1);
+ discovery_request_pending_ = false;
+ num_discovery_sessions_--;
callback.Run();
+
+ // Try to add a new discovery session for each queued request.
+ ProcessQueuedDiscoveryRequests();
}
void BluetoothAdapterChromeOS::OnStopDiscoveryError(
@@ -489,7 +832,30 @@
const std::string& error_message) {
LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
<< error_name << ": " << error_message;
+
+ // Failed to stop discovery. This can only happen if the count is at 1.
+ DCHECK(discovery_request_pending_);
+ DCHECK(num_discovery_sessions_ == 1);
+ discovery_request_pending_ = false;
error_callback.Run();
+
+ // Try to add a new discovery session for each queued request.
+ ProcessQueuedDiscoveryRequests();
+}
+
+void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
+ while (!discovery_request_queue_.empty()) {
+ VLOG(1) << "Process queued discovery request.";
+ DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
+ discovery_request_queue_.pop();
+ AddDiscoverySession(callbacks.first, callbacks.second);
+
+ // If the queued request resulted in a pending call, then let it
+ // asynchonously process the remaining queued requests once the pending
+ // call returns.
+ if (discovery_request_pending_)
+ return;
+ }
}
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
index b400ed3..f9e5ea2 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.h
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -5,14 +5,17 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
+#include <queue>
#include <string>
#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 {
@@ -24,6 +27,7 @@
class BluetoothChromeOSTest;
class BluetoothDeviceChromeOS;
+class BluetoothPairingChromeOS;
// The BluetoothAdapterChromeOS class implements BluetoothAdapter for the
// Chrome OS platform.
@@ -31,7 +35,8 @@
: 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(
@@ -56,17 +61,16 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
virtual bool IsDiscovering() const OVERRIDE;
- virtual void StartDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
- virtual void StopDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
virtual void ReadLocalOutOfBandPairingData(
const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback&
callback,
const ErrorCallback& error_callback) OVERRIDE;
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class device::BluetoothAdapterFactory;
friend class BluetoothChromeOSTest;
@@ -74,6 +78,12 @@
friend class BluetoothProfileChromeOS;
friend class BluetoothProfileChromeOSTest;
+ // typedef for callback parameters that are passed to AddDiscoverySession
+ // and RemoveDiscoverySession. This is used to queue incoming requests while
+ // a call to BlueZ is pending.
+ typedef std::pair<base::Closure, ErrorCallback> DiscoveryCallbackPair;
+ typedef std::queue<DiscoveryCallbackPair> DiscoveryCallbackQueue;
+
BluetoothAdapterChromeOS();
virtual ~BluetoothAdapterChromeOS();
@@ -94,11 +104,52 @@
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;
+
+ // 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);
+
+ // Called by dbus:: on completion of the D-Bus method call to request that
+ // the pairing agent be made the default.
+ void OnRequestDefaultAgent();
+ void OnRequestDefaultAgentError(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 a BluetoothPairingChromeOS object for the device
+ // with path |object_path|. Returns the existing pairing object if the device
+ // already has one (usually an outgoing connection in progress) or a new
+ // pairing object with the default pairing delegate if not. If no default
+ // pairing object exists, NULL will be returned.
+ BluetoothPairingChromeOS* GetPairing(const dbus::ObjectPath& object_path);
+
// 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);
@@ -130,9 +181,18 @@
const ErrorCallback& error_callback,
bool success);
+ // BluetoothAdapter override.
+ virtual void AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
// Called by dbus:: on completion of the D-Bus method call to start discovery.
void OnStartDiscovery(const base::Closure& callback);
- void OnStartDiscoveryError(const ErrorCallback& error_callback,
+ void OnStartDiscoveryError(const base::Closure& callback,
+ const ErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message);
@@ -142,12 +202,39 @@
const std::string& error_name,
const std::string& error_message);
+ // Processes the queued discovery requests. For each DiscoveryCallbackPair in
+ // the queue, this method will try to add a new discovery session. This method
+ // is called whenever a pending D-Bus call to start or stop discovery has
+ // ended (with either success or failure).
+ void ProcessQueuedDiscoveryRequests();
+
+ // Number of discovery sessions that have been added.
+ int num_discovery_sessions_;
+
+ // True, if there is a pending request to start or stop discovery.
+ bool discovery_request_pending_;
+
+ // List of queued requests to add new discovery sessions. While there is a
+ // pending request to BlueZ to start or stop discovery, many requests from
+ // within Chrome to start or stop discovery sessions may occur. We only
+ // queue requests to add new sessions to be processed later. All requests to
+ // remove a session while a call is pending immediately return failure. Note
+ // that since BlueZ keeps its own reference count of applications that have
+ // requested discovery, dropping our count to 0 won't necessarily result in
+ // the controller actually stopping discovery if, for example, an application
+ // other than Chrome, such as bt_console, was also used to start discovery.
+ DiscoveryCallbackQueue discovery_request_queue_;
+
// Object path of the adapter we track.
dbus::ObjectPath object_path_;
// 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_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
index 6639db0..064b6bf 100644
--- a/device/bluetooth/bluetooth_adapter_mac.h
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -63,13 +63,6 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
virtual bool IsDiscovering() const OVERRIDE;
-
- virtual void StartDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
- virtual void StopDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
virtual void ReadLocalOutOfBandPairingData(
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) OVERRIDE;
@@ -82,6 +75,11 @@
IOReturn error,
bool aborted);
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class BluetoothAdapterFactory;
friend class BluetoothAdapterMacTest;
@@ -96,6 +94,14 @@
BluetoothAdapterMac();
virtual ~BluetoothAdapterMac();
+ // BluetoothAdapter override.
+ virtual void AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
void Init();
void InitForTest(scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
void PollAdapter();
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index 502ed81..9ac7caa 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -168,7 +168,12 @@
discovery_status_ == DISCOVERY_STOPPING;
}
-void BluetoothAdapterMac::StartDiscovering(
+void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
+ const BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) {
+}
+
+void BluetoothAdapterMac::AddDiscoverySession(
const base::Closure& callback,
const ErrorCallback& error_callback) {
if (discovery_status_ == DISCOVERING) {
@@ -181,8 +186,9 @@
MaybeStartDeviceInquiry();
}
-void BluetoothAdapterMac::StopDiscovering(const base::Closure& callback,
- const ErrorCallback& error_callback) {
+void BluetoothAdapterMac::RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
if (discovery_status_ == NOT_DISCOVERING) {
error_callback.Run();
return;
@@ -192,9 +198,8 @@
MaybeStopDeviceInquiry();
}
-void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
- const BluetoothOutOfBandPairingDataCallback& callback,
- const ErrorCallback& error_callback) {
+void BluetoothAdapterMac::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
}
void BluetoothAdapterMac::Init() {
diff --git a/device/bluetooth/bluetooth_adapter_unittest.cc b/device/bluetooth/bluetooth_adapter_unittest.cc
new file mode 100644
index 0000000..aac32da
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright 2014 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 "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothDevice;
+
+namespace device {
+
+class TestBluetoothAdapter : public BluetoothAdapter {
+ public:
+ TestBluetoothAdapter() {
+ }
+
+ virtual void AddObserver(BluetoothAdapter::Observer* observer) OVERRIDE {
+ }
+
+ virtual void RemoveObserver(BluetoothAdapter::Observer* observer) OVERRIDE {
+
+ }
+
+ virtual std::string GetAddress() const OVERRIDE {
+ return "";
+ }
+
+ virtual std::string GetName() const OVERRIDE {
+ return "";
+ }
+
+ virtual void SetName(const std::string& name,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsInitialized() const OVERRIDE {
+ return false;
+ }
+
+ virtual bool IsPresent() const OVERRIDE {
+ return false;
+ }
+
+ virtual bool IsPowered() const OVERRIDE {
+ return false;
+ }
+
+ virtual void SetPowered(
+ bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsDiscoverable() const OVERRIDE {
+ return false;
+ }
+
+ virtual void SetDiscoverable(
+ bool discoverable,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsDiscovering() const OVERRIDE {
+ return false;
+ }
+
+ virtual void StartDiscoverySession(
+ const DiscoverySessionCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void ReadLocalOutOfBandPairingData(
+ const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ protected:
+ virtual ~TestBluetoothAdapter() {}
+
+ virtual void AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE {
+ }
+};
+
+class TestPairingDelegate : public BluetoothDevice::PairingDelegate {
+ public:
+ virtual void RequestPinCode(BluetoothDevice* device) OVERRIDE {}
+ virtual void RequestPasskey(BluetoothDevice* device) OVERRIDE {}
+ virtual void DisplayPinCode(BluetoothDevice* device,
+ const std::string& pincode) OVERRIDE {}
+ virtual void DisplayPasskey(BluetoothDevice* device,
+ uint32 passkey) OVERRIDE {}
+ virtual void KeysEntered(BluetoothDevice* device,
+ uint32 entered) OVERRIDE {}
+ virtual void ConfirmPasskey(BluetoothDevice* device,
+ uint32 passkey) OVERRIDE {}
+ virtual void AuthorizePairing(BluetoothDevice* device) OVERRIDE {}
+};
+
+
+TEST(BluetoothAdapterTest, NoDefaultPairingDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there is no registered pairing delegate, NULL is returned.
+ EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL);
+}
+
+TEST(BluetoothAdapterTest, OneDefaultPairingDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there is one registered pairing delegate, it is returned.
+ TestPairingDelegate delegate;
+
+ adapter->AddPairingDelegate(&delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+
+ EXPECT_EQ(&delegate, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, SamePriorityDelegates) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there are two registered pairing delegates of the same
+ // priority, the first one registered is returned.
+ TestPairingDelegate delegate1, delegate2;
+
+ adapter->AddPairingDelegate(&delegate1,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->AddPairingDelegate(&delegate2,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+
+ EXPECT_EQ(&delegate1, adapter->DefaultPairingDelegate());
+
+ // After unregistering the first, the second can be returned.
+ adapter->RemovePairingDelegate(&delegate1);
+
+ EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, HighestPriorityDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there are two registered pairing delegates, the one with
+ // the highest priority is returned.
+ TestPairingDelegate delegate1, delegate2;
+
+ adapter->AddPairingDelegate(&delegate1,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->AddPairingDelegate(&delegate2,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, UnregisterDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that after unregistering a delegate, NULL is returned.
+ TestPairingDelegate delegate;
+
+ adapter->AddPairingDelegate(&delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->RemovePairingDelegate(&delegate);
+
+ EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index 521afae..bf0a9b7 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -97,32 +97,6 @@
discovery_status_ == DISCOVERY_STOPPING;
}
-// If the method is called when |discovery_status_| is DISCOVERY_STOPPING,
-// starting again is handled by BluetoothAdapterWin::DiscoveryStopped().
-void BluetoothAdapterWin::StartDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- if (discovery_status_ == DISCOVERING) {
- num_discovery_listeners_++;
- callback.Run();
- return;
- }
- on_start_discovery_callbacks_.push_back(
- std::make_pair(callback, error_callback));
- MaybePostStartDiscoveryTask();
-}
-
-void BluetoothAdapterWin::StopDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- if (discovery_status_ == NOT_DISCOVERING) {
- error_callback.Run();
- return;
- }
- on_stop_discovery_callbacks_.push_back(callback);
- MaybePostStopDiscoveryTask();
-}
-
void BluetoothAdapterWin::DiscoveryStarted(bool success) {
discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING;
for (std::vector<std::pair<base::Closure, ErrorCallback> >::const_iterator
@@ -176,6 +150,10 @@
NOTIMPLEMENTED();
}
+void BluetoothAdapterWin::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+}
+
void BluetoothAdapterWin::AdapterStateChanged(
const BluetoothTaskManagerWin::AdapterState& state) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -226,6 +204,32 @@
}
}
+// If the method is called when |discovery_status_| is DISCOVERY_STOPPING,
+// starting again is handled by BluetoothAdapterWin::DiscoveryStopped().
+void BluetoothAdapterWin::AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (discovery_status_ == DISCOVERING) {
+ num_discovery_listeners_++;
+ callback.Run();
+ return;
+ }
+ on_start_discovery_callbacks_.push_back(
+ std::make_pair(callback, error_callback));
+ MaybePostStartDiscoveryTask();
+}
+
+void BluetoothAdapterWin::RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (discovery_status_ == NOT_DISCOVERING) {
+ error_callback.Run();
+ return;
+ }
+ on_stop_discovery_callbacks_.push_back(callback);
+ MaybePostStopDiscoveryTask();
+}
+
void BluetoothAdapterWin::Init() {
ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
task_manager_ =
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h
index 773c6f3..6e7382f 100644
--- a/device/bluetooth/bluetooth_adapter_win.h
+++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -55,13 +55,6 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
virtual bool IsDiscovering() const OVERRIDE;
-
- virtual void StartDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
- virtual void StopDiscovering(
- const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
virtual void ReadLocalOutOfBandPairingData(
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) OVERRIDE;
@@ -79,6 +72,11 @@
const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices)
OVERRIDE;
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class BluetoothAdapterFactory;
friend class BluetoothAdapterWinTest;
@@ -93,6 +91,14 @@
explicit BluetoothAdapterWin(const InitCallback& init_callback);
virtual ~BluetoothAdapterWin();
+ // BluetoothAdapter override.
+ virtual void AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
void Init();
void InitForTest(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc
index 4ea7a1e..9a9a23d 100644
--- a/device/bluetooth/bluetooth_adapter_win_unittest.cc
+++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -131,6 +131,18 @@
num_stop_discovery_error_callbacks_++;
}
+ void CallAddDiscoverySession(
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback) {
+ adapter_win_->AddDiscoverySession(callback, error_callback);
+ }
+
+ void CallRemoveDiscoverySession(
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback) {
+ adapter_win_->RemoveDiscoverySession(callback, error_callback);
+ }
+
protected:
scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_;
@@ -194,7 +206,7 @@
TEST_F(BluetoothAdapterWinTest, SingleStartDiscovery) {
bluetooth_task_runner_->ClearPendingTasks();
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -210,7 +222,7 @@
}
TEST_F(BluetoothAdapterWinTest, SingleStartDiscoveryFailure) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(),
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
@@ -226,7 +238,7 @@
bluetooth_task_runner_->ClearPendingTasks();
int num_discoveries = 5;
for (int i = 0; i < num_discoveries; i++) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
@@ -246,7 +258,7 @@
TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesFailure) {
int num_discoveries = 5;
for (int i = 0; i < num_discoveries; i++) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(),
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
@@ -260,7 +272,7 @@
}
TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesAfterDiscovering) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -272,7 +284,7 @@
bluetooth_task_runner_->ClearPendingTasks();
for (int i = 0; i < 5; i++) {
int num_start_discovery_callbacks = num_start_discovery_callbacks_;
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
@@ -287,7 +299,7 @@
}
TEST_F(BluetoothAdapterWinTest, StartDiscoveryAfterDiscoveringFailure) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(),
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
@@ -297,7 +309,7 @@
EXPECT_FALSE(adapter_->IsDiscovering());
EXPECT_EQ(1, num_start_discovery_error_callbacks_);
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -308,11 +320,11 @@
}
TEST_F(BluetoothAdapterWinTest, SingleStopDiscovery) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStarted(true);
ui_task_runner_->ClearPendingTasks();
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -330,14 +342,14 @@
TEST_F(BluetoothAdapterWinTest, MultipleStopDiscoveries) {
int num_discoveries = 5;
for (int i = 0; i < num_discoveries; i++) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
}
adapter_win_->DiscoveryStarted(true);
ui_task_runner_->ClearPendingTasks();
bluetooth_task_runner_->ClearPendingTasks();
for (int i = 0; i < num_discoveries - 1; i++) {
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -345,7 +357,7 @@
ui_task_runner_->RunPendingTasks();
EXPECT_EQ(i + 1, num_stop_discovery_callbacks_);
}
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -360,23 +372,23 @@
TEST_F(BluetoothAdapterWinTest,
StartDiscoveryAndStartDiscoveryAndStopDiscoveries) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStarted(true);
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
ui_task_runner_->ClearPendingTasks();
bluetooth_task_runner_->ClearPendingTasks();
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
@@ -385,27 +397,27 @@
TEST_F(BluetoothAdapterWinTest,
StartDiscoveryAndStopDiscoveryAndStartDiscovery) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStarted(true);
EXPECT_TRUE(adapter_->IsDiscovering());
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStopped();
EXPECT_FALSE(adapter_->IsDiscovering());
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStarted(true);
EXPECT_TRUE(adapter_->IsDiscovering());
}
TEST_F(BluetoothAdapterWinTest, StartDiscoveryBeforeDiscoveryStopped) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
adapter_win_->DiscoveryStarted(true);
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
bluetooth_task_runner_->ClearPendingTasks();
adapter_win_->DiscoveryStopped();
@@ -413,7 +425,7 @@
}
TEST_F(BluetoothAdapterWinTest, StopDiscoveryWithoutStartDiscovery) {
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Closure(),
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks,
@@ -422,9 +434,9 @@
}
TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStarted) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Closure(), BluetoothAdapter::ErrorCallback());
bluetooth_task_runner_->ClearPendingTasks();
adapter_win_->DiscoveryStarted(true);
@@ -435,14 +447,14 @@
int num_expected_start_discoveries = 3;
int num_expected_stop_discoveries = 2;
for (int i = 0; i < num_expected_start_discoveries; i++) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
base::Unretained(this)),
BluetoothAdapter::ErrorCallback());
}
for (int i = 0; i < num_expected_stop_discoveries; i++) {
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
@@ -457,12 +469,12 @@
}
TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStartedAndFailed) {
- adapter_win_->StartDiscovering(
+ CallAddDiscoverySession(
base::Closure(),
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
base::Unretained(this)));
- adapter_win_->StopDiscovering(
+ CallRemoveDiscoverySession(
base::Bind(
&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
base::Unretained(this)),
diff --git a/device/bluetooth/bluetooth_chromeos_unittest.cc b/device/bluetooth/bluetooth_chromeos_unittest.cc
index a1cc67d..ca5ff03 100644
--- a/device/bluetooth/bluetooth_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_chromeos_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/dbus/fake_bluetooth_adapter_client.h"
@@ -15,11 +16,15 @@
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
+#include "device/bluetooth/bluetooth_pairing_chromeos.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
using device::BluetoothDevice;
+using device::BluetoothDiscoverySession;
namespace chromeos {
@@ -38,8 +43,12 @@
device_removed_count_(0),
last_device_(NULL),
adapter_(adapter) {
+ adapter_->AddObserver(this);
}
- virtual ~TestObserver() {}
+
+ virtual ~TestObserver() {
+ adapter_->RemoveObserver(this);
+ }
virtual void AdapterPresentChanged(BluetoothAdapter* adapter,
bool present) OVERRIDE {
@@ -140,7 +149,7 @@
display_passkey_count_(0),
keys_entered_count_(0),
confirm_passkey_count_(0),
- dismiss_count_(0),
+ authorize_pairing_count_(0),
last_passkey_(9999999U),
last_entered_(999U) {}
virtual ~TestPairingDelegate() {}
@@ -188,9 +197,9 @@
QuitMessageLoop();
}
- virtual void DismissDisplayOrConfirm() OVERRIDE {
+ virtual void AuthorizePairing(BluetoothDevice* device) OVERRIDE {
++call_count_;
- ++dismiss_count_;
+ ++authorize_pairing_count_;
QuitMessageLoop();
}
@@ -201,7 +210,7 @@
int display_passkey_count_;
int keys_entered_count_;
int confirm_passkey_count_;
- int dismiss_count_;
+ int authorize_pairing_count_;
uint32 last_passkey_;
uint32 last_entered_;
std::string last_pincode_;
@@ -233,12 +242,32 @@
new FakeBluetoothAgentManagerClient));
DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
+ fake_bluetooth_adapter_client_->SetSimulationIntervalMs(10);
+
callback_count_ = 0;
error_callback_count_ = 0;
last_connect_error_ = BluetoothDevice::ERROR_UNKNOWN;
+ last_client_error_ = "";
}
virtual void TearDown() {
+ for (ScopedVector<BluetoothDiscoverySession>::iterator iter =
+ discovery_sessions_.begin();
+ iter != discovery_sessions_.end();
+ ++iter) {
+ BluetoothDiscoverySession* session = *iter;
+ if (!session->IsActive())
+ continue;
+ callback_count_ = 0;
+ session->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ ASSERT_EQ(1, callback_count_);
+ }
+ discovery_sessions_.clear();
adapter_ = NULL;
DBusThreadManager::Shutdown();
}
@@ -246,13 +275,29 @@
// Generic callbacks
void Callback() {
++callback_count_;
+ QuitMessageLoop();
+ }
+
+ void DiscoverySessionCallback(
+ scoped_ptr<BluetoothDiscoverySession> discovery_session) {
+ ++callback_count_;
+ discovery_sessions_.push_back(discovery_session.release());
+ QuitMessageLoop();
}
void ErrorCallback() {
++error_callback_count_;
+ QuitMessageLoop();
}
- void ConnectErrorCallback(enum BluetoothDevice::ConnectErrorCode error) {
+ void DBusErrorCallback(const std::string& error_name,
+ const std::string& error_message) {
+ ++error_callback_count_;
+ last_client_error_ = error_name;
+ QuitMessageLoop();
+ }
+
+ void ConnectErrorCallback(BluetoothDevice::ConnectErrorCode error) {
++error_callback_count_;
last_connect_error_ = error;
}
@@ -271,17 +316,10 @@
// without using this function.
void DiscoverDevice(const std::string& address) {
ASSERT_TRUE(adapter_.get() != NULL);
-
- if (base::MessageLoop::current() == NULL) {
- base::MessageLoop message_loop;
- DiscoverDevices();
- return;
- }
-
+ ASSERT_TRUE(base::MessageLoop::current() != NULL);
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetPowered(
true,
@@ -289,13 +327,16 @@
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ base::MessageLoop::current()->Run();
ASSERT_EQ(2, callback_count_);
ASSERT_EQ(0, error_callback_count_);
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ ASSERT_TRUE(discovery_sessions_[0]->IsActive());
callback_count_ = 0;
ASSERT_TRUE(adapter_->IsPowered());
@@ -305,18 +346,17 @@
observer.last_device_address_ != address)
base::MessageLoop::current()->Run();
- adapter_->StopDiscovering(
+ discovery_sessions_[0]->Stop(
base::Bind(&BluetoothChromeOSTest::Callback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ base::MessageLoop::current()->Run();
ASSERT_EQ(1, callback_count_);
ASSERT_EQ(0, error_callback_count_);
callback_count_ = 0;
ASSERT_FALSE(adapter_->IsDiscovering());
-
- adapter_->RemoveObserver(&observer);
}
// Run a discovery phase so we have devices that can be paired with.
@@ -327,6 +367,7 @@
}
protected:
+ base::MessageLoop message_loop_;
FakeBluetoothAdapterClient* fake_bluetooth_adapter_client_;
FakeBluetoothDeviceClient* fake_bluetooth_device_client_;
scoped_refptr<BluetoothAdapter> adapter_;
@@ -334,6 +375,17 @@
int callback_count_;
int error_callback_count_;
enum BluetoothDevice::ConnectErrorCode last_connect_error_;
+ std::string last_client_error_;
+ ScopedVector<BluetoothDiscoverySession> discovery_sessions_;
+
+ private:
+ // Some tests use a message loop since background processing is simulated;
+ // break out of those loops.
+ void QuitMessageLoop() {
+ if (base::MessageLoop::current() &&
+ base::MessageLoop::current()->is_running())
+ base::MessageLoop::current()->Quit();
+ }
};
TEST_F(BluetoothChromeOSTest, AlreadyPresent) {
@@ -362,7 +414,6 @@
// Install an observer; expect the AdapterPresentChanged to be called
// with true, and IsPresent() to return true.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
fake_bluetooth_adapter_client_->SetVisible(true);
@@ -390,7 +441,6 @@
// Install an observer; expect the AdapterPresentChanged to be called
// with false, and IsPresent() to return false.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
fake_bluetooth_adapter_client_->SetVisible(false);
@@ -418,7 +468,6 @@
// Install an observer, then add a second adapter. Nothing should change,
// we ignore the second adapter.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
fake_bluetooth_adapter_client_->SetSecondVisible(true);
@@ -465,7 +514,6 @@
// Install an observer; expect the AdapterPoweredChanged to be called
// with true, and IsPowered() to return true.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetPowered(
true,
@@ -499,7 +547,6 @@
// Install an observer; expect the AdapterPoweredChanged to be called
// with false, and IsPowered() to return false.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetPowered(
false,
@@ -540,7 +587,6 @@
// Install an observer; expect the AdapterDiscoverableChanged to be called
// with true, and IsDiscoverable() to return true.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetDiscoverable(
true,
@@ -573,7 +619,6 @@
// Install an observer; expect the AdapterDiscoverableChanged to be called
// with false, and IsDiscoverable() to return false.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetDiscoverable(
false,
@@ -590,8 +635,6 @@
}
TEST_F(BluetoothChromeOSTest, StopDiscovery) {
- base::MessageLoop message_loop;
-
GetAdapter();
adapter_->SetPowered(
@@ -600,100 +643,32 @@
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(2, callback_count_);
EXPECT_EQ(0, error_callback_count_);
callback_count_ = 0;
ASSERT_TRUE(adapter_->IsPowered());
ASSERT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ ASSERT_TRUE(discovery_sessions_[0]->IsActive());
// Install an observer; aside from the callback, expect the
// AdapterDiscoveringChanged method to be called and no longer to be
// discovering,
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
- adapter_->StopDiscovering(
+ discovery_sessions_[0]->Stop(
base::Bind(&BluetoothChromeOSTest::Callback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
- EXPECT_EQ(1, callback_count_);
- EXPECT_EQ(0, error_callback_count_);
-
- EXPECT_EQ(1, observer.discovering_changed_count_);
- EXPECT_FALSE(observer.last_discovering_);
-
- EXPECT_FALSE(adapter_->IsDiscovering());
-}
-
-TEST_F(BluetoothChromeOSTest, StopDiscoveryAfterTwoStarts) {
- base::MessageLoop message_loop;
-
- GetAdapter();
-
- adapter_->SetPowered(
- true,
- base::Bind(&BluetoothChromeOSTest::Callback,
- base::Unretained(this)),
- base::Bind(&BluetoothChromeOSTest::ErrorCallback,
- base::Unretained(this)));
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
- base::Unretained(this)),
- base::Bind(&BluetoothChromeOSTest::ErrorCallback,
- base::Unretained(this)));
- EXPECT_EQ(2, callback_count_);
- EXPECT_EQ(0, error_callback_count_);
- callback_count_ = 0;
-
- ASSERT_TRUE(adapter_->IsPowered());
- ASSERT_TRUE(adapter_->IsDiscovering());
-
- // Install an observer and start discovering again; only the callback
- // should be called since we were already discovering to begin with.
- TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
-
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
- base::Unretained(this)),
- base::Bind(&BluetoothChromeOSTest::ErrorCallback,
- base::Unretained(this)));
- EXPECT_EQ(1, callback_count_);
- EXPECT_EQ(0, error_callback_count_);
- callback_count_ = 0;
-
- EXPECT_EQ(0, observer.discovering_changed_count_);
-
- // Stop discovering; only the callback should be called since we're still
- // discovering. The adapter should be still discovering.
- adapter_->StopDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
- base::Unretained(this)),
- base::Bind(&BluetoothChromeOSTest::ErrorCallback,
- base::Unretained(this)));
- EXPECT_EQ(1, callback_count_);
- EXPECT_EQ(0, error_callback_count_);
- callback_count_ = 0;
-
- EXPECT_EQ(0, observer.discovering_changed_count_);
-
- EXPECT_TRUE(adapter_->IsDiscovering());
-
- // Stop discovering one more time; aside from the callback, expect the
- // AdapterDiscoveringChanged method to be called and no longer to be
- // discovering,
- adapter_->StopDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
- base::Unretained(this)),
- base::Bind(&BluetoothChromeOSTest::ErrorCallback,
- base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -705,13 +680,10 @@
TEST_F(BluetoothChromeOSTest, Discovery) {
// Test a simulated discovery session.
- base::MessageLoop message_loop;
-
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
adapter_->SetPowered(
true,
@@ -719,32 +691,35 @@
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(2, callback_count_);
EXPECT_EQ(0, error_callback_count_);
callback_count_ = 0;
ASSERT_TRUE(adapter_->IsPowered());
ASSERT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ ASSERT_TRUE(discovery_sessions_[0]->IsActive());
- // First device to appear should be an Apple Mouse.
- message_loop.Run();
+ // First device to appear.
+ message_loop_.Run();
EXPECT_EQ(1, observer.device_added_count_);
- EXPECT_EQ(FakeBluetoothDeviceClient::kAppleMouseAddress,
+ EXPECT_EQ(FakeBluetoothDeviceClient::kLegacyAutopairAddress,
observer.last_device_address_);
// Next we should get another two devices...
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(3, observer.device_added_count_);
// Okay, let's run forward until a device is actually removed...
while (!observer.device_removed_count_)
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, observer.device_removed_count_);
EXPECT_EQ(FakeBluetoothDeviceClient::kVanishingDeviceAddress,
@@ -752,8 +727,6 @@
}
TEST_F(BluetoothChromeOSTest, PoweredAndDiscovering) {
- base::MessageLoop message_loop;
-
GetAdapter();
adapter_->SetPowered(
true,
@@ -761,14 +734,17 @@
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
- adapter_->StartDiscovering(
- base::Bind(&BluetoothChromeOSTest::Callback,
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
base::Unretained(this)),
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(2, callback_count_);
EXPECT_EQ(0, error_callback_count_);
callback_count_ = 0;
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ ASSERT_TRUE(discovery_sessions_[0]->IsActive());
// Stop the timers that the simulation uses
fake_bluetooth_device_client_->EndDiscoverySimulation(
@@ -779,13 +755,13 @@
fake_bluetooth_adapter_client_->SetVisible(false);
ASSERT_FALSE(adapter_->IsPresent());
+ ASSERT_FALSE(discovery_sessions_[0]->IsActive());
// Install an observer; expect the AdapterPresentChanged,
// AdapterPoweredChanged and AdapterDiscoveringChanged methods to be called
// with true, and IsPresent(), IsPowered() and IsDiscovering() to all
// return true.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
fake_bluetooth_adapter_client_->SetVisible(true);
@@ -822,6 +798,635 @@
EXPECT_FALSE(adapter_->IsDiscovering());
}
+// This unit test asserts that the basic reference counting logic works
+// correctly for discovery requests done via the BluetoothAdapter.
+TEST_F(BluetoothChromeOSTest, MultipleDiscoverySessions) {
+ GetAdapter();
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(adapter_->IsPowered());
+ callback_count_ = 0;
+
+ TestObserver observer(adapter_);
+
+ EXPECT_EQ(0, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // Request device discovery 3 times.
+ for (int i = 0; i < 3; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ // Run only once, as there should have been one D-Bus call.
+ message_loop_.Run();
+
+ // The observer should have received the discovering changed event exactly
+ // once, the success callback should have been called 3 times and the adapter
+ // should be discovering.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(3, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+
+ // Request to stop discovery twice.
+ for (int i = 0; i < 2; i++) {
+ discovery_sessions_[i]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+
+ // The observer should have received no additional discovering changed events,
+ // the success callback should have been called 2 times and the adapter should
+ // still be discovering.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(5, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+ EXPECT_FALSE(discovery_sessions_[1]->IsActive());
+ EXPECT_TRUE(discovery_sessions_[2]->IsActive());
+
+ // Request device discovery 3 times.
+ for (int i = 0; i < 3; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+
+ // The observer should have received no additional discovering changed events,
+ // the success callback should have been called 3 times and the adapter should
+ // still be discovering.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(8, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)6, discovery_sessions_.size());
+
+ // Request to stop discovery 4 times.
+ for (int i = 2; i < 6; i++) {
+ discovery_sessions_[i]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ // Run only once, as there should have been one D-Bus call.
+ message_loop_.Run();
+
+ // The observer should have received the discovering changed event exactly
+ // once, the success callback should have been called 4 times and the adapter
+ // should no longer be discovering.
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_EQ(12, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // All discovery sessions should be inactive.
+ for (int i = 0; i < 6; i++)
+ EXPECT_FALSE(discovery_sessions_[i]->IsActive());
+
+ // Request to stop discovery on of the inactive sessions.
+ discovery_sessions_[0]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // The call should have failed.
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_EQ(12, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
+// This unit test asserts that the reference counting logic works correctly in
+// the cases when the adapter gets reset and D-Bus calls are made outside of
+// the BluetoothAdapter.
+TEST_F(BluetoothChromeOSTest,
+ UnexpectedChangesDuringMultipleDiscoverySessions) {
+ GetAdapter();
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(adapter_->IsPowered());
+ callback_count_ = 0;
+
+ TestObserver observer(adapter_);
+
+ EXPECT_EQ(0, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // Request device discovery 3 times.
+ for (int i = 0; i < 3; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ // Run only once, as there should have been one D-Bus call.
+ message_loop_.Run();
+
+ // The observer should have received the discovering changed event exactly
+ // once, the success callback should have been called 3 times and the adapter
+ // should be discovering.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(3, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+
+ for (int i = 0; i < 3; i++)
+ EXPECT_TRUE(discovery_sessions_[i]->IsActive());
+
+ // Stop the timers that the simulation uses
+ fake_bluetooth_device_client_->EndDiscoverySimulation(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
+
+ ASSERT_TRUE(adapter_->IsPowered());
+ ASSERT_TRUE(adapter_->IsDiscovering());
+
+ // Stop device discovery behind the adapter. The adapter and the observer
+ // should be notified of the change and the reference count should be reset.
+ // Even though FakeBluetoothAdapterClient does its own reference counting and
+ // we called 3 BluetoothAdapter::StartDiscoverySession 3 times, the
+ // FakeBluetoothAdapterClient's count should be only 1 and a single call to
+ // FakeBluetoothAdapterClient::StopDiscovery should work.
+ fake_bluetooth_adapter_client_->StopDiscovery(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_EQ(4, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // All discovery session instances should have been updated.
+ for (int i = 0; i < 3; i++)
+ EXPECT_FALSE(discovery_sessions_[i]->IsActive());
+ discovery_sessions_.clear();
+
+ // It should be possible to successfully start discovery.
+ for (int i = 0; i < 2; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ // Run only once, as there should have been one D-Bus call.
+ message_loop_.Run();
+ EXPECT_EQ(3, observer.discovering_changed_count_);
+ EXPECT_EQ(6, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)2, discovery_sessions_.size());
+
+ for (int i = 0; i < 2; i++)
+ EXPECT_TRUE(discovery_sessions_[i]->IsActive());
+
+ fake_bluetooth_device_client_->EndDiscoverySimulation(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
+
+ // Make the adapter disappear and appear. This will make it come back as
+ // discovering. When this happens, the reference count should become and
+ // remain 0 as no new request was made through the BluetoothAdapter.
+ fake_bluetooth_adapter_client_->SetVisible(false);
+ ASSERT_FALSE(adapter_->IsPresent());
+ EXPECT_EQ(4, observer.discovering_changed_count_);
+ EXPECT_EQ(6, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ for (int i = 0; i < 2; i++)
+ EXPECT_FALSE(discovery_sessions_[i]->IsActive());
+ discovery_sessions_.clear();
+
+ fake_bluetooth_adapter_client_->SetVisible(true);
+ ASSERT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(5, observer.discovering_changed_count_);
+ EXPECT_EQ(6, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+
+ // Start and stop discovery. At this point, FakeBluetoothAdapterClient has
+ // a reference count that is equal to 1. Pretend that this was done by an
+ // application other than us. Starting and stopping discovery will succeed
+ // but it won't cause the discovery state to change.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run(); // Run the loop, as there should have been a D-Bus call.
+ EXPECT_EQ(5, observer.discovering_changed_count_);
+ EXPECT_EQ(7, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[0]->IsActive());
+
+ discovery_sessions_[0]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run(); // Run the loop, as there should have been a D-Bus call.
+ EXPECT_EQ(5, observer.discovering_changed_count_);
+ EXPECT_EQ(8, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+ discovery_sessions_.clear();
+
+ // Start discovery again.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run(); // Run the loop, as there should have been a D-Bus call.
+ EXPECT_EQ(5, observer.discovering_changed_count_);
+ EXPECT_EQ(9, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[0]->IsActive());
+
+ // Stop discovery via D-Bus. The fake client's reference count will drop but
+ // the discovery state won't change since our BluetoothAdapter also just
+ // requested it via D-Bus.
+ fake_bluetooth_adapter_client_->StopDiscovery(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(5, observer.discovering_changed_count_);
+ EXPECT_EQ(10, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+
+ // Now end the discovery session. This should change the adapter's discovery
+ // state.
+ discovery_sessions_[0]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(6, observer.discovering_changed_count_);
+ EXPECT_EQ(11, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+}
+
+TEST_F(BluetoothChromeOSTest, InvalidatedDiscoverySessions) {
+ GetAdapter();
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(adapter_->IsPowered());
+ callback_count_ = 0;
+
+ TestObserver observer(adapter_);
+
+ EXPECT_EQ(0, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // Request device discovery 3 times.
+ for (int i = 0; i < 3; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ // Run only once, as there should have been one D-Bus call.
+ message_loop_.Run();
+
+ // The observer should have received the discovering changed event exactly
+ // once, the success callback should have been called 3 times and the adapter
+ // should be discovering.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(3, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+
+ for (int i = 0; i < 3; i++)
+ EXPECT_TRUE(discovery_sessions_[i]->IsActive());
+
+ // Stop the timers that the simulation uses
+ fake_bluetooth_device_client_->EndDiscoverySimulation(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
+
+ ASSERT_TRUE(adapter_->IsPowered());
+ ASSERT_TRUE(adapter_->IsDiscovering());
+
+ // Delete all but one discovery session.
+ discovery_sessions_.pop_back();
+ discovery_sessions_.pop_back();
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[0]->IsActive());
+ EXPECT_TRUE(adapter_->IsDiscovering());
+
+ // Stop device discovery behind the adapter. The one active discovery session
+ // should become inactive, but more importantly, we shouldn't run into any
+ // memory errors as the sessions that we explicitly deleted should get
+ // cleaned up.
+ fake_bluetooth_adapter_client_->StopDiscovery(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_EQ(4, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+}
+
+TEST_F(BluetoothChromeOSTest, QueuedDiscoveryRequests) {
+ GetAdapter();
+
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(adapter_->IsPowered());
+ callback_count_ = 0;
+
+ TestObserver observer(adapter_);
+
+ EXPECT_EQ(0, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+
+ // Request to start discovery. The call should be pending.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(0, callback_count_);
+
+ fake_bluetooth_device_client_->EndDiscoverySimulation(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
+
+ // The underlying adapter has started discovery, but our call hasn't returned
+ // yet.
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_TRUE(discovery_sessions_.empty());
+
+ // Request to start discovery twice. These should get queued and there should
+ // be no change in state.
+ for (int i = 0; i < 2; i++) {
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_TRUE(discovery_sessions_.empty());
+
+ // Process the pending call. The queued calls should execute and the discovery
+ // session reference count should increase.
+ message_loop_.Run();
+ EXPECT_EQ(3, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+
+ // Verify the reference count by removing sessions 3 times. The last request
+ // should remain pending.
+ for (int i = 0; i < 3; i++) {
+ discovery_sessions_[i]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ }
+ EXPECT_EQ(5, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+ EXPECT_FALSE(discovery_sessions_[1]->IsActive());
+ EXPECT_TRUE(discovery_sessions_[2]->IsActive());
+
+ // Request to stop the session whose call is pending should fail.
+ discovery_sessions_[2]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(5, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_TRUE(discovery_sessions_[2]->IsActive());
+
+ // Request to start should get queued.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(5, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+
+ // Run the pending request.
+ message_loop_.Run();
+ EXPECT_EQ(6, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(3, observer.discovering_changed_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+ EXPECT_FALSE(discovery_sessions_[2]->IsActive());
+
+ // The queued request to start discovery should have been issued but is still
+ // pending. Run the loop and verify.
+ message_loop_.Run();
+ EXPECT_EQ(7, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(3, observer.discovering_changed_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)4, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[3]->IsActive());
+}
+
+TEST_F(BluetoothChromeOSTest, StartDiscoverySession) {
+ GetAdapter();
+
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(adapter_->IsPowered());
+ callback_count_ = 0;
+
+ TestObserver observer(adapter_);
+
+ EXPECT_EQ(0, observer.discovering_changed_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_TRUE(discovery_sessions_.empty());
+
+ // Request a new discovery session.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)1, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[0]->IsActive());
+
+ // Start another session. A new one should be returned in the callback, which
+ // in turn will destroy the previous session. Adapter should still be
+ // discovering and the reference count should be 1.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(2, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)2, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[0]->IsActive());
+
+ // Request a new session.
+ adapter_->StartDiscoverySession(
+ base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(3, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+ EXPECT_TRUE(discovery_sessions_[1]->IsActive());
+ EXPECT_NE(discovery_sessions_[0], discovery_sessions_[1]);
+
+ // Stop the previous discovery session. The session should end but discovery
+ // should continue.
+ discovery_sessions_[0]->Stop(
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ message_loop_.Run();
+ EXPECT_EQ(1, observer.discovering_changed_count_);
+ EXPECT_EQ(4, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(observer.last_discovering_);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ ASSERT_EQ((size_t)3, discovery_sessions_.size());
+ EXPECT_FALSE(discovery_sessions_[0]->IsActive());
+ EXPECT_TRUE(discovery_sessions_[1]->IsActive());
+
+ // Delete the current active session. Discovery should eventually stop.
+ discovery_sessions_.clear();
+ while (observer.last_discovering_)
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(2, observer.discovering_changed_count_);
+ EXPECT_EQ(4, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(observer.last_discovering_);
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
TEST_F(BluetoothChromeOSTest, DeviceProperties) {
GetAdapter();
@@ -846,6 +1451,7 @@
EXPECT_EQ(uuids[0], "00001800-0000-1000-8000-00805f9b34fb");
EXPECT_EQ(uuids[1], "00001801-0000-1000-8000-00805f9b34fb");
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_USB, devices[0]->GetVendorIDSource());
EXPECT_EQ(0x05ac, devices[0]->GetVendorID());
EXPECT_EQ(0x030d, devices[0]->GetProductID());
EXPECT_EQ(0x0306, devices[0]->GetDeviceID());
@@ -865,7 +1471,6 @@
// Install an observer; expect the DeviceChanged method to be called when
// we change the class of the device.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
@@ -893,7 +1498,6 @@
// Install an observer; expect the DeviceChanged method to be called when
// we change the alias of the device.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
@@ -925,7 +1529,6 @@
// Install an observer; expect the DeviceChanged method to be called when
// we change the class of the device.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
@@ -963,7 +1566,6 @@
// Install an observer; expect the DeviceRemoved method to be called
// with the device we remove.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
devices[0]->Forget(
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
@@ -983,7 +1585,7 @@
DiscoverDevices();
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kMicrosoftMouseAddress);
+ FakeBluetoothDeviceClient::kConnectUnpairableAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
@@ -1005,13 +1607,12 @@
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kMicrosoftMousePath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConnectUnpairablePath));
ASSERT_TRUE(properties->trusted.value());
// Install an observer; expect the DeviceRemoved method to be called
// with the device we remove.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
device->Forget(
base::Bind(&BluetoothChromeOSTest::ErrorCallback,
@@ -1019,12 +1620,12 @@
EXPECT_EQ(0, error_callback_count_);
EXPECT_EQ(1, observer.device_removed_count_);
- EXPECT_EQ(FakeBluetoothDeviceClient::kMicrosoftMouseAddress,
+ EXPECT_EQ(FakeBluetoothDeviceClient::kConnectUnpairableAddress,
observer.last_device_address_);
// GetDevices shouldn't return the device either.
device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kMicrosoftMouseAddress);
+ FakeBluetoothDeviceClient::kConnectUnpairableAddress);
EXPECT_FALSE(device != NULL);
}
@@ -1037,7 +1638,6 @@
ASSERT_TRUE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
// Connect without a pairing delegate; since the device is already Paired
// this should succeed and the device should become connected.
@@ -1065,12 +1665,11 @@
DiscoverDevices();
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kMicrosoftMouseAddress);
+ FakeBluetoothDeviceClient::kConnectUnpairableAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
// Connect without a pairing delegate; since the device does not require
// pairing, this should succeed and the device should become connected.
@@ -1095,7 +1694,7 @@
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kMicrosoftMousePath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConnectUnpairablePath));
EXPECT_TRUE(properties->trusted.value());
// Verify is a HID device and is not connectable.
@@ -1129,7 +1728,6 @@
// Connect again; since the device is already Connected, this shouldn't do
// anything to initiate the connection.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
device->Connect(
NULL,
@@ -1154,12 +1752,11 @@
DiscoverDevices();
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kAppleMouseAddress);
+ FakeBluetoothDeviceClient::kLegacyAutopairAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
// Connect without a pairing delegate; since the device requires pairing,
// this should fail with an error.
@@ -1205,7 +1802,6 @@
// Disconnect the device, we should see the observer method fire and the
// device get dropped.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
device->Disconnect(
base::Bind(&BluetoothChromeOSTest::Callback,
@@ -1234,7 +1830,6 @@
// Disconnect the device, we should see the observer method fire and the
// device get dropped.
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
device->Disconnect(
base::Bind(&BluetoothChromeOSTest::Callback,
@@ -1250,22 +1845,20 @@
EXPECT_FALSE(device->IsConnected());
}
-TEST_F(BluetoothChromeOSTest, PairAppleMouse) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairLegacyAutopair) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // The Apple Mouse requires no PIN or Passkey to pair; this is equivalent
- // to Simple Secure Pairing or a device with a fixed 0000 PIN.
+ // The Legacy Autopair device requires no PIN or Passkey to pair because
+ // the daemon provides 0000 to the device for us.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kAppleMouseAddress);
+ FakeBluetoothDeviceClient::kLegacyAutopairAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1278,7 +1871,7 @@
EXPECT_EQ(0, pairing_delegate.call_count_);
EXPECT_TRUE(device->IsConnecting());
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -1300,33 +1893,26 @@
EXPECT_EQ(uuids[0], "00001124-0000-1000-8000-00805f9b34fb");
EXPECT_TRUE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kAppleMousePath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLegacyAutopairPath));
EXPECT_TRUE(properties->trusted.value());
}
-TEST_F(BluetoothChromeOSTest, PairAppleKeyboard) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairDisplayPinCode) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // The Apple Keyboard requires that we display a randomly generated
- // PIN on the screen.
+ // Requires that we display a randomly generated PIN on the screen.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kAppleKeyboardAddress);
+ FakeBluetoothDeviceClient::kDisplayPinCodeAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1341,7 +1927,7 @@
EXPECT_EQ("123456", pairing_delegate.last_pincode_);
EXPECT_TRUE(device->IsConnecting());
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -1363,32 +1949,27 @@
EXPECT_EQ(uuids[0], "00001124-0000-1000-8000-00805f9b34fb");
EXPECT_TRUE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kAppleKeyboardPath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kDisplayPinCodePath));
EXPECT_TRUE(properties->trusted.value());
}
-TEST_F(BluetoothChromeOSTest, PairMotorolaKeyboard) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairDisplayPasskey) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // The Motorola Keyboard requires that we display a randomly generated
- // Passkey on the screen, and notifies us as it's typed in.
+ // Requires that we display a randomly generated Passkey on the screen,
+ // and notifies us as it's typed in.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kMotorolaKeyboardAddress);
+ FakeBluetoothDeviceClient::kDisplayPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1409,18 +1990,18 @@
// One call to KeysEntered() for each key, including [enter].
for(int i = 1; i <= 7; ++i) {
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(2 + i, pairing_delegate.call_count_);
EXPECT_EQ(1 + i, pairing_delegate.keys_entered_count_);
EXPECT_EQ(static_cast<uint32_t>(i), pairing_delegate.last_entered_);
}
- message_loop.Run();
+ message_loop_.Run();
- // 8 KeysEntered notifications (0 to 7, inclusive). Two aditional calls for
- // DisplayPasskey() and DismissDisplayOrConfirm().
- EXPECT_EQ(10, pairing_delegate.call_count_);
+ // 8 KeysEntered notifications (0 to 7, inclusive) and one aditional call for
+ // DisplayPasskey().
+ EXPECT_EQ(9, pairing_delegate.call_count_);
EXPECT_EQ(8, pairing_delegate.keys_entered_count_);
EXPECT_EQ(7U, pairing_delegate.last_entered_);
@@ -1443,34 +2024,29 @@
ASSERT_EQ(1U, uuids.size());
EXPECT_EQ(uuids[0], "00001124-0000-1000-8000-00805f9b34fb");
- // Fake MotorolaKeyboard is not connectable.
+ // And usually not connectable.
EXPECT_FALSE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kMotorolaKeyboardPath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kDisplayPasskeyPath));
EXPECT_TRUE(properties->trusted.value());
}
-TEST_F(BluetoothChromeOSTest, PairSonyHeadphones) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairRequestPinCode) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // The Sony Headphones fake requires that the user enters a PIN for them.
+ // Requires that the user enters a PIN for them.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kSonyHeadphonesAddress);
+ FakeBluetoothDeviceClient::kRequestPinCodeAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1486,7 +2062,7 @@
// Set the PIN.
device->SetPinCode("1234");
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -1508,32 +2084,26 @@
// Non HID devices are always connectable.
EXPECT_TRUE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kSonyHeadphonesPath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath));
EXPECT_TRUE(properties->trusted.value());
}
-TEST_F(BluetoothChromeOSTest, PairPhone) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairConfirmPasskey) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // The fake phone requests that we confirm a displayed passkey.
+ // Requests that we confirm a displayed passkey.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kPhoneAddress);
+ FakeBluetoothDeviceClient::kConfirmPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1550,7 +2120,7 @@
// Confirm the passkey.
device->ConfirmPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -1568,34 +2138,27 @@
// Non HID devices are always connectable.
EXPECT_TRUE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kPhonePath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
EXPECT_TRUE(properties->trusted.value());
}
-TEST_F(BluetoothChromeOSTest, PairWeirdDevice) {
- base::MessageLoop message_loop;
+TEST_F(BluetoothChromeOSTest, PairRequestPasskey) {
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
DiscoverDevices();
- // Use the "weird device" fake that requires that the user enters a Passkey,
- // this would be some kind of device that has a display, but doesn't use
- // "just works" - maybe a car?
+ // Requires that the user enters a Passkey, this would be some kind of
+ // device that has a display, but doesn't use "just works" - maybe a car?
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1611,7 +2174,7 @@
// Set the Passkey.
device->SetPasskey(1234);
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(0, error_callback_count_);
@@ -1629,19 +2192,64 @@
// Non HID devices are always connectable.
EXPECT_TRUE(device->IsConnectable());
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
+ // Make sure the trusted property has been set to true.
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath));
+ EXPECT_TRUE(properties->trusted.value());
+}
+
+TEST_F(BluetoothChromeOSTest, PairJustWorks) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+ DiscoverDevices();
+
+ // Uses just-works pairing, since this is an outgoing pairing, no delegate
+ // interaction is required.
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kJustWorksAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ TestPairingDelegate pairing_delegate;
+ device->Connect(
+ &pairing_delegate,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::ConnectErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(0, pairing_delegate.call_count_);
+
+ message_loop_.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // Two changes for connecting, one change for connected, one for paired and
+ // two for trusted (after pairing and connection).
+ EXPECT_EQ(6, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsConnected());
+ EXPECT_FALSE(device->IsConnecting());
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // Non HID devices are always connectable.
+ EXPECT_TRUE(device->IsConnectable());
// Make sure the trusted property has been set to true.
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
- dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath));
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath));
EXPECT_TRUE(properties->trusted.value());
}
TEST_F(BluetoothChromeOSTest, PairUnpairableDeviceFails) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1653,7 +2261,6 @@
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1667,7 +2274,7 @@
EXPECT_TRUE(device->IsConnecting());
// Run the loop to get the error..
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1677,14 +2284,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingFails) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1697,7 +2299,6 @@
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1711,7 +2312,7 @@
EXPECT_TRUE(device->IsConnecting());
// Run the loop to get the error..
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1721,14 +2322,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingFailsAtConnection) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1742,7 +2338,6 @@
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1755,7 +2350,7 @@
EXPECT_EQ(0, pairing_delegate.call_count_);
EXPECT_TRUE(device->IsConnecting());
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1771,10 +2366,6 @@
EXPECT_TRUE(device->IsPaired());
- // Pairing dialog should be dismissed
- EXPECT_EQ(1, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
-
// Make sure the trusted property has been set to true still (since pairing
// worked).
FakeBluetoothDeviceClient::Properties* properties =
@@ -1785,7 +2376,6 @@
}
TEST_F(BluetoothChromeOSTest, PairingRejectedAtPinCode) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1793,12 +2383,11 @@
// Reject the pairing after we receive a request for the PIN code.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kSonyHeadphonesAddress);
+ FakeBluetoothDeviceClient::kRequestPinCodeAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1814,7 +2403,7 @@
// Reject the pairing.
device->RejectPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1825,14 +2414,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingCancelledAtPinCode) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1840,12 +2424,11 @@
// Cancel the pairing after we receive a request for the PIN code.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kSonyHeadphonesAddress);
+ FakeBluetoothDeviceClient::kRequestPinCodeAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1861,7 +2444,7 @@
// Cancel the pairing.
device->CancelPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1872,14 +2455,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingRejectedAtPasskey) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1887,12 +2465,11 @@
// Reject the pairing after we receive a request for the passkey.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1908,7 +2485,7 @@
// Reject the pairing.
device->RejectPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1919,14 +2496,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingCancelledAtPasskey) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1934,12 +2506,11 @@
// Cancel the pairing after we receive a request for the passkey.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -1955,7 +2526,7 @@
// Cancel the pairing.
device->CancelPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -1966,14 +2537,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingRejectedAtConfirmation) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -1981,12 +2547,11 @@
// Reject the pairing after we receive a request for passkey confirmation.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kPhoneAddress);
+ FakeBluetoothDeviceClient::kConfirmPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -2002,7 +2567,7 @@
// Reject the pairing.
device->RejectPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -2013,14 +2578,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingCancelledAtConfirmation) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -2028,12 +2588,11 @@
// Cancel the pairing after we receive a request for the passkey.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kPhoneAddress);
+ FakeBluetoothDeviceClient::kConfirmPasskeyAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -2049,7 +2608,7 @@
// Cancel the pairing.
device->CancelPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -2060,14 +2619,9 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
-
- // Pairing dialog should be dismissed
- EXPECT_EQ(2, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
}
TEST_F(BluetoothChromeOSTest, PairingCancelledInFlight) {
- base::MessageLoop message_loop;
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
GetAdapter();
@@ -2075,12 +2629,11 @@
// Cancel the pairing while we're waiting for the remote host.
BluetoothDevice* device = adapter_->GetDevice(
- FakeBluetoothDeviceClient::kAppleMouseAddress);
+ FakeBluetoothDeviceClient::kLegacyAutopairAddress);
ASSERT_TRUE(device != NULL);
ASSERT_FALSE(device->IsPaired());
TestObserver observer(adapter_);
- adapter_->AddObserver(&observer);
TestPairingDelegate pairing_delegate;
device->Connect(
@@ -2095,7 +2648,7 @@
// Cancel the pairing.
device->CancelPairing();
- message_loop.Run();
+ message_loop_.Run();
EXPECT_EQ(0, callback_count_);
EXPECT_EQ(1, error_callback_count_);
@@ -2106,10 +2659,512 @@
EXPECT_FALSE(device->IsConnected());
EXPECT_FALSE(device->IsConnecting());
EXPECT_FALSE(device->IsPaired());
+}
- // Pairing dialog should be dismissed
+TEST_F(BluetoothChromeOSTest, IncomingPairRequestPinCode) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // Requires that we provide a PIN code.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kRequestPinCodeAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
EXPECT_EQ(1, pairing_delegate.call_count_);
- EXPECT_EQ(1, pairing_delegate.dismiss_count_);
+ EXPECT_EQ(1, pairing_delegate.request_pincode_count_);
+
+ // Set the PIN.
+ device->SetPinCode("1234");
+ message_loop_.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One change for paired, and one for trusted.
+ EXPECT_EQ(2, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // Make sure the trusted property has been set to true.
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath));
+ ASSERT_TRUE(properties->trusted.value());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairConfirmPasskey) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // Requests that we confirm a displayed passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kConfirmPasskeyAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_);
+ EXPECT_EQ(123456U, pairing_delegate.last_passkey_);
+
+ // Confirm the passkey.
+ device->ConfirmPairing();
+ message_loop_.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One change for paired, and one for trusted.
+ EXPECT_EQ(2, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // Make sure the trusted property has been set to true.
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
+ ASSERT_TRUE(properties->trusted.value());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairRequestPasskey) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // Requests that we provide a Passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.request_passkey_count_);
+
+ // Set the Passkey.
+ device->SetPasskey(1234);
+ message_loop_.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One change for paired, and one for trusted.
+ EXPECT_EQ(2, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // Make sure the trusted property has been set to true.
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath));
+ ASSERT_TRUE(properties->trusted.value());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairJustWorks) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // Uses just-works pairing so, sinec this an incoming pairing, require
+ // authorization from the user.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kJustWorksAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.authorize_pairing_count_);
+
+ // Confirm the pairing.
+ device->ConfirmPairing();
+ message_loop_.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One change for paired, and one for trusted.
+ EXPECT_EQ(2, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // Make sure the trusted property has been set to true.
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath));
+ ASSERT_TRUE(properties->trusted.value());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairRequestPinCodeWithoutDelegate) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // Requires that we provide a PIN Code, without a pairing delegate,
+ // that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kRequestPinCodeAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairConfirmPasskeyWithoutDelegate) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // Requests that we confirm a displayed passkey, without a pairing delegate,
+ // that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kConfirmPasskeyAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairRequestPasskeyWithoutDelegate) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // Requests that we provide a displayed passkey, without a pairing delegate,
+ // that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairJustWorksWithoutDelegate) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // Uses just-works pairing and thus requires authorization for incoming
+ // pairings, without a pairing delegate, that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kJustWorksAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kJustWorksPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, RemovePairingDelegateDuringPairing) {
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // Requests that we provide a Passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kRequestPasskeyAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPasskeyPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.request_passkey_count_);
+
+ // A pairing context should now be set on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ ASSERT_TRUE(device_chromeos->GetPairing() != NULL);
+
+ // Removing the pairing delegate should remove that pairing context.
+ adapter_->RemovePairingDelegate(&pairing_delegate);
+
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+
+ // Set the Passkey, this should now have no effect since the pairing has
+ // been, in-effect, cancelled
+ device->SetPasskey(1234);
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+}
+
+TEST_F(BluetoothChromeOSTest, DeviceId) {
+ GetAdapter();
+
+ // Use the built-in paired device for this test, grab its Properties
+ // structure so we can adjust the underlying modalias property.
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kPairedDeviceAddress);
+ FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPairedDevicePath));
+
+ ASSERT_TRUE(device != NULL);
+ ASSERT_TRUE(properties != NULL);
+
+ // Valid USB IF-assigned identifier.
+ ASSERT_EQ("usb:v05ACp030Dd0306", properties->modalias.value());
+
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_USB, device->GetVendorIDSource());
+ EXPECT_EQ(0x05ac, device->GetVendorID());
+ EXPECT_EQ(0x030d, device->GetProductID());
+ EXPECT_EQ(0x0306, device->GetDeviceID());
+
+ // Valid Bluetooth SIG-assigned identifier.
+ properties->modalias.ReplaceValue("bluetooth:v00E0p2400d0400");
+
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_BLUETOOTH, device->GetVendorIDSource());
+ EXPECT_EQ(0x00e0, device->GetVendorID());
+ EXPECT_EQ(0x2400, device->GetProductID());
+ EXPECT_EQ(0x0400, device->GetDeviceID());
+
+ // Invalid USB IF-assigned identifier.
+ properties->modalias.ReplaceValue("usb:x00E0p2400d0400");
+
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource());
+ EXPECT_EQ(0, device->GetVendorID());
+ EXPECT_EQ(0, device->GetProductID());
+ EXPECT_EQ(0, device->GetDeviceID());
+
+ // Invalid Bluetooth SIG-assigned identifier.
+ properties->modalias.ReplaceValue("bluetooth:x00E0p2400d0400");
+
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource());
+ EXPECT_EQ(0, device->GetVendorID());
+ EXPECT_EQ(0, device->GetProductID());
+ EXPECT_EQ(0, device->GetDeviceID());
+
+ // Unknown vendor specification identifier.
+ properties->modalias.ReplaceValue("chrome:v00E0p2400d0400");
+
+ EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource());
+ EXPECT_EQ(0, device->GetVendorID());
+ EXPECT_EQ(0, device->GetProductID());
+ EXPECT_EQ(0, device->GetDeviceID());
}
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index 95fe683..cb1e7ec 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -33,6 +33,15 @@
// for devices coming and going, as well as properties being updated.
class BluetoothDevice {
public:
+ // Possible values that may be returned by GetVendorIDSource(),
+ // indicating different organisations that allocate the identifiers returned
+ // by GetVendorID().
+ enum VendorIDSource {
+ VENDOR_ID_UNKNOWN,
+ VENDOR_ID_BLUETOOTH,
+ VENDOR_ID_USB
+ };
+
// Possible values that may be returned by GetDeviceType(), representing
// different types of bluetooth device that we support or are aware of
// decoded from the bluetooth class information.
@@ -102,9 +111,7 @@
// This method will be called when the Bluetooth daemon requires that the
// user enter the PIN code |pincode| into the device |device| so that it
- // may be authenticated. The DismissDisplayOrConfirm() method
- // will be called to dismiss the display once pairing is complete or
- // cancelled.
+ // may be authenticated.
//
// This is used for Bluetooth 2.0 and earlier keyboard devices, the
// |pincode| will always be a six-digit numeric in the range 000000-999999
@@ -114,8 +121,7 @@
// This method will be called when the Bluetooth daemon requires that the
// user enter the Passkey |passkey| into the device |device| so that it
- // may be authenticated. The DismissDisplayOrConfirm() method will be
- // called to dismiss the display once pairing is complete or cancelled.
+ // may be authenticated.
//
// This is used for Bluetooth 2.1 and later devices that support input
// but not display, such as keyboards. The Passkey is a numeric in the
@@ -129,8 +135,7 @@
// using a PIN code or a Passkey.
//
// This method will be called only after DisplayPinCode() or
- // DisplayPasskey() is called and before the corresponding
- // DismissDisplayOrConfirm() is called, but is not warranted to be called
+ // DisplayPasskey() method is called, but is not warranted to be called
// on every pairing process that requires a PIN code or a Passkey because
// some device may not support this feature.
//
@@ -155,10 +160,14 @@
virtual void ConfirmPasskey(BluetoothDevice* device,
uint32 passkey) = 0;
- // This method will be called when any previous DisplayPinCode(),
- // DisplayPasskey() or ConfirmPasskey() request should be concluded
- // and removed from the user.
- virtual void DismissDisplayOrConfirm() = 0;
+ // This method will be called when the Bluetooth daemon requires that a
+ // pairing request, usually only incoming, using the just-works model is
+ // authorized. The delegate should decide whether the user should confirm
+ // or not, then call ConfirmPairing() on the device to confirm the pairing
+ // (whether by user action or by default), RejectPairing() on the device to
+ // reject or CancelPairing() on the device to cancel authorization for
+ // any other reason.
+ virtual void AuthorizePairing(BluetoothDevice* device) = 0;
};
// Returns true if uuid is in a a valid canonical format
@@ -175,6 +184,10 @@
// a unique key to identify the device and copied where needed.
virtual std::string GetAddress() const = 0;
+ // Returns the allocation source of the identifier returned by GetVendorID(),
+ // where available, or VENDOR_ID_UNKNOWN where not.
+ virtual VendorIDSource GetVendorIDSource() const = 0;
+
// Returns the Vendor ID of the device, where available.
virtual uint16 GetVendorID() const = 0;
@@ -283,7 +296,7 @@
// If the request fails, |error_callback| will be called; otherwise,
// |callback| is called when the request is complete.
// After calling Connect, CancelPairing should be called to cancel the pairing
- // process and release |pairing_delegate_| if user cancels the pairing and
+ // process and release the pairing delegate if user cancels the pairing and
// closes the pairing UI.
virtual void Connect(PairingDelegate* pairing_delegate,
const base::Closure& callback,
@@ -309,8 +322,8 @@
// Rejects a pairing or connection request from a remote device.
virtual void RejectPairing() = 0;
- // Cancels a pairing or connection attempt to a remote device or release
- // |pairing_deleage_| and |agent_|.
+ // Cancels a pairing or connection attempt to a remote device, releasing
+ // the pairing delegate.
virtual void CancelPairing() = 0;
// Disconnects the device, terminating the low-level ACL connection
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc
index 76e2097..aa1d66b 100644
--- a/device/bluetooth/bluetooth_device_chromeos.cc
+++ b/device/bluetooth/bluetooth_device_chromeos.cc
@@ -4,18 +4,19 @@
#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include <stdio.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_pairing_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"
@@ -24,24 +25,6 @@
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,
@@ -59,35 +42,37 @@
};
void ParseModalias(const dbus::ObjectPath& object_path,
- uint16 *vendor_id,
- uint16 *product_id,
- uint16 *device_id) {
+ BluetoothDevice::VendorIDSource* vendor_id_source,
+ 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;
- }
+ BluetoothDevice::VendorIDSource source_value;
+ int vendor_value, product_value, device_value;
- 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;
- }
+ 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) {
@@ -133,8 +118,6 @@
: adapter_(adapter),
object_path_(object_path),
num_connecting_calls_(0),
- pairing_delegate_(NULL),
- pairing_delegate_used_(false),
weak_ptr_factory_(this) {
}
@@ -168,21 +151,28 @@
return 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_, &vendor_id, NULL, NULL);
+ ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL);
return vendor_id;
}
uint16 BluetoothDeviceChromeOS::GetProductID() const {
uint16 product_id = 0;
- ParseModalias(object_path_, NULL, &product_id, NULL);
+ ParseModalias(object_path_, NULL, NULL, &product_id, NULL);
return product_id;
}
uint16 BluetoothDeviceChromeOS::GetDeviceID() const {
uint16 device_id = 0;
- ParseModalias(object_path_, NULL, NULL, &device_id);
+ ParseModalias(object_path_, NULL, NULL, NULL, &device_id);
return device_id;
}
@@ -248,15 +238,15 @@
}
bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
- return !pincode_callback_.is_null();
+ return pairing_.get() && pairing_->ExpectingPinCode();
}
bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
- return !passkey_callback_.is_null();
+ return pairing_.get() && pairing_->ExpectingPasskey();
}
bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
- return !confirmation_callback_.is_null();
+ return pairing_.get() && pairing_->ExpectingConfirmation();
}
void BluetoothDeviceChromeOS::Connect(
@@ -274,77 +264,72 @@
ConnectInternal(false, callback, error_callback);
} else {
// Initiate high-security connection with pairing.
- DCHECK(!pairing_delegate_);
- DCHECK(agent_.get() == NULL);
+ BeginPairing(pairing_delegate);
- 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));
+ 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_.get())
return;
- pincode_callback_.Run(SUCCESS, pincode);
- pincode_callback_.Reset();
+ pairing_->SetPinCode(pincode);
}
void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
- if (!agent_.get() || passkey_callback_.is_null())
+ if (!pairing_.get())
return;
- passkey_callback_.Run(SUCCESS, passkey);
- passkey_callback_.Reset();
+ pairing_->SetPasskey(passkey);
}
void BluetoothDeviceChromeOS::ConfirmPairing() {
- if (!agent_.get() || confirmation_callback_.is_null())
+ if (!pairing_.get())
return;
- confirmation_callback_.Run(SUCCESS);
- confirmation_callback_.Reset();
+ pairing_->ConfirmPairing();
}
void BluetoothDeviceChromeOS::RejectPairing() {
- RunPairingCallbacks(REJECTED);
+ if (!pairing_.get())
+ return;
+
+ pairing_->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)) {
+ 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";
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();
}
+
+ // 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,
@@ -419,132 +404,18 @@
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();
+BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
+ return pairing_.get();
}
-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::EndPairing() {
+ pairing_.reset();
}
-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();
+BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
+ return pairing_.get();
}
void BluetoothDeviceChromeOS::ConnectInternal(
@@ -613,56 +484,13 @@
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();
+ EndPairing();
+
ConnectInternal(true, callback, error_callback);
}
@@ -679,7 +507,7 @@
VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
<< " still in progress";
- UnregisterAgent();
+ EndPairing();
// Determine the error code from error_name.
ConnectErrorCode error_code = ERROR_UNKNOWN;
@@ -725,38 +553,6 @@
<< ": 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 +576,6 @@
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..bc94c3c 100644
--- a/device/bluetooth/bluetooth_device_chromeos.h
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -9,7 +9,6 @@
#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_device.h"
@@ -17,16 +16,17 @@
namespace chromeos {
class BluetoothAdapterChromeOS;
+class BluetoothPairingChromeOS;
// 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;
virtual std::string GetAddress() const OVERRIDE;
+ virtual VendorIDSource GetVendorIDSource() const OVERRIDE;
virtual uint16 GetVendorID() const OVERRIDE;
virtual uint16 GetProductID() const OVERRIDE;
virtual uint16 GetDeviceID() const OVERRIDE;
@@ -72,6 +72,19 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ // Creates a pairing object with the given delegate |pairing_delegate| and
+ // establishes it as the pairing context for this device. All pairing-related
+ // method calls will be forwarded to this object until it is released.
+ BluetoothPairingChromeOS* BeginPairing(
+ BluetoothDevice::PairingDelegate* pairing_delegate);
+
+ // Releases the current pairing object, any pairing-related method calls will
+ // be ignored.
+ void EndPairing();
+
+ // Returns the current pairing object or NULL if no pairing is in progress.
+ BluetoothPairingChromeOS* GetPairing() const;
+
protected:
// BluetoothDevice override
virtual std::string GetDeviceName() const OVERRIDE;
@@ -83,28 +96,6 @@
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 +108,6 @@
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 +128,6 @@
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 +142,6 @@
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,
@@ -179,7 +151,7 @@
const std::string& error_name,
const std::string& error_message);
- // Return the object path of the device; used by BluetoothAdapterChromeOS
+ // Returns the object path of the device; used by BluetoothAdapterChromeOS
const dbus::ObjectPath& object_path() const { return object_path_; }
// The adapter that owns this device instance.
@@ -194,22 +166,7 @@
// During pairing this is set to an object that we don't own, but on which
// we can make method calls to request, display or confirm PIN Codes and
// 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<BluetoothPairingChromeOS> pairing_;
// 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_device_mac.h b/device/bluetooth/bluetooth_device_mac.h
index bc887b9..bc3ce19 100644
--- a/device/bluetooth/bluetooth_device_mac.h
+++ b/device/bluetooth/bluetooth_device_mac.h
@@ -26,6 +26,7 @@
// BluetoothDevice override
virtual uint32 GetBluetoothClass() const OVERRIDE;
virtual std::string GetAddress() const OVERRIDE;
+ virtual VendorIDSource GetVendorIDSource() const OVERRIDE;
virtual uint16 GetVendorID() const OVERRIDE;
virtual uint16 GetProductID() const OVERRIDE;
virtual uint16 GetDeviceID() const OVERRIDE;
diff --git a/device/bluetooth/bluetooth_device_mac.mm b/device/bluetooth/bluetooth_device_mac.mm
index 39acbef..50762d2 100644
--- a/device/bluetooth/bluetooth_device_mac.mm
+++ b/device/bluetooth/bluetooth_device_mac.mm
@@ -82,6 +82,11 @@
return base::SysNSStringToUTF8([device_ addressString]);
}
+BluetoothDevice::VendorIDSource
+BluetoothDeviceMac::GetVendorIDSource() const {
+ return VENDOR_ID_UNKNOWN;
+}
+
uint16 BluetoothDeviceMac::GetVendorID() const {
return 0;
}
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index bfd9bc6..3f95efd 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -71,6 +71,11 @@
return address_;
}
+BluetoothDevice::VendorIDSource
+BluetoothDeviceWin::GetVendorIDSource() const {
+ return VENDOR_ID_UNKNOWN;
+}
+
uint16 BluetoothDeviceWin::GetVendorID() const {
return 0;
}
diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h
index 452f6f2..274364b 100644
--- a/device/bluetooth/bluetooth_device_win.h
+++ b/device/bluetooth/bluetooth_device_win.h
@@ -26,6 +26,7 @@
// BluetoothDevice override
virtual uint32 GetBluetoothClass() const OVERRIDE;
virtual std::string GetAddress() const OVERRIDE;
+ virtual VendorIDSource GetVendorIDSource() const OVERRIDE;
virtual uint16 GetVendorID() const OVERRIDE;
virtual uint16 GetProductID() const OVERRIDE;
virtual uint16 GetDeviceID() const OVERRIDE;
diff --git a/device/bluetooth/bluetooth_discovery_session.cc b/device/bluetooth/bluetooth_discovery_session.cc
new file mode 100644
index 0000000..ba5f5fd
--- /dev/null
+++ b/device/bluetooth/bluetooth_discovery_session.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 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_discovery_session.h"
+
+#include "base/bind.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace device {
+
+BluetoothDiscoverySession::BluetoothDiscoverySession(
+ scoped_refptr<BluetoothAdapter> adapter)
+ : active_(true), adapter_(adapter), weak_ptr_factory_(this) {
+ DCHECK(adapter_.get());
+}
+
+BluetoothDiscoverySession::BluetoothDiscoverySession()
+ : active_(false), weak_ptr_factory_(this) {}
+
+BluetoothDiscoverySession::~BluetoothDiscoverySession() {
+ // |adapter_| may be NULL if this instance was initialized as a mock.
+ if (!adapter_.get()) {
+ DCHECK(!active_);
+ return;
+ }
+ Stop(base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
+ MarkAsInactive();
+}
+
+bool BluetoothDiscoverySession::IsActive() const {
+ return active_;
+}
+
+void BluetoothDiscoverySession::Stop(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (!active_) {
+ LOG(WARNING) << "Discovery session not active. Cannot stop.";
+ error_callback.Run();
+ return;
+ }
+ VLOG(1) << "Stopping device discovery session.";
+ DCHECK(adapter_.get());
+ adapter_->RemoveDiscoverySession(
+ base::Bind(&BluetoothDiscoverySession::OnStop,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ error_callback);
+}
+
+void BluetoothDiscoverySession::OnStop(const base::Closure& callback) {
+ MarkAsInactive();
+ callback.Run();
+}
+
+void BluetoothDiscoverySession::MarkAsInactive() {
+ if (!active_)
+ return;
+ active_ = false;
+ DCHECK(adapter_.get());
+ adapter_->DiscoverySessionBecameInactive(this);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_discovery_session.h b/device/bluetooth/bluetooth_discovery_session.h
new file mode 100644
index 0000000..666538b
--- /dev/null
+++ b/device/bluetooth/bluetooth_discovery_session.h
@@ -0,0 +1,90 @@
+// Copyright 2014 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.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_SESSION_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_SESSION_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace device {
+
+class BluetoothAdapter;
+
+// BluetoothDiscoverySession represents a current active or inactive device
+// discovery session. Instances of this class are obtained by calling
+// BluetoothAdapter::StartDiscoverySession. The Bluetooth adapter will be
+// constantly searching for nearby devices, as long as at least one instance
+// of an active BluetoothDiscoverySession exists. A BluetoothDiscoverySession is
+// considered active, as long as the adapter is discovering AND the owner of the
+// instance has not called BluetoothDiscoverySession::Stop. A
+// BluetoothDiscoverySession might unexpectedly become inactive, if the adapter
+// unexpectedly stops discovery. Users can implement the
+// AdapterDiscoveringChanged method of the BluetoothAdapter::Observer interface
+// to be notified of such a change and promptly request a new
+// BluetoothDiscoverySession if their existing sessions have become inactive.
+class BluetoothDiscoverySession {
+ public:
+ // The ErrorCallback is used by methods to asynchronously report errors.
+ typedef base::Closure ErrorCallback;
+
+ // Destructor automatically terminates the discovery session. If this
+ // results in a call to the underlying system to stop device discovery
+ // (i.e. this instance represents the last active discovery session),
+ // the call may not always succeed. To be notified of such failures,
+ // users are highly encouraged to call BluetoothDiscoverySession::Stop,
+ // instead of relying on the destructor.
+ virtual ~BluetoothDiscoverySession();
+
+ // Returns true if the session is active, false otherwise. If false, the
+ // adapter might still be discovering as there might still be other active
+ // sessions; this just means that this instance no longer has a say in
+ // whether or not discovery should continue. In this case, the application
+ // should request a new BluetoothDiscoverySession to make sure that device
+ // discovery continues.
+ virtual bool IsActive() const;
+
+ // Requests this discovery session instance to stop. If this instance is
+ // active, the session will stop. On success, |callback| is called and
+ // on error |error_callback| is called. After a successful invocation, the
+ // adapter may or may not stop device discovery, depending on whether or not
+ // other active discovery sessions are present. Users are highly encouraged
+ // to call this method to end a discovery session, instead of relying on the
+ // destructor, so that they can be notified of the result via the callback
+ // arguments.
+ virtual void Stop(const base::Closure& callback,
+ const ErrorCallback& error_callback);
+
+ protected:
+ BluetoothDiscoverySession(); // Called by mock.
+
+ private:
+ friend class BluetoothAdapter;
+ explicit BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter> adapter);
+
+ // Internal callback invoked when a call to Stop has succeeded.
+ void OnStop(const base::Closure& callback);
+
+ // Marks this instance as inactive. Called by BluetoothAdapter to mark a
+ // session as inactive in the case of an unexpected change to the adapter
+ // discovery state.
+ void MarkAsInactive();
+
+ // Whether or not this instance represents an active discovery session.
+ bool active_;
+
+ // The adapter that created this instance.
+ scoped_refptr<BluetoothAdapter> adapter_;
+
+ // 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<BluetoothDiscoverySession> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoverySession);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_SESSION_H_
diff --git a/device/bluetooth/bluetooth_pairing_chromeos.cc b/device/bluetooth/bluetooth_pairing_chromeos.cc
new file mode 100644
index 0000000..dc73f6d
--- /dev/null
+++ b/device/bluetooth/bluetooth_pairing_chromeos.cc
@@ -0,0 +1,273 @@
+// Copyright 2014 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_pairing_chromeos.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_device_chromeos.h"
+
+using device::BluetoothDevice;
+
+namespace {
+
+// 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
+};
+
+// Number of keys that will be entered for a passkey, six digits plus the
+// final enter.
+const uint16 kPasskeyMaxKeysEntered = 7;
+
+} // namespace
+
+namespace chromeos {
+
+BluetoothPairingChromeOS::BluetoothPairingChromeOS(
+ BluetoothDeviceChromeOS* device,
+ BluetoothDevice::PairingDelegate* pairing_delegate)
+ : device_(device),
+ pairing_delegate_(pairing_delegate),
+ pairing_delegate_used_(false) {
+ VLOG(1) << "Created BluetoothPairingChromeOS for "
+ << device_->GetAddress();
+}
+
+BluetoothPairingChromeOS::~BluetoothPairingChromeOS() {
+ VLOG(1) << "Destroying BluetoothPairingChromeOS for "
+ << device_->GetAddress();
+
+ if (!pairing_delegate_used_) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_NONE,
+ UMA_PAIRING_METHOD_COUNT);
+ }
+
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED, "");
+ }
+
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED, 0);
+ }
+
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED);
+ }
+
+ pairing_delegate_ = NULL;
+}
+
+void BluetoothPairingChromeOS::RequestPinCode(
+ const BluetoothAgentServiceProvider::Delegate::PinCodeCallback& callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ pincode_callback_ = callback;
+ pairing_delegate_used_ = true;
+ pairing_delegate_->RequestPinCode(device_);
+}
+
+bool BluetoothPairingChromeOS::ExpectingPinCode() const {
+ return !pincode_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::SetPinCode(const std::string& pincode) {
+ if (pincode_callback_.is_null())
+ return;
+
+ pincode_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS,
+ pincode);
+ pincode_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::DisplayPinCode(const std::string& pincode) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ pairing_delegate_used_ = true;
+ pairing_delegate_->DisplayPinCode(device_, pincode);
+
+ // If this is not an outgoing connection to the device, the pairing context
+ // needs to be cleaned up again as there's no reliable indication of
+ // completion of incoming pairing.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::RequestPasskey(
+ const BluetoothAgentServiceProvider::Delegate::PasskeyCallback& callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ passkey_callback_ = callback;
+ pairing_delegate_used_ = true;
+ pairing_delegate_->RequestPasskey(device_);
+}
+
+bool BluetoothPairingChromeOS::ExpectingPasskey() const {
+ return !passkey_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::SetPasskey(uint32 passkey) {
+ if (passkey_callback_.is_null())
+ return;
+
+ passkey_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS,
+ passkey);
+ passkey_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::DisplayPasskey(uint32 passkey) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ pairing_delegate_used_ = true;
+ pairing_delegate_->DisplayPasskey(device_, passkey);
+
+}
+
+void BluetoothPairingChromeOS::KeysEntered(uint16 entered) {
+ pairing_delegate_used_ = true;
+ pairing_delegate_->KeysEntered(device_, entered);
+
+ // If this is not an outgoing connection to the device, the pairing context
+ // needs to be cleaned up again as there's no reliable indication of
+ // completion of incoming pairing.
+ if (entered >= kPasskeyMaxKeysEntered && !device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::RequestConfirmation(
+ uint32 passkey,
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ confirmation_callback_ = callback;
+ pairing_delegate_used_ = true;
+ pairing_delegate_->ConfirmPasskey(device_, passkey);
+}
+
+void BluetoothPairingChromeOS::RequestAuthorization(
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_NONE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ ResetCallbacks();
+ confirmation_callback_ = callback;
+ pairing_delegate_used_ = true;
+ pairing_delegate_->AuthorizePairing(device_);
+}
+
+bool BluetoothPairingChromeOS::ExpectingConfirmation() const {
+ return !confirmation_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::ConfirmPairing() {
+ if (confirmation_callback_.is_null())
+ return;
+
+ confirmation_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS);
+ confirmation_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+bool BluetoothPairingChromeOS::RejectPairing() {
+ return RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::REJECTED);
+}
+
+bool BluetoothPairingChromeOS::CancelPairing() {
+ return RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED);
+}
+
+BluetoothDevice::PairingDelegate*
+BluetoothPairingChromeOS::GetPairingDelegate() const {
+ return pairing_delegate_;
+}
+
+void BluetoothPairingChromeOS::ResetCallbacks() {
+ pincode_callback_.Reset();
+ passkey_callback_.Reset();
+ confirmation_callback_.Reset();
+}
+
+bool BluetoothPairingChromeOS::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;
+ }
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+
+ return callback_run;
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_pairing_chromeos.h b/device/bluetooth/bluetooth_pairing_chromeos.h
new file mode 100644
index 0000000..ae906bc
--- /dev/null
+++ b/device/bluetooth/bluetooth_pairing_chromeos.h
@@ -0,0 +1,146 @@
+// Copyright 2014 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.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
+
+#include "chromeos/dbus/bluetooth_agent_service_provider.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace chromeos {
+
+class BluetoothDeviceChromeOS;
+
+// The BluetoothPairingChromeOS class encapsulates the logic for an individual
+// device pairing, acting as a bridge between BluetoothAdapterChromeOS which
+// communicates with the underlying Controller and Host Subsystem, and
+// BluetoothDeviceChromeOS which presents the pairing logic to the application.
+class BluetoothPairingChromeOS {
+ public:
+ BluetoothPairingChromeOS(
+ BluetoothDeviceChromeOS* device,
+ device::BluetoothDevice::PairingDelegate* pairing_delegate);
+ ~BluetoothPairingChromeOS();
+
+ // 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;
+
+ // Requests a PIN code for the current device from the current pairing
+ // delegate, the SetPinCode(), RejectPairing() and CancelPairing() method
+ // calls on this object are translated into the appropriate response to
+ // |callback|.
+ void RequestPinCode(
+ const BluetoothAgentServiceProvider::Delegate::PinCodeCallback& callback);
+
+ // Indicates whether the device is currently pairing and expecting a
+ // PIN Code to be returned.
+ bool ExpectingPinCode() 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);
+
+ // Requests a PIN code for the current device be displayed by the current
+ // pairing delegate. No response is expected from the delegate.
+ void DisplayPinCode(const std::string& pincode);
+
+ // Requests a Passkey for the current device from the current pairing
+ // delegate, the SetPasskey(), RejectPairing() and CancelPairing() method
+ // calls on this object are translated into the appropriate response to
+ // |callback|.
+ void RequestPasskey(
+ const BluetoothAgentServiceProvider::Delegate::PasskeyCallback& callback);
+
+ // 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);
+
+ // Requests a Passkey for the current device be displayed by the current
+ // pairing delegate. No response is expected from the delegate.
+ void DisplayPasskey(uint32 passkey);
+
+ // Informs the current pairing delegate that |entered| keys have been
+ // provided to the remote device since the DisplayPasskey() call. No
+ // response is expected from the delegate.
+ void KeysEntered(uint16 entered);
+
+ // Requests confirmation that |passkey| is displayed on the current device
+ // from the current pairing delegate. The ConfirmPairing(), RejectPairing()
+ // and CancelPairing() method calls on this object are translated into the
+ // appropriate response to |callback|.
+ void RequestConfirmation(
+ uint32 passkey,
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback);
+
+ // Requests authorization that the current device be allowed to pair with
+ // this device from the current pairing delegate. The ConfirmPairing(),
+ // RejectPairing() and CancelPairing() method calls on this object are
+ // translated into the appropriate response to |callback|.
+ void RequestAuthorization(
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback);
+
+ // 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();
+
+ // Returns the pairing delegate being used by this pairing object.
+ device::BluetoothDevice::PairingDelegate* GetPairingDelegate() const;
+
+ private:
+ // Internal method to reset the current set of callbacks because a new
+ // request has arrived that supercedes them.
+ void ResetCallbacks();
+
+ // Internal method to respond to the relevant callback for a RejectPairing
+ // or CancelPairing call.
+ bool RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::Status status);
+
+ // The underlying BluetoothDeviceChromeOS that owns this pairing context.
+ BluetoothDeviceChromeOS* device_;
+
+ // 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().
+ BluetoothAgentServiceProvider::Delegate::PinCodeCallback pincode_callback_;
+ BluetoothAgentServiceProvider::Delegate::PasskeyCallback passkey_callback_;
+ BluetoothAgentServiceProvider::Delegate::ConfirmationCallback
+ confirmation_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothPairingChromeOS);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_profile_chromeos.cc b/device/bluetooth/bluetooth_profile_chromeos.cc
index 31e165e..5fe87fe 100644
--- a/device/bluetooth/bluetooth_profile_chromeos.cc
+++ b/device/bluetooth/bluetooth_profile_chromeos.cc
@@ -30,6 +30,7 @@
#include "device/bluetooth/bluetooth_profile.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/bluetooth_socket_chromeos.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
@@ -60,6 +61,11 @@
BluetoothProfileChromeOS::~BluetoothProfileChromeOS() {
DCHECK(object_path_.value().empty());
DCHECK(profile_.get() == NULL);
+
+ if (adapter_.get()) {
+ adapter_->RemoveObserver(this);
+ adapter_ = NULL;
+ }
}
void BluetoothProfileChromeOS::Init(
@@ -76,16 +82,15 @@
uuid_ = uuid;
- BluetoothProfileManagerClient::Options bluetooth_options;
- bluetooth_options.name = options.name;
- bluetooth_options.service = uuid;
- bluetooth_options.channel = options.channel;
- bluetooth_options.psm = options.psm;
- bluetooth_options.require_authentication = options.require_authentication;
- bluetooth_options.require_authorization = options.require_authorization;
- bluetooth_options.auto_connect = options.auto_connect;
- bluetooth_options.version = options.version;
- bluetooth_options.features = options.features;
+ options_.name = options.name;
+ options_.service = uuid;
+ options_.channel = options.channel;
+ options_.psm = options.psm;
+ options_.require_authentication = options.require_authentication;
+ options_.require_authorization = options.require_authorization;
+ options_.auto_connect = options.auto_connect;
+ options_.version = options.version;
+ options_.features = options.features;
// The object path is relatively meaningless, but has to be unique, so we
// use the UUID of the profile.
@@ -100,18 +105,12 @@
system_bus, object_path_, this));
DCHECK(profile_.get());
- VLOG(1) << object_path_.value() << ": Register profile";
- DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
- RegisterProfile(
- object_path_,
- uuid,
- bluetooth_options,
- base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile,
- weak_ptr_factory_.GetWeakPtr(),
- callback),
- base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
+ // Now the profile object is registered we need an adapter to register it
+ // with.
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothProfileChromeOS::OnGetAdapter,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
}
void BluetoothProfileChromeOS::Unregister() {
@@ -135,6 +134,44 @@
connection_callback_ = callback;
}
+void BluetoothProfileChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
+ bool present) {
+ if (!present)
+ return;
+
+ VLOG(1) << object_path_.value() << ": Register profile";
+ DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
+ RegisterProfile(
+ object_path_,
+ uuid_,
+ options_,
+ base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfile,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfileError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BluetoothProfileChromeOS::OnGetAdapter(
+ const ProfileCallback& callback,
+ scoped_refptr<device::BluetoothAdapter> adapter) {
+ DCHECK(!adapter_.get());
+ adapter_ = adapter;
+ adapter_->AddObserver(this);
+
+ VLOG(1) << object_path_.value() << ": Register profile";
+ DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
+ RegisterProfile(
+ object_path_,
+ uuid_,
+ options_,
+ base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+}
+
void BluetoothProfileChromeOS::Release() {
VLOG(1) << object_path_.value() << ": Release";
}
@@ -145,22 +182,22 @@
const BluetoothProfileServiceProvider::Delegate::Options& options,
const ConfirmationCallback& callback) {
VLOG(1) << object_path_.value() << ": New connection from device: "
- << device_path.value();;
+ << device_path.value();
if (connection_callback_.is_null()) {
callback.Run(REJECTED);
return;
}
// Punt descriptor validity check to a worker thread where i/o is permitted;
- // on return we'll fetch the adapter and then call the connection callback.
+ // on return we'll call the connection callback.
//
// base::Passed is used to take ownership of the file descriptor during the
- // CheckValidity() call and pass that ownership to the GetAdapter() call.
+ // CheckValidity() call and pass that ownership to callback.
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(false).get(),
FROM_HERE,
base::Bind(&CheckValidity, base::Passed(&fd)),
- base::Bind(&BluetoothProfileChromeOS::GetAdapter,
+ base::Bind(&BluetoothProfileChromeOS::OnCheckValidity,
weak_ptr_factory_.GetWeakPtr(),
device_path,
options,
@@ -178,6 +215,22 @@
VLOG(1) << object_path_.value() << ": Cancel";
}
+void BluetoothProfileChromeOS::OnInternalRegisterProfile() {
+ VLOG(1) << object_path_.value() << ": Profile registered";
+}
+
+void BluetoothProfileChromeOS::OnInternalRegisterProfileError(
+ const std::string& error_name,
+ const std::string& error_message) {
+ // It's okay if the profile already exists, it means we registered it on
+ // initialization.
+ if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
+ return;
+
+ LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
+ << error_name << ": " << error_message;
+}
+
void BluetoothProfileChromeOS::OnRegisterProfile(
const ProfileCallback& callback) {
VLOG(1) << object_path_.value() << ": Profile registered";
@@ -188,29 +241,38 @@
const ProfileCallback& callback,
const std::string& error_name,
const std::string& error_message) {
+ // It's okay if the profile already exists, it means we registered it when
+ // we first saw the adapter.
+ if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
+ return;
+
LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
<< error_name << ": " << error_message;
callback.Run(NULL);
-
- Unregister();
}
void BluetoothProfileChromeOS::OnUnregisterProfile() {
VLOG(1) << object_path_.value() << ": Profile unregistered";
object_path_ = dbus::ObjectPath("");
+ adapter_ = NULL;
delete this;
}
void BluetoothProfileChromeOS::OnUnregisterProfileError(
const std::string& error_name,
const std::string& error_message) {
+ // It's okay if the profile didn't exist, it means we never saw an adapter.
+ if (error_name == bluetooth_profile_manager::kErrorDoesNotExist)
+ return;
+
LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
<< error_name << ": " << error_message;
object_path_ = dbus::ObjectPath("");
+ adapter_ = NULL;
delete this;
}
-void BluetoothProfileChromeOS::GetAdapter(
+void BluetoothProfileChromeOS::OnCheckValidity(
const dbus::ObjectPath& device_path,
const BluetoothProfileServiceProvider::Delegate::Options& options,
const ConfirmationCallback& callback,
@@ -221,27 +283,10 @@
return;
}
- BluetoothAdapterFactory::GetAdapter(
- base::Bind(&BluetoothProfileChromeOS::OnGetAdapter,
- weak_ptr_factory_.GetWeakPtr(),
- device_path,
- options,
- callback,
- base::Passed(&fd)));
-}
-
-void BluetoothProfileChromeOS::OnGetAdapter(
- const dbus::ObjectPath& device_path,
- const BluetoothProfileServiceProvider::Delegate::Options&
- options,
- const ConfirmationCallback& callback,
- scoped_ptr<dbus::FileDescriptor> fd,
- scoped_refptr<BluetoothAdapter> adapter) {
- VLOG(1) << object_path_.value() << ": Obtained adapter reference";
callback.Run(SUCCESS);
BluetoothDeviceChromeOS* device =
- static_cast<BluetoothAdapterChromeOS*>(adapter.get())->
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
GetDeviceWithPath(device_path);
DCHECK(device);
diff --git a/device/bluetooth/bluetooth_profile_chromeos.h b/device/bluetooth/bluetooth_profile_chromeos.h
index c13951e..84b7043 100644
--- a/device/bluetooth/bluetooth_profile_chromeos.h
+++ b/device/bluetooth/bluetooth_profile_chromeos.h
@@ -12,8 +12,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/bluetooth_profile_manager_client.h"
#include "chromeos/dbus/bluetooth_profile_service_provider.h"
#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_profile.h"
namespace dbus {
@@ -22,18 +24,13 @@
} // namespace dbus
-namespace device {
-
-class BluetoothAdapter;
-
-} // namespace device
-
namespace chromeos {
// The BluetoothProfileChromeOS class implements BluetoothProfile for the
// Chrome OS platform.
class CHROMEOS_EXPORT BluetoothProfileChromeOS
: public device::BluetoothProfile,
+ private device::BluetoothAdapter::Observer,
private BluetoothProfileServiceProvider::Delegate {
public:
// BluetoothProfile override.
@@ -69,8 +66,22 @@
const ConfirmationCallback& callback) OVERRIDE;
virtual void Cancel() OVERRIDE;
+ // device::BluetoothAdapter::Observer override.
+ virtual void AdapterPresentChanged(device::BluetoothAdapter* adapter,
+ bool present) OVERRIDE;
+
// Called by dbus:: on completion of the D-Bus method call to register the
- // profile object.
+ // profile object as a result of the adapter becoming present.
+ void OnInternalRegisterProfile();
+ void OnInternalRegisterProfileError(const std::string& error_name,
+ const std::string& error_message);
+
+ // Internal method run to get the adapter object during initialization.
+ void OnGetAdapter(const ProfileCallback& callback,
+ scoped_refptr<device::BluetoothAdapter> adapter);
+
+ // Called by dbus:: on completion of the D-Bus method call to register the
+ // profile object during initialization.
void OnRegisterProfile(const ProfileCallback& callback);
void OnRegisterProfileError(const ProfileCallback& callback,
const std::string& error_name,
@@ -83,27 +94,22 @@
const std::string& error_message);
// Method run once the file descriptor has been validated in order to get
- // the default adapter, and method run once the default adapter has been
- // obtained in order to get the device object to be passed to the connection
- // callback.
+ // the device object to be passed to the connection callback.
//
// The |fd| argument is moved compared to the NewConnection() call since it
// becomes the result of a PostTaskAndReplyWithResult() call.
- void GetAdapter(
+ void OnCheckValidity(
const dbus::ObjectPath& device_path,
const BluetoothProfileServiceProvider::Delegate::Options& options,
const ConfirmationCallback& callback,
scoped_ptr<dbus::FileDescriptor> fd);
- void OnGetAdapter(
- const dbus::ObjectPath& device_path,
- const BluetoothProfileServiceProvider::Delegate::Options& options,
- const ConfirmationCallback& callback,
- scoped_ptr<dbus::FileDescriptor> fd,
- scoped_refptr<device::BluetoothAdapter>);
// UUID of the profile passed during initialization.
std::string uuid_;
+ // Copy of the profile options passed during initialization.
+ BluetoothProfileManagerClient::Options options_;
+
// Object path of the local profile D-Bus object.
dbus::ObjectPath object_path_;
@@ -111,6 +117,10 @@
// from BlueZ.
scoped_ptr<BluetoothProfileServiceProvider> profile_;
+ // Reference to the adapter object, the profile is re-registered when the
+ // adapter changes.
+ scoped_refptr<device::BluetoothAdapter> adapter_;
+
// Callback used on both outgoing and incoming connections to pass the
// connected socket to profile object owner.
ConnectionCallback connection_callback_;
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 @@
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(
diff --git a/device/bluetooth/bluetooth_socket_chromeos.cc b/device/bluetooth/bluetooth_socket_chromeos.cc
index 3a881d1..85544d2 100644
--- a/device/bluetooth/bluetooth_socket_chromeos.cc
+++ b/device/bluetooth/bluetooth_socket_chromeos.cc
@@ -160,7 +160,7 @@
DCHECK(fd->is_valid());
BluetoothSocketChromeOS* bluetooth_socket =
- new BluetoothSocketChromeOS(fd->TakeValue());;
+ new BluetoothSocketChromeOS(fd->TakeValue());
return scoped_refptr<BluetoothSocketChromeOS>(bluetooth_socket);
}
diff --git a/device/bluetooth/bluetooth_strings.grd b/device/bluetooth/bluetooth_strings.grd
index 7e10b62..9d3eec4 100644
--- a/device/bluetooth/bluetooth_strings.grd
+++ b/device/bluetooth/bluetooth_strings.grd
@@ -12,34 +12,34 @@
</output>
<output filename="device_bluetooth_strings_am.pak" type="data_package" lang="am" />
<output filename="device_bluetooth_strings_ar.pak" type="data_package" lang="ar" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_ast.pak" type="data_package" lang="ast" />
</if>
<output filename="device_bluetooth_strings_bg.pak" type="data_package" lang="bg" />
<output filename="device_bluetooth_strings_bn.pak" type="data_package" lang="bn" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_bs.pak" type="data_package" lang="bs" />
</if>
<output filename="device_bluetooth_strings_ca.pak" type="data_package" lang="ca" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
</if>
<output filename="device_bluetooth_strings_cs.pak" type="data_package" lang="cs" />
<output filename="device_bluetooth_strings_da.pak" type="data_package" lang="da" />
<output filename="device_bluetooth_strings_de.pak" type="data_package" lang="de" />
<output filename="device_bluetooth_strings_el.pak" type="data_package" lang="el" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_en-AU.pak" type="data_package" lang="en-AU" />
</if>
<output filename="device_bluetooth_strings_en-GB.pak" type="data_package" lang="en-GB" />
<output filename="device_bluetooth_strings_en-US.pak" type="data_package" lang="en" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_eo.pak" type="data_package" lang="eo" />
</if>
<output filename="device_bluetooth_strings_es.pak" type="data_package" lang="es" />
<output filename="device_bluetooth_strings_es-419.pak" type="data_package" lang="es-419" />
<output filename="device_bluetooth_strings_et.pak" type="data_package" lang="et" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_eu.pak" type="data_package" lang="eu" />
</if>
<output filename="device_bluetooth_strings_fa.pak" type="data_package" lang="fa" />
@@ -47,7 +47,7 @@
<output filename="device_bluetooth_strings_fi.pak" type="data_package" lang="fi" />
<output filename="device_bluetooth_strings_fil.pak" type="data_package" lang="fil" />
<output filename="device_bluetooth_strings_fr.pak" type="data_package" lang="fr" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_gl.pak" type="data_package" lang="gl" />
</if>
<output filename="device_bluetooth_strings_gu.pak" type="data_package" lang="gu" />
@@ -55,19 +55,19 @@
<output filename="device_bluetooth_strings_hi.pak" type="data_package" lang="hi" />
<output filename="device_bluetooth_strings_hr.pak" type="data_package" lang="hr" />
<output filename="device_bluetooth_strings_hu.pak" type="data_package" lang="hu" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_hy.pak" type="data_package" lang="hy" />
<output filename="device_bluetooth_strings_ia.pak" type="data_package" lang="ia" />
</if>
<output filename="device_bluetooth_strings_id.pak" type="data_package" lang="id" />
<output filename="device_bluetooth_strings_it.pak" type="data_package" lang="it" />
<output filename="device_bluetooth_strings_ja.pak" type="data_package" lang="ja" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_ka.pak" type="data_package" lang="ka" />
</if>
<output filename="device_bluetooth_strings_kn.pak" type="data_package" lang="kn" />
<output filename="device_bluetooth_strings_ko.pak" type="data_package" lang="ko" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_ku.pak" type="data_package" lang="ku" />
<output filename="device_bluetooth_strings_kw.pak" type="data_package" lang="kw" />
</if>
@@ -94,7 +94,7 @@
<output filename="device_bluetooth_strings_te.pak" type="data_package" lang="te" />
<output filename="device_bluetooth_strings_th.pak" type="data_package" lang="th" />
<output filename="device_bluetooth_strings_tr.pak" type="data_package" lang="tr" />
- <if expr="pp_ifdef('use_third_party_translations')">
+ <if expr="use_third_party_translations">
<output filename="device_bluetooth_strings_ug.pak" type="data_package" lang="ug" />
</if>
<output filename="device_bluetooth_strings_uk.pak" type="data_package" lang="uk" />
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc
index 5848db3..9938cc3 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.cc
+++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -14,4 +14,12 @@
MockBluetoothAdapter::~MockBluetoothAdapter() {}
+void MockBluetoothAdapter::AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {}
+
+void MockBluetoothAdapter::RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {}
+
} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h
index 0266f03..32f40d1 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.h
+++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -52,11 +52,8 @@
const base::Closure& callback,
const ErrorCallback& error_callback));
MOCK_CONST_METHOD0(IsDiscovering, bool());
- MOCK_METHOD2(StartDiscovering,
- void(const base::Closure& callback,
- const ErrorCallback& error_callback));
- MOCK_METHOD2(StopDiscovering,
- void(const base::Closure& callback,
+ MOCK_METHOD2(StartDiscoverySession,
+ void(const DiscoverySessionCallback& callback,
const ErrorCallback& error_callback));
MOCK_CONST_METHOD0(GetDevices, BluetoothAdapter::ConstDeviceList());
MOCK_METHOD1(GetDevice, BluetoothDevice*(const std::string& address));
@@ -66,8 +63,22 @@
ReadLocalOutOfBandPairingData,
void(const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback));
+ MOCK_METHOD2(AddPairingDelegate,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate,
+ enum PairingDelegatePriority priority));
+ MOCK_METHOD1(RemovePairingDelegate,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate));
+ MOCK_METHOD0(DefaultPairingDelegate, BluetoothDevice::PairingDelegate*());
+
protected:
+ virtual void AddDiscoverySession(const base::Closure& callback,
+ const ErrorCallback& error_callback);
+ virtual void RemoveDiscoverySession(const base::Closure& callback,
+ const ErrorCallback& error_callback);
virtual ~MockBluetoothAdapter();
+
+ MOCK_METHOD1(RemovePairingDelegateInternal,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate));
};
} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_device.cc b/device/bluetooth/test/mock_bluetooth_device.cc
index c1fe56f..4804dc0 100644
--- a/device/bluetooth/test/mock_bluetooth_device.cc
+++ b/device/bluetooth/test/mock_bluetooth_device.cc
@@ -24,6 +24,16 @@
.WillByDefault(testing::Return(name_));
ON_CALL(*this, GetAddress())
.WillByDefault(testing::Return(address_));
+ ON_CALL(*this, GetDeviceType())
+ .WillByDefault(testing::Return(DEVICE_UNKNOWN));
+ ON_CALL(*this, GetVendorIDSource())
+ .WillByDefault(testing::Return(VENDOR_ID_UNKNOWN));
+ ON_CALL(*this, GetVendorID())
+ .WillByDefault(testing::Return(0));
+ ON_CALL(*this, GetProductID())
+ .WillByDefault(testing::Return(0));
+ ON_CALL(*this, GetDeviceID())
+ .WillByDefault(testing::Return(0));
ON_CALL(*this, IsPaired())
.WillByDefault(testing::Return(paired));
ON_CALL(*this, IsConnected())
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
index de2907d..bc028e5 100644
--- a/device/bluetooth/test/mock_bluetooth_device.h
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -29,6 +29,7 @@
MOCK_CONST_METHOD0(GetBluetoothClass, uint32());
MOCK_CONST_METHOD0(GetDeviceName, std::string());
MOCK_CONST_METHOD0(GetAddress, std::string());
+ MOCK_CONST_METHOD0(GetVendorIDSource, BluetoothDevice::VendorIDSource());
MOCK_CONST_METHOD0(GetVendorID, uint16());
MOCK_CONST_METHOD0(GetProductID, uint16());
MOCK_CONST_METHOD0(GetDeviceID, uint16());
diff --git a/device/bluetooth/test/mock_bluetooth_discovery_session.cc b/device/bluetooth/test/mock_bluetooth_discovery_session.cc
new file mode 100644
index 0000000..72449ee
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_discovery_session.cc
@@ -0,0 +1,14 @@
+// Copyright 2014 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/test/mock_bluetooth_discovery_session.h"
+
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace device {
+
+MockBluetoothDiscoverySession::MockBluetoothDiscoverySession() {}
+MockBluetoothDiscoverySession::~MockBluetoothDiscoverySession() {}
+
+} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_discovery_session.h b/device/bluetooth/test/mock_bluetooth_discovery_session.h
new file mode 100644
index 0000000..98f2125
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_discovery_session.h
@@ -0,0 +1,32 @@
+// Copyright 2014 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.
+
+#ifndef DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
+#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
+
+#include "base/callback.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace device {
+
+class BluetoothAdapter;
+
+class MockBluetoothDiscoverySession : public BluetoothDiscoverySession {
+ public:
+ MockBluetoothDiscoverySession();
+ virtual ~MockBluetoothDiscoverySession();
+
+ MOCK_CONST_METHOD0(IsActive, bool());
+ MOCK_METHOD2(Stop,
+ void(const base::Closure& callback,
+ const ErrorCallback& error_callback));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockBluetoothDiscoverySession);
+};
+
+} // namespac device
+
+#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index 268b270..0cadffb 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -23,6 +23,7 @@
],
'sources': [
'bluetooth/bluetooth_adapter_mac_unittest.mm',
+ 'bluetooth/bluetooth_adapter_unittest.cc',
'bluetooth/bluetooth_adapter_win_unittest.cc',
'bluetooth/bluetooth_device_win_unittest.cc',
'bluetooth/bluetooth_chromeos_unittest.cc',
@@ -55,7 +56,8 @@
}],
['os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', {
'conditions': [
- ['linux_use_tcmalloc == 1', {
+ # TODO(dmikurube): Kill linux_use_tcmalloc. http://crbug.com/345554
+ ['(use_allocator!="none" and use_allocator!="see_use_tcmalloc") or (use_allocator=="see_use_tcmalloc" and linux_use_tcmalloc==1)', {
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
],
diff --git a/device/hid/hid_connection.cc b/device/hid/hid_connection.cc
index 5678407..c134bf2 100644
--- a/device/hid/hid_connection.cc
+++ b/device/hid/hid_connection.cc
@@ -6,13 +6,17 @@
namespace device {
-HidConnection::HidConnection(HidDeviceInfo device_info)
+PendingHidReport::PendingHidReport() {}
+
+PendingHidReport::~PendingHidReport() {}
+
+PendingHidRead::PendingHidRead() {}
+
+PendingHidRead::~PendingHidRead() {}
+
+HidConnection::HidConnection(const HidDeviceInfo& device_info)
: device_info_(device_info) {}
HidConnection::~HidConnection() {}
-const HidDeviceInfo& HidConnection::device_info() const {
- return device_info_;
-}
-
} // namespace device
diff --git a/device/hid/hid_connection.h b/device/hid/hid_connection.h
index 27792c4..5c08fbc 100644
--- a/device/hid/hid_connection.h
+++ b/device/hid/hid_connection.h
@@ -1,18 +1,16 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
#ifndef DEVICE_HID_HID_CONNECTION_H_
#define DEVICE_HID_HID_CONNECTION_H_
+#include <stdint.h>
+
#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
#include "device/hid/hid_device_info.h"
-
-namespace net {
-class IOBuffer;
-}
+#include "net/base/io_buffer.h"
namespace device {
@@ -20,35 +18,48 @@
public:
typedef base::Callback<void(bool success, size_t size)> IOCallback;
- virtual void Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) = 0;
- virtual void Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) = 0;
- virtual void GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) = 0;
- virtual void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void SendFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) = 0;
- const HidDeviceInfo& device_info() const;
+ const HidDeviceInfo& device_info() const { return device_info_; }
protected:
friend class base::RefCountedThreadSafe<HidConnection>;
friend struct HidDeviceInfo;
- HidConnection(HidDeviceInfo device_info);
+ explicit HidConnection(const HidDeviceInfo& device_info);
virtual ~HidConnection();
+ private:
const HidDeviceInfo device_info_;
- base::ThreadChecker thread_checker_;
-
DISALLOW_COPY_AND_ASSIGN(HidConnection);
};
+struct PendingHidReport {
+ PendingHidReport();
+ ~PendingHidReport();
+
+ scoped_refptr<net::IOBufferWithSize> buffer;
+};
+
+struct PendingHidRead {
+ PendingHidRead();
+ ~PendingHidRead();
+
+ scoped_refptr<net::IOBufferWithSize> buffer;
+ HidConnection::IOCallback callback;
+};
+
} // namespace device
#endif // DEVICE_HID_HID_CONNECTION_H_
diff --git a/device/hid/hid_connection_linux.cc b/device/hid/hid_connection_linux.cc
index 0722fab..75c9e07 100644
--- a/device/hid/hid_connection_linux.cc
+++ b/device/hid/hid_connection_linux.cc
@@ -8,26 +8,47 @@
#include <fcntl.h>
#include <libudev.h>
#include <linux/hidraw.h>
+#include <sys/ioctl.h>
+
#include <string>
+#include "base/files/file_path.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.h"
#include "base/tuple.h"
#include "device/hid/hid_service.h"
#include "device/hid/hid_service_linux.h"
+// These are already defined in newer versions of linux/hidraw.h.
+#ifndef HIDIOCSFEATURE
+#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len)
+#endif
+#ifndef HIDIOCGFEATURE
+#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len)
+#endif
namespace device {
namespace {
+// Copies a buffer into a new one with a report ID byte inserted at the front.
+scoped_refptr<net::IOBufferWithSize> CopyBufferWithReportId(
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ uint8_t report_id) {
+ scoped_refptr<net::IOBufferWithSize> new_buffer(
+ new net::IOBufferWithSize(buffer->size() + 1));
+ new_buffer->data()[0] = report_id;
+ memcpy(new_buffer->data() + 1, buffer->data(), buffer->size());
+ return new_buffer;
+}
+
const char kHidrawSubsystem[] = "hidraw";
} // namespace
HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
ScopedUdevDevicePtr udev_raw_device)
- : HidConnection(device_info),
- initialized_(false) {
+ : HidConnection(device_info) {
DCHECK(thread_checker_.CalledOnValidThread());
udev_device* dev = udev_raw_device.get();
@@ -37,42 +58,32 @@
return;
}
- base::PlatformFileError error;
+ int flags = base::File::FLAG_OPEN |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE |
+ base::File::FLAG_EXCLUSIVE_READ |
+ base::File::FLAG_EXCLUSIVE_WRITE;
- int flags = base::PLATFORM_FILE_OPEN |
- base::PLATFORM_FILE_READ |
- base::PLATFORM_FILE_WRITE |
- base::PLATFORM_FILE_EXCLUSIVE_READ |
- base::PLATFORM_FILE_EXCLUSIVE_WRITE;
-
- base::PlatformFile device_file = base::CreatePlatformFile(
- base::FilePath(dev_node),
- flags,
- NULL,
- &error);
- if (error || device_file <= 0) {
- LOG(ERROR) << error;
- if (device_file)
- base::ClosePlatformFile(device_file);
+ base::File device_file(base::FilePath(dev_node), flags);
+ if (!device_file.IsValid()) {
+ LOG(ERROR) << device_file.error_details();
return;
}
- if (fcntl(device_file, F_SETFL, fcntl(device_file, F_GETFL) | O_NONBLOCK)) {
+ if (fcntl(device_file.GetPlatformFile(), F_SETFL,
+ fcntl(device_file.GetPlatformFile(), F_GETFL) | O_NONBLOCK)) {
PLOG(ERROR) << "Failed to set non-blocking flag to device file.";
return;
}
- device_file_ = device_file;
+ device_file_ = device_file.Pass();
if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
- device_file_,
+ device_file_.GetPlatformFile(),
true,
base::MessageLoopForIO::WATCH_READ_WRITE,
&device_file_watcher_,
this)) {
- LOG(ERROR) << "Cannot start watching file descriptor.";
- return;
+ LOG(ERROR) << "Failed to start watching device file.";
}
-
- initialized_ = true;
}
HidConnectionLinux::~HidConnectionLinux() {
@@ -82,22 +93,23 @@
void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(fd, device_file_);
- DCHECK(initialized_);
+ DCHECK_EQ(fd, device_file_.GetPlatformFile());
uint8 buffer[1024] = {0};
- int bytes = read(device_file_, buffer, 1024);
- if (bytes < 0) {
+ int bytes_read =
+ HANDLE_EINTR(read(device_file_.GetPlatformFile(), buffer, 1024));
+ if (bytes_read < 0) {
if (errno == EAGAIN) {
return;
}
Disconnect();
return;
}
- scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(bytes));
- memcpy(io_buffer->data(), buffer, bytes);
- input_reports_.push(std::make_pair(io_buffer, bytes));
+ PendingHidReport report;
+ report.buffer = new net::IOBufferWithSize(bytes_read);
+ memcpy(report.buffer->data(), buffer, bytes_read);
+ pending_reports_.push(report);
ProcessReadQueue();
}
@@ -105,89 +117,91 @@
void HidConnectionLinux::Disconnect() {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_)
- return;
-
- initialized_ = false;
device_file_watcher_.StopWatchingFileDescriptor();
- close(device_file_);
- while (!read_queue_.empty()) {
- PendingRequest callback = read_queue_.front();
- read_queue_.pop();
- callback.c.Run(false, 0);
+ device_file_.Close();
+ while (!pending_reads_.empty()) {
+ PendingHidRead pending_read = pending_reads_.front();
+ pending_reads_.pop();
+ pending_read.callback.Run(false, 0);
}
}
-void HidConnectionLinux::Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+void HidConnectionLinux::Read(scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
- DCHECK(read_queue_.empty());
- // There might be unread reports.
- if (!input_reports_.empty()){
- read_queue_.push(MakeTuple(buffer, size, callback));
- ProcessReadQueue();
- }
- callback.Run(false, 0);
- return;
- } else {
- read_queue_.push(MakeTuple(buffer, size, callback));
- ProcessReadQueue();
- }
+ PendingHidRead pending_read;
+ pending_read.buffer = buffer;
+ pending_read.callback = callback;
+ pending_reads_.push(pending_read);
+ ProcessReadQueue();
}
-void HidConnectionLinux::Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+void HidConnectionLinux::Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ // If report ID is non-zero, insert it into a new copy of the buffer.
+ if (report_id != 0)
+ buffer = CopyBufferWithReportId(buffer, report_id);
+ int bytes_written = HANDLE_EINTR(
+ write(device_file_.GetPlatformFile(), buffer->data(), buffer->size()));
+ if (bytes_written < 0) {
+ Disconnect();
callback.Run(false, 0);
- return;
} else {
- int bytes = write(device_file_, buffer->data(), size);
- if (bytes < 0) {
- Disconnect();
- callback.Run(false, 0);
- } else {
- callback.Run(true, bytes);
- }
+ callback.Run(true, bytes_written);
}
}
-void HidConnectionLinux::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
+void HidConnectionLinux::GetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+
+ if (buffer->size() == 0) {
callback.Run(false, 0);
return;
}
- NOTIMPLEMENTED();
+
+ // The first byte of the destination buffer is the report ID being requested.
+ buffer->data()[0] = report_id;
+ int result = ioctl(device_file_.GetPlatformFile(),
+ HIDIOCGFEATURE(buffer->size()),
+ buffer->data());
+ if (result < 0)
+ callback.Run(false, 0);
+ else
+ callback.Run(true, result);
}
-void HidConnectionLinux::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
+void HidConnectionLinux::SendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ if (report_id != 0)
+ buffer = CopyBufferWithReportId(buffer, report_id);
+ int result = ioctl(device_file_.GetPlatformFile(),
+ HIDIOCSFEATURE(buffer->size()),
+ buffer->data());
+ if (result < 0)
callback.Run(false, 0);
- return;
- }
- NOTIMPLEMENTED();
+ else
+ callback.Run(true, result);
}
void HidConnectionLinux::ProcessReadQueue() {
- while(read_queue_.size() && input_reports_.size()) {
- PendingRequest request = read_queue_.front();
- read_queue_.pop();
- PendingReport report = input_reports_.front();
- if (report.second > request.b) {
- request.c.Run(false, report.second);
+ while (pending_reads_.size() && pending_reports_.size()) {
+ PendingHidRead read = pending_reads_.front();
+ pending_reads_.pop();
+ PendingHidReport report = pending_reports_.front();
+ if (report.buffer->size() > read.buffer->size()) {
+ read.callback.Run(false, report.buffer->size());
} else {
- memcpy(request.a->data(), report.first->data(), report.second);
- input_reports_.pop();
- request.c.Run(true, report.second);
+ memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
+ pending_reports_.pop();
+ read.callback.Run(true, report.buffer->size());
}
}
}
@@ -195,31 +209,31 @@
bool HidConnectionLinux::FindHidrawDevNode(udev_device* parent,
std::string* result) {
udev* udev = udev_device_get_udev(parent);
- if (!udev)
+ if (!udev) {
return false;
-
+ }
ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev));
- if (!enumerate)
+ if (!enumerate) {
return false;
-
+ }
if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) {
return false;
}
if (udev_enumerate_scan_devices(enumerate.get())) {
return false;
}
-
- const char* parent_path = udev_device_get_devpath(parent);
+ std::string parent_path(udev_device_get_devpath(parent));
+ if (parent_path.length() == 0 || *parent_path.rbegin() != '/')
+ parent_path += '/';
udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
for (udev_list_entry* i = devices; i != NULL;
- i = udev_list_entry_get_next(i)) {
+ i = udev_list_entry_get_next(i)) {
ScopedUdevDevicePtr hid_dev(
udev_device_new_from_syspath(udev, udev_list_entry_get_name(i)));
const char* raw_path = udev_device_get_devnode(hid_dev.get());
- if (strncmp(parent_path,
- udev_device_get_devpath(hid_dev.get()),
- strlen(parent_path)) == 0 &&
- raw_path) {
+ std::string device_path = udev_device_get_devpath(hid_dev.get());
+ if (raw_path &&
+ !device_path.compare(0, parent_path.length(), parent_path)) {
*result = raw_path;
return true;
}
diff --git a/device/hid/hid_connection_linux.h b/device/hid/hid_connection_linux.h
index 37d6cb0..67d6299 100644
--- a/device/hid/hid_connection_linux.h
+++ b/device/hid/hid_connection_linux.h
@@ -5,13 +5,11 @@
#ifndef DEVICE_HID_HID_CONNECTION_LINUX_H_
#define DEVICE_HID_HID_CONNECTION_LINUX_H_
+#include "base/files/file.h"
#include "base/memory/ref_counted.h"
-#include "base/platform_file.h"
-#include "base/tuple.h"
#include "device/hid/hid_connection.h"
#include "device/hid/hid_device_info.h"
#include "device/hid/hid_service_linux.h"
-#include "net/base/io_buffer.h"
namespace device {
@@ -21,21 +19,18 @@
HidConnectionLinux(HidDeviceInfo device_info,
ScopedUdevDevicePtr udev_raw_device);
- virtual void Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void SendFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- bool initialized() const { return initialized_; }
-
// Implements base::MessagePumpLibevent::Watcher
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
@@ -49,17 +44,13 @@
void ProcessReadQueue();
void Disconnect();
- base::PlatformFile device_file_;
+ base::File device_file_;
base::MessagePumpLibevent::FileDescriptorWatcher device_file_watcher_;
- typedef std::pair<scoped_refptr<net::IOBuffer>, size_t> PendingReport;
- typedef Tuple3<scoped_refptr<net::IOBuffer>, size_t, IOCallback>
- PendingRequest;
+ std::queue<PendingHidReport> pending_reports_;
+ std::queue<PendingHidRead> pending_reads_;
- std::queue<PendingReport> input_reports_;
- std::queue<PendingRequest> read_queue_;
-
- bool initialized_;
+ base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(HidConnectionLinux);
};
diff --git a/device/hid/hid_connection_mac.cc b/device/hid/hid_connection_mac.cc
index bce7113..63b7998 100644
--- a/device/hid/hid_connection_mac.cc
+++ b/device/hid/hid_connection_mac.cc
@@ -5,184 +5,170 @@
#include "device/hid/hid_connection_mac.h"
#include "base/bind.h"
-#include "base/callback.h"
#include "base/mac/foundation_util.h"
+#include "base/message_loop/message_loop.h"
#include "base/threading/thread_restrictions.h"
-#include "base/tuple.h"
-#include "device/hid/hid_service.h"
-#include "device/hid/hid_service_mac.h"
-#include "net/base/io_buffer.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/hid/IOHIDManager.h>
+#include "device/hid/hid_connection_mac.h"
namespace device {
-HidConnectionMac::HidConnectionMac(HidServiceMac* service,
- HidDeviceInfo device_info,
- IOHIDDeviceRef device)
+HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info)
: HidConnection(device_info),
- service_(service),
- device_(device),
- disconnected_(false) {
+ device_(device_info.device_id, base::scoped_policy::RETAIN) {
DCHECK(thread_checker_.CalledOnValidThread());
message_loop_ = base::MessageLoopProxy::current();
- CFRetain(device);
- inbound_buffer_.reset((uint8_t*) malloc(device_info.input_report_size + 1));
- IOHIDDeviceRegisterInputReportCallback(
- device_.get(),
- inbound_buffer_.get(),
- device_info.input_report_size + 1,
- &HidConnectionMac::InputReportCallback,
- this);
+ DCHECK(device_.get());
+ inbound_buffer_.reset((uint8_t*)malloc(device_info.input_report_size));
+ IOHIDDeviceRegisterInputReportCallback(device_.get(),
+ inbound_buffer_.get(),
+ device_info.input_report_size,
+ &HidConnectionMac::InputReportCallback,
+ this);
IOHIDDeviceOpen(device_, kIOHIDOptionsTypeNone);
}
+
HidConnectionMac::~HidConnectionMac() {
DCHECK(thread_checker_.CalledOnValidThread());
- while (read_queue_.size()) {
- read_queue_.front().c.Run(false, 0);
- read_queue_.pop();
+ while (!pending_reads_.empty()) {
+ pending_reads_.front().callback.Run(false, 0);
+ pending_reads_.pop();
}
IOHIDDeviceClose(device_, kIOHIDOptionsTypeNone);
}
-void HidConnectionMac::InputReportCallback(void * context,
+void HidConnectionMac::Read(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!device_) {
+ callback.Run(false, 0);
+ return;
+ }
+ PendingHidRead read;
+ read.buffer = buffer;
+ read.callback = callback;
+ pending_reads_.push(read);
+ ProcessReadQueue();
+}
+
+void HidConnectionMac::Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ WriteReport(kIOHIDReportTypeOutput, report_id, buffer, callback);
+}
+
+void HidConnectionMac::GetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info().feature_report_size == 0) {
+ callback.Run(false, 0);
+ return;
+ }
+
+ if (buffer->size() < device_info().feature_report_size) {
+ callback.Run(false, 0);
+ return;
+ }
+
+ uint8_t* feature_report_buffer = reinterpret_cast<uint8_t*>(buffer->data());
+ CFIndex feature_report_size = device_info().feature_report_size;
+ IOReturn result = IOHIDDeviceGetReport(device_,
+ kIOHIDReportTypeFeature,
+ report_id,
+ feature_report_buffer,
+ &feature_report_size);
+ if (result == kIOReturnSuccess)
+ callback.Run(true, feature_report_size);
+ else
+ callback.Run(false, 0);
+}
+
+void HidConnectionMac::SendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ WriteReport(kIOHIDReportTypeFeature, report_id, buffer, callback);
+}
+
+void HidConnectionMac::InputReportCallback(void* context,
IOReturn result,
- void * sender,
+ void* sender,
IOHIDReportType type,
- uint32_t reportID,
- uint8_t * report,
- CFIndex reportLength) {
- HidConnectionMac* connection = reinterpret_cast<HidConnectionMac*>(context);
- size_t length = reportLength + (reportID != 0);
- scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(length));
- if (reportID) {
- buffer->data()[0] = reportID;
- memcpy(buffer->data() + 1, report, reportLength);
+ uint32_t report_id,
+ uint8_t* report_bytes,
+ CFIndex report_length) {
+ HidConnectionMac* connection = static_cast<HidConnectionMac*>(context);
+ // If a report ID was received, inject it into a copy of the received
+ // report. This is consistent with how input reports are received on
+ // other platforms.
+ scoped_refptr<net::IOBufferWithSize> buffer;
+ if (report_id != 0) {
+ buffer = new net::IOBufferWithSize(report_length + 1);
+ buffer->data()[0] = static_cast<uint8_t>(report_id);
+ memcpy(buffer->data() + 1, report_bytes, report_length);
} else {
- memcpy(buffer->data(), report, reportLength);
+ buffer = new net::IOBufferWithSize(report_length);
+ memcpy(buffer->data(), report_bytes, report_length);
}
connection->message_loop_->PostTask(
FROM_HERE,
- base::Bind(&HidConnectionMac::ProcessInputReport,
- connection,
- type,
- buffer,
- length));
+ base::Bind(
+ &HidConnectionMac::ProcessInputReport, connection, type, buffer));
}
void HidConnectionMac::ProcessReadQueue() {
DCHECK(thread_checker_.CalledOnValidThread());
-
- while(read_queue_.size() && input_reports_.size()) {
- PendingRead read = read_queue_.front();
- read_queue_.pop();
- PendingReport report = input_reports_.front();
-
- if (read.b < report.second) {
- read.c.Run(false, report.second);
+ while (pending_reads_.size() && pending_reports_.size()) {
+ PendingHidRead read = pending_reads_.front();
+ pending_reads_.pop();
+ PendingHidReport report = pending_reports_.front();
+ if (read.buffer->size() < report.buffer->size()) {
+ read.callback.Run(false, report.buffer->size());
} else {
- memcpy(read.a->data(), report.first->data(), report.second);
- input_reports_.pop();
- read.c.Run(true, report.second);
+ memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
+ pending_reports_.pop();
+ read.callback.Run(true, report.buffer->size());
}
}
}
-void HidConnectionMac::ProcessInputReport(IOHIDReportType type,
- scoped_refptr<net::IOBuffer> report,
- CFIndex reportLength) {
+void HidConnectionMac::ProcessInputReport(
+ IOHIDReportType type,
+ scoped_refptr<net::IOBufferWithSize> buffer) {
DCHECK(thread_checker_.CalledOnValidThread());
-
- input_reports_.push(std::make_pair(report, reportLength));
+ PendingHidReport report;
+ report.buffer = buffer;
+ pending_reports_.push(report);
ProcessReadQueue();
}
void HidConnectionMac::WriteReport(IOHIDReportType type,
- scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (disconnected_ || !device_) {
+ if (!device_) {
callback.Run(false, 0);
return;
}
- const unsigned char* data_to_send =
- reinterpret_cast<const unsigned char*>(buffer->data());
- size_t length_to_send = size;
- if (data_to_send[0] == 0x0) {
- /* Not using numbered Reports.
- Don't send the report number. */
- ++data_to_send;
- --length_to_send;
- }
- IOReturn res = IOHIDDeviceSetReport(device_.get(),
- type,
- buffer->data()[0], /* Report ID*/
- data_to_send,
- length_to_send);
+ IOReturn res =
+ IOHIDDeviceSetReport(device_.get(),
+ type,
+ report_id,
+ reinterpret_cast<uint8_t*>(buffer->data()),
+ buffer->size());
if (res != kIOReturnSuccess) {
callback.Run(false, 0);
} else {
- callback.Run(true, size);
+ callback.Run(true, buffer->size());
}
}
-void HidConnectionMac::Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (disconnected_ || !device_) {
- callback.Run(false, 0);
- return;
- }
- read_queue_.push(MakeTuple(buffer, size, callback));
- ProcessReadQueue();
-}
-
-void HidConnectionMac::Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- WriteReport(kIOHIDReportTypeOutput, buffer, size, callback);
-}
-
-void HidConnectionMac::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- WriteReport(kIOHIDReportTypeFeature, buffer, size, callback);
-}
-
-void HidConnectionMac::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (disconnected_ || !device_ || device_info_.feature_report_size == 0) {
- callback.Run(false, 0);
- return;
- }
-
- if (device_info_.feature_report_size != 0 &&
- device_info_.feature_report_size != size) {
- callback.Run(false, 0);
- return;
- }
-
- CFIndex len = device_info_.feature_report_size;
- IOReturn res = IOHIDDeviceGetReport(device_,
- kIOHIDReportTypeFeature,
- 0,
- (uint8_t*) buffer->data(),
- &len);
- if (res == kIOReturnSuccess)
- callback.Run(true, len);
- else
- callback.Run(false, 0);
-}
-
} // namespace device
diff --git a/device/hid/hid_connection_mac.h b/device/hid/hid_connection_mac.h
index 730eeae..c307fb6 100644
--- a/device/hid/hid_connection_mac.h
+++ b/device/hid/hid_connection_mac.h
@@ -5,12 +5,21 @@
#ifndef DEVICE_HID_HID_CONNECTION_MAC_H_
#define DEVICE_HID_HID_CONNECTION_MAC_H_
-#include "base/callback.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/hid/IOHIDManager.h>
+
+#include <queue>
+
+#include "base/mac/foundation_util.h"
#include "base/memory/ref_counted.h"
-#include "base/tuple.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
#include "device/hid/hid_connection.h"
#include "device/hid/hid_device_info.h"
-#include "device/hid/hid_service_mac.h"
+
+namespace base {
+class MessageLoopProxy;
+}
namespace net {
class IOBuffer;
@@ -20,53 +29,48 @@
class HidConnectionMac : public HidConnection {
public:
- HidConnectionMac(HidServiceMac* service,
- HidDeviceInfo device_info,
- IOHIDDeviceRef device);
+ explicit HidConnectionMac(HidDeviceInfo device_info);
- virtual void Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void SendFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
private:
virtual ~HidConnectionMac();
- static void InputReportCallback(void * context,
+ static void InputReportCallback(void* context,
IOReturn result,
- void * sender,
+ void* sender,
IOHIDReportType type,
- uint32_t reportID,
- uint8_t * report,
- CFIndex reportLength);
+ uint32_t report_id,
+ uint8_t* report_bytes,
+ CFIndex report_length);
void ProcessReadQueue();
void ProcessInputReport(IOHIDReportType type,
- scoped_refptr<net::IOBuffer> report,
- CFIndex reportLength);
+ scoped_refptr<net::IOBufferWithSize> buffer);
void WriteReport(IOHIDReportType type,
- scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback);
- HidServiceMac* service_;
scoped_refptr<base::MessageLoopProxy> message_loop_;
- base::ScopedCFTypeRef<IOHIDDeviceRef> device_;
- scoped_ptr_malloc<uint8_t> inbound_buffer_;
- bool disconnected_;
- typedef std::pair<scoped_refptr<net::IOBuffer>, size_t> PendingReport;
- std::queue<PendingReport> input_reports_;
- typedef Tuple3<scoped_refptr<net::IOBuffer>, size_t, IOCallback> PendingRead;
- std::queue<PendingRead> read_queue_;
+ base::ScopedCFTypeRef<IOHIDDeviceRef> device_;
+ scoped_ptr<uint8_t, base::FreeDeleter> inbound_buffer_;
+
+ std::queue<PendingHidReport> pending_reports_;
+ std::queue<PendingHidRead> pending_reads_;
+
+ base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(HidConnectionMac);
};
diff --git a/device/hid/hid_connection_unittest.cc b/device/hid/hid_connection_unittest.cc
index 14a2ef9..2725481 100644
--- a/device/hid/hid_connection_unittest.cc
+++ b/device/hid/hid_connection_unittest.cc
@@ -17,7 +17,7 @@
namespace {
-using net::IOBuffer;
+using net::IOBufferWithSize;
const int kUSBLUFADemoVID = 0x03eb;
const int kUSBLUFADemoPID = 0x204f;
@@ -27,7 +27,7 @@
void Read(scoped_refptr<HidConnection> conn);
void OnRead(scoped_refptr<HidConnection> conn,
- scoped_refptr<net::IOBuffer> buffer,
+ scoped_refptr<IOBufferWithSize> buffer,
bool success,
size_t bytes) {
EXPECT_TRUE(success);
@@ -53,8 +53,8 @@
}
void Read(scoped_refptr<HidConnection> conn) {
- scoped_refptr<IOBuffer> buffer(new IOBuffer(8));
- conn->Read(buffer, 8, base::Bind(OnRead, conn, buffer));
+ scoped_refptr<IOBufferWithSize> buffer(new IOBufferWithSize(8));
+ conn->Read(buffer, base::Bind(OnRead, conn, buffer));
}
void OnWriteNormal(bool success,
@@ -64,10 +64,10 @@
}
void WriteNormal(scoped_refptr<HidConnection> conn) {
- scoped_refptr<IOBuffer> buffer(new IOBuffer(8));
+ scoped_refptr<IOBufferWithSize> buffer(new IOBufferWithSize(8));
*(int64_t*)buffer->data() = kReport;
- conn->Write(buffer, 8, base::Bind(OnWriteNormal));
+ conn->Write(0, buffer, base::Bind(OnWriteNormal));
}
} // namespace
@@ -81,6 +81,7 @@
std::vector<HidDeviceInfo> devices;
service_->GetDevices(&devices);
+ device_id_ = kInvalidHidDeviceId;
for (std::vector<HidDeviceInfo>::iterator it = devices.begin();
it != devices.end();
++it) {
@@ -97,21 +98,19 @@
message_loop_.reset(NULL);
}
- std::string device_id_;
+ HidDeviceId device_id_;
scoped_ptr<base::MessageLoopForIO> message_loop_;
scoped_ptr<HidService> service_;
};
TEST_F(HidConnectionTest, Create) {
scoped_refptr<HidConnection> connection = service_->Connect(device_id_);
- ASSERT_TRUE(connection || device_id_.empty());
+ ASSERT_TRUE(connection || device_id_ == kInvalidHidDeviceId);
}
TEST_F(HidConnectionTest, Read) {
scoped_refptr<HidConnection> connection = service_->Connect(device_id_);
-
- if (!device_id_.empty()) {
- ASSERT_TRUE(connection);
+ if (connection) {
message_loop_->PostTask(FROM_HERE, base::Bind(Read, connection));
message_loop_->Run();
}
@@ -120,8 +119,7 @@
TEST_F(HidConnectionTest, Write) {
scoped_refptr<HidConnection> connection = service_->Connect(device_id_);
- if (!device_id_.empty()) {
- ASSERT_TRUE(connection);
+ if (connection) {
message_loop_->PostTask(FROM_HERE, base::Bind(WriteNormal, connection));
message_loop_->Run();
}
diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc
index bbb158f..44bd847 100644
--- a/device/hid/hid_connection_win.cc
+++ b/device/hid/hid_connection_win.cc
@@ -9,11 +9,10 @@
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
#include "device/hid/hid_service.h"
#include "device/hid/hid_service_win.h"
-#include "net/base/io_buffer.h"
-
-#if defined(OS_WIN)
#define INITGUID
@@ -21,41 +20,69 @@
#include <hidclass.h>
extern "C" {
-
#include <hidsdi.h>
-
}
#include <setupapi.h>
#include <winioctl.h>
-#include "base/win/scoped_handle.h"
-
-#endif // defined(OS_WIN)
namespace device {
-HidConnectionWin::PendingTransfer::PendingTransfer(
- scoped_refptr<HidConnectionWin> conn,
- scoped_refptr<net::IOBuffer> target,
- scoped_refptr<net::IOBuffer> receiving,
- bool is_input,
- IOCallback callback)
- : conn_(conn),
- is_input_(is_input),
- target_(target),
- receiving_(receiving),
+struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>,
+ public base::win::ObjectWatcher::Delegate,
+ public base::MessageLoop::DestructionObserver {
+ PendingHidTransfer(scoped_refptr<HidConnectionWin> connection,
+ scoped_refptr<net::IOBufferWithSize> target_buffer,
+ scoped_refptr<net::IOBufferWithSize> receive_buffer,
+ HidConnection::IOCallback callback);
+
+ void TakeResultFromWindowsAPI(BOOL result);
+
+ OVERLAPPED* GetOverlapped() { return &overlapped_; }
+
+ // Implements base::win::ObjectWatcher::Delegate.
+ virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
+
+ // Implements base::MessageLoop::DestructionObserver
+ virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+
+ scoped_refptr<HidConnectionWin> connection_;
+ scoped_refptr<net::IOBufferWithSize> target_buffer_;
+ scoped_refptr<net::IOBufferWithSize> receive_buffer_;
+ HidConnection::IOCallback callback_;
+ OVERLAPPED overlapped_;
+ base::win::ScopedHandle event_;
+ base::win::ObjectWatcher watcher_;
+
+ private:
+ friend class base::RefCounted<PendingHidTransfer>;
+
+ virtual ~PendingHidTransfer();
+
+ DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer);
+};
+
+PendingHidTransfer::PendingHidTransfer(
+ scoped_refptr<HidConnectionWin> connection,
+ scoped_refptr<net::IOBufferWithSize> target_buffer,
+ scoped_refptr<net::IOBufferWithSize> receive_buffer,
+ HidConnection::IOCallback callback)
+ : connection_(connection),
+ target_buffer_(target_buffer),
+ receive_buffer_(receive_buffer),
callback_(callback),
event_(CreateEvent(NULL, FALSE, FALSE, NULL)) {
memset(&overlapped_, 0, sizeof(OVERLAPPED));
overlapped_.hEvent = event_.Get();
}
-HidConnectionWin::PendingTransfer::~PendingTransfer() {
+
+PendingHidTransfer::~PendingHidTransfer() {
base::MessageLoop::current()->RemoveDestructionObserver(this);
}
-void HidConnectionWin::PendingTransfer::TakeResultFromWindowsAPI(BOOL result) {
+void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
if (result || GetLastError() != ERROR_IO_PENDING) {
- conn_->OnTransferFinished(this);
+ connection_->OnTransferFinished(this);
} else {
base::MessageLoop::current()->AddDestructionObserver(this);
AddRef();
@@ -63,46 +90,18 @@
}
}
-void HidConnectionWin::PendingTransfer::OnObjectSignaled(HANDLE event_handle) {
- conn_->OnTransferFinished(this);
+void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
+ connection_->OnTransferFinished(this);
Release();
}
-void HidConnectionWin::PendingTransfer::WillDestroyCurrentMessageLoop() {
+void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
watcher_.StopWatching();
- conn_->OnTransferCanceled(this);
+ connection_->OnTransferCanceled(this);
}
-void HidConnectionWin::OnTransferFinished(
- scoped_refptr<PendingTransfer> transfer) {
- DWORD bytes_transfered;
- transfers_.erase(transfer);
- if (GetOverlappedResult(file_,
- transfer->GetOverlapped(),
- &bytes_transfered,
- FALSE)) {
- if (transfer->is_input_ && !device_info_.has_report_id) {
- // Move one byte forward.
- --bytes_transfered;
- memcpy(transfer->target_->data(),
- transfer->receiving_->data() + 1,
- bytes_transfered);
- }
- transfer->callback_.Run(true, bytes_transfered);
- } else {
- transfer->callback_.Run(false, 0);
- }
-}
-
-void HidConnectionWin::OnTransferCanceled(
- scoped_refptr<PendingTransfer> transfer) {
- transfers_.erase(transfer);
- transfer->callback_.Run(false, 0);
-}
-
-HidConnectionWin::HidConnectionWin(HidDeviceInfo device_info)
- : HidConnection(device_info),
- available_(false) {
+HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
+ : HidConnection(device_info) {
DCHECK(thread_checker_.CalledOnValidThread());
file_.Set(CreateFileA(device_info.device_id.c_str(),
GENERIC_WRITE | GENERIC_READ,
@@ -111,7 +110,10 @@
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL));
- available_ = file_.IsValid();
+}
+
+bool HidConnectionWin::available() const {
+ return file_.IsValid();
}
HidConnectionWin::~HidConnectionWin() {
@@ -119,161 +121,168 @@
CancelIo(file_.Get());
}
-void HidConnectionWin::Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+void HidConnectionWin::Read(scoped_refptr<net::IOBufferWithSize> buffer,
const HidConnection::IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- size_t report_size = device_info_.input_report_size;
- if (report_size == 0) {
- // The device does not supoort input reports.
+ if (device_info().input_report_size == 0) {
+ // The device does not support input reports.
callback.Run(false, 0);
return;
}
- if (size + !device_info_.has_report_id < report_size) {
- // Buffer too short.
+ if (buffer->size() < device_info().input_report_size) {
callback.Run(false, 0);
return;
}
- scoped_refptr<net::IOBuffer> expanded_buffer;
- if (!device_info_.has_report_id) {
- ++size;
- expanded_buffer = new net::IOBuffer(static_cast<int>(size));
- }
+ // If the device doesn't support report IDs, the caller should not be
+ // expecting one; however, Windows will always expect enough space for one,
+ // so we need to use a buffer with one extra byte of space in this case.
+ scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer);
+ if (!device_info().has_report_id)
+ receive_buffer = new net::IOBufferWithSize(buffer->size() + 1);
- scoped_refptr<PendingTransfer> transfer(
- new PendingTransfer(this, buffer, expanded_buffer, true, callback));
+ scoped_refptr<PendingHidTransfer> transfer(
+ new PendingHidTransfer(this, buffer, receive_buffer, callback));
transfers_.insert(transfer);
- transfer->TakeResultFromWindowsAPI(ReadFile(file_.Get(),
- device_info_.has_report_id ?
- buffer->data() :
- expanded_buffer->data(),
- static_cast<DWORD>(size),
- NULL,
- transfer->GetOverlapped()));
+ transfer->TakeResultFromWindowsAPI(
+ ReadFile(file_.Get(),
+ receive_buffer->data(),
+ static_cast<DWORD>(receive_buffer->size()),
+ NULL,
+ transfer->GetOverlapped()));
}
-void HidConnectionWin::Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+void HidConnectionWin::Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const HidConnection::IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- size_t report_size = device_info_.output_report_size;
- if (report_size == 0) {
- // The device does not supoort output reports.
+ if (device_info().output_report_size == 0) {
+ // The device does not support output reports.
callback.Run(false, 0);
return;
}
- if (size + !device_info_.has_report_id > report_size) {
- // Size of report too long.
- callback.Run(false, 0);
- return;
- }
+ // The Windows API always wants either a report ID (if supported) or
+ // zero at the front of every output report.
+ scoped_refptr<net::IOBufferWithSize> output_buffer(buffer);
+ output_buffer = new net::IOBufferWithSize(buffer->size() + 1);
+ output_buffer->data()[0] = report_id;
+ memcpy(output_buffer->data() + 1, buffer->data(), buffer->size());
- scoped_refptr<net::IOBuffer> expanded_buffer;
- if (!device_info_.has_report_id) {
- expanded_buffer = new net::IOBuffer(
- static_cast<int>(device_info_.output_report_size));
- memset(expanded_buffer->data(), 0, device_info_.output_report_size);
- memcpy(expanded_buffer->data() + 1,
- buffer->data(),
- size);
- size++;
- }
-
- scoped_refptr<PendingTransfer> transfer(
- new PendingTransfer(this, buffer, expanded_buffer, false, callback));
+ scoped_refptr<PendingHidTransfer> transfer(
+ new PendingHidTransfer(this, buffer, NULL, callback));
transfers_.insert(transfer);
transfer->TakeResultFromWindowsAPI(
WriteFile(file_.Get(),
- device_info_.has_report_id ?
- buffer->data() : expanded_buffer->data(),
- static_cast<DWORD>(device_info_.output_report_size),
+ output_buffer->data(),
+ static_cast<DWORD>(output_buffer->size()),
NULL,
transfer->GetOverlapped()));
}
-void HidConnectionWin::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
+void HidConnectionWin::GetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- size_t report_size = device_info_.feature_report_size;
- if (report_size == 0) {
- // The device does not supoort input reports.
+ if (device_info().feature_report_size == 0) {
+ // The device does not support feature reports.
callback.Run(false, 0);
return;
}
- if (size + !device_info_.has_report_id < report_size) {
- // Buffer too short.
+ if (buffer->size() < device_info().feature_report_size) {
callback.Run(false, 0);
return;
}
- scoped_refptr<net::IOBuffer> expanded_buffer;
- if (!device_info_.has_report_id) {
- ++size;
- expanded_buffer = new net::IOBuffer(static_cast<int>(size));
- }
+ scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer);
+ if (!device_info().has_report_id)
+ receive_buffer = new net::IOBufferWithSize(buffer->size() + 1);
- scoped_refptr<PendingTransfer> transfer(
- new PendingTransfer(this, buffer, expanded_buffer, true, callback));
+ // The first byte of the destination buffer is the report ID being requested.
+ receive_buffer->data()[0] = report_id;
+ scoped_refptr<PendingHidTransfer> transfer(
+ new PendingHidTransfer(this, buffer, receive_buffer, callback));
transfers_.insert(transfer);
transfer->TakeResultFromWindowsAPI(
DeviceIoControl(file_.Get(),
IOCTL_HID_GET_FEATURE,
NULL,
0,
- device_info_.has_report_id ?
- buffer->data() :
- expanded_buffer->data(),
- static_cast<DWORD>(size),
+ receive_buffer->data(),
+ static_cast<DWORD>(receive_buffer->size()),
NULL,
transfer->GetOverlapped()));
}
-void HidConnectionWin::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const IOCallback& callback) {
+void HidConnectionWin::SendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- size_t report_size = device_info_.feature_report_size;
- if (report_size == 0) {
- // The device does not supoort output reports.
+ if (device_info().feature_report_size == 0) {
+ // The device does not support feature reports.
callback.Run(false, 0);
return;
}
- if (size + !device_info_.has_report_id > report_size) {
- // Size of report too long.
+ if (buffer->size() < device_info().feature_report_size) {
callback.Run(false, 0);
return;
}
- scoped_refptr<net::IOBuffer> expanded_buffer;
- if (!device_info_.has_report_id) {
- expanded_buffer = new net::IOBuffer(
- static_cast<int>(device_info_.feature_report_size));
- memset(expanded_buffer->data(), 0, device_info_.feature_report_size);
- memcpy(expanded_buffer->data() + 1,
- buffer->data(),
- size);
- size++;
- }
+ // The Windows API always wants either a report ID (if supported) or
+ // zero at the front of every output report.
+ scoped_refptr<net::IOBufferWithSize> output_buffer(buffer);
+ output_buffer = new net::IOBufferWithSize(buffer->size() + 1);
+ output_buffer->data()[0] = report_id;
+ memcpy(output_buffer->data() + 1, buffer->data(), buffer->size());
- scoped_refptr<PendingTransfer> transfer(
- new PendingTransfer(this, buffer, expanded_buffer, false, callback));
+ scoped_refptr<PendingHidTransfer> transfer(
+ new PendingHidTransfer(this, buffer, NULL, callback));
transfer->TakeResultFromWindowsAPI(
DeviceIoControl(file_.Get(),
IOCTL_HID_SET_FEATURE,
- device_info_.has_report_id ?
- buffer->data() :
- expanded_buffer->data(),
- static_cast<DWORD>(device_info_.output_report_size),
+ output_buffer->data(),
+ static_cast<DWORD>(output_buffer->size()),
NULL,
0,
NULL,
transfer->GetOverlapped()));
}
+void HidConnectionWin::OnTransferFinished(
+ scoped_refptr<PendingHidTransfer> transfer) {
+ DWORD bytes_transferred;
+ transfers_.erase(transfer);
+ if (GetOverlappedResult(
+ file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
+ if (bytes_transferred == 0)
+ transfer->callback_.Run(true, 0);
+ // If this is an input transfer and the receive buffer is not the same as
+ // the target buffer, we need to copy the receive buffer into the target
+ // buffer, discarding the first byte. This is because the target buffer's
+ // owner is not expecting a report ID but Windows will always provide one.
+ if (transfer->receive_buffer_ &&
+ transfer->receive_buffer_ != transfer->target_buffer_) {
+ // Move one byte forward.
+ --bytes_transferred;
+ memcpy(transfer->target_buffer_->data(),
+ transfer->receive_buffer_->data() + 1,
+ bytes_transferred);
+ }
+ transfer->callback_.Run(true, bytes_transferred);
+ } else {
+ transfer->callback_.Run(false, 0);
+ }
+}
+
+void HidConnectionWin::OnTransferCanceled(
+ scoped_refptr<PendingHidTransfer> transfer) {
+ transfers_.erase(transfer);
+ transfer->callback_.Run(false, 0);
+}
+
} // namespace device
diff --git a/device/hid/hid_connection_win.h b/device/hid/hid_connection_win.h
index 6cbb9e9..263897a 100644
--- a/device/hid/hid_connection_win.h
+++ b/device/hid/hid_connection_win.h
@@ -5,90 +5,51 @@
#ifndef DEVICE_HID_HID_CONNECTION_WIN_H_
#define DEVICE_HID_HID_CONNECTION_WIN_H_
-#include <set>
#include <windows.h>
+#include <set>
+
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_checker.h"
-#include "base/win/object_watcher.h"
#include "device/hid/hid_connection.h"
#include "device/hid/hid_device_info.h"
-#include "net/base/io_buffer.h"
namespace device {
+struct PendingHidTransfer;
+
class HidConnectionWin : public HidConnection {
public:
- struct PendingTransfer : public base::RefCounted<PendingTransfer>,
- public base::win::ObjectWatcher::Delegate,
- public base::MessageLoop::DestructionObserver {
- public:
- PendingTransfer(scoped_refptr<HidConnectionWin> conn,
- scoped_refptr<net::IOBuffer> target,
- scoped_refptr<net::IOBuffer> receiving,
- bool is_input,
- IOCallback callback);
+ explicit HidConnectionWin(const HidDeviceInfo& device_info);
- void TakeResultFromWindowsAPI(BOOL result);
+ bool available() const;
- OVERLAPPED* GetOverlapped() { return &overlapped_; }
-
- // Implements base::win::ObjectWatcher::Delegate.
- virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
-
- // Implements base::MessageLoop::DestructionObserver
- virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
-
-
- private:
- friend class base::RefCounted<PendingTransfer>;
- friend class HidConnectionWin;
-
- virtual ~PendingTransfer();
-
- scoped_refptr<HidConnectionWin> conn_;
- bool is_input_;
- scoped_refptr<net::IOBuffer> target_;
- scoped_refptr<net::IOBuffer> receiving_;
- IOCallback callback_;
- OVERLAPPED overlapped_;
- base::win::ScopedHandle event_;
- base::win::ObjectWatcher watcher_;
-
- DISALLOW_COPY_AND_ASSIGN(PendingTransfer);
- };
-
- HidConnectionWin(HidDeviceInfo device_info);
-
- virtual void Read(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void Write(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
+ virtual void SendFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) OVERRIDE;
- void OnTransferFinished(scoped_refptr<PendingTransfer> transfer);
- void OnTransferCanceled(scoped_refptr<PendingTransfer> transfer);
-
- bool available() const { return available_; }
+ void OnTransferFinished(scoped_refptr<PendingHidTransfer> transfer);
+ void OnTransferCanceled(scoped_refptr<PendingHidTransfer> transfer);
private:
~HidConnectionWin();
base::win::ScopedHandle file_;
- std::set<scoped_refptr<PendingTransfer> > transfers_;
+ std::set<scoped_refptr<PendingHidTransfer> > transfers_;
+
+ base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(HidConnectionWin);
-
- bool available_;
};
} // namespace device
diff --git a/device/hid/hid_device_info.cc b/device/hid/hid_device_info.cc
index 34ea686..fdc747d 100644
--- a/device/hid/hid_device_info.cc
+++ b/device/hid/hid_device_info.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
@@ -6,8 +6,13 @@
namespace device {
+#if !defined(OS_MACOSX)
+const char kInvalidHidDeviceId[] = "";
+#endif
+
HidDeviceInfo::HidDeviceInfo()
- : bus_type(kHIDBusTypeUSB),
+ : device_id(kInvalidHidDeviceId),
+ bus_type(kHIDBusTypeUSB),
vendor_id(0),
product_id(0),
input_report_size(0),
diff --git a/device/hid/hid_device_info.h b/device/hid/hid_device_info.h
index b665944..7531042 100644
--- a/device/hid/hid_device_info.h
+++ b/device/hid/hid_device_info.h
@@ -1,13 +1,19 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
#ifndef DEVICE_HID_HID_DEVICE_INFO_H_
#define DEVICE_HID_HID_DEVICE_INFO_H_
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <IOKit/hid/IOHIDDevice.h>
+#endif
namespace device {
@@ -16,22 +22,30 @@
kHIDBusTypeBluetooth = 1,
};
+#if defined(OS_MACOSX)
+typedef IOHIDDeviceRef HidDeviceId;
+const HidDeviceId kInvalidHidDeviceId = NULL;
+#else
+typedef std::string HidDeviceId;
+extern const char kInvalidHidDeviceId[];
+#endif
+
struct HidDeviceInfo {
HidDeviceInfo();
~HidDeviceInfo();
- std::string device_id;
+ HidDeviceId device_id;
HidBusType bus_type;
- uint16 vendor_id;
- uint16 product_id;
+ uint16_t vendor_id;
+ uint16_t product_id;
- size_t input_report_size;
- size_t output_report_size;
- size_t feature_report_size;
+ int input_report_size;
+ int output_report_size;
+ int feature_report_size;
- uint16 usage_page;
- uint16 usage;
+ uint16_t usage_page;
+ uint16_t usage;
bool has_report_id;
std::string product_name;
diff --git a/device/hid/hid_service.cc b/device/hid/hid_service.cc
index 973e901..2d0569b 100644
--- a/device/hid/hid_service.cc
+++ b/device/hid/hid_service.cc
@@ -1,18 +1,14 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/hid/hid_service.h"
-#include <vector>
-
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
-#include "device/hid/hid_device_info.h"
#if defined(OS_LINUX)
#include "device/hid/hid_service_linux.h"
@@ -32,22 +28,6 @@
} // namespace
-HidService::HidService() : initialized_(false) {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(thread_checker_.CalledOnValidThread());
- base::MessageLoop::current()->AddDestructionObserver(this);
-}
-
-HidService::~HidService() {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-}
-
-void HidService::WillDestroyCurrentMessageLoop() {
- DCHECK(thread_checker_.CalledOnValidThread());
- g_hid_service_ptr.Get().reset(NULL);
-}
-
void HidService::GetDevices(std::vector<HidDeviceInfo>* devices) {
DCHECK(thread_checker_.CalledOnValidThread());
STLClearObject(devices);
@@ -59,7 +39,8 @@
}
// Fills in the device info struct of the given device_id.
-bool HidService::GetInfo(std::string device_id, HidDeviceInfo* info) const {
+bool HidService::GetDeviceInfo(const HidDeviceId& device_id,
+ HidDeviceInfo* info) const {
DeviceMap::const_iterator it = devices_.find(device_id);
if (it == devices_.end())
return false;
@@ -67,18 +48,20 @@
return true;
}
-void HidService::AddDevice(HidDeviceInfo info) {
- if (!ContainsKey(devices_, info.device_id)) {
- DCHECK(thread_checker_.CalledOnValidThread());
- devices_[info.device_id] = info;
- }
+void HidService::WillDestroyCurrentMessageLoop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ g_hid_service_ptr.Get().reset(NULL);
}
-void HidService::RemoveDevice(std::string device_id) {
- if (ContainsKey(devices_, device_id)) {
- DCHECK(thread_checker_.CalledOnValidThread());
- devices_.erase(device_id);
- }
+HidService::HidService() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::MessageLoop::current()->AddDestructionObserver(this);
+}
+
+HidService::~HidService() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::MessageLoop::current()->RemoveDestructionObserver(this);
}
HidService* HidService::CreateInstance() {
@@ -93,13 +76,23 @@
#endif
}
-HidService* HidService::GetInstance() {
- if (!g_hid_service_ptr.Get().get()){
- scoped_ptr<HidService> service(CreateInstance());
-
- if (service && service->initialized())
- g_hid_service_ptr.Get().reset(service.release());
+void HidService::AddDevice(const HidDeviceInfo& info) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(devices_, info.device_id)) {
+ devices_[info.device_id] = info;
}
+}
+
+void HidService::RemoveDevice(const HidDeviceId& device_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DeviceMap::iterator it = devices_.find(device_id);
+ if (it != devices_.end())
+ devices_.erase(it);
+}
+
+HidService* HidService::GetInstance() {
+ if (!g_hid_service_ptr.Get().get())
+ g_hid_service_ptr.Get().reset(CreateInstance());
return g_hid_service_ptr.Get().get();
}
diff --git a/device/hid/hid_service.h b/device/hid/hid_service.h
index 2589220..ee0ebb7 100644
--- a/device/hid/hid_service.h
+++ b/device/hid/hid_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
@@ -9,25 +9,15 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
-#include "build/build_config.h"
#include "device/hid/hid_device_info.h"
namespace device {
-namespace {
-
-class HidServiceContainer;
-
-} // namespace
-
class HidConnection;
-class HidService;
class HidService : public base::MessageLoop::DestructionObserver {
public:
@@ -37,40 +27,35 @@
// Enumerates and returns a list of device identifiers.
virtual void GetDevices(std::vector<HidDeviceInfo>* devices);
- // Fills in the device info struct of the given device_id.
- // Returns true if succeed.
- // Returns false if the device_id is invalid, with info untouched.
- bool GetInfo(std::string device_id, HidDeviceInfo* info) const;
+ // Fills in a DeviceInfo struct with info for the given device_id.
+ // Returns |true| if successful or |false| if |device_id| is invalid.
+ bool GetDeviceInfo(const HidDeviceId& device_id, HidDeviceInfo* info) const;
virtual scoped_refptr<HidConnection> Connect(
- std::string platform_device_id) = 0;
+ const HidDeviceId& device_id) = 0;
// Implements base::MessageLoop::DestructionObserver
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
- // Gets whether the HidService have been successfully initialized.
- bool initialized() const { return initialized_; }
-
protected:
- friend class HidServiceContainer;
friend struct base::DefaultDeleter<HidService>;
friend class HidConnectionTest;
+ typedef std::map<HidDeviceId, HidDeviceInfo> DeviceMap;
+
HidService();
virtual ~HidService();
static HidService* CreateInstance();
- virtual void AddDevice(HidDeviceInfo info);
- virtual void RemoveDevice(std::string platform_device_id);
-
- typedef std::map<std::string, HidDeviceInfo> DeviceMap;
- DeviceMap devices_;
-
- bool initialized_;
+ void AddDevice(const HidDeviceInfo& info);
+ void RemoveDevice(const HidDeviceId& device_id);
base::ThreadChecker thread_checker_;
+ private:
+ DeviceMap devices_;
+
DISALLOW_COPY_AND_ASSIGN(HidService);
};
diff --git a/device/hid/hid_service_linux.cc b/device/hid/hid_service_linux.cc
index f02a550..04a3c16 100644
--- a/device/hid/hid_service_linux.cc
+++ b/device/hid/hid_service_linux.cc
@@ -1,22 +1,19 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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 <libudev.h>
+#include <stdint.h>
+
#include <string>
#include <vector>
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/callback.h"
#include "base/logging.h"
-#include "base/memory/scoped_vector.h"
#include "base/platform_file.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
-#include "base/threading/thread_restrictions.h"
-#include "device/hid/hid_connection.h"
#include "device/hid/hid_connection_linux.h"
#include "device/hid/hid_device_info.h"
#include "device/hid/hid_service_linux.h"
@@ -79,6 +76,37 @@
Enumerate();
}
+scoped_refptr<HidConnection> HidServiceLinux::Connect(
+ const HidDeviceId& device_id) {
+ HidDeviceInfo device_info;
+ if (!GetDeviceInfo(device_id, &device_info))
+ return NULL;
+
+ ScopedUdevDevicePtr hid_device(
+ udev_device_new_from_syspath(udev_.get(), device_info.device_id.c_str()));
+ if (hid_device) {
+ return new HidConnectionLinux(device_info, hid_device.Pass());
+ }
+ return NULL;
+}
+
+void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd) {
+ DCHECK_EQ(monitor_fd_, fd);
+
+ ScopedUdevDevicePtr dev(udev_monitor_receive_device(monitor_.get()));
+ if (!dev)
+ return;
+
+ std::string action(udev_device_get_action(dev.get()));
+ if (action == kUdevActionAdd) {
+ PlatformAddDevice(dev.get());
+ } else if (action == kUdevActionRemove) {
+ PlatformRemoveDevice(dev.get());
+ }
+}
+
+void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd) {}
+
HidServiceLinux::~HidServiceLinux() {
monitor_watcher_.StopWatchingFileDescriptor();
close(monitor_fd_);
@@ -110,26 +138,23 @@
ScopedUdevDevicePtr hid_dev(
udev_device_new_from_syspath(udev_.get(), udev_list_entry_get_name(i)));
if (hid_dev) {
- PlatformDeviceAdd(hid_dev.get());
+ PlatformAddDevice(hid_dev.get());
}
}
-
- initialized_ = true;
}
-void HidServiceLinux::PlatformDeviceAdd(udev_device* device) {
+void HidServiceLinux::PlatformAddDevice(udev_device* device) {
if (!device)
return;
- const char* device_id = udev_device_get_syspath(device);
- if (!device_id)
+ const char* device_path = udev_device_get_syspath(device);
+ if (!device_path)
return;
-
HidDeviceInfo device_info;
- device_info.device_id = device_id;
+ device_info.device_id = device_path;
- uint32 int_property = 0;
+ uint32_t int_property = 0;
const char* str_property = NULL;
const char* hid_id = udev_device_get_property_value(device, kHIDID);
@@ -161,51 +186,12 @@
AddDevice(device_info);
}
-void HidServiceLinux::PlatformDeviceRemove(udev_device* raw_dev) {
- // The returned the device is not referenced.
- udev_device* hid_dev =
- udev_device_get_parent_with_subsystem_devtype(raw_dev, "hid", NULL);
-
- if (!hid_dev)
+void HidServiceLinux::PlatformRemoveDevice(udev_device* raw_dev) {
+ const char* device_path = NULL;
+ device_path = udev_device_get_syspath(raw_dev);
+ if (device_path == NULL)
return;
-
- const char* device_id = NULL;
- device_id = udev_device_get_syspath(hid_dev);
- if (device_id == NULL)
- return;
-
- RemoveDevice(device_id);
+ RemoveDevice(device_path);
}
-scoped_refptr<HidConnection> HidServiceLinux::Connect(std::string device_id) {
- if (!ContainsKey(devices_, device_id))
- return NULL;
- ScopedUdevDevicePtr hid_device(
- udev_device_new_from_syspath(udev_.get(), device_id.c_str()));
- if (hid_device) {
- scoped_refptr<HidConnectionLinux> connection =
- new HidConnectionLinux(devices_[device_id], hid_device.Pass());
- if (connection->initialized())
- return connection;
- }
- return NULL;
-}
-
-void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd) {
- DCHECK_EQ(monitor_fd_, fd);
-
- ScopedUdevDevicePtr dev(udev_monitor_receive_device(monitor_.get()));
- if (!dev)
- return;
-
- std::string action(udev_device_get_action(dev.get()));
- if (action == kUdevActionAdd) {
- PlatformDeviceAdd(dev.get());
- } else if (action == kUdevActionRemove) {
- PlatformDeviceRemove(dev.get());
- }
-}
-
-void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd) {}
-
} // namespace dev
diff --git a/device/hid/hid_service_linux.h b/device/hid/hid_service_linux.h
index ba58fad..ae730ce 100644
--- a/device/hid/hid_service_linux.h
+++ b/device/hid/hid_service_linux.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
@@ -7,6 +7,9 @@
#include <libudev.h>
+#include <map>
+#include <string>
+
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump_libevent.h"
@@ -50,7 +53,8 @@
public:
HidServiceLinux();
- virtual scoped_refptr<HidConnection> Connect(std::string device_id) OVERRIDE;
+ virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id)
+ OVERRIDE;
// Implements base::MessagePumpLibevent::Watcher
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
@@ -60,8 +64,8 @@
virtual ~HidServiceLinux();
void Enumerate();
- void PlatformDeviceAdd(udev_device* device);
- void PlatformDeviceRemove(udev_device* raw_dev);
+ void PlatformAddDevice(udev_device* device);
+ void PlatformRemoveDevice(udev_device* raw_dev);
scoped_ptr<udev, UdevDeleter> udev_;
scoped_ptr<udev_monitor, UdevMonitorDeleter> monitor_;
diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc
index 12da7cc..3df7e59 100644
--- a/device/hid/hid_service_mac.cc
+++ b/device/hid/hid_service_mac.cc
@@ -1,250 +1,178 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/hid/hid_service_mac.h"
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/memory/scoped_vector.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "device/hid/hid_connection.h"
-#include "device/hid/hid_connection_mac.h"
-#include "device/hid/hid_utils_mac.h"
-#include "net/base/io_buffer.h"
-
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDManager.h>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "device/hid/hid_connection_mac.h"
+#include "device/hid/hid_utils_mac.h"
+
namespace device {
class HidServiceMac;
-HidServiceMac::HidServiceMac() : enumeration_runloop_init_(true, false) {
- base::ThreadRestrictions::AssertIOAllowed();
+namespace {
- hid_manager_ref_.reset(IOHIDManagerCreate(kCFAllocatorDefault,
- kIOHIDOptionsTypeNone));
- if (!hid_manager_ref_ ||
- CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) {
+typedef std::vector<IOHIDDeviceRef> HidDeviceList;
+
+HidServiceMac* HidServiceFromContext(void* context) {
+ return static_cast<HidServiceMac*>(context);
+}
+
+// Callback for CFSetApplyFunction as used by EnumerateHidDevices.
+void HidEnumerationBackInserter(const void* value, void* context) {
+ HidDeviceList* devices = static_cast<HidDeviceList*>(context);
+ const IOHIDDeviceRef device =
+ static_cast<IOHIDDeviceRef>(const_cast<void*>(value));
+ devices->push_back(device);
+}
+
+void EnumerateHidDevices(IOHIDManagerRef hid_manager,
+ HidDeviceList* device_list) {
+ DCHECK(device_list->size() == 0);
+ // Note that our ownership of each copied device is implied.
+ base::ScopedCFTypeRef<CFSetRef> devices(IOHIDManagerCopyDevices(hid_manager));
+ if (devices)
+ CFSetApplyFunction(devices, HidEnumerationBackInserter, device_list);
+}
+
+} // namespace
+
+HidServiceMac::HidServiceMac() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ message_loop_ = base::MessageLoopProxy::current();
+ DCHECK(message_loop_);
+ hid_manager_.reset(IOHIDManagerCreate(NULL, 0));
+ if (!hid_manager_) {
LOG(ERROR) << "Failed to initialize HidManager";
return;
}
- CFRetain(hid_manager_ref_);
+ DCHECK(CFGetTypeID(hid_manager_) == IOHIDManagerGetTypeID());
+ IOHIDManagerOpen(hid_manager_, kIOHIDOptionsTypeNone);
+ IOHIDManagerSetDeviceMatching(hid_manager_, NULL);
- // Register for plug/unplug notifications.
- IOHIDManagerSetDeviceMatching(hid_manager_ref_.get(), NULL);
- IOHIDManagerRegisterDeviceMatchingCallback(
- hid_manager_ref_.get(),
- &HidServiceMac::AddDeviceCallback,
- this);
- IOHIDManagerRegisterDeviceRemovalCallback(
- hid_manager_ref_.get(),
- &HidServiceMac::RemoveDeviceCallback,
- this);
-
- // Blocking operation to enumerate all the pre-existing devices.
+ // Enumerate all the currently known devices.
Enumerate();
- // Save the owner message loop.
- message_loop_ = base::MessageLoopProxy::current();
-
- // Start a thread to monitor HID device changes.
- // The reason to create a new thread is that by default the only thread in the
- // browser process having a CFRunLoop is the UI thread. We do not want to
- // run potentially blocking routines on it.
- enumeration_runloop_thread_.reset(
- new base::Thread("HidService Device Enumeration Thread"));
-
- base::Thread::Options options;
- options.message_loop_type = base::MessageLoop::TYPE_UI;
- enumeration_runloop_thread_->StartWithOptions(options);
- enumeration_runloop_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&HidServiceMac::ScheduleRunLoop, base::Unretained(this)));
-
- enumeration_runloop_init_.Wait();
- initialized_ = true;
+ // Register for plug/unplug notifications.
+ StartWatchingDevices();
}
HidServiceMac::~HidServiceMac() {
- enumeration_runloop_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&HidServiceMac::UnscheduleRunLoop, base::Unretained(this)));
-
- enumeration_runloop_thread_->Stop();
+ StopWatchingDevices();
}
-void HidServiceMac::ScheduleRunLoop() {
- enumeration_runloop_ = CFRunLoopGetCurrent();
-
+void HidServiceMac::StartWatchingDevices() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ IOHIDManagerRegisterDeviceMatchingCallback(
+ hid_manager_, &AddDeviceCallback, this);
+ IOHIDManagerRegisterDeviceRemovalCallback(
+ hid_manager_, &RemoveDeviceCallback, this);
IOHIDManagerScheduleWithRunLoop(
- hid_manager_ref_,
- enumeration_runloop_,
- kCFRunLoopDefaultMode);
-
- IOHIDManagerOpen(hid_manager_ref_, kIOHIDOptionsTypeNone);
-
- enumeration_runloop_init_.Signal();
+ hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
}
-void HidServiceMac::UnscheduleRunLoop() {
+void HidServiceMac::StopWatchingDevices() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!hid_manager_)
+ return;
IOHIDManagerUnscheduleFromRunLoop(
- hid_manager_ref_,
- enumeration_runloop_,
- kCFRunLoopDefaultMode);
-
- IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone);
-
-}
-
-HidServiceMac* HidServiceMac::InstanceFromContext(void* context) {
- return reinterpret_cast<HidServiceMac*>(context);
+ hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+ IOHIDManagerClose(hid_manager_, kIOHIDOptionsTypeNone);
}
void HidServiceMac::AddDeviceCallback(void* context,
IOReturn result,
void* sender,
- IOHIDDeviceRef ref) {
- HidServiceMac* service = InstanceFromContext(context);
-
- // Takes ownership of ref. Will be released inside PlatformDeviceAdd.
- CFRetain(ref);
- service->message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&HidServiceMac::PlatformAddDevice,
- base::Unretained(service),
- base::Unretained(ref)));
+ IOHIDDeviceRef hid_device) {
+ DCHECK(CFRunLoopGetMain() == CFRunLoopGetCurrent());
+ // Claim ownership of the device.
+ CFRetain(hid_device);
+ HidServiceMac* service = HidServiceFromContext(context);
+ service->message_loop_->PostTask(FROM_HERE,
+ base::Bind(&HidServiceMac::PlatformAddDevice,
+ base::Unretained(service),
+ base::Unretained(hid_device)));
}
void HidServiceMac::RemoveDeviceCallback(void* context,
IOReturn result,
void* sender,
- IOHIDDeviceRef ref) {
- HidServiceMac* service = InstanceFromContext(context);
-
- // Takes ownership of ref. Will be released inside PlatformDeviceRemove.
- CFRetain(ref);
+ IOHIDDeviceRef hid_device) {
+ DCHECK(CFRunLoopGetMain() == CFRunLoopGetCurrent());
+ HidServiceMac* service = HidServiceFromContext(context);
service->message_loop_->PostTask(
FROM_HERE,
base::Bind(&HidServiceMac::PlatformRemoveDevice,
base::Unretained(service),
- base::Unretained(ref)));
-}
-
-IOHIDDeviceRef HidServiceMac::FindDevice(std::string id) {
- base::ScopedCFTypeRef<CFSetRef> devices(
- IOHIDManagerCopyDevices(hid_manager_ref_));
- CFIndex count = CFSetGetCount(devices);
- scoped_ptr<IOHIDDeviceRef[]> device_refs(new IOHIDDeviceRef[count]);
- CFSetGetValues(devices, (const void **)(device_refs.get()));
-
- for (CFIndex i = 0; i < count; i++) {
- int32_t int_property = 0;
- if (GetHidIntProperty(device_refs[i], CFSTR(kIOHIDLocationIDKey),
- &int_property)) {
- if (id == base::HexEncode(&int_property, sizeof(int_property))) {
- return device_refs[i];
- }
- }
- }
-
- return NULL;
+ base::Unretained(hid_device)));
}
void HidServiceMac::Enumerate() {
- base::ScopedCFTypeRef<CFSetRef> devices(
- IOHIDManagerCopyDevices(hid_manager_ref_));
- CFIndex count = CFSetGetCount(devices);
- scoped_ptr<IOHIDDeviceRef[]> device_refs(new IOHIDDeviceRef[count]);
- CFSetGetValues(devices, (const void **)(device_refs.get()));
-
- for (CFIndex i = 0; i < count; i++) {
- // Takes ownership. Will be released inside PlatformDeviceAdd.
- CFRetain(device_refs[i]);
- PlatformAddDevice(device_refs[i]);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ HidDeviceList devices;
+ EnumerateHidDevices(hid_manager_, &devices);
+ for (HidDeviceList::const_iterator iter = devices.begin();
+ iter != devices.end();
+ ++iter) {
+ IOHIDDeviceRef hid_device = *iter;
+ PlatformAddDevice(hid_device);
}
}
-void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef raw_ref) {
- HidDeviceInfo device;
- int32_t int_property = 0;
- std::string str_property;
+void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef hid_device) {
+ // Note that our ownership of hid_device is implied if calling this method.
+ // It is balanced in PlatformRemoveDevice.
+ DCHECK(thread_checker_.CalledOnValidThread());
- // Auto-release.
- base::ScopedCFTypeRef<IOHIDDeviceRef> ref(raw_ref);
-
- // Unique identifier for HID device.
- if (GetHidIntProperty(ref, CFSTR(kIOHIDLocationIDKey), &int_property)) {
- device.device_id = base::HexEncode(&int_property, sizeof(int_property));
- } else {
- // Not an available device.
- return;
- }
-
- if (GetHidIntProperty(ref, CFSTR(kIOHIDVendorIDKey), &int_property)) {
- device.vendor_id = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDProductIDKey), &int_property)) {
- device.product_id = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDPrimaryUsageKey), &int_property)) {
- device.usage = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDPrimaryUsagePageKey), &int_property)) {
- device.usage_page = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxInputReportSizeKey),
- &int_property)) {
- device.input_report_size = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxOutputReportSizeKey),
- &int_property)) {
- device.output_report_size = int_property;
- }
- if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxFeatureReportSizeKey),
- &int_property)) {
- device.feature_report_size = int_property;
- }
- if (GetHidStringProperty(ref, CFSTR(kIOHIDProductKey), &str_property)) {
- device.product_name = str_property;
- }
- if (GetHidStringProperty(ref, CFSTR(kIOHIDSerialNumberKey), &str_property)) {
- device.serial_number = str_property;
- }
- HidService::AddDevice(device);
+ HidDeviceInfo device_info;
+ device_info.device_id = hid_device;
+ device_info.vendor_id =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey));
+ device_info.product_id =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey));
+ device_info.usage =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDPrimaryUsageKey));
+ device_info.usage_page =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDPrimaryUsagePageKey));
+ device_info.input_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxInputReportSizeKey));
+ device_info.output_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxOutputReportSizeKey));
+ device_info.feature_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxFeatureReportSizeKey));
+ device_info.product_name =
+ GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey));
+ device_info.serial_number =
+ GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey));
+ AddDevice(device_info);
}
-void HidServiceMac::PlatformRemoveDevice(IOHIDDeviceRef raw_ref) {
- std::string device_id;
- int32_t int_property = 0;
- // Auto-release.
- base::ScopedCFTypeRef<IOHIDDeviceRef> ref(raw_ref);
- if (!GetHidIntProperty(ref, CFSTR(kIOHIDLocationIDKey), &int_property)) {
- return;
- }
- device_id = base::HexEncode(&int_property, sizeof(int_property));
- HidService::RemoveDevice(device_id);
+void HidServiceMac::PlatformRemoveDevice(IOHIDDeviceRef hid_device) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ RemoveDevice(hid_device);
+ CFRelease(hid_device);
}
-scoped_refptr<HidConnection>
-HidServiceMac::Connect(std::string device_id) {
- if (!ContainsKey(devices_, device_id))
+scoped_refptr<HidConnection> HidServiceMac::Connect(
+ const HidDeviceId& device_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ HidDeviceInfo device_info;
+ if (!GetDeviceInfo(device_id, &device_info))
return NULL;
-
- IOHIDDeviceRef ref = FindDevice(device_id);
- if (ref == NULL)
- return NULL;
- return scoped_refptr<HidConnection>(
- new HidConnectionMac(this, devices_[device_id], ref));
+ return scoped_refptr<HidConnection>(new HidConnectionMac(device_info));
}
} // namespace device
diff --git a/device/hid/hid_service_mac.h b/device/hid/hid_service_mac.h
index 9351d1e..7c43234 100644
--- a/device/hid/hid_service_mac.h
+++ b/device/hid/hid_service_mac.h
@@ -1,77 +1,60 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
#ifndef DEVICE_HID_HID_SERVICE_MAC_H_
#define DEVICE_HID_HID_SERVICE_MAC_H_
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/mac/foundation_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_checker.h"
-#include "build/build_config.h"
-#include "device/hid/hid_device_info.h"
-#include "device/hid/hid_service.h"
-
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDManager.h>
+#include <string>
+
+#include "base/mac/foundation_util.h"
+#include "base/memory/ref_counted.h"
+#include "device/hid/hid_service.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
namespace device {
class HidConnection;
-class HidService;
class HidServiceMac : public HidService {
public:
HidServiceMac();
- virtual scoped_refptr<HidConnection> Connect(std::string device_id) OVERRIDE;
+ virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id)
+ OVERRIDE;
private:
virtual ~HidServiceMac();
- void ScheduleRunLoop();
- void UnscheduleRunLoop();
+ void StartWatchingDevices();
+ void StopWatchingDevices();
// Device changing callbacks.
static void AddDeviceCallback(void* context,
IOReturn result,
void* sender,
- IOHIDDeviceRef ref);
+ IOHIDDeviceRef hid_device);
static void RemoveDeviceCallback(void* context,
IOReturn result,
void* sender,
- IOHIDDeviceRef ref);
- static HidServiceMac* InstanceFromContext(void* context);
-
- IOHIDDeviceRef FindDevice(std::string id);
+ IOHIDDeviceRef hid_device);
void Enumerate();
- void PlatformAddDevice(IOHIDDeviceRef ref);
- void PlatformRemoveDevice(IOHIDDeviceRef ref);
-
- // The message loop this object belongs to.
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ void PlatformAddDevice(IOHIDDeviceRef hid_device);
+ void PlatformRemoveDevice(IOHIDDeviceRef hid_device);
// Platform HID Manager
- base::ScopedCFTypeRef<IOHIDManagerRef> hid_manager_ref_;
+ base::ScopedCFTypeRef<IOHIDManagerRef> hid_manager_;
- // Enumeration thread.
- scoped_ptr<base::Thread> enumeration_runloop_thread_;
- CFRunLoopRef enumeration_runloop_;
- base::WaitableEvent enumeration_runloop_init_;
-
- bool available_;
+ // The message loop for the thread on which this service was created.
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
DISALLOW_COPY_AND_ASSIGN(HidServiceMac);
};
diff --git a/device/hid/hid_service_unittest.cc b/device/hid/hid_service_unittest.cc
index 1fa1c0a..0b5043b 100644
--- a/device/hid/hid_service_unittest.cc
+++ b/device/hid/hid_service_unittest.cc
@@ -1,16 +1,11 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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 <string>
#include <vector>
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "device/hid/hid_connection.h"
#include "device/hid/hid_service.h"
-#include "net/base/io_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
@@ -22,11 +17,10 @@
std::vector<HidDeviceInfo> devices;
service->GetDevices(&devices);
-
for (std::vector<HidDeviceInfo>::iterator it = devices.begin();
it != devices.end();
++it) {
- ASSERT_TRUE(!it->device_id.empty());
+ ASSERT_TRUE(it->device_id != kInvalidHidDeviceId);
}
}
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc
index cf9db15..27f4499 100644
--- a/device/hid/hid_service_win.cc
+++ b/device/hid/hid_service_win.cc
@@ -1,20 +1,15 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/hid/hid_service_win.h"
#include <cstdlib>
-#include <string>
-#include "base/callback_helpers.h"
-#include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
-#include "device/hid/hid_connection.h"
#include "device/hid/hid_connection_win.h"
-#include "device/hid/hid_service.h"
+#include "device/hid/hid_device_info.h"
#include "net/base/io_buffer.h"
#if defined(OS_WIN)
@@ -49,11 +44,12 @@
} // namespace
HidServiceWin::HidServiceWin() {
- initialized_ = Enumerate();
+ Enumerate();
}
+
HidServiceWin::~HidServiceWin() {}
-bool HidServiceWin::Enumerate() {
+void HidServiceWin::Enumerate() {
BOOL res;
HDEVINFO device_info_set;
SP_DEVINFO_DATA devinfo_data;
@@ -70,15 +66,15 @@
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (device_info_set == INVALID_HANDLE_VALUE)
- return false;
+ return;
for (int device_index = 0;
- SetupDiEnumDeviceInterfaces(device_info_set,
- NULL,
- &GUID_DEVINTERFACE_HID,
- device_index,
- &device_interface_data);
- device_index++) {
+ SetupDiEnumDeviceInterfaces(device_info_set,
+ NULL,
+ &GUID_DEVINTERFACE_HID,
+ device_index,
+ &device_interface_data);
+ ++device_index) {
DWORD required_size = 0;
// Determime the required size of detail struct.
@@ -89,9 +85,9 @@
&required_size,
NULL);
- scoped_ptr_malloc<SP_DEVICE_INTERFACE_DETAIL_DATA_A>
+ scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
device_interface_detail_data(
- reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
+ static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
malloc(required_size)));
device_interface_detail_data->cbSize =
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
@@ -131,7 +127,7 @@
sizeof(driver_name) - 1,
NULL);
if (res) {
- // Found the drive.
+ // Found the driver.
break;
}
}
@@ -142,11 +138,9 @@
PlatformAddDevice(device_interface_detail_data->DevicePath);
}
-
- return true;
}
-void HidServiceWin::PlatformAddDevice(std::string device_path) {
+void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
HidDeviceInfo device_info;
device_info.device_id = device_path;
@@ -195,6 +189,17 @@
if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
preparsed_data) == HIDP_STATUS_SUCCESS) {
device_info.has_report_id = (value_caps[0].ReportID != 0);
+ // If report IDs are supported, adjust all the expected report sizes
+ // down by one byte. This is because Windows will always provide sizes
+ // which assume the presence of a report ID.
+ if (device_info.has_report_id) {
+ if (device_info.input_report_size > 0)
+ device_info.input_report_size -= 1;
+ if (device_info.output_report_size > 0)
+ device_info.output_report_size -= 1;
+ if (device_info.feature_report_size > 0)
+ device_info.feature_report_size -= 1;
+ }
}
}
HidD_FreePreparsedData(preparsed_data);
@@ -214,11 +219,11 @@
device_info.product_name = base::SysWideToUTF8(str_property);
}
- HidService::AddDevice(device_info);
+ AddDevice(device_info);
}
-void HidServiceWin::PlatformRemoveDevice(std::string device_path) {
- HidService::RemoveDevice(device_path);
+void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
+ RemoveDevice(device_path);
}
void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
@@ -226,10 +231,12 @@
HidService::GetDevices(devices);
}
-scoped_refptr<HidConnection> HidServiceWin::Connect(std::string device_id) {
- if (!ContainsKey(devices_, device_id)) return NULL;
- scoped_refptr<HidConnectionWin> connection(
- new HidConnectionWin(devices_[device_id]));
+scoped_refptr<HidConnection> HidServiceWin::Connect(
+ const HidDeviceId& device_id) {
+ HidDeviceInfo device_info;
+ if (!GetDeviceInfo(device_id, &device_info))
+ return NULL;
+ scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
if (!connection->available()) {
LOG_GETLASTERROR(ERROR) << "Failed to open device.";
return NULL;
diff --git a/device/hid/hid_service_win.h b/device/hid/hid_service_win.h
index 428420e..8f18765 100644
--- a/device/hid/hid_service_win.h
+++ b/device/hid/hid_service_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
@@ -6,18 +6,13 @@
#define DEVICE_HID_HID_SERVICE_WIN_H_
#include <map>
-#include <string>
-#include <vector>
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
#include "device/hid/hid_device_info.h"
#include "device/hid/hid_service.h"
namespace device {
class HidConnection;
-class HidService;
class HidServiceWin : public HidService {
public:
@@ -25,14 +20,15 @@
virtual void GetDevices(std::vector<HidDeviceInfo>* devices) OVERRIDE;
- virtual scoped_refptr<HidConnection> Connect(std::string device_id) OVERRIDE;
+ virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id)
+ OVERRIDE;
private:
virtual ~HidServiceWin();
- bool Enumerate();
- void PlatformAddDevice(std::string device_path);
- void PlatformRemoveDevice(std::string device_path);
+ void Enumerate();
+ void PlatformAddDevice(const std::string& device_path);
+ void PlatformRemoveDevice(const std::string& device_path);
DISALLOW_COPY_AND_ASSIGN(HidServiceWin);
};
diff --git a/device/hid/hid_utils_mac.cc b/device/hid/hid_utils_mac.cc
index 588041a..46605d8 100644
--- a/device/hid/hid_utils_mac.cc
+++ b/device/hid/hid_utils_mac.cc
@@ -1,32 +1,38 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/hid/hid_utils_mac.h"
-#include "base/basictypes.h"
-#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
-#if defined(OS_MACOSX)
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/hid/IOHIDManager.h>
-#endif
-
namespace device {
-bool GetHidIntProperty(IOHIDDeviceRef device,
- CFStringRef key,
- int32_t* result) {
+int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) {
+ int32_t value;
+ if (TryGetHidIntProperty(device, key, &value))
+ return value;
+ return 0;
+}
+
+std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key) {
+ std::string value;
+ TryGetHidStringProperty(device, key, &value);
+ return value;
+}
+
+bool TryGetHidIntProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ int32_t* result) {
CFNumberRef ref = base::mac::CFCast<CFNumberRef>(
IOHIDDeviceGetProperty(device, key));
return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result);
}
-bool GetHidStringProperty(IOHIDDeviceRef device,
- CFStringRef key,
- std::string* result) {
+bool TryGetHidStringProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ std::string* result) {
CFStringRef ref = base::mac::CFCast<CFStringRef>(
IOHIDDeviceGetProperty(device, key));
if (!ref) {
diff --git a/device/hid/hid_utils_mac.h b/device/hid/hid_utils_mac.h
index f1349ae..e9b2524 100644
--- a/device/hid/hid_utils_mac.h
+++ b/device/hid/hid_utils_mac.h
@@ -1,22 +1,29 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
#ifndef DEVICE_HID_HID_UTILS_MAC_H_
#define DEVICE_HID_HID_UTILS_MAC_H_
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-
+#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDManager.h>
+#include <stdint.h>
+
+#include <string>
namespace device {
-bool GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key, int32_t* result);
+int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key);
-bool GetHidStringProperty(IOHIDDeviceRef device,
- CFStringRef key,
- std::string* result);
+std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key);
+
+bool TryGetHidIntProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ int32_t* result);
+
+bool TryGetHidStringProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ std::string* result);
} // namespace device
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
index 41ac37e..4edfc60 100644
--- a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
@@ -19,6 +19,7 @@
namespace {
const char kInvalidResponseMsg[] = "Invalid Response: ";
+uint32 kMaxChunkSize = 1024*1024; // D-Bus has message size limits.
// The MediaTransferProtocolDaemonClient implementation.
class MediaTransferProtocolDaemonClientImpl
@@ -140,6 +141,7 @@
uint32 bytes_to_read,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
+ DCHECK_LE(bytes_to_read, kMaxChunkSize);
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadFileChunkByPath);
dbus::MessageWriter writer(&method_call);
@@ -162,6 +164,7 @@
uint32 bytes_to_read,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
+ DCHECK_LE(bytes_to_read, kMaxChunkSize);
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadFileChunkById);
dbus::MessageWriter writer(&method_call);
@@ -349,7 +352,7 @@
return;
}
- uint8* data_bytes = NULL;
+ const uint8* data_bytes = NULL;
size_t data_length = 0;
dbus::MessageReader reader(response);
if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) {
diff --git a/device/nfc/OWNERS b/device/nfc/OWNERS
new file mode 100644
index 0000000..7bf8537
--- /dev/null
+++ b/device/nfc/OWNERS
@@ -0,0 +1,2 @@
+keybuk@chromium.org
+armansito@chromium.org
diff --git a/device/serial/serial_device_enumerator_win.cc b/device/serial/serial_device_enumerator_win.cc
index e3bde29..a45a609 100644
--- a/device/serial/serial_device_enumerator_win.cc
+++ b/device/serial/serial_device_enumerator_win.cc
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
namespace device {
@@ -34,7 +35,7 @@
for (; iter_key.Valid(); ++iter_key) {
base::string16 value(iter_key.Value());
linked_ptr<SerialDeviceInfo> info(new SerialDeviceInfo);
- info->path = WideToASCII(value);
+ info->path = base::UTF16ToASCII(value);
devices->push_back(info);
}
}