summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authoryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 22:15:23 +0000
committeryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 22:15:23 +0000
commitcab208eb0702d3541a7fa430889c26a3d1182120 (patch)
treea5ddeb04c32edd7ca0288ea8614d33caf2bb01e1 /device
parent2b392e59ab9a72858d224bad9e422fe40a696a69 (diff)
downloadchromium_src-cab208eb0702d3541a7fa430889c26a3d1182120.zip
chromium_src-cab208eb0702d3541a7fa430889c26a3d1182120.tar.gz
chromium_src-cab208eb0702d3541a7fa430889c26a3d1182120.tar.bz2
Moved bluetooth adapter files from chrome/browser/chromeos/bluetooth/ to device/bluetooth/. device/bluetooth/ is a new directory to host the bluetooth related files.
I also changed the namespace from chromeos to bluetooth under new directory. BUG=135470 Review URL: https://chromiumcodereview.appspot.com/11075006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162811 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device')
-rw-r--r--device/DEPS4
-rw-r--r--device/bluetooth/DEPS11
-rw-r--r--device/bluetooth/OWNERS2
-rw-r--r--device/bluetooth/bluetooth_adapter.cc34
-rw-r--r--device/bluetooth/bluetooth_adapter.h155
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.cc539
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.h245
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc168
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos_unittest.cc1557
-rw-r--r--device/bluetooth/bluetooth_adapter_factory.cc55
-rw-r--r--device/bluetooth/bluetooth_adapter_factory.h33
-rw-r--r--device/bluetooth/bluetooth_device.cc170
-rw-r--r--device/bluetooth/bluetooth_device.h318
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.cc690
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.h375
-rw-r--r--device/bluetooth/bluetooth_out_of_band_pairing_data.h27
-rw-r--r--device/bluetooth/bluetooth_service_record.cc122
-rw-r--r--device/bluetooth/bluetooth_service_record.h59
-rw-r--r--device/bluetooth/bluetooth_service_record_unittest.cc78
-rw-r--r--device/bluetooth/bluetooth_socket.h30
-rw-r--r--device/bluetooth/bluetooth_socket_chromeos.cc71
-rw-r--r--device/bluetooth/bluetooth_socket_chromeos.h45
-rw-r--r--device/bluetooth/bluetooth_utils.cc92
-rw-r--r--device/bluetooth/bluetooth_utils.h42
-rw-r--r--device/bluetooth/bluetooth_utils_unittest.cc76
-rw-r--r--device/bluetooth/test/mock_bluetooth_adapter.cc20
-rw-r--r--device/bluetooth/test/mock_bluetooth_adapter.h61
-rw-r--r--device/bluetooth/test/mock_bluetooth_device.cc41
-rw-r--r--device/bluetooth/test/mock_bluetooth_device.h79
-rw-r--r--device/device.gyp111
-rw-r--r--device/test/data/bluetooth/invalid_uuid.xml8
-rw-r--r--device/test/data/bluetooth/medium_uuid.xml8
-rw-r--r--device/test/data/bluetooth/rfcomm.xml39
-rw-r--r--device/test/data/bluetooth/short_uuid.xml8
-rw-r--r--device/test/data/bluetooth/uppercase_uuid.xml8
-rw-r--r--device/test/device_test_suite.cc18
-rw-r--r--device/test/device_test_suite.h19
-rw-r--r--device/test/run_all_unittests.cc10
38 files changed, 5428 insertions, 0 deletions
diff --git a/device/DEPS b/device/DEPS
new file mode 100644
index 0000000..2beaf5d
--- /dev/null
+++ b/device/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+content/public/common",
+ "+content/public/test",
+]
diff --git a/device/bluetooth/DEPS b/device/bluetooth/DEPS
new file mode 100644
index 0000000..730c30e
--- /dev/null
+++ b/device/bluetooth/DEPS
@@ -0,0 +1,11 @@
+include_rules = [
+ "+chrome/common",
+ "+chrome/test/base",
+ "+content/public/test",
+ "+chromeos/dbus",
+ "+dbus",
+ "+grit",
+ "+ui/base/l10n",
+ "+third_party/cros_system_api/dbus",
+ "+third_party/libxml/chromium",
+]
diff --git a/device/bluetooth/OWNERS b/device/bluetooth/OWNERS
new file mode 100644
index 0000000..47f6cfa
--- /dev/null
+++ b/device/bluetooth/OWNERS
@@ -0,0 +1,2 @@
+keybuk@chromium.org
+bryeung@chromium.org
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
new file mode 100644
index 0000000..b36cd0b
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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_adapter.h"
+
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace device {
+
+BluetoothAdapter::~BluetoothAdapter() {
+}
+
+const std::string& BluetoothAdapter::address() const {
+ return address_;
+}
+
+const std::string& BluetoothAdapter::name() const {
+ return name_;
+}
+
+BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() {
+ ConstDeviceList const_devices =
+ const_cast<const BluetoothAdapter *>(this)->GetDevices();
+
+ DeviceList devices;
+ for (ConstDeviceList::const_iterator i = const_devices.begin();
+ i != const_devices.end(); ++i)
+ devices.push_back(const_cast<BluetoothDevice *>(*i));
+
+ return devices;
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h
new file mode 100644
index 0000000..86de361
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 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_ADAPTER_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+
+namespace device {
+
+class BluetoothDevice;
+
+struct BluetoothOutOfBandPairingData;
+
+// BluetoothAdapter represents a local Bluetooth adapter which may be used to
+// interact with remote Bluetooth devices. As well as providing support for
+// determining whether an adapter is present, and whether the radio is powered,
+// this class also provides support for obtaining the list of remote devices
+// known to the adapter, discovering new devices, and providing notification of
+// updates to device information.
+class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> {
+ public:
+ // Interface for observing changes from bluetooth adapters.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // Called when the presence of the adapter |adapter| changes, when
+ // |present| is true the adapter is now present, false means the adapter
+ // has been removed from the system.
+ virtual void AdapterPresentChanged(BluetoothAdapter* adapter,
+ bool present) {}
+
+ // Called when the radio power state of the adapter |adapter| changes,
+ // when |powered| is true the adapter radio is powered, false means the
+ // adapter radio is off.
+ virtual void AdapterPoweredChanged(BluetoothAdapter* adapter,
+ bool powered) {}
+
+ // Called when the discovering state of the adapter |adapter| changes,
+ // when |discovering| is true the adapter is seeking new devices, false
+ // means it is not. Note that device discovery involves both states when
+ // the adapter is seeking new devices and states when it is not because
+ // it is interrogating the devices it found.
+ virtual void AdapterDiscoveringChanged(BluetoothAdapter* adapter,
+ bool discovering) {}
+
+ // Called when a new device |device| is added to the adapter |adapter|,
+ // either because it has been discovered or a connection made. |device|
+ // should not be cached, instead copy its address.
+ virtual void DeviceAdded(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {}
+
+ // Called when properties of the device |device| known to the adapter
+ // |adapter| change. |device| should not be cached, instead copy its
+ // address.
+ virtual void DeviceChanged(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {}
+
+ // Called when the device |device| is removed from the adapter |adapter|,
+ // either as a result of a discovered device being lost between discovering
+ // phases or pairing information deleted. |device| should not be cached.
+ virtual void DeviceRemoved(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {}
+ };
+
+ // 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;
+
+ // The BluetoothOutOfBandPairingDataCallback is used to return
+ // BluetoothOutOfBandPairingData to the caller.
+ typedef base::Callback<void(const BluetoothOutOfBandPairingData& data)>
+ BluetoothOutOfBandPairingDataCallback;
+
+ // Adds and removes observers for events on this bluetooth adapter,
+ // if monitoring multiple adapters check the |adapter| parameter of
+ // observer methods to determine which adapter is issuing the event.
+ virtual void AddObserver(BluetoothAdapter::Observer* observer) = 0;
+ virtual void RemoveObserver(
+ BluetoothAdapter::Observer* observer) = 0;
+
+ // The address of this adapter. The address format is "XX:XX:XX:XX:XX:XX",
+ // where each XX is a hexadecimal number.
+ virtual const std::string& address() const;
+
+ // The name of the adapter.
+ virtual const std::string& name() const;
+
+ // Indicates whether the adapter is actually present on the system, for
+ // the default adapter this indicates whether any adapter is present. An
+ // adapter is only considered present if the address has been obtained.
+ virtual bool IsPresent() const = 0;
+
+ // Indicates whether the adapter radio is powered.
+ virtual bool IsPowered() const = 0;
+
+ // Requests a change to the adapter radio power, setting |powered| to true
+ // will turn on the radio and false will turn it off. On success, callback
+ // will be called. On failure, |error_callback| will be called.
+ virtual void SetPowered(bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Indicates whether the adapter is currently discovering new devices,
+ // note that a typical discovery process has phases of this being true
+ // followed by phases of being false when the adapter interrogates the
+ // devices found.
+ virtual bool IsDiscovering() const = 0;
+
+ // Requests that the adapter either begin discovering new devices when
+ // |discovering| is true, or cease any discovery when false. On success,
+ // callback will be called. On failure, |error_callback| will be called.
+ virtual void SetDiscovering(bool discovering,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Requests the list of devices from the adapter, all are returned
+ // including those currently connected and those paired. Use the
+ // returned device pointers to determine which they are.
+ typedef std::vector<BluetoothDevice*> DeviceList;
+ virtual DeviceList GetDevices();
+ typedef std::vector<const BluetoothDevice*> ConstDeviceList;
+ virtual ConstDeviceList GetDevices() const = 0;
+
+ // Returns a pointer to the device with the given address |address| or
+ // NULL if no such device is known.
+ virtual BluetoothDevice* GetDevice(const std::string& address) = 0;
+ virtual const BluetoothDevice* GetDevice(
+ const std::string& address) const = 0;
+
+ // Requests the local Out Of Band pairing data.
+ virtual void ReadLocalOutOfBandPairingData(
+ const BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ protected:
+ friend class base::RefCounted<BluetoothAdapter>;
+ virtual ~BluetoothAdapter();
+
+ // Address of the adapter.
+ std::string address_;
+
+ // Name of the adapter.
+ std::string name_;
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
new file mode 100644
index 0000000..36699e5
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -0,0 +1,539 @@
+// Copyright (c) 2012 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_adapter_chromeos.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "chromeos/dbus/bluetooth_adapter_client.h"
+#include "chromeos/dbus/bluetooth_device_client.h"
+#include "chromeos/dbus/bluetooth_manager_client.h"
+#include "chromeos/dbus/bluetooth_out_of_band_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothDevice;
+using device::BluetoothOutOfBandPairingData;
+
+namespace chromeos {
+
+BluetoothAdapterChromeOs::BluetoothAdapterChromeOs() : track_default_(false),
+ powered_(false),
+ discovering_(false),
+ weak_ptr_factory_(this) {
+ DBusThreadManager::Get()->GetBluetoothManagerClient()->
+ AddObserver(this);
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ AddObserver(this);
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ AddObserver(this);
+}
+
+BluetoothAdapterChromeOs::~BluetoothAdapterChromeOs() {
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ RemoveObserver(this);
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ RemoveObserver(this);
+ DBusThreadManager::Get()->GetBluetoothManagerClient()->
+ RemoveObserver(this);
+
+ STLDeleteValues(&devices_);
+}
+
+void BluetoothAdapterChromeOs::AddObserver(
+ BluetoothAdapter::Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void BluetoothAdapterChromeOs::RemoveObserver(
+ BluetoothAdapter::Observer* observer) {
+ DCHECK(observer);
+ observers_.RemoveObserver(observer);
+}
+
+bool BluetoothAdapterChromeOs::IsPresent() const {
+ return !object_path_.value().empty() && !address_.empty();
+}
+
+bool BluetoothAdapterChromeOs::IsPowered() const {
+ return powered_;
+}
+
+void BluetoothAdapterChromeOs::SetPowered(bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ GetProperties(object_path_)->powered.Set(
+ powered,
+ base::Bind(&BluetoothAdapterChromeOs::OnSetPowered,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+bool BluetoothAdapterChromeOs::IsDiscovering() const {
+ return discovering_;
+}
+
+void BluetoothAdapterChromeOs::SetDiscovering(
+ bool discovering,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (discovering) {
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StartDiscovery(object_path_,
+ base::Bind(&BluetoothAdapterChromeOs::OnStartDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ } else {
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StopDiscovery(object_path_,
+ base::Bind(&BluetoothAdapterChromeOs::OnStopDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+}
+
+BluetoothAdapter::ConstDeviceList BluetoothAdapterChromeOs::GetDevices() const {
+ ConstDeviceList devices;
+ for (DevicesMap::const_iterator iter = devices_.begin();
+ iter != devices_.end();
+ ++iter)
+ devices.push_back(iter->second);
+
+ return devices;
+}
+
+BluetoothDevice* BluetoothAdapterChromeOs::GetDevice(
+ const std::string& address) {
+ return const_cast<BluetoothDevice *>(
+ const_cast<const BluetoothAdapterChromeOs *>(this)->GetDevice(address));
+}
+
+const BluetoothDevice* BluetoothAdapterChromeOs::GetDevice(
+ const std::string& address) const {
+ DevicesMap::const_iterator iter = devices_.find(address);
+ if (iter != devices_.end())
+ return iter->second;
+
+ return NULL;
+}
+
+void BluetoothAdapterChromeOs::ReadLocalOutOfBandPairingData(
+ const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
+ ReadLocalData(object_path_,
+ base::Bind(&BluetoothAdapterChromeOs::OnReadLocalData,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+void BluetoothAdapterChromeOs::TrackDefaultAdapter() {
+ DVLOG(1) << "Tracking default adapter";
+ track_default_ = true;
+ DBusThreadManager::Get()->GetBluetoothManagerClient()->
+ DefaultAdapter(base::Bind(&BluetoothAdapterChromeOs::AdapterCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BluetoothAdapterChromeOs::FindAdapter(const std::string& address) {
+ DVLOG(1) << "Using adapter " << address;
+ track_default_ = false;
+ DBusThreadManager::Get()->GetBluetoothManagerClient()->
+ FindAdapter(address,
+ base::Bind(&BluetoothAdapterChromeOs::AdapterCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BluetoothAdapterChromeOs::AdapterCallback(
+ const dbus::ObjectPath& adapter_path,
+ bool success) {
+ if (success) {
+ ChangeAdapter(adapter_path);
+ } else if (!object_path_.value().empty()) {
+ RemoveAdapter();
+ }
+}
+
+void BluetoothAdapterChromeOs::DefaultAdapterChanged(
+ const dbus::ObjectPath& adapter_path) {
+ if (track_default_)
+ ChangeAdapter(adapter_path);
+}
+
+void BluetoothAdapterChromeOs::AdapterRemoved(
+ const dbus::ObjectPath& adapter_path) {
+ if (adapter_path == object_path_)
+ RemoveAdapter();
+}
+
+void BluetoothAdapterChromeOs::ChangeAdapter(
+ const dbus::ObjectPath& adapter_path) {
+ if (object_path_.value().empty()) {
+ DVLOG(1) << "Adapter path initialized to " << adapter_path.value();
+ } else if (object_path_.value() != adapter_path.value()) {
+ DVLOG(1) << "Adapter path changed from " << object_path_.value()
+ << " to " << adapter_path.value();
+
+ RemoveAdapter();
+ } else {
+ DVLOG(1) << "Adapter address updated";
+ }
+
+ object_path_ = adapter_path;
+
+ // Update properties to their new values.
+ BluetoothAdapterClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ GetProperties(object_path_);
+
+ address_ = properties->address.value();
+ name_ = properties->name.value();
+
+ // Delay announcing a new adapter until we have an address.
+ if (address_.empty()) {
+ DVLOG(1) << "Adapter address not yet known";
+ return;
+ }
+
+ PoweredChanged(properties->powered.value());
+ DiscoveringChanged(properties->discovering.value());
+ DevicesChanged(properties->devices.value());
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPresentChanged(this, true));
+}
+
+void BluetoothAdapterChromeOs::RemoveAdapter() {
+ const bool adapter_was_present = IsPresent();
+
+ DVLOG(1) << "Adapter lost.";
+ PoweredChanged(false);
+ DiscoveringChanged(false);
+ ClearDevices();
+
+ object_path_ = dbus::ObjectPath("");
+ address_.clear();
+ name_.clear();
+
+ if (adapter_was_present)
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPresentChanged(this, false));
+}
+
+void BluetoothAdapterChromeOs::OnSetPowered(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success) {
+ if (success)
+ callback.Run();
+ else
+ error_callback.Run();
+}
+
+void BluetoothAdapterChromeOs::PoweredChanged(bool powered) {
+ if (powered == powered_)
+ return;
+
+ powered_ = powered;
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPoweredChanged(this, powered_));
+}
+
+void BluetoothAdapterChromeOs::OnStartDiscovery(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path,
+ bool success) {
+ if (success) {
+ DVLOG(1) << object_path_.value() << ": started discovery.";
+
+ // Clear devices found in previous discovery attempts
+ ClearDiscoveredDevices();
+ callback.Run();
+ } else {
+ // TODO(keybuk): in future, don't run the callback if the error was just
+ // that we were already discovering.
+ error_callback.Run();
+ }
+}
+
+void BluetoothAdapterChromeOs::OnStopDiscovery(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path,
+ bool success) {
+ if (success) {
+ DVLOG(1) << object_path_.value() << ": stopped discovery.";
+ callback.Run();
+ // Leave found devices available for perusing.
+ } else {
+ // TODO(keybuk): in future, don't run the callback if the error was just
+ // that we weren't discovering.
+ error_callback.Run();
+ }
+}
+
+void BluetoothAdapterChromeOs::DiscoveringChanged(bool discovering) {
+ if (discovering == discovering_)
+ return;
+
+ discovering_ = discovering;
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterDiscoveringChanged(this, discovering_));
+}
+
+void BluetoothAdapterChromeOs::OnReadLocalData(
+ const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback,
+ const BluetoothOutOfBandPairingData& data,
+ bool success) {
+ if (success)
+ callback.Run(data);
+ else
+ error_callback.Run();
+}
+
+void BluetoothAdapterChromeOs::AdapterPropertyChanged(
+ const dbus::ObjectPath& adapter_path,
+ const std::string& property_name) {
+ if (adapter_path != object_path_)
+ return;
+
+ BluetoothAdapterClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ GetProperties(object_path_);
+
+ if (property_name == properties->address.name()) {
+ ChangeAdapter(object_path_);
+
+ } else if (!address_.empty()) {
+ if (property_name == properties->powered.name()) {
+ PoweredChanged(properties->powered.value());
+
+ } else if (property_name == properties->discovering.name()) {
+ DiscoveringChanged(properties->discovering.value());
+
+ } else if (property_name == properties->devices.name()) {
+ DevicesChanged(properties->devices.value());
+
+ } else if (property_name == properties->name.name()) {
+ name_ = properties->name.value();
+
+ }
+ }
+}
+
+void BluetoothAdapterChromeOs::DevicePropertyChanged(
+ const dbus::ObjectPath& device_path,
+ const std::string& property_name) {
+ UpdateDevice(device_path);
+}
+
+void BluetoothAdapterChromeOs::UpdateDevice(
+ const dbus::ObjectPath& device_path) {
+ BluetoothDeviceClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ GetProperties(device_path);
+
+ // When we first see a device, we may not know the address yet and need to
+ // wait for the DevicePropertyChanged signal before adding the device.
+ const std::string address = properties->address.value();
+ if (address.empty())
+ return;
+
+ // The device may be already known to us, either because this is an update
+ // to properties, or the device going from discovered to connected and
+ // pairing gaining an object path in the process. In any case, we want
+ // to update the existing object, not create a new one.
+ DevicesMap::iterator iter = devices_.find(address);
+ BluetoothDeviceChromeOs* device;
+ const bool update_device = (iter != devices_.end());
+ if (update_device) {
+ device = iter->second;
+ } else {
+ device = BluetoothDeviceChromeOs::Create(this);
+ devices_[address] = device;
+ }
+
+ const bool was_paired = device->IsPaired();
+ if (!was_paired) {
+ DVLOG(1) << "Assigned object path " << device_path.value() << " to device "
+ << address;
+ device->SetObjectPath(device_path);
+ }
+ device->Update(properties, true);
+
+ if (update_device) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, device));
+ } else {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceAdded(this, device));
+ }
+}
+
+void BluetoothAdapterChromeOs::ClearDevices() {
+ DevicesMap replace;
+ devices_.swap(replace);
+ for (DevicesMap::iterator iter = replace.begin();
+ iter != replace.end(); ++iter) {
+ BluetoothDeviceChromeOs* device = iter->second;
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device));
+
+ delete device;
+ }
+}
+
+void BluetoothAdapterChromeOs::DeviceCreated(
+ const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path) {
+ if (adapter_path != object_path_)
+ return;
+
+ UpdateDevice(device_path);
+}
+
+void BluetoothAdapterChromeOs::DeviceRemoved(
+ const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path) {
+ if (adapter_path != object_path_)
+ return;
+
+ DevicesMap::iterator iter = devices_.begin();
+ while (iter != devices_.end()) {
+ BluetoothDeviceChromeOs* device = iter->second;
+ DevicesMap::iterator temp = iter;
+ ++iter;
+
+ if (device->object_path_ != device_path)
+ continue;
+
+ // DeviceRemoved can also be called to indicate a device that is visible
+ // during discovery has disconnected, but it is still visible to the
+ // adapter, so don't remove in that case and only clear the object path.
+ if (!device->IsVisible()) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device));
+
+ DVLOG(1) << "Removed device " << device->address();
+
+ delete device;
+ devices_.erase(temp);
+ } else {
+ DVLOG(1) << "Removed object path from device " << device->address();
+ device->RemoveObjectPath();
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, device));
+ }
+ }
+}
+
+void BluetoothAdapterChromeOs::DevicesChanged(
+ const std::vector<dbus::ObjectPath>& devices) {
+ for (std::vector<dbus::ObjectPath>::const_iterator iter =
+ devices.begin(); iter != devices.end(); ++iter)
+ UpdateDevice(*iter);
+}
+
+void BluetoothAdapterChromeOs::ClearDiscoveredDevices() {
+ DevicesMap::iterator iter = devices_.begin();
+ while (iter != devices_.end()) {
+ BluetoothDeviceChromeOs* device = iter->second;
+ DevicesMap::iterator temp = iter;
+ ++iter;
+
+ if (!device->IsPaired()) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device));
+
+ delete device;
+ devices_.erase(temp);
+ }
+ }
+}
+
+void BluetoothAdapterChromeOs::DeviceFound(
+ const dbus::ObjectPath& adapter_path,
+ const std::string& address,
+ const BluetoothDeviceClient::Properties& properties) {
+ if (adapter_path != object_path_)
+ return;
+
+ // DeviceFound can also be called to indicate that a device we've
+ // paired with is now visible to the adapter during discovery, in which
+ // case we want to update the existing object, not create a new one.
+ BluetoothDeviceChromeOs* device;
+ DevicesMap::iterator iter = devices_.find(address);
+ const bool update_device = (iter != devices_.end());
+ if (update_device) {
+ device = iter->second;
+ } else {
+ device = BluetoothDeviceChromeOs::Create(this);
+ devices_[address] = device;
+ }
+
+ DVLOG(1) << "Device " << address << " is visible to the adapter";
+ device->SetVisible(true);
+ device->Update(&properties, false);
+
+ if (update_device) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, device));
+ } else {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceAdded(this, device));
+ }
+}
+
+void BluetoothAdapterChromeOs::DeviceDisappeared(
+ const dbus::ObjectPath& adapter_path,
+ const std::string& address) {
+ if (adapter_path != object_path_)
+ return;
+
+ DevicesMap::iterator iter = devices_.find(address);
+ if (iter == devices_.end())
+ return;
+
+ BluetoothDeviceChromeOs* device = iter->second;
+
+ // DeviceDisappeared can also be called to indicate that a device we've
+ // paired with is no longer visible to the adapter, so don't remove
+ // in that case and only clear the visible flag.
+ if (!device->IsPaired()) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device));
+
+ DVLOG(1) << "Discovered device " << device->address()
+ << " is no longer visible to the adapter";
+
+ delete device;
+ devices_.erase(iter);
+ } else {
+ DVLOG(1) << "Paired device " << device->address()
+ << " is no longer visible to the adapter";
+ device->SetVisible(false);
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, device));
+ }
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
new file mode 100644
index 0000000..18cb7aa
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 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_ADAPTER_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/observer_list.h"
+#include "chromeos/dbus/bluetooth_adapter_client.h"
+#include "chromeos/dbus/bluetooth_device_client.h"
+#include "chromeos/dbus/bluetooth_manager_client.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace device {
+
+class BluetoothAdapterFactory;
+class MockBluetoothAdapter;
+struct BluetoothOutOfBandPairingData;
+
+} // namespace device
+
+namespace chromeos {
+
+class BluetoothDeviceChromeOs;
+
+// The BluetoothAdapterChromeOs class is an implementation of BluetoothAdapter
+// for Chrome OS platform.
+class BluetoothAdapterChromeOs
+ : public device::BluetoothAdapter,
+ public BluetoothManagerClient::Observer,
+ public BluetoothAdapterClient::Observer,
+ public BluetoothDeviceClient::Observer {
+ public:
+ // BluetoothAdapter override
+ virtual void AddObserver(
+ device::BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ device::BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual bool IsPresent() const OVERRIDE;
+ virtual bool IsPowered() const OVERRIDE;
+ virtual void SetPowered(
+ bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual bool IsDiscovering() const OVERRIDE;
+ virtual void SetDiscovering(
+ bool discovering,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual ConstDeviceList GetDevices() const OVERRIDE;
+ virtual device::BluetoothDevice* GetDevice(
+ const std::string& address) OVERRIDE;
+ virtual const device::BluetoothDevice* GetDevice(
+ const std::string& address) const OVERRIDE;
+ virtual void ReadLocalOutOfBandPairingData(
+ const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback&
+ callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
+ private:
+ friend class BluetoothDeviceChromeOs;
+ friend class device::BluetoothAdapterFactory;
+ friend class device::MockBluetoothAdapter;
+
+ BluetoothAdapterChromeOs();
+ virtual ~BluetoothAdapterChromeOs();
+
+ // Obtains the default adapter object path from the Bluetooth Daemon
+ // and tracks future changes to it.
+ void TrackDefaultAdapter();
+
+ // Obtains the object paht for the adapter named by |address| from the
+ // Bluetooth Daemon.
+ void FindAdapter(const std::string& address);
+
+ // Called by dbus:: in response to the method call sent by both
+ // DefaultAdapter() and FindAdapter(), |object_path| will contain the
+ // dbus object path of the requested adapter when |success| is true.
+ void AdapterCallback(const dbus::ObjectPath& adapter_path, bool success);
+
+ // BluetoothManagerClient::Observer override.
+ //
+ // Called when the default local bluetooth adapter changes.
+ // |object_path| is the dbus object path of the new default adapter.
+ // Not called if all adapters are removed.
+ virtual void DefaultAdapterChanged(const dbus::ObjectPath& adapter_path)
+ OVERRIDE;
+
+ // BluetoothManagerClient::Observer override.
+ //
+ // Called when a local bluetooth adapter is removed.
+ // |object_path| is the dbus object path of the adapter.
+ virtual void AdapterRemoved(const dbus::ObjectPath& adapter_path) OVERRIDE;
+
+ // Changes the tracked adapter to the dbus object path |adapter_path|,
+ // clearing information from the previously tracked adapter and updating
+ // to the new adapter.
+ void ChangeAdapter(const dbus::ObjectPath& adapter_path);
+
+ // Clears the tracked adapter information.
+ void RemoveAdapter();
+
+ // Called by dbus:: in response to the method call send by SetPowered().
+ // |callback| and |error_callback| are the callbacks passed to SetPowered().
+ void OnSetPowered(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success);
+
+ // Updates the tracked state of the adapter's radio power to |powered|
+ // and notifies observers. Called on receipt of a property changed signal,
+ // and directly using values obtained from properties.
+ void PoweredChanged(bool powered);
+
+ // Called by dbus:: in response to the method calls send by SetDiscovering().
+ // |callback| and |error_callback| are the callbacks passed to
+ // SetDiscovering().
+ void OnStartDiscovery(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path,
+ bool success);
+ void OnStopDiscovery(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path,
+ bool success);
+
+ // Updates the tracked state of the adapter's discovering state to
+ // |discovering| and notifies observers. Called on receipt of a property
+ // changed signal, and directly using values obtained from properties.
+ void DiscoveringChanged(bool discovering);
+
+ // Called by dbus:: in response to the ReadLocalData method call.
+ void OnReadLocalData(
+ const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback&
+ callback,
+ const ErrorCallback& error_callback,
+ const device::BluetoothOutOfBandPairingData& data,
+ bool success);
+
+ // BluetoothAdapterClient::Observer override.
+ //
+ // Called when the adapter with object path |adapter_path| has a
+ // change in value of the property named |property_name|.
+ virtual void AdapterPropertyChanged(const dbus::ObjectPath& adapter_path,
+ const std::string& property_name)
+ OVERRIDE;
+
+ // BluetoothDeviceClient::Observer override.
+ //
+ // Called when the device with object path |device_path| has a
+ // change in value of the property named |property_name|.
+ virtual void DevicePropertyChanged(const dbus::ObjectPath& device_path,
+ const std::string& property_name)
+ OVERRIDE;
+
+ // Updates information on the device with object path |device_path|,
+ // adding it to the |devices_| map if not already present.
+ void UpdateDevice(const dbus::ObjectPath& device_path);
+
+ // Clears the |devices_| list, notifying obsevers of the device removal.
+ void ClearDevices();
+
+ // BluetoothAdapterClient::Observer override.
+ //
+ // Called when the adapter with object path |object_path| has a
+ // new known device with object path |object_path|.
+ virtual void DeviceCreated(const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path) OVERRIDE;
+
+ // BluetoothAdapterClient::Observer override.
+ //
+ // Called when the adapter with object path |object_path| removes
+ // the known device with object path |object_path|.
+ virtual void DeviceRemoved(const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path) OVERRIDE;
+
+ // Updates the adapter |devices_| list, adding or updating devices using
+ // the object paths in the|devices| list. This doesn't remove devices,
+ // relying instead on the DeviceRemoved() signal for that. Called on
+ // receipt of a property changed signal, and directly using values obtained
+ // from properties.
+ void DevicesChanged(const std::vector<dbus::ObjectPath>& devices);
+
+ // Clears discovered devices from the |devices_| list, notifying
+ // observers, and leaving only those devices with a dbus object path.
+ void ClearDiscoveredDevices();
+
+ // BluetoothAdapterClient::Observer override.
+ //
+ // Called when the adapter with object path |object_path| discovers
+ // a new remote device with address |address| and properties
+ // |properties|, there is no device object path until connected.
+ //
+ // |properties| supports only value() calls, not Get() or Set(), and
+ // should be copied if needed.
+ virtual void DeviceFound(
+ const dbus::ObjectPath& adapter_path,
+ const std::string& address,
+ const BluetoothDeviceClient::Properties& properties) OVERRIDE;
+
+ // BluetoothAdapterClient::Observer override.
+ //
+ // Called when the adapter with object path |object_path| can no
+ // longer communicate with the discovered removed device with
+ // address |address|.
+ virtual void DeviceDisappeared(const dbus::ObjectPath& object_path,
+ const std::string& address) OVERRIDE;
+
+ // List of observers interested in event notifications from us.
+ ObserverList<device::BluetoothAdapter::Observer> observers_;
+
+ // Object path of adapter for this instance, this is fixed at creation time
+ // unless |track_default_| is true in which case we update it to always
+ // point at the default adapter.
+ bool track_default_;
+ dbus::ObjectPath object_path_;
+
+ // Tracked adapter state, cached locally so we only send change notifications
+ // to observers on a genuine change.
+ bool powered_;
+ bool discovering_;
+
+ // 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 BluetoothDeviceChromeOs object whose lifetime is managed by the
+ // adapter instance.
+ typedef std::map<const std::string, BluetoothDeviceChromeOs*> DevicesMap;
+ DevicesMap devices_;
+
+ // 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterChromeOs);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc b/device/bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc
new file mode 100644
index 0000000..0ff8d3d
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 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 "chromeos/dbus/mock_bluetooth_adapter_client.h"
+#include "chromeos/dbus/mock_bluetooth_device_client.h"
+#include "chromeos/dbus/mock_bluetooth_manager_client.h"
+#include "chromeos/dbus/mock_dbus_thread_manager.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothAdapterFactory;
+using device::BluetoothDevice;
+using device::MockBluetoothAdapter;
+using ::testing::_;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace chromeos {
+
+class BluetoothAdapterChromeOsDevicesTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager;
+
+ EXPECT_CALL(*mock_dbus_thread_manager, GetSystemBus())
+ .WillRepeatedly(Return(reinterpret_cast<dbus::Bus*>(NULL)));
+ DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+
+ mock_manager_client_ =
+ mock_dbus_thread_manager->mock_bluetooth_manager_client();
+ mock_adapter_client_ =
+ mock_dbus_thread_manager->mock_bluetooth_adapter_client();
+ mock_device_client_ =
+ mock_dbus_thread_manager->mock_bluetooth_device_client();
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ EXPECT_CALL(*mock_manager_client_, AddObserver(_))
+ .Times(1);
+ EXPECT_CALL(*mock_adapter_client_, AddObserver(_))
+ .Times(1);
+
+ adapter_ = BluetoothAdapterFactory::DefaultAdapter();
+ ASSERT_TRUE(adapter_.get() != NULL);
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address_);
+ adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path_))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // Add an observer to the adapter; expect the usual set of changes to
+ // an adapter becoming present and then clear to clean up for the test.
+ adapter_->AddObserver(&adapter_observer_);
+
+ EXPECT_CALL(adapter_observer_, AdapterPresentChanged(adapter_.get(), true))
+ .Times(1);
+ EXPECT_CALL(adapter_observer_, AdapterPoweredChanged(adapter_.get(), true))
+ .Times(1);
+
+ adapter_callback.Run(adapter_path_, true);
+
+ Mock::VerifyAndClearExpectations(mock_manager_client_);
+ Mock::VerifyAndClearExpectations(mock_adapter_client_);
+ Mock::VerifyAndClearExpectations(mock_device_client_);
+ Mock::VerifyAndClearExpectations(&adapter_observer_);
+ }
+
+ virtual void TearDown() {
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter_.get());
+ EXPECT_CALL(*mock_device_client_, RemoveObserver(adapter_chromeos))
+ .Times(1);
+ EXPECT_CALL(*mock_adapter_client_, RemoveObserver(adapter_chromeos))
+ .Times(1);
+ EXPECT_CALL(*mock_manager_client_, RemoveObserver(adapter_chromeos))
+ .Times(1);
+
+ adapter_ = NULL;
+ DBusThreadManager::Shutdown();
+ }
+
+ protected:
+ MockBluetoothManagerClient* mock_manager_client_;
+ MockBluetoothAdapterClient* mock_adapter_client_;
+ MockBluetoothDeviceClient* mock_device_client_;
+
+ static const dbus::ObjectPath adapter_path_;
+ static const std::string adapter_address_;
+ scoped_refptr<BluetoothAdapter> adapter_;
+
+ MockBluetoothAdapter::Observer adapter_observer_;
+};
+
+const dbus::ObjectPath BluetoothAdapterChromeOsDevicesTest::adapter_path_(
+ "/fake/hci0");
+const std::string BluetoothAdapterChromeOsDevicesTest::adapter_address_ =
+ "CA:FE:4A:C0:FE:FE";
+
+TEST_F(BluetoothAdapterChromeOsDevicesTest, DeviceRemovedAfterFound) {
+ const dbus::ObjectPath device_path("/fake/hci0/dev_ba_c0_11_00_00_01");
+ const std::string device_address = "BA:C0:11:00:00:01";
+
+ MockBluetoothDeviceClient::Properties device_properties;
+ device_properties.address.ReplaceValue(device_address);
+ device_properties.name.ReplaceValue("Fake Keyboard");
+ device_properties.bluetooth_class.ReplaceValue(0x2540);
+
+ // Inform the adapter that the device has been found;
+ // BluetoothAdapterClient::Observer::DeviceAdded will be called, passing
+ // the device object.
+ BluetoothDevice* device;
+ EXPECT_CALL(adapter_observer_, DeviceAdded(adapter_.get(), _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&device));
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter_.get());
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->DeviceFound(adapter_path_, device_address, device_properties);
+
+ // Now inform the adapter that the device has been added and assigned an
+ // object path; BluetoothDeviceClient::GetProperties will be called to
+ // obtain the property set; and
+ // BluetoothAdapterClient::Observer::DeviceChanged will be called passing
+ // the same device object as before.
+ EXPECT_CALL(*mock_device_client_, GetProperties(device_path))
+ .WillRepeatedly(Return(&device_properties));
+
+ EXPECT_CALL(adapter_observer_, DeviceChanged(adapter_chromeos, device))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->DeviceCreated(adapter_path_, device_path);
+
+ // Finally remove the adapter again;
+ // BluetoothAdapterClient::Observer::DeviceRemoved should be not called,
+ // instead BluetoothAdapterClient::Observer::DeviceChanged will be called.
+ EXPECT_CALL(adapter_observer_, DeviceRemoved(adapter_.get(), device))
+ .Times(0);
+ EXPECT_CALL(adapter_observer_, DeviceChanged(adapter_.get(), device))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->DeviceRemoved(adapter_path_, device_path);
+
+ // Verify that the device is still visible, just no longer paired.
+ EXPECT_TRUE(device->IsVisible());
+ EXPECT_FALSE(device->IsPaired());
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc b/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc
new file mode 100644
index 0000000..890d241
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc
@@ -0,0 +1,1557 @@
+// Copyright (c) 2012 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 "chromeos/dbus/mock_bluetooth_adapter_client.h"
+#include "chromeos/dbus/mock_bluetooth_manager_client.h"
+#include "chromeos/dbus/mock_dbus_thread_manager.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothAdapterFactory;
+using device::MockBluetoothAdapter;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace chromeos {
+
+class BluetoothAdapterChromeOsTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager;
+
+ EXPECT_CALL(*mock_dbus_thread_manager, GetSystemBus())
+ .WillRepeatedly(Return(reinterpret_cast<dbus::Bus*>(NULL)));
+ DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+
+ mock_manager_client_ =
+ mock_dbus_thread_manager->mock_bluetooth_manager_client();
+ mock_adapter_client_ =
+ mock_dbus_thread_manager->mock_bluetooth_adapter_client();
+
+ set_callback_called_ = false;
+ error_callback_called_ = false;
+ }
+
+ virtual void TearDown() {
+ DBusThreadManager::Shutdown();
+ }
+
+ void SetCallback() {
+ set_callback_called_ = true;
+ }
+
+ void ErrorCallback() {
+ error_callback_called_ = true;
+ }
+
+ protected:
+ MockBluetoothManagerClient* mock_manager_client_;
+ MockBluetoothAdapterClient* mock_adapter_client_;
+
+ bool set_callback_called_;
+ bool error_callback_called_;
+};
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterNotPresent) {
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+ ASSERT_TRUE(adapter.get() != NULL);
+
+ // Call the adapter callback; make out it failed.
+ // BluetoothAdapter::Observer::AdapterPresentChanged must not be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(dbus::ObjectPath(""), false);
+
+ // Adapter should not be present.
+ EXPECT_FALSE(adapter->IsPresent());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged will be called to
+ // indicate the adapter is now present.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should be present with the given address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged must not be called
+ // yet.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should not be present yet.
+ EXPECT_FALSE(adapter->IsPresent());
+
+ // Tell the adapter the address now;
+ // BluetoothAdapter::Observer::AdapterPresentChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should be present with the given address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterBecomesPresentWithAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback; make out it failed.
+ adapter_callback.Run(dbus::ObjectPath(""), false);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged must be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(adapter_path);
+
+ // Adapter should be present with the new address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterReplacedWithAddress) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "BA:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged must be called once
+ // with false to indicate the old adapter being removed and once with true
+ // to announce the new adapter.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should be present with the new address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(new_adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterBecomesPresentWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback; make out it failed.
+ adapter_callback.Run(dbus::ObjectPath(""), false);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged must not be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(adapter_path);
+
+ // Adapter should not be present yet.
+ EXPECT_FALSE(adapter->IsPresent());
+
+ // Tell the adapter the address now;
+ // BluetoothAdapter::Observer::AdapterPresentChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should be present with the new address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterReplacedWithoutAddress) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "BA:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPresentChanged must be called to
+ // indicate the adapter has gone away.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should be now marked not present.
+ EXPECT_FALSE(adapter->IsPresent());
+
+ // Tell the adapter the address now;
+ // BluetoothAdapter::Observer::AdapterPresentChanged now must be called.
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(new_adapter_path,
+ new_adapter_properties.address.name());
+
+ // Adapter should be present with the new address.
+ EXPECT_TRUE(adapter->IsPresent());
+ EXPECT_EQ(new_adapter_address, adapter->address());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterRemoved) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Report that the adapter has been removed;
+ // BluetoothAdapter::Observer::AdapterPresentChanged will be called to
+ // indicate the adapter is no longer present.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->AdapterRemoved(adapter_path);
+
+ // Adapter should be no longer present.
+ EXPECT_FALSE(adapter->IsPresent());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithoutAddressRemoved) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Report that the adapter has been removed;
+ // BluetoothAdapter::Observer::AdapterPresentChanged must not be called
+ // since we never should have announced it in the first place.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->AdapterRemoved(adapter_path);
+
+ // Adapter should be still no longer present.
+ EXPECT_FALSE(adapter->IsPresent());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyInitiallyFalse) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.powered.ReplaceValue(false);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyInitiallyTrue) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ .Times(1);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyInitiallyTrueWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set but BluetoothAdapter::Observer::AdapterPoweredChanged
+ // should not yet be called.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.powered.ReplaceValue(true);
+
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should not yet have the property value.
+ EXPECT_FALSE(adapter->IsPowered());
+
+ // Tell the adapter the address now,
+ // BluetoothAdapter::Observer::AdapterPresentChanged and
+ // BluetoothAdapter::Observer::AdapterPoweredChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterPoweredPropertyChanged) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.powered.ReplaceValue(false);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter->IsPowered());
+
+ // Report that the property has been changed;
+ // BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ .Times(1);
+
+ adapter_properties.powered.ReplaceValue(true);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.powered.name());
+
+ // Adapter should have the new property values.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterPoweredPropertyUnchanged) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsPowered());
+
+ // Report that the property has been changed, but don't change the value;
+ // BluetoothAdapter::Observer::AdapterPoweredChanged should not be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.powered.name());
+
+ // Adapter should still have the same property values.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyChangedWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set but BluetoothAdapter::Observer::AdapterPoweredChanged
+ // should not yet be called.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Tell the adapter that its powered property changed, the observer
+ // method should still not be called because there is no address for
+ // the adapter so it is not present.
+ adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.powered.name());
+
+ // Adapter should not yet have the property value.
+ EXPECT_FALSE(adapter->IsPowered());
+
+ // Tell the adapter the address now,
+ // BluetoothAdapter::Observer::AdapterPresentChanged and
+ // BluetoothAdapter::Observer::AdapterPoweredChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should now have the correct property value.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyResetOnReplace) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "00:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+ initial_adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+ }
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_FALSE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyResetOnReplaceWhenTrue) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "BA:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+ initial_adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+ new_adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterPoweredChanged will be called once
+ // to set the value to false for the previous adapter and once to set the
+ // value to true for the new adapter.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+ }
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ .Times(1);
+ }
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_TRUE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterPoweredPropertyResetOnRemove) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.powered.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Report that the adapter has been removed;
+ // BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->AdapterRemoved(adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_FALSE(adapter->IsPowered());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterSetPowered) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Request that the powered property be changed;
+ // MockBluetoothAdapterClient::Set should be called, passing the address
+ // of the powered property and a callback to receive the response.
+ dbus::PropertySet::SetCallback set_callback;
+ EXPECT_CALL(adapter_properties, Set(&adapter_properties.powered, _))
+ .WillOnce(SaveArg<1>(&set_callback));
+
+ adapter->SetPowered(true,
+ base::Bind(&BluetoothAdapterChromeOsTest::SetCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOsTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // Reply to the callback to indicate success, the set callback we provided
+ // should be called but the properties should not be refetched.
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .Times(0);
+
+ set_callback.Run(true);
+
+ EXPECT_TRUE(set_callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterSetPoweredError) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Request that the powered property be changed;
+ // MockBluetoothAdapterClient::Set should be called, passing the address
+ // of the powered property and a callback to receive the response.
+ dbus::PropertySet::SetCallback set_callback;
+ EXPECT_CALL(adapter_properties, Set(&adapter_properties.powered, _))
+ .WillOnce(SaveArg<1>(&set_callback));
+
+ adapter->SetPowered(true,
+ base::Bind(&BluetoothAdapterChromeOsTest::SetCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOsTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // Reply to the callback to indicate failure, the error callback we provided
+ // should be called but the properties should not be refetched.
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .Times(0);
+
+ set_callback.Run(false);
+
+ EXPECT_FALSE(set_callback_called_);
+ EXPECT_TRUE(error_callback_called_);
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyInitiallyFalse) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.discovering.ReplaceValue(false);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyInitiallyTrue) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ .Times(1);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyInitiallyTrueWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set but BluetoothAdapter::Observer::AdapterDiscoveringChanged
+ // should not yet be called.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.discovering.ReplaceValue(true);
+
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should not yet have the property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+
+ // Tell the adapter the address now,
+ // BluetoothAdapter::Observer::AdapterPresentChanged and
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterDiscoveringPropertyChanged) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.discovering.ReplaceValue(false);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+
+ // Report that the property has been changed;
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ .Times(1);
+
+ adapter_properties.discovering.ReplaceValue(true);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.discovering.name());
+
+ // Adapter should have the new property values.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyUnchanged) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter->IsDiscovering());
+
+ // Report that the property has been changed, but don't change the value;
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged should not be
+ // called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.discovering.name());
+
+ // Adapter should still have the same property values.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyChangedWithoutAddress) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set but BluetoothAdapter::Observer::AdapterDiscoveringChanged
+ // should not yet be called.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ .Times(0);
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Tell the adapter that its discovering property changed, the observer
+ // method should still not be called because there is no address for
+ // the adapter so it is not present.
+ adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ .Times(0);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.discovering.name());
+
+ // Adapter should not yet have the property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+
+ // Tell the adapter the address now,
+ // BluetoothAdapter::Observer::AdapterPresentChanged and
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged now must be called.
+ adapter_properties.address.ReplaceValue(adapter_address);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ .Times(1);
+
+ static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
+ ->AdapterPropertyChanged(adapter_path,
+ adapter_properties.address.name());
+
+ // Adapter should now have the correct property value.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyResetOnReplace) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "BA:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+ initial_adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+ }
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyResetOnReplaceWhenTrue) {
+ const dbus::ObjectPath initial_adapter_path("/fake/hci0");
+ const dbus::ObjectPath new_adapter_path("/fake/hci1");
+ const std::string initial_adapter_address = "CA:FE:4A:C0:FE:FE";
+ const std::string new_adapter_address = "BA:C0:11:CO:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties initial_adapter_properties;
+ initial_adapter_properties.address.ReplaceValue(initial_adapter_address);
+ initial_adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(initial_adapter_path))
+ .WillRepeatedly(Return(&initial_adapter_properties));
+
+ adapter_callback.Run(initial_adapter_path, true);
+
+ // Tell the adapter the default adapter changed;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties new_adapter_properties;
+ new_adapter_properties.address.ReplaceValue(new_adapter_address);
+ new_adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
+ .WillRepeatedly(Return(&new_adapter_properties));
+
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called once
+ // to set the value to false for the previous adapter and once to set the
+ // value to true for the new adapter.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ .Times(1);
+ }
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(),
+ false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(),
+ true))
+ .Times(1);
+ }
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->DefaultAdapterChanged(new_adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_TRUE(adapter->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOsTest,
+ DefaultAdapterDiscoveringPropertyResetOnRemove) {
+ const dbus::ObjectPath adapter_path("/fake/hci0");
+ const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
+
+ // Create the default adapter instance;
+ // BluetoothManagerClient::DefaultAdapter will be called once, passing
+ // a callback to obtain the adapter path.
+ BluetoothManagerClient::AdapterCallback adapter_callback;
+ EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
+ .WillOnce(SaveArg<0>(&adapter_callback));
+
+ scoped_refptr<BluetoothAdapter> adapter =
+ BluetoothAdapterFactory::DefaultAdapter();
+
+ // Call the adapter callback;
+ // BluetoothAdapterClient::GetProperties will be called once to obtain
+ // the property set.
+ MockBluetoothAdapterClient::Properties adapter_properties;
+ adapter_properties.address.ReplaceValue(adapter_address);
+ adapter_properties.discovering.ReplaceValue(true);
+
+ EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
+ .WillRepeatedly(Return(&adapter_properties));
+
+ adapter_callback.Run(adapter_path, true);
+
+ // Report that the adapter has been removed;
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ .Times(1);
+ EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), false))
+ .Times(1);
+
+ BluetoothAdapterChromeOs* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+
+ static_cast<BluetoothManagerClient::Observer*>(adapter_chromeos)
+ ->AdapterRemoved(adapter_path);
+
+ // Adapter should have the new property value.
+ EXPECT_FALSE(adapter->IsDiscovering());
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
new file mode 100644
index 0000000..03d633f
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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_adapter_factory.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+#if defined(OS_CHROMEOS)
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#endif
+
+namespace {
+
+// Shared default adapter instance, we don't want to keep this class around
+// if nobody is using it so use a WeakPtr and create the object when needed;
+// since Google C++ Style (and clang's static analyzer) forbids us having
+// exit-time destructors we use a leaky lazy instance for it.
+base::LazyInstance<base::WeakPtr<device::BluetoothAdapter> >::Leaky
+ default_adapter = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace device {
+
+// static
+scoped_refptr<BluetoothAdapter> BluetoothAdapterFactory::DefaultAdapter() {
+ if (!default_adapter.Get().get()) {
+#if defined(OS_CHROMEOS)
+ chromeos::BluetoothAdapterChromeOs* new_adapter =
+ new chromeos::BluetoothAdapterChromeOs;
+ new_adapter->TrackDefaultAdapter();
+ default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
+#endif
+ }
+
+ return scoped_refptr<BluetoothAdapter>(default_adapter.Get());
+}
+
+// static
+BluetoothAdapter* BluetoothAdapterFactory::Create(const std::string& address) {
+ BluetoothAdapter* adapter = NULL;
+#if defined(OS_CHROMEOS)
+ chromeos::BluetoothAdapterChromeOs* adapter_chromeos =
+ new chromeos::BluetoothAdapterChromeOs;
+ adapter_chromeos->FindAdapter(address);
+ adapter = adapter_chromeos;
+#endif
+ return adapter;
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_factory.h b/device/bluetooth/bluetooth_adapter_factory.h
new file mode 100644
index 0000000..82e1e6f
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_factory.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 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_ADAPTER_FACTORY_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_FACTORY_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+
+namespace device {
+
+class BluetoothAdapter;
+
+// BluetoothAdapterFactory is a class that contains static methods, which
+// instantiate either a specific bluetooth adapter, or the generic "default
+// adapter" which may change depending on availability.
+class BluetoothAdapterFactory {
+ public:
+ // Returns the shared instance for the default adapter, whichever that may
+ // be at the time. Check the returned scoped_refptr does not point to NULL and
+ // use IsPresent() and the AdapterPresentChanged() observer method to
+ // determine whether an adapter is actually available or not.
+ static scoped_refptr<BluetoothAdapter> DefaultAdapter();
+
+ // Creates an instance for a specific adapter at address |address|.
+ static BluetoothAdapter* Create(const std::string& address);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_FACTORY_H_
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc
new file mode 100644
index 0000000..378c6ce
--- /dev/null
+++ b/device/bluetooth/bluetooth_device.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_device.h"
+
+#include "base/utf_string_conversions.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace device {
+
+BluetoothDevice::BluetoothDevice()
+ : bluetooth_class_(0),
+ visible_(false),
+ bonded_(false),
+ connected_(false) {
+}
+
+BluetoothDevice::~BluetoothDevice() {
+}
+
+const std::string& BluetoothDevice::address() const {
+ return address_;
+}
+
+string16 BluetoothDevice::GetName() const {
+ if (!name_.empty()) {
+ return UTF8ToUTF16(name_);
+ } else {
+ return GetAddressWithLocalizedDeviceTypeName();
+ }
+}
+
+string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
+ string16 address = UTF8ToUTF16(address_);
+ BluetoothDevice::DeviceType device_type = GetDeviceType();
+ switch (device_type) {
+ case DEVICE_COMPUTER:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
+ address);
+ case DEVICE_PHONE:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
+ address);
+ case DEVICE_MODEM:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
+ address);
+ case DEVICE_AUDIO:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
+ address);
+ case DEVICE_CAR_AUDIO:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
+ address);
+ case DEVICE_VIDEO:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
+ address);
+ case DEVICE_JOYSTICK:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
+ address);
+ case DEVICE_GAMEPAD:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
+ address);
+ case DEVICE_KEYBOARD:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
+ address);
+ case DEVICE_MOUSE:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
+ address);
+ case DEVICE_TABLET:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
+ address);
+ case DEVICE_KEYBOARD_MOUSE_COMBO:
+ return l10n_util::GetStringFUTF16(
+ IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address);
+ default:
+ return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN, address);
+ }
+}
+
+BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
+ // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
+ switch ((bluetooth_class_ & 0x1f00) >> 8) {
+ case 0x01:
+ // Computer major device class.
+ return DEVICE_COMPUTER;
+ case 0x02:
+ // Phone major device class.
+ switch ((bluetooth_class_ & 0xfc) >> 2) {
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ // Cellular, cordless and smart phones.
+ return DEVICE_PHONE;
+ case 0x04:
+ case 0x05:
+ // Modems: wired or voice gateway and common ISDN access.
+ return DEVICE_MODEM;
+ }
+ break;
+ case 0x04:
+ // Audio major device class.
+ switch ((bluetooth_class_ & 0xfc) >> 2) {
+ case 0x08:
+ // Car audio.
+ return DEVICE_CAR_AUDIO;
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x010:
+ // Video devices.
+ return DEVICE_VIDEO;
+ default:
+ return DEVICE_AUDIO;
+ }
+ break;
+ case 0x05:
+ // Peripheral major device class.
+ switch ((bluetooth_class_ & 0xc0) >> 6) {
+ case 0x00:
+ // "Not a keyboard or pointing device."
+ switch ((bluetooth_class_ & 0x01e) >> 2) {
+ case 0x01:
+ // Joystick.
+ return DEVICE_JOYSTICK;
+ case 0x02:
+ // Gamepad.
+ return DEVICE_GAMEPAD;
+ default:
+ return DEVICE_PERIPHERAL;
+ }
+ break;
+ case 0x01:
+ // Keyboard.
+ return DEVICE_KEYBOARD;
+ case 0x02:
+ // Pointing device.
+ switch ((bluetooth_class_ & 0x01e) >> 2) {
+ case 0x05:
+ // Digitizer tablet.
+ return DEVICE_TABLET;
+ default:
+ // Mouse.
+ return DEVICE_MOUSE;
+ }
+ break;
+ case 0x03:
+ // Combo device.
+ return DEVICE_KEYBOARD_MOUSE_COMBO;
+ }
+ break;
+ }
+
+ return DEVICE_UNKNOWN;
+}
+
+bool BluetoothDevice::IsVisible() const {
+ return visible_;
+}
+
+bool BluetoothDevice::IsBonded() const {
+ return bonded_;
+}
+
+bool BluetoothDevice::IsConnected() const {
+ return connected_;
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
new file mode 100644
index 0000000..90e420b
--- /dev/null
+++ b/device/bluetooth/bluetooth_device.h
@@ -0,0 +1,318 @@
+// Copyright (c) 2012 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_DEVICE_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/string16.h"
+#include "base/memory/ref_counted.h"
+
+namespace device {
+
+class BluetoothServiceRecord;
+class BluetoothSocket;
+
+struct BluetoothOutOfBandPairingData;
+
+// BluetoothDevice represents a remote Bluetooth device, both its properties and
+// capabilities as discovered by a local adapter and actions that may be
+// performed on the remove device such as pairing, connection and disconnection.
+//
+// The class is instantiated and managed by the BluetoothAdapter class
+// and pointers should only be obtained from that class and not cached,
+// instead use the address() method as a unique key for a device.
+//
+// Since the lifecycle of BluetoothDevice instances is managed by
+// BluetoothAdapter, that class rather than this provides observer methods
+// for devices coming and going, as well as properties being updated.
+class BluetoothDevice {
+ public:
+ // 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.
+ enum DeviceType {
+ DEVICE_UNKNOWN,
+ DEVICE_COMPUTER,
+ DEVICE_PHONE,
+ DEVICE_MODEM,
+ DEVICE_AUDIO,
+ DEVICE_CAR_AUDIO,
+ DEVICE_VIDEO,
+ DEVICE_PERIPHERAL,
+ DEVICE_JOYSTICK,
+ DEVICE_GAMEPAD,
+ DEVICE_KEYBOARD,
+ DEVICE_MOUSE,
+ DEVICE_TABLET,
+ DEVICE_KEYBOARD_MOUSE_COMBO
+ };
+
+ // Interface for observing changes from bluetooth devices.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // TODO(keybuk): add observers for pairing and connection.
+ };
+
+ // Interface for negotiating pairing of bluetooth devices.
+ class PairingDelegate {
+ public:
+ virtual ~PairingDelegate() {}
+
+ // This method will be called when the Bluetooth daemon requires a
+ // PIN Code for authentication of the device |device|, the delegate should
+ // obtain the code from the user and call SetPinCode() on the device to
+ // provide it, or RejectPairing() or CancelPairing() to reject or cancel
+ // the request.
+ //
+ // PIN Codes are generally required for Bluetooth 2.0 and earlier devices
+ // for which there is no automatic pairing or special handling.
+ virtual void RequestPinCode(BluetoothDevice* device) = 0;
+
+ // This method will be called when the Bluetooth daemon requires a
+ // Passkey for authentication of the device |device|, the delegate should
+ // obtain the passkey from the user (a numeric in the range 0-999999) and
+ // call SetPasskey() on the device to provide it, or RejectPairing() or
+ // CancelPairing() to reject or cancel the request.
+ //
+ // 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.
+ virtual void RequestPasskey(BluetoothDevice* device) = 0;
+
+ // 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.
+ //
+ // 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
+ // for compatibilty with later specifications.
+ virtual void DisplayPinCode(BluetoothDevice* device,
+ const std::string& pincode) = 0;
+
+ // 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.
+ //
+ // 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
+ // range 0-999999 and should be always presented zero-padded to six
+ // digits.
+ virtual void DisplayPasskey(BluetoothDevice* device,
+ uint32 passkey) = 0;
+
+ // This method will be called when the Bluetooth daemon requires that the
+ // user confirm that the Passkey |passkey| is displayed on the screen
+ // of the device |device| so that it may be authenticated. The delegate
+ // should display to the user and ask for confirmation, then call
+ // ConfirmPairing() on the device to confirm, RejectPairing() on the device
+ // to reject or CancelPairing() on the device to cancel authentication
+ // for any other reason.
+ //
+ // This is used for Bluetooth 2.1 and later devices that support display,
+ // such as other computers or phones. The Passkey is a numeric in the
+ // range 0-999999 and should be always present zero-padded to six
+ // digits.
+ 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;
+ };
+
+ virtual ~BluetoothDevice();
+
+ // Returns the Bluetooth of address the device. This should be used as
+ // a unique key to identify the device and copied where needed.
+ virtual const std::string& address() const;
+
+ // Returns the name of the device suitable for displaying, this may
+ // be a synthesied string containing the address and localized type name
+ // if the device has no obtained name.
+ virtual string16 GetName() const;
+
+ // Returns the type of the device, limited to those we support or are
+ // aware of, by decoding the bluetooth class information. The returned
+ // values are unique, and do not overlap, so DEVICE_KEYBOARD is not also
+ // DEVICE_PERIPHERAL.
+ DeviceType GetDeviceType() const;
+
+ // Indicates whether the device is paired to the adapter, whether or not
+ // that pairing is permanent or temporary.
+ virtual bool IsPaired() const = 0;
+
+ // Indicates whether the device is visible to the adapter, this is not
+ // mutually exclusive to being paired.
+ virtual bool IsVisible() const;
+
+ // Indicates whether the device is bonded to the adapter, bonding is
+ // formed by pairing and exchanging high-security link keys so that
+ // connections may be encrypted.
+ virtual bool IsBonded() const;
+
+ // Indicates whether the device is currently connected to the adapter
+ // and at least one service available for use.
+ virtual bool IsConnected() const;
+
+ // Returns the services (as UUID strings) that this device provides.
+ typedef std::vector<std::string> ServiceList;
+ virtual const ServiceList& GetServices() const = 0;
+
+ // 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;
+
+ // Returns the services (as BluetoothServiceRecord objects) that this device
+ // provides.
+ typedef ScopedVector<BluetoothServiceRecord> ServiceRecordList;
+ typedef base::Callback<void(const ServiceRecordList&)> ServiceRecordsCallback;
+ virtual void GetServiceRecords(const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Indicates whether this device provides the given service. |uuid| should
+ // be in canonical form (see utils::CanonicalUuid).
+ virtual bool ProvidesServiceWithUUID(const std::string& uuid) const = 0;
+
+ // The ProvidesServiceCallback is used by ProvidesServiceWithName to indicate
+ // whether or not a matching service was found.
+ typedef base::Callback<void(bool)> ProvidesServiceCallback;
+
+ // Indicates whether this device provides the given service.
+ virtual void ProvidesServiceWithName(
+ const std::string& name,
+ const ProvidesServiceCallback& callback) = 0;
+
+ // Indicates whether the device is currently pairing and expecting a
+ // PIN Code to be returned.
+ virtual bool ExpectingPinCode() const = 0;
+
+ // Indicates whether the device is currently pairing and expecting a
+ // Passkey to be returned.
+ virtual bool ExpectingPasskey() const = 0;
+
+ // Indicates whether the device is currently pairing and expecting
+ // confirmation of a displayed passkey.
+ virtual bool ExpectingConfirmation() const = 0;
+
+ // SocketCallback is used by ConnectToService to return a BluetoothSocket to
+ // the caller, or NULL if there was an error. The socket will remain open
+ // until the last reference to the returned BluetoothSocket is released.
+ typedef base::Callback<void(scoped_refptr<BluetoothSocket>)>
+ SocketCallback;
+
+ // Initiates a connection to the device, pairing first if necessary.
+ //
+ // Method calls will be made on the supplied object |pairing_delegate|
+ // to indicate what display, and in response should make method calls
+ // back to the device object. Not all devices require user responses
+ // during pairing, so it is normal for |pairing_delegate| to receive no
+ // calls. To explicitly force a low-security connection without bonding,
+ // pass NULL, though this is ignored if the device is already paired.
+ //
+ // If the request fails, |error_callback| will be called; otherwise,
+ // |callback| is called when the request is complete.
+ virtual void Connect(PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // 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.
+ virtual void SetPinCode(const std::string& pincode) = 0;
+
+ // 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.
+ virtual void SetPasskey(uint32 passkey) = 0;
+
+ // Confirms to the remote device during pairing that a passkey provided by
+ // the ConfirmPasskey() delegate call is displayed on both devices.
+ virtual void ConfirmPairing() = 0;
+
+ // Rejects a pairing or connection request from a remote device.
+ virtual void RejectPairing() = 0;
+
+ // Cancels a pairing or connection attempt to a remote device.
+ virtual void CancelPairing() = 0;
+
+ // Disconnects the device, terminating the low-level ACL connection
+ // and any application connections using it. Link keys and other pairing
+ // information are not discarded, and the device object is not deleted.
+ // If the request fails, |error_callback| will be called; otherwise,
+ // |callback| is called when the request is complete.
+ virtual void Disconnect(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Disconnects the device, terminating the low-level ACL connection
+ // and any application connections using it, and then discards link keys
+ // and other pairing information. The device object remainds valid until
+ // returing from the calling function, after which it should be assumed to
+ // have been deleted. If the request fails, |error_callback| will be called.
+ // There is no callback for success beause this object is often deleted
+ // before that callback would be called.
+ virtual void Forget(const ErrorCallback& error_callback) = 0;
+
+ // Attempts to open a socket to a service matching |uuid| on this device. If
+ // the connection is successful, |callback| is called with a BluetoothSocket.
+ // Otherwise |callback| is called with NULL. The socket is closed as soon as
+ // all references to the BluetoothSocket are released. Note that the
+ // BluetoothSocket object can outlive both this BluetoothDevice and the
+ // BluetoothAdapter for this device.
+ virtual void ConnectToService(const std::string& service_uuid,
+ const SocketCallback& callback) = 0;
+
+ // Sets the Out Of Band pairing data for this device to |data|. Exactly one
+ // of |callback| or |error_callback| will be run.
+ virtual void SetOutOfBandPairingData(
+ const BluetoothOutOfBandPairingData& data,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Clears the Out Of Band pairing data for this device. Exactly one of
+ // |callback| or |error_callback| will be run.
+ virtual void ClearOutOfBandPairingData(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ protected:
+ BluetoothDevice();
+
+ // The Bluetooth class of the device, a bitmask that may be decoded using
+ // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
+ uint32 bluetooth_class_;
+
+ // The name of the device, as supplied by the remote device.
+ std::string name_;
+
+ // The Bluetooth address of the device.
+ std::string address_;
+
+ // Tracked device state, updated by the adapter managing the lifecyle of
+ // the device.
+ bool visible_;
+ bool bonded_;
+ bool connected_;
+
+ private:
+ // Returns a localized string containing the device's bluetooth address and
+ // a device type for display when |name_| is empty.
+ string16 GetAddressWithLocalizedDeviceTypeName() const;
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_H_
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc
new file mode 100644
index 0000000..2a09cac
--- /dev/null
+++ b/device/bluetooth/bluetooth_device_chromeos.cc
@@ -0,0 +1,690 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_device_chromeos.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/values.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 "chromeos/dbus/bluetooth_out_of_band_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/introspectable_client.h"
+#include "dbus/bus.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+#include "device/bluetooth/bluetooth_socket_chromeos.h"
+#include "device/bluetooth/bluetooth_utils.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+using device::BluetoothDevice;
+using device::BluetoothOutOfBandPairingData;
+using device::BluetoothServiceRecord;
+using device::BluetoothSocket;
+
+namespace chromeos {
+
+BluetoothDeviceChromeOs::BluetoothDeviceChromeOs(
+ BluetoothAdapterChromeOs* adapter)
+ : BluetoothDevice(),
+ adapter_(adapter),
+ pairing_delegate_(NULL),
+ connecting_applications_counter_(0),
+ weak_ptr_factory_(this) {
+}
+
+BluetoothDeviceChromeOs::~BluetoothDeviceChromeOs() {
+}
+
+bool BluetoothDeviceChromeOs::IsPaired() const {
+ return !object_path_.value().empty();
+}
+
+const BluetoothDevice::ServiceList&
+BluetoothDeviceChromeOs::GetServices() const {
+ return service_uuids_;
+}
+
+void BluetoothDeviceChromeOs::GetServiceRecords(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ DiscoverServices(
+ object_path_,
+ "", // empty pattern to browse all services
+ base::Bind(&BluetoothDeviceChromeOs::CollectServiceRecordsCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+bool BluetoothDeviceChromeOs::ProvidesServiceWithUUID(
+ const std::string& uuid) const {
+ const BluetoothDevice::ServiceList& services = GetServices();
+ for (BluetoothDevice::ServiceList::const_iterator iter = services.begin();
+ iter != services.end();
+ ++iter) {
+ if (device::bluetooth_utils::CanonicalUuid(*iter) == uuid)
+ return true;
+ }
+ return false;
+}
+
+void BluetoothDeviceChromeOs::ProvidesServiceWithName(
+ const std::string& name,
+ const ProvidesServiceCallback& callback) {
+ GetServiceRecords(
+ base::Bind(&BluetoothDeviceChromeOs::SearchServicesForNameCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ name,
+ callback),
+ base::Bind(&BluetoothDeviceChromeOs::SearchServicesForNameErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+}
+
+bool BluetoothDeviceChromeOs::ExpectingPinCode() const {
+ return !pincode_callback_.is_null();
+}
+
+bool BluetoothDeviceChromeOs::ExpectingPasskey() const {
+ return !passkey_callback_.is_null();
+}
+
+bool BluetoothDeviceChromeOs::ExpectingConfirmation() const {
+ return !confirmation_callback_.is_null();
+}
+
+void BluetoothDeviceChromeOs::Connect(PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (IsPaired() || IsBonded() || IsConnected()) {
+ // Connection to already paired or connected device.
+ ConnectApplications(callback, error_callback);
+
+ } else if (!pairing_delegate) {
+ // No pairing delegate supplied, initiate low-security connection only.
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ CreateDevice(adapter_->object_path_,
+ address_,
+ base::Bind(&BluetoothDeviceChromeOs::ConnectCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback),
+ base::Bind(&BluetoothDeviceChromeOs::ConnectErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback));
+ } else {
+ // Initiate high-security connection with pairing.
+ DCHECK(!pairing_delegate_);
+ pairing_delegate_ = pairing_delegate;
+
+ // The agent path is relatively meaningless, we use the device address
+ // to generate it as we only support one pairing attempt at a time for
+ // a given bluetooth device.
+ DCHECK(agent_.get() == NULL);
+
+ std::string agent_path_basename;
+ ReplaceChars(address_, ":", "_", &agent_path_basename);
+ dbus::ObjectPath agent_path("/org/chromium/bluetooth_agent/" +
+ agent_path_basename);
+
+ dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
+ if (system_bus) {
+ agent_.reset(BluetoothAgentServiceProvider::Create(system_bus,
+ agent_path,
+ this));
+ } else {
+ agent_.reset(NULL);
+ }
+
+ DVLOG(1) << "Pairing: " << address_;
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ CreatePairedDevice(
+ adapter_->object_path_,
+ address_,
+ agent_path,
+ bluetooth_agent::kDisplayYesNoCapability,
+ base::Bind(&BluetoothDeviceChromeOs::ConnectCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback),
+ base::Bind(&BluetoothDeviceChromeOs::ConnectErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback));
+ }
+}
+
+void BluetoothDeviceChromeOs::SetPinCode(const std::string& pincode) {
+ if (!agent_.get() || pincode_callback_.is_null())
+ return;
+
+ pincode_callback_.Run(SUCCESS, pincode);
+ pincode_callback_.Reset();
+}
+
+void BluetoothDeviceChromeOs::SetPasskey(uint32 passkey) {
+ if (!agent_.get() || passkey_callback_.is_null())
+ return;
+
+ passkey_callback_.Run(SUCCESS, passkey);
+ passkey_callback_.Reset();
+}
+
+void BluetoothDeviceChromeOs::ConfirmPairing() {
+ if (!agent_.get() || confirmation_callback_.is_null())
+ return;
+
+ confirmation_callback_.Run(SUCCESS);
+ confirmation_callback_.Reset();
+}
+
+void BluetoothDeviceChromeOs::RejectPairing() {
+ if (!agent_.get())
+ return;
+
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(REJECTED, "");
+ pincode_callback_.Reset();
+ }
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(REJECTED, 0);
+ passkey_callback_.Reset();
+ }
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(REJECTED);
+ confirmation_callback_.Reset();
+ }
+}
+
+void BluetoothDeviceChromeOs::CancelPairing() {
+ if (!agent_.get())
+ return;
+
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(CANCELLED, "");
+ pincode_callback_.Reset();
+ }
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(CANCELLED, 0);
+ passkey_callback_.Reset();
+ }
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(CANCELLED);
+ confirmation_callback_.Reset();
+ }
+}
+
+void BluetoothDeviceChromeOs::Disconnect(const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ Disconnect(object_path_,
+ base::Bind(&BluetoothDeviceChromeOs::DisconnectCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+
+}
+
+void BluetoothDeviceChromeOs::Forget(const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ RemoveDevice(adapter_->object_path_,
+ object_path_,
+ base::Bind(&BluetoothDeviceChromeOs::ForgetCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback));
+}
+
+void BluetoothDeviceChromeOs::ConnectToService(const std::string& service_uuid,
+ const SocketCallback& callback) {
+ GetServiceRecords(
+ base::Bind(&BluetoothDeviceChromeOs::GetServiceRecordsForConnectCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ service_uuid,
+ callback),
+ base::Bind(
+ &BluetoothDeviceChromeOs::GetServiceRecordsForConnectErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+}
+
+void BluetoothDeviceChromeOs::SetOutOfBandPairingData(
+ const BluetoothOutOfBandPairingData& data,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
+ AddRemoteData(
+ object_path_,
+ address(),
+ data,
+ base::Bind(&BluetoothDeviceChromeOs::OnRemoteDataCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+void BluetoothDeviceChromeOs::ClearOutOfBandPairingData(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
+ RemoveRemoteData(
+ object_path_,
+ address(),
+ base::Bind(&BluetoothDeviceChromeOs::OnRemoteDataCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+void BluetoothDeviceChromeOs::SetObjectPath(
+ const dbus::ObjectPath& object_path) {
+ DCHECK(object_path_ == dbus::ObjectPath(""));
+ object_path_ = object_path;
+}
+
+void BluetoothDeviceChromeOs::RemoveObjectPath() {
+ DCHECK(object_path_ != dbus::ObjectPath(""));
+ object_path_ = dbus::ObjectPath("");
+}
+
+void BluetoothDeviceChromeOs::Update(
+ const BluetoothDeviceClient::Properties* properties,
+ bool update_state) {
+ std::string address = properties->address.value();
+ std::string name = properties->name.value();
+ uint32 bluetooth_class = properties->bluetooth_class.value();
+ const std::vector<std::string>& uuids = properties->uuids.value();
+
+ if (!address.empty())
+ address_ = address;
+ if (!name.empty())
+ name_ = name;
+ if (bluetooth_class)
+ bluetooth_class_ = bluetooth_class;
+ if (!uuids.empty()) {
+ service_uuids_.clear();
+ service_uuids_.assign(uuids.begin(), uuids.end());
+ }
+
+ if (update_state) {
+ // BlueZ uses paired to mean link keys exchanged, whereas the Bluetooth
+ // spec refers to this as bonded. Use the spec name for our interface.
+ bonded_ = properties->paired.value();
+ connected_ = properties->connected.value();
+ }
+}
+
+void BluetoothDeviceChromeOs::ConnectCallback(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path) {
+ DVLOG(1) << "Connection successful: " << device_path.value();
+ if (object_path_.value().empty()) {
+ object_path_ = device_path;
+ } else {
+ LOG_IF(WARNING, object_path_ != device_path)
+ << "Conflicting device paths for objects, result gave: "
+ << device_path.value() << " but signal gave: "
+ << object_path_.value();
+ }
+
+ // Mark the device trusted so it can connect to us automatically, and
+ // we can connect after rebooting. This information is part of the
+ // pairing information of the device, and is unique to the combination
+ // of our bluetooth address and the device's bluetooth address. A
+ // different host needs a new pairing, so it's not useful to sync.
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->
+ GetProperties(object_path_)->trusted.Set(
+ true,
+ base::Bind(&BluetoothDeviceChromeOs::OnSetTrusted,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+
+ // Connect application-layer protocols.
+ ConnectApplications(callback, error_callback);
+}
+
+void BluetoothDeviceChromeOs::ConnectErrorCallback(
+ const ErrorCallback& error_callback,
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << "Connection failed: " << address_
+ << ": " << error_name << ": " << error_message;
+ error_callback.Run();
+}
+
+void BluetoothDeviceChromeOs::CollectServiceRecordsCallback(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path,
+ const BluetoothDeviceClient::ServiceMap& service_map,
+ bool success) {
+ if (!success) {
+ error_callback.Run();
+ return;
+ }
+
+ ScopedVector<BluetoothServiceRecord> records;
+ for (BluetoothDeviceClient::ServiceMap::const_iterator i =
+ service_map.begin(); i != service_map.end(); ++i) {
+ records.push_back(
+ new BluetoothServiceRecord(address(), i->second));
+ }
+ callback.Run(records);
+}
+
+void BluetoothDeviceChromeOs::OnSetTrusted(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success) {
+ if (success) {
+ callback.Run();
+ } else {
+ LOG(WARNING) << "Failed to set device as trusted: " << address_;
+ error_callback.Run();
+ }
+}
+
+void BluetoothDeviceChromeOs::ConnectApplications(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ // Introspect the device object to determine supported applications.
+ DBusThreadManager::Get()->GetIntrospectableClient()->
+ Introspect(bluetooth_device::kBluetoothDeviceServiceName,
+ object_path_,
+ base::Bind(&BluetoothDeviceChromeOs::OnIntrospect,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+}
+
+void BluetoothDeviceChromeOs::OnIntrospect(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const std::string& service_name,
+ const dbus::ObjectPath& device_path,
+ const std::string& xml_data,
+ bool success) {
+ if (!success) {
+ LOG(WARNING) << "Failed to determine supported applications: " << address_;
+ error_callback.Run();
+ return;
+ }
+
+ // The introspection data for the device object may list one or more
+ // additional D-Bus interfaces that BlueZ supports for this particular
+ // device. Send appropraite Connect calls for each of those interfaces
+ // to connect all of the application protocols for this device.
+ std::vector<std::string> interfaces =
+ IntrospectableClient::GetInterfacesFromIntrospectResult(xml_data);
+
+ DCHECK_EQ(0, connecting_applications_counter_);
+ connecting_applications_counter_ = 0;
+ for (std::vector<std::string>::iterator iter = interfaces.begin();
+ iter != interfaces.end(); ++iter) {
+ if (*iter == bluetooth_input::kBluetoothInputInterface) {
+ connecting_applications_counter_++;
+ // Supports Input interface.
+ DBusThreadManager::Get()->GetBluetoothInputClient()->
+ Connect(object_path_,
+ base::Bind(&BluetoothDeviceChromeOs::OnConnect,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ *iter),
+ base::Bind(&BluetoothDeviceChromeOs::OnConnectError,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback, *iter));
+ }
+ }
+
+ // If OnConnect has been called for every call to Connect above, then this
+ // will decrement the counter to -1. In that case, call the callback
+ // directly as it has not been called by any of the OnConnect callbacks.
+ // This is safe because OnIntrospect and OnConnect run on the same thread.
+ connecting_applications_counter_--;
+ if (connecting_applications_counter_ == -1)
+ callback.Run();
+}
+
+void BluetoothDeviceChromeOs::OnConnect(const base::Closure& callback,
+ const std::string& interface_name,
+ const dbus::ObjectPath& device_path) {
+ DVLOG(1) << "Application connection successful: " << device_path.value()
+ << ": " << interface_name;
+
+ connecting_applications_counter_--;
+ // |callback| should only be called once, meaning it cannot be called before
+ // all requests have been started. The extra decrement after all requests
+ // have been started, and the check for -1 instead of 0 below, insure only a
+ // single call to |callback| will occur (provided OnConnect and OnIntrospect
+ // run on the same thread, which is true).
+ if (connecting_applications_counter_ == -1) {
+ connecting_applications_counter_ = 0;
+ callback.Run();
+ }
+}
+
+void BluetoothDeviceChromeOs::OnConnectError(
+ const ErrorCallback& error_callback,
+ const std::string& interface_name,
+ const dbus::ObjectPath& device_path,
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << "Connection failed: " << address_ << ": " << interface_name
+ << ": " << error_name << ": " << error_message;
+ error_callback.Run();
+}
+
+void BluetoothDeviceChromeOs::DisconnectCallback(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path,
+ bool success) {
+ DCHECK(device_path == object_path_);
+ if (success) {
+ DVLOG(1) << "Disconnection successful: " << address_;
+ callback.Run();
+ } else {
+ LOG(WARNING) << "Disconnection failed: " << address_;
+ error_callback.Run();
+ }
+}
+
+void BluetoothDeviceChromeOs::ForgetCallback(
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path,
+ bool success) {
+ // It's quite normal that this path never gets called on success; we use a
+ // weak pointer, and bluetoothd might send the DeviceRemoved signal before
+ // the method reply, in which case this object is deleted and the
+ // callback never takes place. Therefore don't do anything here for the
+ // success case.
+ if (!success) {
+ LOG(WARNING) << "Forget failed: " << address_;
+ error_callback.Run();
+ }
+}
+
+void BluetoothDeviceChromeOs::SearchServicesForNameErrorCallback(
+ const ProvidesServiceCallback& callback) {
+ callback.Run(false);
+}
+
+void BluetoothDeviceChromeOs::SearchServicesForNameCallback(
+ const std::string& name,
+ const ProvidesServiceCallback& callback,
+ const ServiceRecordList& list) {
+ for (ServiceRecordList::const_iterator i = list.begin();
+ i != list.end(); ++i) {
+ if ((*i)->name() == name) {
+ callback.Run(true);
+ return;
+ }
+ }
+ callback.Run(false);
+}
+
+void BluetoothDeviceChromeOs::GetServiceRecordsForConnectErrorCallback(
+ const SocketCallback& callback) {
+ callback.Run(NULL);
+}
+
+void BluetoothDeviceChromeOs::GetServiceRecordsForConnectCallback(
+ const std::string& service_uuid,
+ const SocketCallback& callback,
+ const ServiceRecordList& list) {
+ for (ServiceRecordList::const_iterator i = list.begin();
+ i != list.end(); ++i) {
+ if ((*i)->uuid() == service_uuid) {
+ // If multiple service records are found, use the first one that works.
+ scoped_refptr<BluetoothSocket> socket(
+ BluetoothSocketChromeOs::CreateBluetoothSocket(**i));
+ if (socket.get() != NULL) {
+ callback.Run(socket);
+ return;
+ }
+ }
+ }
+ callback.Run(NULL);
+}
+
+void BluetoothDeviceChromeOs::OnRemoteDataCallback(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success) {
+ if (success)
+ callback.Run();
+ else
+ error_callback.Run();
+}
+
+void BluetoothDeviceChromeOs::DisconnectRequested(
+ const dbus::ObjectPath& object_path) {
+ DCHECK(object_path == object_path_);
+}
+
+void BluetoothDeviceChromeOs::Release() {
+ DCHECK(agent_.get());
+ DVLOG(1) << "Release: " << address_;
+
+ DCHECK(pairing_delegate_);
+ pairing_delegate_->DismissDisplayOrConfirm();
+ pairing_delegate_ = NULL;
+
+ pincode_callback_.Reset();
+ passkey_callback_.Reset();
+ confirmation_callback_.Reset();
+
+ agent_.reset();
+}
+
+void BluetoothDeviceChromeOs::RequestPinCode(
+ const dbus::ObjectPath& device_path,
+ const PinCodeCallback& callback) {
+ DCHECK(agent_.get());
+ DVLOG(1) << "RequestPinCode: " << device_path.value();
+
+ DCHECK(pairing_delegate_);
+ DCHECK(pincode_callback_.is_null());
+ pincode_callback_ = callback;
+ pairing_delegate_->RequestPinCode(this);
+}
+
+void BluetoothDeviceChromeOs::RequestPasskey(
+ const dbus::ObjectPath& device_path,
+ const PasskeyCallback& callback) {
+ DCHECK(agent_.get());
+ DCHECK(device_path == object_path_);
+ DVLOG(1) << "RequestPasskey: " << device_path.value();
+
+ DCHECK(pairing_delegate_);
+ DCHECK(passkey_callback_.is_null());
+ passkey_callback_ = callback;
+ pairing_delegate_->RequestPasskey(this);
+}
+
+void BluetoothDeviceChromeOs::DisplayPinCode(
+ const dbus::ObjectPath& device_path,
+ const std::string& pincode) {
+ DCHECK(agent_.get());
+ DCHECK(device_path == object_path_);
+ DVLOG(1) << "DisplayPinCode: " << device_path.value() << " " << pincode;
+
+ DCHECK(pairing_delegate_);
+ pairing_delegate_->DisplayPinCode(this, pincode);
+}
+
+void BluetoothDeviceChromeOs::DisplayPasskey(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey) {
+ DCHECK(agent_.get());
+ DCHECK(device_path == object_path_);
+ DVLOG(1) << "DisplayPasskey: " << device_path.value() << " " << passkey;
+
+ DCHECK(pairing_delegate_);
+ pairing_delegate_->DisplayPasskey(this, passkey);
+}
+
+void BluetoothDeviceChromeOs::RequestConfirmation(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ DCHECK(device_path == object_path_);
+ DVLOG(1) << "RequestConfirmation: " << device_path.value() << " " << passkey;
+
+ DCHECK(pairing_delegate_);
+ DCHECK(confirmation_callback_.is_null());
+ confirmation_callback_ = callback;
+ pairing_delegate_->ConfirmPasskey(this, passkey);
+}
+
+void BluetoothDeviceChromeOs::Authorize(const dbus::ObjectPath& device_path,
+ const std::string& uuid,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ DCHECK(device_path == object_path_);
+ LOG(WARNING) << "Rejected authorization for service: " << uuid
+ << " requested from device: " << device_path.value();
+ callback.Run(REJECTED);
+}
+
+void BluetoothDeviceChromeOs::ConfirmModeChange(
+ Mode mode,
+ const ConfirmationCallback& callback) {
+ DCHECK(agent_.get());
+ LOG(WARNING) << "Rejected adapter-level mode change: " << mode
+ << " made on agent for device: " << address_;
+ callback.Run(REJECTED);
+}
+
+void BluetoothDeviceChromeOs::Cancel() {
+ DCHECK(agent_.get());
+ DVLOG(1) << "Cancel: " << address_;
+
+ DCHECK(pairing_delegate_);
+ pairing_delegate_->DismissDisplayOrConfirm();
+}
+
+
+// static
+BluetoothDeviceChromeOs* BluetoothDeviceChromeOs::Create(
+ BluetoothAdapterChromeOs* adapter) {
+ return new BluetoothDeviceChromeOs(adapter);
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_device_chromeos.h b/device/bluetooth/bluetooth_device_chromeos.h
new file mode 100644
index 0000000..4b2d3b5
--- /dev/null
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -0,0 +1,375 @@
+// Copyright (c) 2012 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_DEVICE_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_CHROMEOS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/string16.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"
+
+namespace device {
+
+class BluetoothServiceRecord;
+class MockBluetoothDevice;
+struct BluetoothOutOfBandPairingData;
+
+} // namespace device
+
+namespace chromeos {
+
+class BluetoothAdapterChromeOs;
+
+// The BluetoothDeviceChromeOs class is an implementation of BluetoothDevice
+// for Chrome OS platform.
+class BluetoothDeviceChromeOs
+ : public device::BluetoothDevice,
+ public BluetoothDeviceClient::Observer,
+ public BluetoothAgentServiceProvider::Delegate {
+ public:
+ virtual ~BluetoothDeviceChromeOs();
+
+ // BluetoothDevice override
+ virtual bool IsPaired() const OVERRIDE;
+ virtual const ServiceList& GetServices() const OVERRIDE;
+ virtual void GetServiceRecords(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual bool ProvidesServiceWithUUID(const std::string& uuid) const OVERRIDE;
+ virtual void ProvidesServiceWithName(
+ const std::string& name,
+ const ProvidesServiceCallback& callback) OVERRIDE;
+ virtual bool ExpectingPinCode() const OVERRIDE;
+ virtual bool ExpectingPasskey() const OVERRIDE;
+ virtual bool ExpectingConfirmation() const OVERRIDE;
+ virtual void Connect(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void SetPinCode(const std::string& pincode) OVERRIDE;
+ virtual void SetPasskey(uint32 passkey) OVERRIDE;
+ virtual void ConfirmPairing() OVERRIDE;
+ virtual void RejectPairing() OVERRIDE;
+ virtual void CancelPairing() OVERRIDE;
+ virtual void Disconnect(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void Forget(const ErrorCallback& error_callback) OVERRIDE;
+ virtual void ConnectToService(
+ const std::string& service_uuid,
+ const SocketCallback& callback) OVERRIDE;
+ virtual void SetOutOfBandPairingData(
+ const device::BluetoothOutOfBandPairingData& data,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void ClearOutOfBandPairingData(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
+ private:
+ friend class BluetoothAdapterChromeOs;
+ friend class device::MockBluetoothDevice;
+
+ explicit BluetoothDeviceChromeOs(BluetoothAdapterChromeOs* adapter);
+
+ // Sets the dbus object path for the device to |object_path|, indicating
+ // that the device has gone from being discovered to paired or bonded.
+ void SetObjectPath(const dbus::ObjectPath& object_path);
+
+ // Removes the dbus object path from the device, indicating that the
+ // device is no longer paired or bonded, but perhaps still visible.
+ void RemoveObjectPath();
+
+ // Sets whether the device is visible to the owning adapter to |visible|.
+ void SetVisible(bool visible) { visible_ = visible; }
+
+ // Updates device information from the properties in |properties|, device
+ // state properties such as |paired_| and |connected_| are ignored unless
+ // |update_state| is true.
+ void Update(const BluetoothDeviceClient::Properties* properties,
+ bool update_state);
+
+ // Called by BluetoothAdapterClient when a call to CreateDevice() or
+ // CreatePairedDevice() succeeds, provides the new object path for the remote
+ // device in |device_path|. |callback| and |error_callback| are the callbacks
+ // provided to Connect().
+ void ConnectCallback(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path);
+
+ // Called by BluetoothAdapterClient when a call to CreateDevice() or
+ // CreatePairedDevice() fails with the error named |error_name| and
+ // optional message |error_message|, |error_callback| is the callback
+ // provided to Connect().
+ void ConnectErrorCallback(const ErrorCallback& error_callback,
+ const std::string& error_name,
+ const std::string& error_message);
+
+ // Called by BluetoothAdapterClient when a call to DiscoverServices()
+ // completes. |callback| and |error_callback| are the callbacks provided to
+ // GetServiceRecords.
+ void CollectServiceRecordsCallback(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path,
+ const BluetoothDeviceClient::ServiceMap& service_map,
+ bool success);
+
+ // Called by BluetoothProperty when the call to Set() for the Trusted
+ // property completes. |success| indicates whether or not the request
+ // succeeded, |callback| and |error_callback| are the callbacks provided to
+ // Connect().
+ void OnSetTrusted(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success);
+
+ // Connect application-level protocols of the device to the system, called
+ // on a successful connection or to reconnect to a device that is already
+ // paired or previously connected. |error_callback| is called on failure.
+ // Otherwise, |callback| is called when the request is complete.
+ void ConnectApplications(const base::Closure& callback,
+ const ErrorCallback& error_callback);
+
+ // Called by IntrospectableClient when a call to Introspect() completes.
+ // |success| indicates whether or not the request succeeded, |callback| and
+ // |error_callback| are the callbacks provided to ConnectApplications(),
+ // |service_name| and |device_path| specify the remote object being
+ // introspected and |xml_data| contains the XML-formatted protocol data.
+ void OnIntrospect(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const std::string& service_name,
+ const dbus::ObjectPath& device_path,
+ const std::string& xml_data, bool success);
+
+ // Called by BluetoothInputClient when the call to Connect() succeeds.
+ // |error_callback| is the callback provided to ConnectApplications(),
+ // |interface_name| specifies the interface being connected and
+ // |device_path| the remote object path.
+ void OnConnect(const base::Closure& callback,
+ const std::string& interface_name,
+ const dbus::ObjectPath& device_path);
+
+ // Called by BluetoothInputClient when the call to Connect() fails.
+ // |error_callback| is the callback provided to ConnectApplications(),
+ // |interface_name| specifies the interface being connected,
+ // |device_path| the remote object path,
+ // |error_name| the error name and |error_message| the optional message.
+ void OnConnectError(const ErrorCallback& error_callback,
+ const std::string& interface_name,
+ const dbus::ObjectPath& device_path,
+ const std::string& error_name,
+ const std::string& error_message);
+
+ // Called by BluetoothDeviceClient when a call to Disconnect() completes,
+ // |success| indicates whether or not the request succeeded, |callback| and
+ // |error_callback| are the callbacks provided to Disconnect() and
+ // |device_path| is the device disconnected.
+ void DisconnectCallback(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ const dbus::ObjectPath& device_path, bool success);
+
+ // Called by BluetoothAdapterClient when a call to RemoveDevice()
+ // completes, |success| indicates whether or not the request succeeded,
+ // |error_callback| is the callback provided to Forget() and |adapter_path| is
+ // the d-bus object path of the adapter that performed the removal.
+ void ForgetCallback(const ErrorCallback& error_callback,
+ const dbus::ObjectPath& adapter_path, bool success);
+
+ // Called if the call to GetServiceRecords from ProvidesServiceWithName fails.
+ void SearchServicesForNameErrorCallback(
+ const ProvidesServiceCallback& callback);
+
+ // Called by GetServiceRecords with the list of BluetoothServiceRecords to
+ // search for |name|. |callback| is the callback from
+ // ProvidesServiceWithName.
+ void SearchServicesForNameCallback(
+ const std::string& name,
+ const ProvidesServiceCallback& callback,
+ const ServiceRecordList& list);
+
+ // Called if the call to GetServiceRecords from Connect fails.
+ void GetServiceRecordsForConnectErrorCallback(
+ const SocketCallback& callback);
+
+ // Called by GetServiceRecords with the list of BluetoothServiceRecords.
+ // Connections are attempted to each service in the list matching
+ // |service_uuid|, and the socket from the first successful connection is
+ // passed to |callback|.
+ void GetServiceRecordsForConnectCallback(
+ const std::string& service_uuid,
+ const SocketCallback& callback,
+ const ServiceRecordList& list);
+
+ // Called by BlueoothDeviceClient in response to the AddRemoteData and
+ // RemoveRemoteData method calls.
+ void OnRemoteDataCallback(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success);
+
+ // BluetoothDeviceClient::Observer override.
+ //
+ // Called when the device with object path |object_path| is about
+ // to be disconnected, giving a chance for application layers to
+ // shut down cleanly.
+ virtual void DisconnectRequested(
+ const dbus::ObjectPath& object_path) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the agent is unregistered from the
+ // Bluetooth daemon, generally at the end of a pairing request. It may be
+ // used to perform cleanup tasks.
+ virtual void Release() OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires a
+ // PIN Code for authentication of the device with object path |device_path|,
+ // the agent should obtain the code from the user and call |callback|
+ // to provide it, or indicate rejection or cancellation of the request.
+ //
+ // PIN Codes are generally required for Bluetooth 2.0 and earlier devices
+ // for which there is no automatic pairing or special handling.
+ virtual void RequestPinCode(const dbus::ObjectPath& device_path,
+ const PinCodeCallback& callback) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires a
+ // Passkey for authentication of the device with object path |device_path|,
+ // the agent should obtain the passkey from the user (a numeric in the
+ // range 0-999999) and call |callback| to provide it, or indicate
+ // rejection or cancellation of the request.
+ //
+ // 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.
+ virtual void RequestPasskey(const dbus::ObjectPath& device_path,
+ const PasskeyCallback& callback) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires that the
+ // user enter the PIN code |pincode| into the device with object path
+ // |device_path| so that it may be authenticated. The Cancel() method
+ // will be called to dismiss the display once pairing is complete or
+ // cancelled.
+ //
+ // 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
+ // for compatibilty with later specifications.
+ virtual void DisplayPinCode(const dbus::ObjectPath& device_path,
+ const std::string& pincode) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires that the
+ // user enter the Passkey |passkey| into the device with object path
+ // |device_path| so that it may be authenticated. The Cancel() method
+ // will be called to dismiss the display once pairing is complete or
+ // cancelled.
+ //
+ // 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
+ // range 0-999999 and should be always presented zero-padded to six
+ // digits.
+ virtual void DisplayPasskey(const dbus::ObjectPath& device_path,
+ uint32 passkey) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires that the
+ // user confirm that the Passkey |passkey| is displayed on the screen
+ // of the device with object path |object_path| so that it may be
+ // authentication. The agent should display to the user and ask for
+ // confirmation, then call |callback| to provide their response (success,
+ // rejected or cancelled).
+ //
+ // This is used for Bluetooth 2.1 and later devices that support display,
+ // such as other computers or phones. The Passkey is a numeric in the
+ // range 0-999999 and should be always present zero-padded to six
+ // digits.
+ virtual void RequestConfirmation(
+ const dbus::ObjectPath& device_path,
+ uint32 passkey,
+ const ConfirmationCallback& callback) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires that the
+ // user confirm that the device with object path |object_path| is
+ // authorized to connect to the service with UUID |uuid|. The agent should
+ // confirm with the user and call |callback| to provide their response
+ // (success, rejected or cancelled).
+ virtual void Authorize(const dbus::ObjectPath& device_path,
+ const std::string& uuid,
+ const ConfirmationCallback& callback) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called when the Bluetooth daemon requires that the
+ // user confirm that the device adapter may switch to mode |mode|. The
+ // agent should confirm with the user and call |callback| to provide
+ // their response (success, rejected or cancelled).
+ virtual void ConfirmModeChange(Mode mode,
+ const ConfirmationCallback& callback) OVERRIDE;
+
+ // BluetoothAgentServiceProvider::Delegate override.
+ //
+ // This method will be called by the Bluetooth daemon to indicate that
+ // the request failed before a reply was returned from the device.
+ virtual void Cancel() OVERRIDE;
+
+ // Creates a new BluetoothDeviceChromeOs object bound to the adapter
+ // |adapter|.
+ static BluetoothDeviceChromeOs* Create(BluetoothAdapterChromeOs* adapter);
+
+ // The adapter that owns this device instance.
+ BluetoothAdapterChromeOs* adapter_;
+
+ // The dbus object path of the device, will be empty if the device has only
+ // been discovered and not yet paired with.
+ dbus::ObjectPath object_path_;
+
+ // The services (identified by UUIDs) that this device provides.
+ std::vector<std::string> service_uuids_;
+
+ // 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.
+ device::BluetoothDevice::PairingDelegate* pairing_delegate_;
+
+ // 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_;
+
+ // Used to keep track of pending application connection requests.
+ int connecting_applications_counter_;
+
+ // 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<BluetoothDeviceChromeOs> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceChromeOs);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_out_of_band_pairing_data.h b/device/bluetooth/bluetooth_out_of_band_pairing_data.h
new file mode 100644
index 0000000..1b45bb0
--- /dev/null
+++ b/device/bluetooth/bluetooth_out_of_band_pairing_data.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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_OUT_OF_BAND_PAIRING_DATA_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_OUT_OF_BAND_PAIRING_DATA_H_
+
+#include "base/basictypes.h"
+
+namespace device {
+
+const size_t kBluetoothOutOfBandPairingDataSize = 16;
+
+// A simple structure representing the data required to perform Out Of Band
+// Pairing. See
+// http://mclean-linsky.net/joel/cv/Simple%20Pairing_WP_V10r00.pdf
+struct BluetoothOutOfBandPairingData {
+ // Simple Pairing Hash C.
+ uint8 hash[kBluetoothOutOfBandPairingDataSize];
+
+ // Simple Pairing Randomizer R.
+ uint8 randomizer[kBluetoothOutOfBandPairingDataSize];
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_OUT_OF_BAND_PAIRING_DATA_H_
diff --git a/device/bluetooth/bluetooth_service_record.cc b/device/bluetooth/bluetooth_service_record.cc
new file mode 100644
index 0000000..0ea18d7
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 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_service_record.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "device/bluetooth/bluetooth_utils.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+
+namespace {
+
+static const char* kAttributeNode = "attribute";
+static const char* kIdAttribute = "id";
+static const char* kProtocolDescriptorListId = "0x0004";
+static const char* kRfcommUuid = "0x0003";
+static const char* kSdpNameId = "0x0100";
+static const char* kSequenceNode = "sequence";
+static const char* kTextNode = "text";
+static const char* kUint8Node = "uint8";
+static const char* kUuidId = "0x0001";
+static const char* kUuidNode = "uuid";
+static const char* kValueAttribute = "value";
+
+bool AdvanceToTag(XmlReader* reader, const char* node_type) {
+ do {
+ if (!reader->Read())
+ return false;
+ } while (reader->NodeName() != node_type);
+ return true;
+}
+
+bool ExtractTextValue(XmlReader* reader, std::string* value_out) {
+ if (AdvanceToTag(reader, kTextNode)) {
+ reader->NodeAttribute(kValueAttribute, value_out);
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+namespace device {
+
+BluetoothServiceRecord::BluetoothServiceRecord(
+ const std::string& address,
+ const std::string& xml_data)
+ : address_(address),
+ supports_rfcomm_(false) {
+
+ XmlReader reader;
+ if (!reader.Load(xml_data))
+ return;
+
+ while (AdvanceToTag(&reader, kAttributeNode)) {
+ std::string id;
+ if (reader.NodeAttribute(kIdAttribute, &id)) {
+ if (id == kSdpNameId) {
+ ExtractTextValue(&reader, &name_);
+ } else if (id == kProtocolDescriptorListId) {
+ if (AdvanceToTag(&reader, kSequenceNode)) {
+ ExtractChannels(&reader);
+ }
+ } else if (id == kUuidId) {
+ if (AdvanceToTag(&reader, kSequenceNode)) {
+ ExtractUuid(&reader);
+ }
+ }
+ }
+ // We don't care about anything else here, so find the closing tag
+ AdvanceToTag(&reader, kAttributeNode);
+ }
+}
+
+void BluetoothServiceRecord::ExtractChannels(XmlReader* reader) {
+ const int start_depth = reader->Depth();
+ do {
+ if (reader->NodeName() == kSequenceNode) {
+ if (AdvanceToTag(reader, kUuidNode)) {
+ std::string type;
+ if (reader->NodeAttribute(kValueAttribute, &type) &&
+ type == kRfcommUuid) {
+ if (AdvanceToTag(reader, kUint8Node)) {
+ std::string channel_string;
+ if (reader->NodeAttribute(kValueAttribute, &channel_string)) {
+ std::vector<uint8> channel_bytes;
+ if (base::HexStringToBytes(channel_string.substr(2),
+ &channel_bytes)) {
+ if (channel_bytes.size() == 1) {
+ rfcomm_channel_ = channel_bytes[0];
+ supports_rfcomm_ = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (AdvanceToTag(reader, kSequenceNode) &&
+ reader->Depth() != start_depth);
+}
+
+void BluetoothServiceRecord::ExtractUuid(XmlReader* reader) {
+ const int start_depth = reader->Depth();
+ do {
+ if (reader->NodeName() == kSequenceNode) {
+ if (AdvanceToTag(reader, kUuidNode)) {
+ if (!reader->NodeAttribute(kValueAttribute, &uuid_))
+ uuid_.clear();
+ }
+ }
+ } while (AdvanceToTag(reader, kSequenceNode) &&
+ reader->Depth() != start_depth);
+
+ uuid_ = device::bluetooth_utils::CanonicalUuid(uuid_);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_service_record.h b/device/bluetooth/bluetooth_service_record.h
new file mode 100644
index 0000000..e04d73a
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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_SERVICE_RECORD_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class XmlReader;
+
+namespace device {
+
+// BluetoothServiceRecord represents an SDP service record.
+//
+// This implementation is currently incomplete: it only supports those fields
+// that have been necessary so far.
+class BluetoothServiceRecord {
+ public:
+ BluetoothServiceRecord(
+ const std::string& address,
+ const std::string& xml_data);
+
+ // The human-readable name of this service.
+ const std::string& name() const { return name_; }
+
+ // The address of the BluetoothDevice providing this service.
+ const std::string& address() const { return address_; }
+
+ // The UUID of the service. This field may be empty if no UUID was
+ // specified in the service record.
+ const std::string& uuid() const { return uuid_; }
+
+ // Indicates if this service supports RFCOMM communication.
+ bool SupportsRfcomm() const { return supports_rfcomm_; }
+
+ // The RFCOMM channel to use, if this service supports RFCOMM communication.
+ // The return value is undefined if SupportsRfcomm() returns false.
+ uint8 rfcomm_channel() const { return rfcomm_channel_; }
+
+ private:
+ void ExtractChannels(XmlReader* reader);
+ void ExtractUuid(XmlReader* reader);
+
+ std::string address_;
+ std::string name_;
+ std::string uuid_;
+
+ bool supports_rfcomm_;
+ uint8 rfcomm_channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecord);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_H_
diff --git a/device/bluetooth/bluetooth_service_record_unittest.cc b/device/bluetooth/bluetooth_service_record_unittest.cc
new file mode 100644
index 0000000..b59474f5
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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 "base/base_paths.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const char* kAddress = "01:02:03:04:05:06";
+static const char* kCustomUuid = "01234567-89ab-cdef-0123-456789abcdef";
+static const char* kSerialUuid = "00001101-0000-1000-8000-00805f9b34fb";
+
+} // namespace
+
+namespace device {
+
+class BluetoothServiceRecordTest : public testing::Test {
+ public:
+ FilePath GetTestDataFilePath(const char* file) {
+ FilePath path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ path = path.AppendASCII("device");
+ path = path.AppendASCII("test");
+ path = path.AppendASCII("data");
+ path = path.AppendASCII("bluetooth");
+ path = path.AppendASCII(file);
+ return path;
+ }
+};
+
+TEST_F(BluetoothServiceRecordTest, RfcommService) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("rfcomm.xml"), &xml_data);
+
+ BluetoothServiceRecord service_record(kAddress, xml_data);
+ EXPECT_EQ(kAddress, service_record.address());
+ EXPECT_EQ("Headset Audio Gateway", service_record.name());
+ EXPECT_TRUE(service_record.SupportsRfcomm());
+ EXPECT_EQ((uint8)12, service_record.rfcomm_channel());
+ EXPECT_EQ(kCustomUuid, service_record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordTest, ShortUuid) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("short_uuid.xml"), &xml_data);
+ BluetoothServiceRecord short_uuid_service_record(kAddress, xml_data);
+ EXPECT_EQ(kSerialUuid, short_uuid_service_record.uuid());
+
+ xml_data.clear();
+ file_util::ReadFileToString(
+ GetTestDataFilePath("medium_uuid.xml"), &xml_data);
+ BluetoothServiceRecord medium_uuid_service_record(kAddress, xml_data);
+ EXPECT_EQ(kSerialUuid, medium_uuid_service_record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordTest, CleanUuid) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("uppercase_uuid.xml"),
+ &xml_data);
+ BluetoothServiceRecord service_record(kAddress, xml_data);
+ EXPECT_EQ(kCustomUuid, service_record.uuid());
+
+ xml_data.clear();
+ file_util::ReadFileToString(GetTestDataFilePath("invalid_uuid.xml"),
+ &xml_data);
+ BluetoothServiceRecord invalid_service_record(kAddress, xml_data);
+ EXPECT_EQ("", invalid_service_record.uuid());
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_socket.h b/device/bluetooth/bluetooth_socket.h
new file mode 100644
index 0000000..b444110
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 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_SOCKET_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace device {
+
+// BluetoothSocket represents a socket to a specific service on a
+// BluetoothDevice. BluetoothSocket objects are ref counted and may outlive
+// both the BluetoothDevice and BluetoothAdapter that were involved in their
+// creation.
+class BluetoothSocket : public base::RefCounted<BluetoothSocket> {
+ public:
+ // TODO(youngki): Replace this with an opaque id when read/write calls are
+ // added. This interface is platform-independent and file descriptor is
+ // linux-specific hence this method has to be renamed.
+ virtual int fd() const = 0;
+
+ protected:
+ friend class base::RefCounted<BluetoothSocket>;
+ virtual ~BluetoothSocket() {}
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_H_
diff --git a/device/bluetooth/bluetooth_socket_chromeos.cc b/device/bluetooth/bluetooth_socket_chromeos.cc
new file mode 100644
index 0000000..7e75a9d
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket_chromeos.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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_socket_chromeos.h"
+
+#include <vector>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+#include "device/bluetooth/bluetooth_utils.h"
+
+using device::BluetoothServiceRecord;
+using device::BluetoothSocket;
+
+namespace chromeos {
+
+BluetoothSocketChromeOs::BluetoothSocketChromeOs(
+ const std::string& address, int fd)
+ : address_(address),
+ fd_(fd) {
+}
+
+BluetoothSocketChromeOs::~BluetoothSocketChromeOs() {
+ close(fd_);
+}
+
+// static
+scoped_refptr<BluetoothSocket> BluetoothSocketChromeOs::CreateBluetoothSocket(
+ const BluetoothServiceRecord& service_record) {
+ BluetoothSocketChromeOs* bluetooth_socket = NULL;
+ if (service_record.SupportsRfcomm()) {
+ int socket_fd = socket(
+ AF_BLUETOOTH, SOCK_STREAM | SOCK_NONBLOCK, BTPROTO_RFCOMM);
+ struct sockaddr_rc socket_address = { 0 };
+ socket_address.rc_family = AF_BLUETOOTH;
+ socket_address.rc_channel = service_record.rfcomm_channel();
+ device::bluetooth_utils::str2ba(service_record.address(),
+ &socket_address.rc_bdaddr);
+
+ int status = connect(socket_fd, (struct sockaddr *)&socket_address,
+ sizeof(socket_address));
+ int errsv = errno;
+ if (status == 0 || errno == EINPROGRESS) {
+ bluetooth_socket = new BluetoothSocketChromeOs(service_record.address(),
+ socket_fd);
+ } else {
+ LOG(ERROR) << "Failed to connect bluetooth socket "
+ << "(" << service_record.address() << "): "
+ << "(" << errsv << ") " << strerror(errsv);
+ close(socket_fd);
+ }
+ }
+ // TODO(bryeung): add support for L2CAP sockets as well.
+
+ return scoped_refptr<BluetoothSocketChromeOs>(bluetooth_socket);
+}
+
+int BluetoothSocketChromeOs::fd() const {
+ return fd_;
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_socket_chromeos.h b/device/bluetooth/bluetooth_socket_chromeos.h
new file mode 100644
index 0000000..0685830
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket_chromeos.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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_SOCKET_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_CHROMEOS_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_socket.h"
+
+namespace device {
+
+class BluetoothServiceRecord;
+
+} // namespace device
+
+namespace chromeos {
+
+// This class is an implementation of BluetoothSocket class for Chrome OS
+// platform.
+class BluetoothSocketChromeOs : public device::BluetoothSocket {
+ public:
+ static scoped_refptr<device::BluetoothSocket> CreateBluetoothSocket(
+ const device::BluetoothServiceRecord& service_record);
+
+ // BluetoothSocket override
+ virtual int fd() const OVERRIDE;
+
+ protected:
+ virtual ~BluetoothSocketChromeOs();
+
+ private:
+ BluetoothSocketChromeOs(const std::string& address, int fd);
+
+ const std::string address_;
+ const int fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothSocketChromeOs);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_utils.cc b/device/bluetooth/bluetooth_utils.cc
new file mode 100644
index 0000000..6d06409
--- /dev/null
+++ b/device/bluetooth/bluetooth_utils.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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_utils.h"
+
+#include <vector>
+
+#if defined(OS_CHROMEOS)
+#include <bluetooth/bluetooth.h>
+#endif
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+
+namespace {
+static const char* kCommonUuidPostfix = "-0000-1000-8000-00805f9b34fb";
+static const char* kCommonUuidPrefix = "0000";
+static const int kUuidSize = 36;
+} // namespace
+
+namespace device {
+namespace bluetooth_utils {
+
+#if defined(OS_CHROMEOS)
+bool str2ba(const std::string& in_address, bdaddr_t* out_address) {
+ if (!out_address)
+ return false;
+
+ memset(out_address, 0, sizeof(*out_address));
+
+ if (in_address.size() != 17)
+ return false;
+
+ std::string numbers_only;
+ for (int i = 0; i < 6; ++i) {
+ numbers_only += in_address.substr(i * 3, 2);
+ }
+
+ std::vector<uint8> address_bytes;
+ if (base::HexStringToBytes(numbers_only, &address_bytes)) {
+ if (address_bytes.size() == 6) {
+ for (int i = 0; i < 6; ++i) {
+ out_address->b[5 - i] = address_bytes[i];
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+std::string CanonicalUuid(std::string uuid) {
+ if (uuid.empty())
+ return "";
+
+ if (uuid.size() < 11 && uuid.find("0x") == 0)
+ uuid = uuid.substr(2);
+
+ if (!(uuid.size() == 4 || uuid.size() == 8 || uuid.size() == 36))
+ return "";
+
+ if (uuid.size() == 4 || uuid.size() == 8) {
+ for (size_t i = 0; i < uuid.size(); ++i) {
+ if (!IsHexDigit(uuid[i]))
+ return "";
+ }
+
+ if (uuid.size() == 4)
+ return kCommonUuidPrefix + uuid + kCommonUuidPostfix;
+
+ return uuid + kCommonUuidPostfix;
+ }
+
+ std::string uuid_result(uuid);
+ for (int i = 0; i < kUuidSize; ++i) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (uuid[i] != '-')
+ return "";
+ } else {
+ if (!IsHexDigit(uuid[i]))
+ return "";
+ uuid_result[i] = tolower(uuid[i]);
+ }
+ }
+ return uuid_result;
+}
+
+} // namespace bluetooth_utils
+} // namespace device
diff --git a/device/bluetooth/bluetooth_utils.h b/device/bluetooth/bluetooth_utils.h
new file mode 100644
index 0000000..f796d5d
--- /dev/null
+++ b/device/bluetooth/bluetooth_utils.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 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_UTILS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_UTILS_H_
+
+#include <string>
+
+#if defined(OS_CHROMEOS)
+#include <bluetooth/bluetooth.h>
+#endif
+
+namespace device {
+namespace bluetooth_utils {
+
+#if defined(OS_CHROMEOS)
+// Converts a bluetooth address in the format "B0:D0:9C:0F:3A:2D" into a
+// bdaddr_t struct. Returns true on success, false on failure. The contents
+// of |out_address| are zeroed on failure.
+// Note that the order is reversed upon conversion. For example,
+// "B0:D0:9C:0F:3A:2D" -> {"0x2d", "0x3a", "0x0f", "0x9c", "0xd0", "0xb0"}
+bool str2ba(const std::string& in_address, bdaddr_t* out_address);
+#endif
+
+// Takes a 4, 8 or 36 character UUID, validates it and returns it in 36
+// character format with all hex digits lower case. If |uuid| is invalid, the
+// empty string is returned.
+//
+// Valid inputs are:
+// XXXX
+// 0xXXXX
+// XXXXXXXX
+// 0xXXXXXXXX
+// XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+std::string CanonicalUuid(std::string uuid);
+
+} // namespace bluetooth_utils
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_UTILS_H_
+
diff --git a/device/bluetooth/bluetooth_utils_unittest.cc b/device/bluetooth/bluetooth_utils_unittest.cc
new file mode 100644
index 0000000..0e05f8e
--- /dev/null
+++ b/device/bluetooth/bluetooth_utils_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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.
+
+#if defined(OS_CHROMEOS)
+#include <bluetooth/bluetooth.h>
+#endif
+
+#include "device/bluetooth/bluetooth_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+#if defined(OS_CHROMEOS)
+TEST(BluetoothUtilsTest, str2ba) {
+ bdaddr_t bluetooth_address;
+
+ EXPECT_TRUE(bluetooth_utils::str2ba("01:02:03:0A:10:A0", &bluetooth_address));
+ EXPECT_EQ(1, bluetooth_address.b[5]);
+ EXPECT_EQ(2, bluetooth_address.b[4]);
+ EXPECT_EQ(3, bluetooth_address.b[3]);
+ EXPECT_EQ(10, bluetooth_address.b[2]);
+ EXPECT_EQ(16, bluetooth_address.b[1]);
+ EXPECT_EQ(160, bluetooth_address.b[0]);
+
+ EXPECT_FALSE(bluetooth_utils::str2ba("obviously wrong", &bluetooth_address));
+ EXPECT_FALSE(bluetooth_utils::str2ba("00:00", &bluetooth_address));
+ EXPECT_FALSE(
+ bluetooth_utils::str2ba("00:00:00:00:00:00:00", &bluetooth_address));
+ EXPECT_FALSE(bluetooth_utils::str2ba("01:02:03:0A:10:A0", NULL));
+}
+#endif
+
+TEST(BluetoothUtilsTest, CanonicalUuid) {
+ // Does nothing for an already canonical UUID
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("00001101-0000-1000-8000-00805f9b34fb"));
+
+ // Rejects misformatted
+ EXPECT_EQ("", bluetooth_utils::CanonicalUuid("1101a"));
+ EXPECT_EQ("", bluetooth_utils::CanonicalUuid("Z101"));
+ EXPECT_EQ("", bluetooth_utils::CanonicalUuid("0000-1101"));
+ EXPECT_EQ("", bluetooth_utils::CanonicalUuid("0000Z101"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("0001101-0000-1000-8000-00805f9b34fb"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("Z0001101-0000-1000-8000-00805f9b34fb"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("00001101 0000-1000-8000-00805f9b34fb"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("00001101-0000:1000-8000-00805f9b34fb"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("00001101-0000-1000;8000-00805f9b34fb"));
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("00001101-0000-1000-8000000805f9b34fb"));
+
+ // Lower case
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("00001101-0000-1000-8000-00805F9B34FB"));
+
+ // Short to full
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("1101"));
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("0x1101"));
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("00001101"));
+ EXPECT_EQ("00001101-0000-1000-8000-00805f9b34fb",
+ bluetooth_utils::CanonicalUuid("0x00001101"));
+
+ // No 0x prefix on 36 character
+ EXPECT_EQ("",
+ bluetooth_utils::CanonicalUuid("0x00001101-0000-1000-8000-00805f9b34fb"));
+}
+
+} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc
new file mode 100644
index 0000000..cae8829
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 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_adapter.h"
+
+namespace device {
+
+MockBluetoothAdapter::Observer::Observer() {}
+MockBluetoothAdapter::Observer::~Observer() {}
+
+MockBluetoothAdapter::MockBluetoothAdapter(const std::string& address,
+ const std::string& name) {
+ address_ = address;
+ name_ = name;
+}
+
+MockBluetoothAdapter::~MockBluetoothAdapter() {}
+
+} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h
new file mode 100644
index 0000000..33f7afb
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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_ADAPTER_H_
+#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_ADAPTER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace device {
+
+class MockBluetoothAdapter : public BluetoothAdapter {
+ public:
+ class Observer : public BluetoothAdapter::Observer {
+ public:
+ Observer();
+ virtual ~Observer();
+
+ MOCK_METHOD2(AdapterPresentChanged, void(BluetoothAdapter*, bool));
+ MOCK_METHOD2(AdapterPoweredChanged, void(BluetoothAdapter*, bool));
+ MOCK_METHOD2(AdapterDiscoveringChanged, void(BluetoothAdapter*, bool));
+ MOCK_METHOD2(DeviceAdded, void(BluetoothAdapter*, BluetoothDevice*));
+ MOCK_METHOD2(DeviceChanged, void(BluetoothAdapter*, BluetoothDevice*));
+ MOCK_METHOD2(DeviceRemoved, void(BluetoothAdapter*, BluetoothDevice*));
+ };
+
+ MockBluetoothAdapter(const std::string& address, const std::string& name);
+
+ MOCK_METHOD1(AddObserver, void(BluetoothAdapter::Observer*));
+ MOCK_METHOD1(RemoveObserver, void(BluetoothAdapter::Observer*));
+ MOCK_CONST_METHOD0(IsPresent, bool());
+ MOCK_CONST_METHOD0(IsPowered, bool());
+ MOCK_METHOD3(SetPowered,
+ void(bool discovering,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback));
+ MOCK_CONST_METHOD0(IsDiscovering, bool());
+ MOCK_METHOD3(SetDiscovering,
+ void(bool discovering,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback));
+ MOCK_CONST_METHOD0(GetDevices, BluetoothAdapter::ConstDeviceList());
+ MOCK_METHOD1(GetDevice, BluetoothDevice*(const std::string& address));
+ MOCK_CONST_METHOD1(GetDevice,
+ const BluetoothDevice*(const std::string& address));
+ MOCK_METHOD2(
+ ReadLocalOutOfBandPairingData,
+ void(const BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback));
+ protected:
+ virtual ~MockBluetoothAdapter();
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_ADAPTER_H_
diff --git a/device/bluetooth/test/mock_bluetooth_device.cc b/device/bluetooth/test/mock_bluetooth_device.cc
new file mode 100644
index 0000000..f2f358d
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_device.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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/utf_string_conversions.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/test/mock_bluetooth_device.h"
+
+namespace device {
+
+MockBluetoothDevice::MockBluetoothDevice(MockBluetoothAdapter* adapter,
+ const std::string& name,
+ const std::string& address,
+ bool paired,
+ bool bonded,
+ bool connected)
+ : name_(UTF8ToUTF16(name)),
+ address_(address) {
+ ON_CALL(*this, GetName())
+ .WillByDefault(testing::Return(name_));
+ ON_CALL(*this, address())
+ .WillByDefault(testing::ReturnRef(address_));
+ ON_CALL(*this, IsPaired())
+ .WillByDefault(testing::Return(paired));
+ ON_CALL(*this, IsBonded())
+ .WillByDefault(testing::Return(bonded));
+ ON_CALL(*this, IsConnected())
+ .WillByDefault(testing::Return(connected));
+ ON_CALL(*this, ExpectingPinCode())
+ .WillByDefault(testing::Return(false));
+ ON_CALL(*this, ExpectingPasskey())
+ .WillByDefault(testing::Return(false));
+ ON_CALL(*this, ExpectingConfirmation())
+ .WillByDefault(testing::Return(false));
+ ON_CALL(*this, GetServices())
+ .WillByDefault(testing::ReturnRef(service_list_));
+}
+
+MockBluetoothDevice::~MockBluetoothDevice() {}
+
+} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
new file mode 100644
index 0000000..e917a30
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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_DEVICE_H_
+#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DEVICE_H_
+
+#include <string>
+
+#include "base/string16.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace device {
+
+class MockBluetoothAdapter;
+
+class MockBluetoothDevice : public BluetoothDevice {
+ public:
+ MockBluetoothDevice(MockBluetoothAdapter* adapter,
+ const std::string& name,
+ const std::string& address,
+ bool paired,
+ bool bonded,
+ bool connected);
+ virtual ~MockBluetoothDevice();
+
+ MOCK_CONST_METHOD0(address, const std::string&());
+ MOCK_CONST_METHOD0(GetName, string16());
+ MOCK_CONST_METHOD0(GetDeviceType, BluetoothDevice::DeviceType());
+ MOCK_CONST_METHOD0(IsPaired, bool());
+ MOCK_CONST_METHOD0(IsBonded, bool());
+ MOCK_CONST_METHOD0(IsConnected, bool());
+ MOCK_CONST_METHOD0(GetServices, const ServiceList&());
+ MOCK_METHOD2(GetServiceRecords,
+ void(const BluetoothDevice::ServiceRecordsCallback&,
+ const BluetoothDevice::ErrorCallback&));
+ MOCK_CONST_METHOD1(ProvidesServiceWithUUID, bool(const std::string&));
+ MOCK_METHOD2(ProvidesServiceWithName,
+ void(const std::string&,
+ const BluetoothDevice::ProvidesServiceCallback&));
+ MOCK_CONST_METHOD0(ExpectingPinCode, bool());
+ MOCK_CONST_METHOD0(ExpectingPasskey, bool());
+ MOCK_CONST_METHOD0(ExpectingConfirmation, bool());
+ MOCK_METHOD3(Connect,
+ void(BluetoothDevice::PairingDelegate* pairnig_delegate,
+ const base::Closure& callback,
+ const BluetoothDevice::ErrorCallback& error_callback));
+ MOCK_METHOD1(SetPinCode, void(const std::string&));
+ MOCK_METHOD1(SetPasskey, void(uint32));
+ MOCK_METHOD0(ConfirmPairing, void());
+ MOCK_METHOD0(RejectPairing, void());
+ MOCK_METHOD0(CancelPairing, void());
+ MOCK_METHOD2(Disconnect,
+ void(const base::Closure& callback,
+ const BluetoothDevice::ErrorCallback& error_callback));
+ MOCK_METHOD1(Forget, void(const BluetoothDevice::ErrorCallback&));
+ MOCK_METHOD2(ConnectToService,
+ void(const std::string&,
+ const BluetoothDevice::SocketCallback&));
+
+ MOCK_METHOD3(SetOutOfBandPairingData,
+ void(const BluetoothOutOfBandPairingData& data,
+ const base::Closure& callback,
+ const BluetoothDevice::ErrorCallback& error_callback));
+ MOCK_METHOD2(ClearOutOfBandPairingData,
+ void(const base::Closure& callback,
+ const BluetoothDevice::ErrorCallback& error_callback));
+
+ private:
+ string16 name_;
+ std::string address_;
+ BluetoothDevice::ServiceList service_list_;
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DEVICE_H_
diff --git a/device/device.gyp b/device/device.gyp
new file mode 100644
index 0000000..4b4c1ad
--- /dev/null
+++ b/device/device.gyp
@@ -0,0 +1,111 @@
+# Copyright (c) 2012 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.
+
+{
+ 'variables': {
+ },
+ 'targets': [
+ {
+ 'target_name': 'device_bluetooth',
+ 'type': '<(library)',
+ 'dependencies': [
+ '../chrome/chrome_resources.gyp:chrome_strings',
+ '../third_party/libxml/libxml.gyp:libxml',
+ '../ui/ui.gyp:ui'
+ ],
+ 'sources': [
+ 'bluetooth/bluetooth_adapter.cc',
+ 'bluetooth/bluetooth_adapter.h',
+ 'bluetooth/bluetooth_adapter_chromeos.cc',
+ 'bluetooth/bluetooth_adapter_chromeos.h',
+ 'bluetooth/bluetooth_adapter_factory.cc',
+ 'bluetooth/bluetooth_adapter_factory.h',
+ 'bluetooth/bluetooth_device.cc',
+ 'bluetooth/bluetooth_device.h',
+ 'bluetooth/bluetooth_device_chromeos.cc',
+ 'bluetooth/bluetooth_device_chromeos.h',
+ 'bluetooth/bluetooth_out_of_band_pairing_data.h',
+ 'bluetooth/bluetooth_service_record.cc',
+ 'bluetooth/bluetooth_service_record.h',
+ 'bluetooth/bluetooth_socket.h',
+ 'bluetooth/bluetooth_socket_chromeos.cc',
+ 'bluetooth/bluetooth_socket_chromeos.h',
+ 'bluetooth/bluetooth_utils.cc',
+ 'bluetooth/bluetooth_utils.h',
+ ],
+ 'conditions': [
+ ['chromeos==0', {
+ 'sources!': [
+ # ChromeOs-only; exclude on other platforms.
+ 'bluetooth/bluetooth_adapter_chromeos.cc',
+ 'bluetooth/bluetooth_adapter_chromeos.h',
+ 'bluetooth/bluetooth_device_chromeos.cc',
+ 'bluetooth/bluetooth_device_chromeos.h',
+ 'bluetooth/bluetooth_socket_chromeos.cc',
+ 'bluetooth/bluetooth_socket_chromeos.h',
+ ]
+ }, { # chromeos==1
+ 'dependencies': [
+ '../build/linux/system.gyp:dbus-glib',
+ '../chromeos/chromeos.gyp:chromeos',
+ '../dbus/dbus.gyp:dbus',
+ ]
+ }],
+ ],
+ },
+ {
+ 'target_name': 'device_bluetooth_mocks',
+ 'type': '<(library)',
+ 'dependencies': [
+ 'device_bluetooth',
+ '../testing/gmock.gyp:gmock',
+ ],
+ 'sources': [
+ 'bluetooth/test/mock_bluetooth_adapter.cc',
+ 'bluetooth/test/mock_bluetooth_adapter.h',
+ 'bluetooth/test/mock_bluetooth_device.cc',
+ 'bluetooth/test/mock_bluetooth_device.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ {
+ 'target_name': 'device_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ 'device_bluetooth',
+ 'device_bluetooth_mocks',
+ '../base/base.gyp:test_support_base',
+ '../content/content.gyp:test_support_content',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'sources': [
+ 'bluetooth/bluetooth_adapter_chromeos_unittest.cc',
+ 'bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc',
+ 'bluetooth/bluetooth_service_record_unittest.cc',
+ 'bluetooth/bluetooth_utils_unittest.cc',
+ 'test/device_test_suite.cc',
+ 'test/device_test_suite.h',
+ 'test/run_all_unittests.cc',
+ ],
+ 'conditions': [
+ ['chromeos==0', {
+ 'sources!': [
+ # ChromeOs-only; exclude on other platforms.
+ 'bluetooth/bluetooth_adapter_chromeos_unittest.cc',
+ 'bluetooth/bluetooth_adapter_chromeos_devices_unittest.cc',
+ ]
+ }, { # chromeos==1
+ 'dependencies': [
+ '../build/linux/system.gyp:dbus-glib',
+ '../chromeos/chromeos.gyp:chromeos_test_support',
+ '../dbus/dbus.gyp:dbus',
+ ]
+ }],
+ ],
+ },
+ ],
+}
diff --git a/device/test/data/bluetooth/invalid_uuid.xml b/device/test/data/bluetooth/invalid_uuid.xml
new file mode 100644
index 0000000..2b33304
--- /dev/null
+++ b/device/test/data/bluetooth/invalid_uuid.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="01234567:89AB-CDEF-0123-456789ABCDEF" />
+ </sequence>
+ </attribute>
+</record>
diff --git a/device/test/data/bluetooth/medium_uuid.xml b/device/test/data/bluetooth/medium_uuid.xml
new file mode 100644
index 0000000..432d7fe
--- /dev/null
+++ b/device/test/data/bluetooth/medium_uuid.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x00001101" />
+ </sequence>
+ </attribute>
+</record>
diff --git a/device/test/data/bluetooth/rfcomm.xml b/device/test/data/bluetooth/rfcomm.xml
new file mode 100644
index 0000000..ec3bdec
--- /dev/null
+++ b/device/test/data/bluetooth/rfcomm.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<record>
+ <attribute id="0x0000">
+ <uint32 value="0x00010003" />
+ </attribute>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="01234567-89ab-cdef-0123-456789abcdef" />
+ </sequence>
+ </attribute>
+ <attribute id="0x0004">
+ <sequence>
+ <sequence>
+ <uuid value="0x0100" />
+ </sequence>
+ <sequence>
+ <uuid value="0x0003" />
+ <uint8 value="0x0c" />
+ </sequence>
+ </sequence>
+ </attribute>
+ <attribute id="0x0005">
+ <sequence>
+ <uuid value="0x1002" />
+ </sequence>
+ </attribute>
+ <attribute id="0x0009">
+ <sequence>
+ <sequence>
+ <uuid value="0x1108" />
+ <uint16 value="0x0102" />
+ </sequence>
+ </sequence>
+ </attribute>
+ <attribute id="0x0100">
+ <text value="Headset Audio Gateway" />
+ </attribute>
+</record>
diff --git a/device/test/data/bluetooth/short_uuid.xml b/device/test/data/bluetooth/short_uuid.xml
new file mode 100644
index 0000000..9ad3c9f
--- /dev/null
+++ b/device/test/data/bluetooth/short_uuid.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x1101" />
+ </sequence>
+ </attribute>
+</record>
diff --git a/device/test/data/bluetooth/uppercase_uuid.xml b/device/test/data/bluetooth/uppercase_uuid.xml
new file mode 100644
index 0000000..4e0574f
--- /dev/null
+++ b/device/test/data/bluetooth/uppercase_uuid.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="01234567-89AB-CDEF-0123-456789ABCDEF" />
+ </sequence>
+ </attribute>
+</record>
diff --git a/device/test/device_test_suite.cc b/device/test/device_test_suite.cc
new file mode 100644
index 0000000..6556076
--- /dev/null
+++ b/device/test/device_test_suite.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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/test/device_test_suite.h"
+
+#include "content/public/common/content_client.h"
+
+DeviceTestSuite::DeviceTestSuite(int argc, char** argv)
+ : content::ContentTestSuiteBase(argc, argv) {
+}
+
+DeviceTestSuite::~DeviceTestSuite() {
+}
+
+content::ContentClient* DeviceTestSuite::CreateClientForInitialization() {
+ return new content::ContentClient();
+}
diff --git a/device/test/device_test_suite.h b/device/test/device_test_suite.h
new file mode 100644
index 0000000..15059ab
--- /dev/null
+++ b/device/test/device_test_suite.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 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_TEST_DEVICE_TEST_SUITE_H_
+#define DEVICE_TEST_DEVICE_TEST_SUITE_H_
+
+#include "content/public/test/content_test_suite_base.h"
+
+class DeviceTestSuite : public content::ContentTestSuiteBase {
+ public:
+ DeviceTestSuite(int argc, char** argv);
+ virtual ~DeviceTestSuite();
+
+ protected:
+ virtual content::ContentClient* CreateClientForInitialization() OVERRIDE;
+};
+
+#endif // DEVICE_TEST_DEVICE_TEST_SUITE_H_
diff --git a/device/test/run_all_unittests.cc b/device/test/run_all_unittests.cc
new file mode 100644
index 0000000..36e6e51
--- /dev/null
+++ b/device/test/run_all_unittests.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2011 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 "content/public/test/unittest_test_suite.h"
+#include "device/test/device_test_suite.h"
+
+int main(int argc, char **argv) {
+ return content::UnitTestTestSuite(new DeviceTestSuite(argc, argv)).Run();
+}