Merge from Chromium at DEPS revision r190564
This commit was generated by merge_to_master.py.
Change-Id: Icadecbce29854b8fa25fd335b2c1949b5ca5d170
diff --git a/device/DEPS b/device/DEPS
index 2beaf5d..79b8e8b 100644
--- a/device/DEPS
+++ b/device/DEPS
@@ -1,4 +1,3 @@
include_rules = [
- "+content/public/common",
- "+content/public/test",
+ "+chromeos",
]
diff --git a/device/OWNERS b/device/OWNERS
index c5acbb9..a83889f 100644
--- a/device/OWNERS
+++ b/device/OWNERS
@@ -1,3 +1,3 @@
-bryeung@chromium.org
+keybuk@chromium.org
gdk@chromium.org
miket@chromium.org
diff --git a/device/bluetooth/DEPS b/device/bluetooth/DEPS
index 730c30e..7f93e42 100644
--- a/device/bluetooth/DEPS
+++ b/device/bluetooth/DEPS
@@ -1,10 +1,8 @@
include_rules = [
- "+chrome/common",
- "+chrome/test/base",
- "+content/public/test",
"+chromeos/dbus",
"+dbus",
"+grit",
+ "+net/base",
"+ui/base/l10n",
"+third_party/cros_system_api/dbus",
"+third_party/libxml/chromium",
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index b36cd0b..b64c143 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -4,11 +4,16 @@
#include "device/bluetooth/bluetooth_adapter.h"
+#include "base/stl_util.h"
#include "device/bluetooth/bluetooth_device.h"
namespace device {
+BluetoothAdapter::BluetoothAdapter() {
+}
+
BluetoothAdapter::~BluetoothAdapter() {
+ STLDeleteValues(&devices_);
}
const std::string& BluetoothAdapter::address() const {
@@ -31,4 +36,28 @@
return devices;
}
+BluetoothAdapter::ConstDeviceList BluetoothAdapter::GetDevices() const {
+ ConstDeviceList devices;
+ for (DevicesMap::const_iterator iter = devices_.begin();
+ iter != devices_.end();
+ ++iter)
+ devices.push_back(iter->second);
+
+ return devices;
+}
+
+BluetoothDevice* BluetoothAdapter::GetDevice(const std::string& address) {
+ return const_cast<BluetoothDevice *>(
+ const_cast<const BluetoothAdapter *>(this)->GetDevice(address));
+}
+
+const BluetoothDevice* BluetoothAdapter::GetDevice(
+ const std::string& address) const {
+ DevicesMap::const_iterator iter = devices_.find(address);
+ if (iter != devices_.end())
+ return iter->second;
+
+ return NULL;
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h
index 86de361..75c0606 100644
--- a/device/bluetooth/bluetooth_adapter.h
+++ b/device/bluetooth/bluetooth_adapter.h
@@ -5,6 +5,7 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
+#include <map>
#include <string>
#include <vector>
@@ -44,12 +45,18 @@
// 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.
+ // means it is not.
virtual void AdapterDiscoveringChanged(BluetoothAdapter* adapter,
bool discovering) {}
+ // Called when the scanning discovery state of the adapter |adapter|
+ // changes during discovery. When |scanning| is true the adapter is
+ // actively scanning for new devices and when false it is contacting
+ // the devices found to update information; the adapter will repeatedly
+ // cycle between both states during discovery.
+ virtual void AdapterScanningChanged(BluetoothAdapter* adapter,
+ bool scanning) {}
+
// 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.
@@ -92,6 +99,9 @@
// The name of the adapter.
virtual const std::string& name() const;
+ // Indicates whether the adapter is initialized and ready to use.
+ virtual bool IsInitialized() const = 0;
+
// 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.
@@ -107,18 +117,34 @@
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.
+ // Indicates whether the adapter is currently discovering new devices.
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;
+ // Indicates whether the adapter is currently scanning for new devices
+ // during discovery; when false the adapter is contacting the devices found
+ // to obtain information.
+ virtual bool IsScanning() const = 0;
+
+ // Requests that the adapter begin discovering new devices, code must
+ // always call this method if they require the adapter be in discovery
+ // and should not make it conditional on the value of IsDiscovering()
+ // as other adapter users may be making the same request. Code must also
+ // call StopDiscovering() when done. On success |callback| will be called,
+ // on failure |error_callback| will be called instead.
+ //
+ // Since discovery may already be in progress when this method is called,
+ // callers should retrieve the current set of discovered devices by calling
+ // GetDevices() and checking for those with IsVisible() as true.
+ virtual void StartDiscovering(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Requests that an earlier call to StartDiscovering() be cancelled; the
+ // adapter may not actually cease discovering devices if other callers
+ // have called StartDiscovering() and not yet called this method. On
+ // success |callback| will be called, on failure |error_callback| will be
+ // called instead.
+ virtual void StopDiscovering(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
// Requests the list of devices from the adapter, all are returned
// including those currently connected and those paired. Use the
@@ -126,13 +152,13 @@
typedef std::vector<BluetoothDevice*> DeviceList;
virtual DeviceList GetDevices();
typedef std::vector<const BluetoothDevice*> ConstDeviceList;
- virtual ConstDeviceList GetDevices() const = 0;
+ virtual ConstDeviceList GetDevices() const;
// 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 BluetoothDevice* GetDevice(const std::string& address);
virtual const BluetoothDevice* GetDevice(
- const std::string& address) const = 0;
+ const std::string& address) const;
// Requests the local Out Of Band pairing data.
virtual void ReadLocalOutOfBandPairingData(
@@ -141,6 +167,7 @@
protected:
friend class base::RefCounted<BluetoothAdapter>;
+ BluetoothAdapter();
virtual ~BluetoothAdapter();
// Address of the adapter.
@@ -148,6 +175,13 @@
// Name of the adapter.
std::string name_;
+
+ // Devices paired with, connected to, discovered by, or visible to the
+ // adapter. The key is the Bluetooth address of the device and the value
+ // is the BluetoothDevice object whose lifetime is managed by the
+ // adapter instance.
+ typedef std::map<const std::string, BluetoothDevice*> DevicesMap;
+ DevicesMap devices_;
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index 36699e5..d92a021 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -25,9 +25,11 @@
namespace chromeos {
-BluetoothAdapterChromeOs::BluetoothAdapterChromeOs() : track_default_(false),
+BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() : BluetoothAdapter(),
+ track_default_(false),
powered_(false),
- discovering_(false),
+ scanning_(false),
+ discovering_count_(0),
weak_ptr_factory_(this) {
DBusThreadManager::Get()->GetBluetoothManagerClient()->
AddObserver(this);
@@ -37,128 +39,107 @@
AddObserver(this);
}
-BluetoothAdapterChromeOs::~BluetoothAdapterChromeOs() {
+BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
RemoveObserver(this);
DBusThreadManager::Get()->GetBluetoothAdapterClient()->
RemoveObserver(this);
DBusThreadManager::Get()->GetBluetoothManagerClient()->
RemoveObserver(this);
-
- STLDeleteValues(&devices_);
}
-void BluetoothAdapterChromeOs::AddObserver(
+void BluetoothAdapterChromeOS::AddObserver(
BluetoothAdapter::Observer* observer) {
DCHECK(observer);
observers_.AddObserver(observer);
}
-void BluetoothAdapterChromeOs::RemoveObserver(
+void BluetoothAdapterChromeOS::RemoveObserver(
BluetoothAdapter::Observer* observer) {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
-bool BluetoothAdapterChromeOs::IsPresent() const {
+// TODO(youngki) Return true when object path and properties of the adapter are
+// initialized.
+bool BluetoothAdapterChromeOS::IsInitialized() const {
+ return true;
+}
+
+bool BluetoothAdapterChromeOS::IsPresent() const {
return !object_path_.value().empty() && !address_.empty();
}
-bool BluetoothAdapterChromeOs::IsPowered() const {
+bool BluetoothAdapterChromeOS::IsPowered() const {
return powered_;
}
-void BluetoothAdapterChromeOs::SetPowered(bool 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,
+ base::Bind(&BluetoothAdapterChromeOS::OnSetPowered,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
-bool BluetoothAdapterChromeOs::IsDiscovering() const {
- return discovering_;
+bool BluetoothAdapterChromeOS::IsDiscovering() const {
+ return discovering_count_ > 0;
}
-void BluetoothAdapterChromeOs::SetDiscovering(
- bool discovering,
+bool BluetoothAdapterChromeOS::IsScanning() const {
+ return scanning_;
+}
+
+void BluetoothAdapterChromeOS::StartDiscovering(
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));
- }
+ // BlueZ counts discovery sessions, and permits multiple sessions for a
+ // single connection, so issue a StartDiscovery() call for every use
+ // within Chromium for the right behavior.
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StartDiscovery(object_path_,
+ base::Bind(
+ &BluetoothAdapterChromeOS::OnStartDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback, 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;
+void BluetoothAdapterChromeOS::StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ // Inform BlueZ to stop one of our open discovery sessions.
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->
+ StopDiscovery(object_path_,
+ base::Bind(
+ &BluetoothAdapterChromeOS::OnStopDiscovery,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback, error_callback));
}
-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(
+void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) {
DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
ReadLocalData(object_path_,
- base::Bind(&BluetoothAdapterChromeOs::OnReadLocalData,
+ base::Bind(&BluetoothAdapterChromeOS::OnReadLocalData,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
-void BluetoothAdapterChromeOs::TrackDefaultAdapter() {
- DVLOG(1) << "Tracking default adapter";
+void BluetoothAdapterChromeOS::TrackDefaultAdapter() {
+ VLOG(1) << "Tracking default adapter";
track_default_ = true;
DBusThreadManager::Get()->GetBluetoothManagerClient()->
- DefaultAdapter(base::Bind(&BluetoothAdapterChromeOs::AdapterCallback,
+ 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(
+void BluetoothAdapterChromeOS::AdapterCallback(
const dbus::ObjectPath& adapter_path,
bool success) {
if (success) {
@@ -168,29 +149,29 @@
}
}
-void BluetoothAdapterChromeOs::DefaultAdapterChanged(
+void BluetoothAdapterChromeOS::DefaultAdapterChanged(
const dbus::ObjectPath& adapter_path) {
if (track_default_)
ChangeAdapter(adapter_path);
}
-void BluetoothAdapterChromeOs::AdapterRemoved(
+void BluetoothAdapterChromeOS::AdapterRemoved(
const dbus::ObjectPath& adapter_path) {
if (adapter_path == object_path_)
RemoveAdapter();
}
-void BluetoothAdapterChromeOs::ChangeAdapter(
+void BluetoothAdapterChromeOS::ChangeAdapter(
const dbus::ObjectPath& adapter_path) {
if (object_path_.value().empty()) {
- DVLOG(1) << "Adapter path initialized to " << adapter_path.value();
+ VLOG(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();
+ VLOG(1) << "Adapter path changed from " << object_path_.value()
+ << " to " << adapter_path.value();
RemoveAdapter();
} else {
- DVLOG(1) << "Adapter address updated";
+ VLOG(1) << "Adapter address updated";
}
object_path_ = adapter_path;
@@ -205,7 +186,7 @@
// Delay announcing a new adapter until we have an address.
if (address_.empty()) {
- DVLOG(1) << "Adapter address not yet known";
+ VLOG(1) << "Adapter address not yet known";
return;
}
@@ -217,10 +198,10 @@
AdapterPresentChanged(this, true));
}
-void BluetoothAdapterChromeOs::RemoveAdapter() {
+void BluetoothAdapterChromeOS::RemoveAdapter() {
const bool adapter_was_present = IsPresent();
- DVLOG(1) << "Adapter lost.";
+ VLOG(1) << "Adapter lost.";
PoweredChanged(false);
DiscoveringChanged(false);
ClearDevices();
@@ -234,7 +215,7 @@
AdapterPresentChanged(this, false));
}
-void BluetoothAdapterChromeOs::OnSetPowered(const base::Closure& callback,
+void BluetoothAdapterChromeOS::OnSetPowered(const base::Closure& callback,
const ErrorCallback& error_callback,
bool success) {
if (success)
@@ -243,7 +224,7 @@
error_callback.Run();
}
-void BluetoothAdapterChromeOs::PoweredChanged(bool powered) {
+void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
if (powered == powered_)
return;
@@ -253,51 +234,67 @@
AdapterPoweredChanged(this, powered_));
}
-void BluetoothAdapterChromeOs::OnStartDiscovery(
+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.";
+ if (discovering_count_++ == 0) {
+ VLOG(1) << object_path_.value() << ": started discovery.";
- // Clear devices found in previous discovery attempts
- ClearDiscoveredDevices();
+ // Clear devices found in previous discovery attempts
+ ClearDiscoveredDevices();
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterDiscoveringChanged(this, true));
+ }
+
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(
+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.";
+ if (--discovering_count_ == 0) {
+ VLOG(1) << object_path_.value() << ": stopped discovery.";
+
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterDiscoveringChanged(this, false));
+ } else if (discovering_count_ < 0) {
+ LOG(WARNING) << adapter_path.value() << ": call to StopDiscovering "
+ << "without matching StartDiscovering.";
+ error_callback.Run();
+ return;
+ }
+
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_)
+void BluetoothAdapterChromeOS::DiscoveringChanged(bool discovering) {
+ // The BlueZ discovering property actually just indicates whether the
+ // device is in an inquiry scan, so update our scanning property.
+ if (discovering == scanning_)
return;
- discovering_ = discovering;
+ scanning_ = discovering;
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
- AdapterDiscoveringChanged(this, discovering_));
+ AdapterScanningChanged(this, scanning_));
}
-void BluetoothAdapterChromeOs::OnReadLocalData(
+void BluetoothAdapterChromeOS::OnReadLocalData(
const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback,
const BluetoothOutOfBandPairingData& data,
@@ -308,7 +305,7 @@
error_callback.Run();
}
-void BluetoothAdapterChromeOs::AdapterPropertyChanged(
+void BluetoothAdapterChromeOS::AdapterPropertyChanged(
const dbus::ObjectPath& adapter_path,
const std::string& property_name) {
if (adapter_path != object_path_)
@@ -338,13 +335,13 @@
}
}
-void BluetoothAdapterChromeOs::DevicePropertyChanged(
+void BluetoothAdapterChromeOS::DevicePropertyChanged(
const dbus::ObjectPath& device_path,
const std::string& property_name) {
UpdateDevice(device_path);
}
-void BluetoothAdapterChromeOs::UpdateDevice(
+void BluetoothAdapterChromeOS::UpdateDevice(
const dbus::ObjectPath& device_path) {
BluetoothDeviceClient::Properties* properties =
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
@@ -361,19 +358,19 @@
// 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;
+ BluetoothDeviceChromeOS* device;
const bool update_device = (iter != devices_.end());
if (update_device) {
- device = iter->second;
+ device = static_cast<BluetoothDeviceChromeOS*>(iter->second);
} else {
- device = BluetoothDeviceChromeOs::Create(this);
+ 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;
+ VLOG(1) << "Assigned object path " << device_path.value() << " to device "
+ << address;
device->SetObjectPath(device_path);
}
device->Update(properties, true);
@@ -387,12 +384,12 @@
}
}
-void BluetoothAdapterChromeOs::ClearDevices() {
+void BluetoothAdapterChromeOS::ClearDevices() {
DevicesMap replace;
devices_.swap(replace);
for (DevicesMap::iterator iter = replace.begin();
iter != replace.end(); ++iter) {
- BluetoothDeviceChromeOs* device = iter->second;
+ BluetoothDevice* device = iter->second;
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
DeviceRemoved(this, device));
@@ -400,7 +397,7 @@
}
}
-void BluetoothAdapterChromeOs::DeviceCreated(
+void BluetoothAdapterChromeOS::DeviceCreated(
const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path) {
if (adapter_path != object_path_)
@@ -409,7 +406,7 @@
UpdateDevice(device_path);
}
-void BluetoothAdapterChromeOs::DeviceRemoved(
+void BluetoothAdapterChromeOS::DeviceRemoved(
const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path) {
if (adapter_path != object_path_)
@@ -417,7 +414,8 @@
DevicesMap::iterator iter = devices_.begin();
while (iter != devices_.end()) {
- BluetoothDeviceChromeOs* device = iter->second;
+ BluetoothDeviceChromeOS* device =
+ static_cast<BluetoothDeviceChromeOS*>(iter->second);
DevicesMap::iterator temp = iter;
++iter;
@@ -431,12 +429,12 @@
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
DeviceRemoved(this, device));
- DVLOG(1) << "Removed device " << device->address();
+ VLOG(1) << "Removed device " << device->address();
delete device;
devices_.erase(temp);
} else {
- DVLOG(1) << "Removed object path from device " << device->address();
+ VLOG(1) << "Removed object path from device " << device->address();
device->RemoveObjectPath();
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
@@ -445,17 +443,17 @@
}
}
-void BluetoothAdapterChromeOs::DevicesChanged(
+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() {
+void BluetoothAdapterChromeOS::ClearDiscoveredDevices() {
DevicesMap::iterator iter = devices_.begin();
while (iter != devices_.end()) {
- BluetoothDeviceChromeOs* device = iter->second;
+ BluetoothDevice* device = iter->second;
DevicesMap::iterator temp = iter;
++iter;
@@ -469,7 +467,7 @@
}
}
-void BluetoothAdapterChromeOs::DeviceFound(
+void BluetoothAdapterChromeOS::DeviceFound(
const dbus::ObjectPath& adapter_path,
const std::string& address,
const BluetoothDeviceClient::Properties& properties) {
@@ -479,17 +477,17 @@
// 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;
+ BluetoothDeviceChromeOS* device;
DevicesMap::iterator iter = devices_.find(address);
const bool update_device = (iter != devices_.end());
if (update_device) {
- device = iter->second;
+ device = static_cast<BluetoothDeviceChromeOS*>(iter->second);
} else {
- device = BluetoothDeviceChromeOs::Create(this);
+ device = BluetoothDeviceChromeOS::Create(this);
devices_[address] = device;
}
- DVLOG(1) << "Device " << address << " is visible to the adapter";
+ VLOG(1) << "Device " << address << " is visible to the adapter";
device->SetVisible(true);
device->Update(&properties, false);
@@ -502,7 +500,7 @@
}
}
-void BluetoothAdapterChromeOs::DeviceDisappeared(
+void BluetoothAdapterChromeOS::DeviceDisappeared(
const dbus::ObjectPath& adapter_path,
const std::string& address) {
if (adapter_path != object_path_)
@@ -512,7 +510,8 @@
if (iter == devices_.end())
return;
- BluetoothDeviceChromeOs* device = iter->second;
+ BluetoothDeviceChromeOS* device =
+ static_cast<BluetoothDeviceChromeOS*>(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
@@ -521,14 +520,14 @@
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
DeviceRemoved(this, device));
- DVLOG(1) << "Discovered device " << device->address()
+ VLOG(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";
+ VLOG(1) << "Paired device " << device->address()
+ << " is no longer visible to the adapter";
device->SetVisible(false);
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
index 18cb7aa..093cdd0 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.h
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -5,7 +5,6 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
-#include <map>
#include <string>
#include <vector>
@@ -28,11 +27,11 @@
namespace chromeos {
-class BluetoothDeviceChromeOs;
+class BluetoothDeviceChromeOS;
-// The BluetoothAdapterChromeOs class is an implementation of BluetoothAdapter
+// The BluetoothAdapterChromeOS class is an implementation of BluetoothAdapter
// for Chrome OS platform.
-class BluetoothAdapterChromeOs
+class BluetoothAdapterChromeOS
: public device::BluetoothAdapter,
public BluetoothManagerClient::Observer,
public BluetoothAdapterClient::Observer,
@@ -43,6 +42,7 @@
device::BluetoothAdapter::Observer* observer) OVERRIDE;
virtual void RemoveObserver(
device::BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual bool IsInitialized() const OVERRIDE;
virtual bool IsPresent() const OVERRIDE;
virtual bool IsPowered() const OVERRIDE;
virtual void SetPowered(
@@ -50,39 +50,33 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
virtual bool IsDiscovering() const OVERRIDE;
- virtual void SetDiscovering(
- bool discovering,
+ virtual bool IsScanning() const OVERRIDE;
+ virtual void StartDiscovering(
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 StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
virtual void ReadLocalOutOfBandPairingData(
const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback&
callback,
const ErrorCallback& error_callback) OVERRIDE;
private:
- friend class BluetoothDeviceChromeOs;
+ friend class BluetoothDeviceChromeOS;
friend class device::BluetoothAdapterFactory;
friend class device::MockBluetoothAdapter;
- BluetoothAdapterChromeOs();
- virtual ~BluetoothAdapterChromeOs();
+ 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.
+ // Called by dbus:: in response to the method call sent by DefaultAdapter().
+ // |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.
@@ -118,19 +112,23 @@
// 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().
+ // Called by BluetoothAdapterClient in response to the method call sent
+ // by StartDiscovering(), |callback| and |error_callback| are the callbacks
+ // provided to that method.
void OnStartDiscovery(const base::Closure& callback,
const ErrorCallback& error_callback,
const dbus::ObjectPath& adapter_path,
bool success);
+
+ // Called by BluetoothAdapterClient in response to the method call sent
+ // by StopDiscovering(), |callback| and |error_callback| are the callbacks
+ // provided to that method.
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
+ // Updates the tracked state of the adapter's scanning 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);
@@ -224,20 +222,17 @@
// Tracked adapter state, cached locally so we only send change notifications
// to observers on a genuine change.
bool powered_;
- bool discovering_;
+ bool scanning_;
- // 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_;
+ // Count of callers to StartDiscovering() and StopDiscovering(), used to
+ // provide the IsDiscovering() status.
+ int discovering_count_;
// 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_;
+ base::WeakPtrFactory<BluetoothAdapterChromeOS> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterChromeOs);
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterChromeOS);
};
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_chromeos_experimental.cc b/device/bluetooth/bluetooth_adapter_chromeos_experimental.cc
new file mode 100644
index 0000000..c382f08
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos_experimental.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_adapter_chromeos_experimental.h"
+
+#include <string>
+
+using device::BluetoothAdapter;
+
+namespace chromeos {
+
+BluetoothAdapterChromeOSExperimental::BluetoothAdapterChromeOSExperimental()
+ : BluetoothAdapter(),
+ weak_ptr_factory_(this) {
+}
+
+BluetoothAdapterChromeOSExperimental::~BluetoothAdapterChromeOSExperimental() {
+}
+
+void BluetoothAdapterChromeOSExperimental::AddObserver(
+ BluetoothAdapter::Observer* observer) {
+}
+
+void BluetoothAdapterChromeOSExperimental::RemoveObserver(
+ BluetoothAdapter::Observer* observer) {
+}
+
+bool BluetoothAdapterChromeOSExperimental::IsInitialized() const {
+ return true;
+}
+
+bool BluetoothAdapterChromeOSExperimental::IsPresent() const {
+ return false;
+}
+
+bool BluetoothAdapterChromeOSExperimental::IsPowered() const {
+ return false;
+}
+
+void BluetoothAdapterChromeOSExperimental::SetPowered(bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ error_callback.Run();
+}
+
+bool BluetoothAdapterChromeOSExperimental::IsDiscovering() const {
+ return false;
+}
+
+bool BluetoothAdapterChromeOSExperimental::IsScanning() const {
+ return false;
+}
+
+void BluetoothAdapterChromeOSExperimental::StartDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ error_callback.Run();
+}
+
+void BluetoothAdapterChromeOSExperimental::StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ error_callback.Run();
+}
+
+void BluetoothAdapterChromeOSExperimental::ReadLocalOutOfBandPairingData(
+ const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) {
+ error_callback.Run();
+}
+
+void BluetoothAdapterChromeOSExperimental::TrackDefaultAdapter() {
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_chromeos_experimental.h b/device/bluetooth/bluetooth_adapter_chromeos_experimental.h
new file mode 100644
index 0000000..fdb0ca5
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_chromeos_experimental.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_EXPERIMENTAL_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_EXPERIMENTAL_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace device {
+
+class BluetoothAdapterFactory;
+
+} // namespace device
+
+namespace chromeos {
+
+// The BluetoothAdapterChromeOSExperimental class is an alternate implementation
+// of BluetoothAdapter for the Chrome OS platform using the Bluetooth Smart
+// capable backend. It will become the sole implementation for Chrome OS, and
+// be renamed to BluetoothAdapterChromeOS, once the backend is switched,
+class BluetoothAdapterChromeOSExperimental
+ : public device::BluetoothAdapter {
+ public:
+ // BluetoothAdapter override
+ virtual void AddObserver(
+ device::BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ device::BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual bool IsInitialized() const 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 bool IsScanning() const OVERRIDE;
+ virtual void StartDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void ReadLocalOutOfBandPairingData(
+ const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback&
+ callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
+ private:
+ friend class device::BluetoothAdapterFactory;
+
+ BluetoothAdapterChromeOSExperimental();
+ virtual ~BluetoothAdapterChromeOSExperimental();
+
+ // Obtains the default adapter object path from the Bluetooth Daemon
+ // and tracks future changes to it.
+ void TrackDefaultAdapter();
+
+ // 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<BluetoothAdapterChromeOSExperimental> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterChromeOSExperimental);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_EXPERIMENTAL_H_
diff --git a/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc b/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc
index 890d241..517a27e 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos_unittest.cc
@@ -22,7 +22,7 @@
namespace chromeos {
-class BluetoothAdapterChromeOsTest : public testing::Test {
+class BluetoothAdapterChromeOSTest : public testing::Test {
public:
virtual void SetUp() {
MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager;
@@ -36,31 +36,38 @@
mock_adapter_client_ =
mock_dbus_thread_manager->mock_bluetooth_adapter_client();
- set_callback_called_ = false;
+ callback_called_ = false;
error_callback_called_ = false;
}
virtual void TearDown() {
+ adapter_ = NULL;
DBusThreadManager::Shutdown();
}
- void SetCallback() {
- set_callback_called_ = true;
+ void Callback() {
+ callback_called_ = true;
}
void ErrorCallback() {
error_callback_called_ = true;
}
+ void SetAdapter(scoped_refptr<device::BluetoothAdapter> adapter) {
+ adapter_ = adapter;
+ }
+
protected:
MockBluetoothManagerClient* mock_manager_client_;
MockBluetoothAdapterClient* mock_adapter_client_;
- bool set_callback_called_;
+ bool callback_called_;
bool error_callback_called_;
+
+ scoped_refptr<BluetoothAdapter> adapter_;
};
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterNotPresent) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterNotPresent) {
// Create the default adapter instance;
// BluetoothManagerClient::DefaultAdapter will be called once, passing
// a callback to obtain the adapter path.
@@ -68,25 +75,26 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
- ASSERT_TRUE(adapter.get() != NULL);
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+ ASSERT_TRUE(adapter_ != NULL);
// Call the adapter callback; make out it failed.
// BluetoothAdapter::Observer::AdapterPresentChanged must not be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), _))
.Times(0);
adapter_callback.Run(dbus::ObjectPath(""), false);
// Adapter should not be present.
- EXPECT_FALSE(adapter->IsPresent());
+ EXPECT_FALSE(adapter_->IsPresent());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithAddress) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterWithAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -97,8 +105,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -112,19 +121,19 @@
// BluetoothAdapter::Observer::AdapterPresentChanged will be called to
// indicate the adapter is now present.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ 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());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithoutAddress) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -135,8 +144,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -149,36 +159,36 @@
// BluetoothAdapter::Observer::AdapterPresentChanged must not be called
// yet.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ 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());
+ 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))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterBecomesPresentWithAddress) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterBecomesPresentWithAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -189,8 +199,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback; make out it failed.
adapter_callback.Run(dbus::ObjectPath(""), false);
@@ -206,23 +217,23 @@
// BluetoothAdapter::Observer::AdapterPresentChanged must be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterReplacedWithAddress) {
+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";
@@ -235,8 +246,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -262,25 +274,25 @@
// 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);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(new_adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterBecomesPresentWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -292,8 +304,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback; make out it failed.
adapter_callback.Run(dbus::ObjectPath(""), false);
@@ -308,25 +321,25 @@
// BluetoothAdapter::Observer::AdapterPresentChanged must not be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ 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))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
@@ -334,11 +347,11 @@
adapter_properties.address.name());
// Adapter should be present with the new address.
- EXPECT_TRUE(adapter->IsPresent());
- EXPECT_EQ(adapter_address, adapter->address());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterReplacedWithoutAddress) {
+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";
@@ -351,8 +364,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -376,25 +390,25 @@
// BluetoothAdapter::Observer::AdapterPresentChanged must be called to
// indicate the adapter has gone away.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ 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))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
@@ -402,11 +416,11 @@
new_adapter_properties.address.name());
// Adapter should be present with the new address.
- EXPECT_TRUE(adapter->IsPresent());
- EXPECT_EQ(new_adapter_address, adapter->address());
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_EQ(new_adapter_address, adapter_->address());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterRemoved) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterRemoved) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -417,8 +431,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -435,22 +450,22 @@
// BluetoothAdapter::Observer::AdapterPresentChanged will be called to
// indicate the adapter is no longer present.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsPresent());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterWithoutAddressRemoved) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterWithoutAddressRemoved) {
const dbus::ObjectPath adapter_path("/fake/hci0");
// Create the default adapter instance;
@@ -460,8 +475,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -477,22 +493,22 @@
// 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);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsPresent());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyInitiallyFalse) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -504,8 +520,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -520,10 +537,10 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_FALSE(adapter->IsPowered());
+ EXPECT_FALSE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyInitiallyTrue) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -535,8 +552,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -550,21 +568,21 @@
// BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ 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());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyInitiallyTrueWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -576,8 +594,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -587,42 +606,42 @@
adapter_properties.powered.ReplaceValue(true);
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&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(), _))
+ 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());
+ 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))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), true))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterPoweredPropertyChanged) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterPoweredPropertyChanged) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -633,8 +652,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -649,30 +669,30 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_FALSE(adapter->IsPowered());
+ 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);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), true))
.Times(1);
adapter_properties.powered.ReplaceValue(true);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterPoweredPropertyUnchanged) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterPoweredPropertyUnchanged) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -683,8 +703,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -699,28 +720,28 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_TRUE(adapter->IsPowered());
+ 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);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyChangedWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -732,8 +753,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -742,12 +764,12 @@
MockBluetoothAdapterClient::Properties adapter_properties;
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&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(), _))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), _))
.Times(0);
adapter_callback.Run(adapter_path, true);
@@ -757,28 +779,28 @@
// the adapter so it is not present.
adapter_properties.powered.ReplaceValue(true);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ 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))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), true))
.Times(1);
static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
@@ -786,10 +808,10 @@
adapter_properties.address.name());
// Adapter should now have the correct property value.
- EXPECT_TRUE(adapter->IsPowered());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyResetOnReplace) {
const dbus::ObjectPath initial_adapter_path("/fake/hci0");
const dbus::ObjectPath new_adapter_path("/fake/hci1");
@@ -803,8 +825,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -829,31 +852,31 @@
// BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
}
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyResetOnReplaceWhenTrue) {
const dbus::ObjectPath initial_adapter_path("/fake/hci0");
const dbus::ObjectPath new_adapter_path("/fake/hci1");
@@ -867,8 +890,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -896,37 +920,37 @@
// 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);
+ adapter_->AddObserver(&adapter_observer);
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
}
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), true))
.Times(1);
}
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterPoweredPropertyResetOnRemove) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -938,8 +962,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -956,24 +981,24 @@
// Report that the adapter has been removed;
// BluetoothAdapter::Observer::AdapterPoweredChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPoweredChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsPowered());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterSetPowered) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterSetPowered) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -984,8 +1009,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1004,10 +1030,10 @@
EXPECT_CALL(adapter_properties, Set(&adapter_properties.powered, _))
.WillOnce(SaveArg<1>(&set_callback));
- adapter->SetPowered(true,
- base::Bind(&BluetoothAdapterChromeOsTest::SetCallback,
+ adapter_->SetPowered(true,
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
base::Unretained(this)),
- base::Bind(&BluetoothAdapterChromeOsTest::ErrorCallback,
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
base::Unretained(this)));
// Reply to the callback to indicate success, the set callback we provided
@@ -1017,11 +1043,11 @@
set_callback.Run(true);
- EXPECT_TRUE(set_callback_called_);
+ EXPECT_TRUE(callback_called_);
EXPECT_FALSE(error_callback_called_);
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterSetPoweredError) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterSetPoweredError) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1032,8 +1058,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1052,11 +1079,11 @@
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)));
+ adapter_->SetPowered(true,
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ 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.
@@ -1065,11 +1092,11 @@
set_callback.Run(false);
- EXPECT_FALSE(set_callback_called_);
+ EXPECT_FALSE(callback_called_);
EXPECT_TRUE(error_callback_called_);
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyInitiallyFalse) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1081,8 +1108,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1097,10 +1125,10 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_FALSE(adapter->IsDiscovering());
+ EXPECT_FALSE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyInitiallyTrue) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1112,8 +1140,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1125,23 +1154,23 @@
EXPECT_CALL(*mock_adapter_client_, GetProperties(adapter_path))
.WillRepeatedly(Return(&adapter_properties));
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), true))
.Times(1);
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_TRUE(adapter->IsDiscovering());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyInitiallyTrueWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1153,53 +1182,54 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
- // the property set but BluetoothAdapter::Observer::AdapterDiscoveringChanged
+ // the property set but BluetoothAdapter::Observer::AdapterScanningChanged
// should not yet be called.
MockBluetoothAdapterClient::Properties adapter_properties;
adapter_properties.discovering.ReplaceValue(true);
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&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(), _))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), _))
.Times(0);
adapter_callback.Run(adapter_path, true);
// Adapter should not yet have the property value.
- EXPECT_FALSE(adapter->IsDiscovering());
+ EXPECT_FALSE(adapter_->IsScanning());
// Tell the adapter the address now,
// BluetoothAdapter::Observer::AdapterPresentChanged and
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged now must be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged now must be called.
adapter_properties.address.ReplaceValue(adapter_address);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), true))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest, DefaultAdapterDiscoveringPropertyChanged) {
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterDiscoveringPropertyChanged) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1210,8 +1240,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1226,30 +1257,30 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_FALSE(adapter->IsDiscovering());
+ EXPECT_FALSE(adapter_->IsScanning());
// Report that the property has been changed;
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), true))
.Times(1);
adapter_properties.discovering.ReplaceValue(true);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyUnchanged) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1261,8 +1292,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1277,29 +1309,29 @@
adapter_callback.Run(adapter_path, true);
// Adapter should have the correct property value.
- EXPECT_TRUE(adapter->IsDiscovering());
+ EXPECT_TRUE(adapter_->IsScanning());
// Report that the property has been changed, but don't change the value;
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged should not be
+ // BluetoothAdapter::Observer::AdapterScanningChanged should not be
// called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyChangedWithoutAddress) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1311,22 +1343,23 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
- // the property set but BluetoothAdapter::Observer::AdapterDiscoveringChanged
+ // the property set but BluetoothAdapter::Observer::AdapterScanningChanged
// should not yet be called.
MockBluetoothAdapterClient::Properties adapter_properties;
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&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(), _))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), _))
.Times(0);
adapter_callback.Run(adapter_path, true);
@@ -1336,28 +1369,28 @@
// the adapter so it is not present.
adapter_properties.discovering.ReplaceValue(true);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), _))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), _))
.Times(0);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsScanning());
// Tell the adapter the address now,
// BluetoothAdapter::Observer::AdapterPresentChanged and
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged now must be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged now must be called.
adapter_properties.address.ReplaceValue(adapter_address);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), true))
.Times(1);
static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
@@ -1365,10 +1398,10 @@
adapter_properties.address.name());
// Adapter should now have the correct property value.
- EXPECT_TRUE(adapter->IsDiscovering());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyResetOnReplace) {
const dbus::ObjectPath initial_adapter_path("/fake/hci0");
const dbus::ObjectPath new_adapter_path("/fake/hci1");
@@ -1382,8 +1415,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1406,33 +1440,33 @@
EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
.WillRepeatedly(Return(&new_adapter_properties));
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
}
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyResetOnReplaceWhenTrue) {
const dbus::ObjectPath initial_adapter_path("/fake/hci0");
const dbus::ObjectPath new_adapter_path("/fake/hci1");
@@ -1446,8 +1480,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1471,43 +1506,43 @@
EXPECT_CALL(*mock_adapter_client_, GetProperties(new_adapter_path))
.WillRepeatedly(Return(&new_adapter_properties));
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called once
+ // BluetoothAdapter::Observer::AdapterScanningChanged 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);
+ adapter_->AddObserver(&adapter_observer);
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), true))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), true))
.Times(1);
}
{
InSequence s;
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(),
- false))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(),
+ false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(),
- true))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(),
+ true))
.Times(1);
}
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_TRUE(adapter_->IsScanning());
}
-TEST_F(BluetoothAdapterChromeOsTest,
+TEST_F(BluetoothAdapterChromeOSTest,
DefaultAdapterDiscoveringPropertyResetOnRemove) {
const dbus::ObjectPath adapter_path("/fake/hci0");
const std::string adapter_address = "CA:FE:4A:C0:FE:FE";
@@ -1519,8 +1554,9 @@
EXPECT_CALL(*mock_manager_client_, DefaultAdapter(_))
.WillOnce(SaveArg<0>(&adapter_callback));
- scoped_refptr<BluetoothAdapter> adapter =
- BluetoothAdapterFactory::DefaultAdapter();
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -1535,23 +1571,815 @@
adapter_callback.Run(adapter_path, true);
// Report that the adapter has been removed;
- // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ // BluetoothAdapter::Observer::AdapterScanningChanged will be called.
MockBluetoothAdapter::Observer adapter_observer;
- adapter->AddObserver(&adapter_observer);
+ adapter_->AddObserver(&adapter_observer);
- EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterPresentChanged(adapter_.get(), false))
.Times(1);
- EXPECT_CALL(adapter_observer, AdapterDiscoveringChanged(adapter.get(), false))
+ EXPECT_CALL(adapter_observer, AdapterScanningChanged(adapter_.get(), false))
.Times(1);
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter.get());
+ 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());
+ EXPECT_FALSE(adapter_->IsScanning());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterNotInitiallyDiscovering) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterStartDiscovering) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterStartDiscoveringError) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate failure,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will not be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, false);
+
+ EXPECT_FALSE(callback_called_);
+ EXPECT_TRUE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterSecondStartDiscovering) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to start discovering devices again;
+ // BluetoothAdapterClient::StartDiscovery will be called again.
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since it has not changed.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest,
+ DefaultAdapterSecondStartDiscoveringError) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to start discovering devices again;
+ // BluetoothAdapterClient::StartDiscovery will be called again.
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate failure, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since it has not really changed.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, false);
+
+ EXPECT_FALSE(callback_called_);
+ EXPECT_TRUE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterStopDiscovering) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to stop discovering devices;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback stop_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged should be called.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), false))
+ .Times(1);
+
+ stop_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest, DefaultAdapterStopDiscoveringError) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to stop discovering devices;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback stop_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate failure,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will not be called.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ stop_discovery_callback.Run(adapter_path, false);
+
+ EXPECT_FALSE(callback_called_);
+ EXPECT_TRUE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest,
+ DefaultAdapterStopDiscoveringAfterSecondStart) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to start discovering devices again;
+ // BluetoothAdapterClient::StartDiscovery will be called again.
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since it has not changed.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to stop discovering devices;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback stop_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since there is still an open session.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ stop_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest,
+ DefaultAdapterStopDiscoveringAfterSecondStartError) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to start discovering devices again;
+ // BluetoothAdapterClient::StartDiscovery will be called again.
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate failure, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since it has not changed.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, false);
+
+ // Ask the adapter to stop discovering devices;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback stop_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged should be called.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), false))
+ .Times(1);
+
+ stop_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterChromeOSTest,
+ DefaultAdapterSecondStopDiscoveringAfterSecondStart) {
+ 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));
+
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+
+ // 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);
+
+ // Ask the adapter to start discovering devices;
+ // BluetoothAdapterClient::StartDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback start_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged will be called.
+ MockBluetoothAdapter::Observer adapter_observer;
+ adapter_->AddObserver(&adapter_observer);
+
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), true))
+ .Times(1);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to start discovering devices again;
+ // BluetoothAdapterClient::StartDiscovery will be called again.
+ EXPECT_CALL(*mock_adapter_client_, StartDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&start_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StartDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since it has not changed.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ start_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to stop discovering devices;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ BluetoothAdapterClient::AdapterCallback stop_discovery_callback;
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success, we do not expect
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged to be called
+ // since there is still an open session.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), _))
+ .Times(0);
+
+ stop_discovery_callback.Run(adapter_path, true);
+
+ // Ask the adapter to stop discovering devices again;
+ // BluetoothAdapterClient::StopDiscovery will be called.
+ EXPECT_CALL(*mock_adapter_client_, StopDiscovery(adapter_path, _))
+ .WillOnce(SaveArg<1>(&stop_discovery_callback));
+
+ callback_called_ = false;
+ error_callback_called_ = false;
+
+ adapter_->StopDiscovering(
+ base::Bind(&BluetoothAdapterChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ // After returning to indicate success,
+ // BluetoothAdapter::Observer::AdapterDiscoveringChanged should be called.
+ EXPECT_CALL(adapter_observer,
+ AdapterDiscoveringChanged(adapter_.get(), false))
+ .Times(1);
+
+ stop_discovery_callback.Run(adapter_path, true);
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_FALSE(error_callback_called_);
+
+ // Adapter should have the correct property value.
+ EXPECT_FALSE(adapter_->IsDiscovering());
}
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_devices_chromeos_unittest.cc b/device/bluetooth/bluetooth_adapter_devices_chromeos_unittest.cc
index ac7677b..a4e01de 100644
--- a/device/bluetooth/bluetooth_adapter_devices_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_adapter_devices_chromeos_unittest.cc
@@ -24,7 +24,7 @@
namespace chromeos {
-class BluetoothAdapterDevicesChromeOsTest : public testing::Test {
+class BluetoothAdapterDevicesChromeOSTest : public testing::Test {
public:
virtual void SetUp() {
MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager;
@@ -52,8 +52,10 @@
EXPECT_CALL(*mock_adapter_client_, AddObserver(_))
.Times(1);
- adapter_ = BluetoothAdapterFactory::DefaultAdapter();
- ASSERT_TRUE(adapter_.get() != NULL);
+ BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterDevicesChromeOSTest::SetAdapter,
+ base::Unretained(this)));
+ ASSERT_TRUE(adapter_ != NULL);
// Call the adapter callback;
// BluetoothAdapterClient::GetProperties will be called once to obtain
@@ -83,8 +85,8 @@
}
virtual void TearDown() {
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter_.get());
+ 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))
@@ -96,6 +98,10 @@
DBusThreadManager::Shutdown();
}
+ void SetAdapter(scoped_refptr<device::BluetoothAdapter> adapter) {
+ adapter_ = adapter;
+ }
+
protected:
MockBluetoothManagerClient* mock_manager_client_;
MockBluetoothAdapterClient* mock_adapter_client_;
@@ -108,12 +114,12 @@
MockBluetoothAdapter::Observer adapter_observer_;
};
-const dbus::ObjectPath BluetoothAdapterDevicesChromeOsTest::adapter_path_(
+const dbus::ObjectPath BluetoothAdapterDevicesChromeOSTest::adapter_path_(
"/fake/hci0");
-const std::string BluetoothAdapterDevicesChromeOsTest::adapter_address_ =
+const std::string BluetoothAdapterDevicesChromeOSTest::adapter_address_ =
"CA:FE:4A:C0:FE:FE";
-TEST_F(BluetoothAdapterDevicesChromeOsTest, DeviceRemovedAfterFound) {
+TEST_F(BluetoothAdapterDevicesChromeOSTest, 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";
@@ -130,8 +136,8 @@
.Times(1)
.WillOnce(SaveArg<1>(&device));
- BluetoothAdapterChromeOs* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOs*>(adapter_.get());
+ BluetoothAdapterChromeOS* adapter_chromeos =
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get());
static_cast<BluetoothAdapterClient::Observer*>(adapter_chromeos)
->DeviceFound(adapter_path_, device_address, device_properties);
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
index 03d633f..f772431 100644
--- a/device/bluetooth/bluetooth_adapter_factory.cc
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -4,17 +4,28 @@
#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "chromeos/chromeos_switches.h"
#include "device/bluetooth/bluetooth_adapter.h"
#if defined(OS_CHROMEOS)
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos_experimental.h"
+#elif defined(OS_WIN)
+#include "device/bluetooth/bluetooth_adapter_win.h"
#endif
namespace {
+using device::BluetoothAdapter;
+using device::BluetoothAdapterFactory;
+
// 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
@@ -22,34 +33,75 @@
base::LazyInstance<base::WeakPtr<device::BluetoothAdapter> >::Leaky
default_adapter = LAZY_INSTANCE_INITIALIZER;
+typedef std::vector<BluetoothAdapterFactory::AdapterCallback>
+ AdapterCallbackList;
+
+// List of adapter callbacks to be called once the adapter is initialized.
+// Since Google C++ Style (and clang's static analyzer) forbids us having
+// exit-time destructors we use a lazy instance for it.
+base::LazyInstance<AdapterCallbackList> adapter_callbacks =
+ LAZY_INSTANCE_INITIALIZER;
+
+void RunAdapterCallbacks() {
+ CHECK(default_adapter.Get().get());
+ scoped_refptr<BluetoothAdapter> adapter(default_adapter.Get());
+ for (std::vector<BluetoothAdapterFactory::AdapterCallback>::const_iterator
+ iter = adapter_callbacks.Get().begin();
+ iter != adapter_callbacks.Get().end();
+ ++iter) {
+ iter->Run(adapter);
+ }
+ adapter_callbacks.Get().clear();
+}
+
} // namespace
namespace device {
// static
-scoped_refptr<BluetoothAdapter> BluetoothAdapterFactory::DefaultAdapter() {
+bool BluetoothAdapterFactory::IsBluetoothAdapterAvailable() {
+#if defined(OS_CHROMEOS)
+ return true;
+#elif defined(OS_WIN)
+ return true;
+#endif
+ return false;
+}
+
+// static
+void BluetoothAdapterFactory::GetAdapter(const AdapterCallback& callback) {
if (!default_adapter.Get().get()) {
#if defined(OS_CHROMEOS)
- chromeos::BluetoothAdapterChromeOs* new_adapter =
- new chromeos::BluetoothAdapterChromeOs;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kEnableExperimentalBluetooth)) {
+ chromeos::BluetoothAdapterChromeOSExperimental* new_adapter =
+ new chromeos::BluetoothAdapterChromeOSExperimental;
+ new_adapter->TrackDefaultAdapter();
+ default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
+ } else {
+ chromeos::BluetoothAdapterChromeOS* new_adapter =
+ new chromeos::BluetoothAdapterChromeOS;
+ new_adapter->TrackDefaultAdapter();
+ default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
+ }
+#elif defined(OS_WIN)
+ BluetoothAdapterWin* new_adapter = new BluetoothAdapterWin(
+ base::Bind(&RunAdapterCallbacks));
new_adapter->TrackDefaultAdapter();
default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
#endif
}
- return scoped_refptr<BluetoothAdapter>(default_adapter.Get());
+ if (default_adapter.Get()->IsInitialized()) {
+ callback.Run(scoped_refptr<BluetoothAdapter>(default_adapter.Get()));
+ } else {
+ adapter_callbacks.Get().push_back(callback);
+ }
}
// 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;
+scoped_refptr<BluetoothAdapter> BluetoothAdapterFactory::MaybeGetAdapter() {
+ return scoped_refptr<BluetoothAdapter>(default_adapter.Get());
}
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_factory.h b/device/bluetooth/bluetooth_adapter_factory.h
index 82e1e6f..3b6a2c2 100644
--- a/device/bluetooth/bluetooth_adapter_factory.h
+++ b/device/bluetooth/bluetooth_adapter_factory.h
@@ -7,25 +7,34 @@
#include <string>
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_adapter.h"
namespace device {
-class BluetoothAdapter;
-
// BluetoothAdapterFactory is a class that contains static methods, which
-// instantiate either a specific bluetooth adapter, or the generic "default
+// 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();
+ typedef base::Callback<void(scoped_refptr<BluetoothAdapter> adapter)>
+ AdapterCallback;
- // Creates an instance for a specific adapter at address |address|.
- static BluetoothAdapter* Create(const std::string& address);
+ // Returns true if the Bluetooth adapter is available for the current
+ // platform.
+ static bool IsBluetoothAdapterAvailable();
+
+ // Returns the shared instance of the default adapter, creating and
+ // initializing it if necessary. |callback| is called with the adapter
+ // instance passed only once the adapter is fully initialized and ready to
+ // use.
+ static void GetAdapter(const AdapterCallback& callback);
+
+ // Returns the shared instance of the adapter that has already been created,
+ // but may or may not have been initialized.
+ // It returns NULL if no adapter has been created at the time.
+ static scoped_refptr<BluetoothAdapter> MaybeGetAdapter();
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
new file mode 100644
index 0000000..8d646a3
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_MAC_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+#ifdef __OBJC__
+@class NSArray;
+#else
+class NSArray;
+#endif
+
+namespace base {
+
+class SequencedTaskRunner;
+
+} // namespace base
+
+namespace device {
+
+class BluetoothAdapterMacTest;
+
+class BluetoothAdapterMac : public BluetoothAdapter {
+ public:
+ // BluetoothAdapter override
+ virtual void AddObserver(BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual bool IsInitialized() const 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 bool IsScanning() const OVERRIDE;
+
+ virtual void StartDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void ReadLocalOutOfBandPairingData(
+ const BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
+ private:
+ friend class BluetoothAdapterFactory;
+ friend class BluetoothAdapterMacTest;
+
+ BluetoothAdapterMac();
+ virtual ~BluetoothAdapterMac();
+
+ void TrackDefaultAdapter();
+ void TrackTestAdapter(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
+ void PollAdapter();
+
+ // Adds |devices| into |devices_| and notifies observers of the changes.
+ // |devices| is an array of pointers to discovered or paired
+ // |IOBluetoothDevice| objects.
+ void AddDevices(NSArray* devices);
+
+ // Removes devices that used to be paired but are unpaired by the system from
+ // |devices_|.
+ // |devices| is an array of pointers to paired |IOBluetoothDevice| objects.
+ void RemoveUnpairedDevices(NSArray* paired_devices);
+
+ bool powered_;
+
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+
+ // List of observers interested in event notifications from us.
+ ObserverList<BluetoothAdapter::Observer> observers_;
+
+ base::WeakPtrFactory<BluetoothAdapterMac> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_MAC_H_
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
new file mode 100644
index 0000000..c7d0eb5
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -0,0 +1,203 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_adapter_mac.h"
+
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+#import <IOBluetooth/objc/IOBluetoothHostController.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time.h"
+#include "base/strings/sys_string_conversions.h"
+#include "device/bluetooth/bluetooth_device_mac.h"
+
+// Replicate specific 10.7 SDK declarations for building with prior SDKs.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface IOBluetoothHostController (LionSDKDeclarations)
+- (NSString*)nameAsString;
+- (BluetoothHCIPowerState)powerState;
+@end
+
+@interface IOBluetoothDevice (LionSDKDeclarations)
+- (NSString*)addressString;
+@end
+
+#endif // MAC_OS_X_VERSION_10_7
+
+namespace {
+
+const int kPollIntervalMs = 500;
+
+} // namespace
+
+namespace device {
+
+BluetoothAdapterMac::BluetoothAdapterMac()
+ : BluetoothAdapter(),
+ powered_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+}
+
+BluetoothAdapterMac::~BluetoothAdapterMac() {
+}
+
+void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) {
+ DCHECK(observer);
+ observers_.RemoveObserver(observer);
+}
+
+bool BluetoothAdapterMac::IsInitialized() const {
+ return true;
+}
+
+bool BluetoothAdapterMac::IsPresent() const {
+ return !address_.empty();
+}
+
+bool BluetoothAdapterMac::IsPowered() const {
+ return powered_;
+}
+
+void BluetoothAdapterMac::SetPowered(bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+}
+
+bool BluetoothAdapterMac::IsDiscovering() const {
+ return false;
+}
+
+bool BluetoothAdapterMac::IsScanning() const {
+ return false;
+}
+
+void BluetoothAdapterMac::StartDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+}
+
+void BluetoothAdapterMac::StopDiscovering(const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+}
+
+void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
+ const BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) {
+}
+
+void BluetoothAdapterMac::TrackDefaultAdapter() {
+ ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ PollAdapter();
+}
+
+void BluetoothAdapterMac::TrackTestAdapter(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
+ ui_task_runner_ = ui_task_runner;
+ PollAdapter();
+}
+
+void BluetoothAdapterMac::PollAdapter() {
+ bool was_present = IsPresent();
+ std::string name = "";
+ std::string address = "";
+ bool powered = false;
+ IOBluetoothHostController* controller =
+ [IOBluetoothHostController defaultController];
+
+ if (controller != nil) {
+ name = base::SysNSStringToUTF8([controller nameAsString]);
+ address = base::SysNSStringToUTF8([controller addressAsString]);
+ powered = ([controller powerState] == kBluetoothHCIPowerStateON);
+ }
+
+ bool is_present = !address.empty();
+ name_ = name;
+ address_ = address;
+
+ if (was_present != is_present) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPresentChanged(this, is_present));
+ }
+ if (powered_ != powered) {
+ powered_ = powered;
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPoweredChanged(this, powered_));
+ }
+
+ NSArray* paired_devices = [IOBluetoothDevice pairedDevices];
+ AddDevices(paired_devices);
+ RemoveUnpairedDevices(paired_devices);
+
+ ui_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&BluetoothAdapterMac::PollAdapter,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kPollIntervalMs));
+}
+
+void BluetoothAdapterMac::AddDevices(NSArray* devices) {
+ for (IOBluetoothDevice* device in devices) {
+ std::string device_address =
+ base::SysNSStringToUTF8([device addressString]);
+ DevicesMap::iterator found_device_iter = devices_.find(device_address);
+
+ if (found_device_iter == devices_.end()) {
+ devices_[device_address] = new BluetoothDeviceMac(device);
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceAdded(this, devices_[device_address]));
+ continue;
+ }
+ BluetoothDeviceMac* device_mac =
+ static_cast<BluetoothDeviceMac*>(found_device_iter->second);
+ if (device_mac->device_fingerprint() !=
+ BluetoothDeviceMac::ComputeDeviceFingerprint(device)) {
+ devices_[device_address] = new BluetoothDeviceMac(device);
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, devices_[device_address]));
+ delete device_mac;
+ }
+ }
+}
+
+void BluetoothAdapterMac::RemoveUnpairedDevices(NSArray* paired_devices) {
+ base::hash_set<std::string> paired_device_address_list;
+ for (IOBluetoothDevice* device in paired_devices) {
+ paired_device_address_list.insert(
+ base::SysNSStringToUTF8([device addressString]));
+ }
+
+ DevicesMap::iterator iter = devices_.begin();
+ while (iter != devices_.end()) {
+ DevicesMap::iterator device_iter = iter;
+ ++iter;
+
+ if (paired_device_address_list.find(device_iter->first) !=
+ paired_device_address_list.end())
+ continue;
+
+ if (device_iter->second->IsPaired()) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device_iter->second));
+ delete device_iter->second;
+ devices_.erase(device_iter);
+ }
+ }
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_mac_unittest.mm b/device/bluetooth/bluetooth_adapter_mac_unittest.mm
new file mode 100644
index 0000000..19e2a8a
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_mac_unittest.mm
@@ -0,0 +1,215 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <IOBluetooth/IOBluetoothUtilities.h>
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/test/test_simple_task_runner.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface TestIOBluetoothDevice : IOBluetoothDevice {
+ @private
+ NSString* device_name_;
+ NSString* device_address_;
+ BOOL paired_;
+}
+
++ (TestIOBluetoothDevice*)deviceWithName:(NSString*)device_name
+ address:(NSString*)device_address
+ paired:(BOOL)paired;
+- (id)initWithName:(NSString*)device_name
+ address:(NSString*)device_address
+ paired:(BOOL)paired;
+
+@property (nonatomic, copy, getter=name) NSString* deviceName;
+@property (nonatomic, copy, getter=addressString) NSString* deviceAddress;
+@property (nonatomic, assign, getter=isPaired) BOOL paired;
+
+@end
+
+@implementation TestIOBluetoothDevice
+
+@synthesize deviceName = device_name_;
+@synthesize deviceAddress = device_address_;
+@synthesize paired = paired_;
+
++ (TestIOBluetoothDevice*)deviceWithName:(NSString*)device_name
+ address:(NSString*)device_address
+ paired:(BOOL)paired {
+ return [[[TestIOBluetoothDevice alloc] initWithName:device_name
+ address:device_address
+ paired:paired] autorelease];
+}
+
+- (id)initWithName:(NSString*)device_name
+ address:(NSString*)device_address
+ paired:(BOOL)paired {
+ if (self = [super init]) {
+ [self setDeviceName:device_name];
+ [self setDeviceAddress:device_address];
+ [self setPaired:paired];
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [self setDeviceName:nil];
+ [self setDeviceAddress:nil];
+ [super dealloc];
+}
+
+@end
+
+namespace {
+
+class AdapterObserver : public device::BluetoothAdapter::Observer {
+ public:
+ AdapterObserver() {
+ Clear();
+ }
+
+ void Clear() {
+ num_device_added_ = 0;
+ num_device_changed_ = 0;
+ num_device_removed_ = 0;
+ }
+
+ virtual void DeviceAdded(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_added_++;
+ }
+
+ virtual void DeviceChanged(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_changed_++;
+ }
+
+ virtual void DeviceRemoved(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_removed_++;
+ }
+
+ int num_device_added() const {
+ return num_device_added_;
+ }
+
+ int num_device_changed() const {
+ return num_device_changed_;
+ }
+
+ int num_device_removed() const {
+ return num_device_removed_;
+ }
+
+ private:
+ int num_device_added_;
+ int num_device_changed_;
+ int num_device_removed_;
+};
+
+} // namespace
+
+namespace device {
+
+class BluetoothAdapterMacTest : public testing::Test {
+ public:
+ BluetoothAdapterMacTest()
+ : ui_task_runner_(new base::TestSimpleTaskRunner()),
+ adapter_(new BluetoothAdapterMac()),
+ adapter_mac_(static_cast<BluetoothAdapterMac*>(adapter_.get())) {
+ adapter_mac_->TrackTestAdapter(ui_task_runner_);
+ adapter_mac_->RemoveUnpairedDevices([NSArray array]);
+ adapter_observer_.Clear();
+ }
+
+ virtual void SetUp() OVERRIDE {
+ adapter_mac_->AddObserver(&adapter_observer_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ adapter_mac_->RemoveObserver(&adapter_observer_);
+ }
+
+ void AddDevices(NSArray* devices) {
+ adapter_mac_->AddDevices(devices);
+ }
+
+ void RemoveUnpairedDevices(NSArray* devices) {
+ adapter_mac_->RemoveUnpairedDevices(devices);
+ }
+
+ protected:
+ scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
+ scoped_refptr<BluetoothAdapter> adapter_;
+ BluetoothAdapterMac* adapter_mac_;
+ AdapterObserver adapter_observer_;
+};
+
+TEST_F(BluetoothAdapterMacTest, Poll) {
+ EXPECT_FALSE(ui_task_runner_->GetPendingTasks().empty());
+}
+
+TEST_F(BluetoothAdapterMacTest, AddDevices) {
+ TestIOBluetoothDevice* android_device =
+ [TestIOBluetoothDevice deviceWithName:@"android"
+ address:@"11:22:33:44:55:66"
+ paired:false];
+ TestIOBluetoothDevice* laptop_device =
+ [TestIOBluetoothDevice deviceWithName:@"laptop"
+ address:@"77:88:99:aa:bb:cc"
+ paired:false];
+ TestIOBluetoothDevice* iphone_device =
+ [TestIOBluetoothDevice deviceWithName:@"iphone"
+ address:@"dd:ee:ff:11:22:33"
+ paired:false];
+ NSMutableArray* devices = [NSMutableArray arrayWithCapacity:3];
+ [devices addObject:android_device];
+ [devices addObject:laptop_device];
+ [devices addObject:iphone_device];
+ AddDevices(devices);
+ EXPECT_EQ(3, adapter_observer_.num_device_added());
+ adapter_observer_.Clear();
+
+ AddDevices(devices);
+ EXPECT_EQ(0, adapter_observer_.num_device_added());
+ EXPECT_EQ(0, adapter_observer_.num_device_changed());
+
+ [iphone_device setDeviceName:@"apple phone"];
+ AddDevices(devices);
+ EXPECT_EQ(0, adapter_observer_.num_device_added());
+ EXPECT_EQ(1, adapter_observer_.num_device_changed());
+ adapter_observer_.Clear();
+}
+
+TEST_F(BluetoothAdapterMacTest, RemoveUnpairedDevices) {
+ TestIOBluetoothDevice* android_device =
+ [TestIOBluetoothDevice deviceWithName:@"android"
+ address:@"11:22:33:44:55:66"
+ paired:true];
+ TestIOBluetoothDevice* laptop_device =
+ [TestIOBluetoothDevice deviceWithName:@"laptop"
+ address:@"77:88:99:aa:bb:cc"
+ paired:false];
+ NSMutableArray* devices = [NSMutableArray arrayWithCapacity:2];
+ [devices addObject:android_device];
+ [devices addObject:laptop_device];
+ AddDevices(devices);
+ adapter_observer_.Clear();
+
+ RemoveUnpairedDevices([NSArray arrayWithObject:android_device]);
+ EXPECT_EQ(0, adapter_observer_.num_device_removed());
+
+ RemoveUnpairedDevices([NSArray array]);
+ EXPECT_EQ(1, adapter_observer_.num_device_removed());
+
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index 97eca65..374620b 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -1,75 +1,152 @@
// 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.
-//
-// TODO(youngki): Implement this file.
#include "device/bluetooth/bluetooth_adapter_win.h"
+#include <hash_set>
#include <string>
+#include <utility>
+
#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "device/bluetooth/bluetooth_device_win.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
namespace device {
-BluetoothAdapterWin::BluetoothAdapterWin()
+BluetoothAdapterWin::BluetoothAdapterWin(const InitCallback& init_callback)
: BluetoothAdapter(),
+ init_callback_(init_callback),
+ initialized_(false),
+ powered_(false),
+ discovery_status_(NOT_DISCOVERING),
+ scanning_(false),
+ num_discovery_listeners_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
BluetoothAdapterWin::~BluetoothAdapterWin() {
+ if (task_manager_) {
+ task_manager_->RemoveObserver(this);
+ task_manager_->Shutdown();
+ }
}
void BluetoothAdapterWin::AddObserver(BluetoothAdapter::Observer* observer) {
- NOTIMPLEMENTED();
+ DCHECK(observer);
+ observers_.AddObserver(observer);
}
void BluetoothAdapterWin::RemoveObserver(BluetoothAdapter::Observer* observer) {
- NOTIMPLEMENTED();
+ DCHECK(observer);
+ observers_.RemoveObserver(observer);
+}
+
+// TODO(youngki): Return true when |task_manager_| initializes the adapter
+// state.
+bool BluetoothAdapterWin::IsInitialized() const {
+ return initialized_;
}
bool BluetoothAdapterWin::IsPresent() const {
- NOTIMPLEMENTED();
- return false;
+ return !address_.empty();
}
bool BluetoothAdapterWin::IsPowered() const {
- NOTIMPLEMENTED();
- return false;
+ return powered_;
}
void BluetoothAdapterWin::SetPowered(
bool powered,
const base::Closure& callback,
const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
+ task_manager_->PostSetPoweredBluetoothTask(powered, callback, error_callback);
}
bool BluetoothAdapterWin::IsDiscovering() const {
- NOTIMPLEMENTED();
- return false;
+ return discovery_status_ == DISCOVERING ||
+ discovery_status_ == DISCOVERY_STOPPING;
}
-void BluetoothAdapterWin::SetDiscovering(
- bool discovering,
+bool BluetoothAdapterWin::IsScanning() const {
+ return scanning_;
+}
+
+// If the method is called when |discovery_status_| is DISCOVERY_STOPPING,
+// starting again is handled by BluetoothAdapterWin::DiscoveryStopped().
+void BluetoothAdapterWin::StartDiscovering(
const base::Closure& callback,
const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
+ if (discovery_status_ == DISCOVERING) {
+ num_discovery_listeners_++;
+ callback.Run();
+ return;
+ }
+ on_start_discovery_callbacks_.push_back(
+ std::make_pair(callback, error_callback));
+ MaybePostStartDiscoveryTask();
}
-BluetoothAdapter::ConstDeviceList BluetoothAdapterWin::GetDevices() const {
- NOTIMPLEMENTED();
- return BluetoothAdapter::ConstDeviceList();
+void BluetoothAdapterWin::StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ if (discovery_status_ == NOT_DISCOVERING) {
+ error_callback.Run();
+ return;
+ }
+ on_stop_discovery_callbacks_.push_back(callback);
+ MaybePostStopDiscoveryTask();
}
-BluetoothDevice* BluetoothAdapterWin::GetDevice(const std::string& address) {
- NOTIMPLEMENTED();
- return NULL;
+void BluetoothAdapterWin::DiscoveryStarted(bool success) {
+ discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING;
+ for (std::vector<std::pair<base::Closure, ErrorCallback> >::const_iterator
+ iter = on_start_discovery_callbacks_.begin();
+ iter != on_start_discovery_callbacks_.end();
+ ++iter) {
+ if (success)
+ ui_task_runner_->PostTask(FROM_HERE, iter->first);
+ else
+ ui_task_runner_->PostTask(FROM_HERE, iter->second);
+ }
+ num_discovery_listeners_ = on_start_discovery_callbacks_.size();
+ on_start_discovery_callbacks_.clear();
+
+ if (success) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterDiscoveringChanged(this, true));
+
+ // If there are stop discovery requests, post the stop discovery again.
+ MaybePostStopDiscoveryTask();
+ } else if (!on_stop_discovery_callbacks_.empty()) {
+ // If there are stop discovery requests but start discovery has failed,
+ // notify that stop discovery has been complete.
+ DiscoveryStopped();
+ }
}
-const BluetoothDevice* BluetoothAdapterWin::GetDevice(
- const std::string& address) const {
- NOTIMPLEMENTED();
- return NULL;
+void BluetoothAdapterWin::DiscoveryStopped() {
+ bool was_discovering = IsDiscovering();
+ discovery_status_ = NOT_DISCOVERING;
+ for (std::vector<base::Closure>::const_iterator iter =
+ on_stop_discovery_callbacks_.begin();
+ iter != on_stop_discovery_callbacks_.end();
+ ++iter) {
+ ui_task_runner_->PostTask(FROM_HERE, *iter);
+ }
+ num_discovery_listeners_ = 0;
+ on_stop_discovery_callbacks_.clear();
+ ScanningChanged(false);
+ if (was_discovering)
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterDiscoveringChanged(this, false));
+
+ // If there are start discovery requests, post the start discovery again.
+ MaybePostStartDiscoveryTask();
}
void BluetoothAdapterWin::ReadLocalOutOfBandPairingData(
@@ -78,4 +155,130 @@
NOTIMPLEMENTED();
}
+void BluetoothAdapterWin::AdapterStateChanged(
+ const BluetoothTaskManagerWin::AdapterState& state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ name_ = state.name;
+ bool was_present = IsPresent();
+ bool is_present = !state.address.empty();
+ address_ = state.address;
+ if (was_present != is_present) {
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPresentChanged(this, is_present));
+ }
+ if (powered_ != state.powered) {
+ powered_ = state.powered;
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterPoweredChanged(this, powered_));
+ }
+ if (!initialized_) {
+ initialized_ = true;
+ init_callback_.Run();
+ }
+}
+
+void BluetoothAdapterWin::ScanningChanged(bool scanning) {
+ if (scanning_ != scanning) {
+ scanning_ = scanning;
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ AdapterScanningChanged(this, scanning_));
+ }
+}
+
+void BluetoothAdapterWin::DevicesDiscovered(
+ const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices) {
+ std::hash_set<std::string> device_address_list;
+ for (ScopedVector<BluetoothTaskManagerWin::DeviceState>::const_iterator iter =
+ devices.begin();
+ iter != devices.end();
+ ++iter) {
+ device_address_list.insert((*iter)->address);
+ DevicesMap::iterator found_device_iter = devices_.find((*iter)->address);
+
+ if (found_device_iter == devices_.end()) {
+ devices_[(*iter)->address] = new BluetoothDeviceWin(**iter);
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceAdded(this, devices_[(*iter)->address]));
+ continue;
+ }
+ BluetoothDeviceWin* device_win =
+ static_cast<BluetoothDeviceWin*>(found_device_iter->second);
+ if (device_win->device_fingerprint() !=
+ BluetoothDeviceWin::ComputeDeviceFingerprint(**iter)) {
+ devices_[(*iter)->address] = new BluetoothDeviceWin(**iter);
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, devices_[(*iter)->address]));
+ delete device_win;
+ }
+ }
+
+ DevicesMap::iterator device_iter = devices_.begin();
+ while (device_iter != devices_.end()) {
+ if (device_address_list.find(device_iter->first) !=
+ device_address_list.end()) {
+ ++device_iter;
+ continue;
+ }
+ if (device_iter->second->IsConnected() || device_iter->second->IsPaired()) {
+ BluetoothDeviceWin* device_win =
+ static_cast<BluetoothDeviceWin*>(device_iter->second);
+ device_win->SetVisible(false);
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceChanged(this, device_win));
+ ++device_iter;
+ continue;
+ }
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
+ DeviceRemoved(this, device_iter->second));
+ delete device_iter->second;
+ device_iter = devices_.erase(device_iter);
+ }
+}
+
+void BluetoothAdapterWin::TrackDefaultAdapter() {
+ ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ task_manager_ =
+ new BluetoothTaskManagerWin(ui_task_runner_);
+ task_manager_->AddObserver(this);
+ task_manager_->Initialize();
+}
+
+void BluetoothAdapterWin::TrackTestAdapter(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
+ ui_task_runner_ = ui_task_runner;
+ task_manager_ =
+ new BluetoothTaskManagerWin(ui_task_runner_);
+ task_manager_->AddObserver(this);
+ task_manager_->InitializeWithBluetoothTaskRunner(bluetooth_task_runner);
+}
+
+void BluetoothAdapterWin::MaybePostStartDiscoveryTask() {
+ if (discovery_status_ == NOT_DISCOVERING &&
+ !on_start_discovery_callbacks_.empty()) {
+ discovery_status_ = DISCOVERY_STARTING;
+ task_manager_->PostStartDiscoveryTask();
+ }
+}
+
+void BluetoothAdapterWin::MaybePostStopDiscoveryTask() {
+ if (discovery_status_ != DISCOVERING)
+ return;
+
+ if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
+ for (std::vector<base::Closure>::const_iterator iter =
+ on_stop_discovery_callbacks_.begin();
+ iter != on_stop_discovery_callbacks_.end();
+ ++iter) {
+ ui_task_runner_->PostTask(FROM_HERE, *iter);
+ }
+ num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
+ on_stop_discovery_callbacks_.clear();
+ return;
+ }
+
+ discovery_status_ = DISCOVERY_STOPPING;
+ task_manager_->PostStopDiscoveryTask();
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h
index de76b18..76581d9 100644
--- a/device/bluetooth/bluetooth_adapter_win.h
+++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -6,19 +6,37 @@
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_WIN_H_
#include <string>
+#include <utility>
+#include <vector>
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+
+} // namespace base
namespace device {
class BluetoothAdapterFactory;
+class BluetoothAdapterWinTest;
class BluetoothDevice;
-class BluetoothAdapterWin : public BluetoothAdapter {
+class BluetoothAdapterWin : public BluetoothAdapter,
+ public BluetoothTaskManagerWin::Observer {
+ public:
+ typedef base::Callback<void()> InitCallback;
+
// BluetoothAdapter override
virtual void AddObserver(BluetoothAdapter::Observer* observer) OVERRIDE;
virtual void RemoveObserver(BluetoothAdapter::Observer* observer) OVERRIDE;
+ virtual bool IsInitialized() const OVERRIDE;
virtual bool IsPresent() const OVERRIDE;
virtual bool IsPowered() const OVERRIDE;
virtual void SetPowered(
@@ -26,24 +44,69 @@
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
virtual bool IsDiscovering() const OVERRIDE;
- virtual void SetDiscovering(
- bool discovering,
+ virtual bool IsScanning() const OVERRIDE;
+
+ virtual void StartDiscovering(
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
- virtual ConstDeviceList GetDevices() const OVERRIDE;
- virtual BluetoothDevice* GetDevice(const std::string& address) OVERRIDE;
- virtual const BluetoothDevice* GetDevice(
- const std::string& address) const OVERRIDE;
+ virtual void StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
virtual void ReadLocalOutOfBandPairingData(
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) OVERRIDE;
- private:
- friend class device::BluetoothAdapterFactory;
+ // BluetoothTaskManagerWin::Observer override
+ virtual void AdapterStateChanged(
+ const BluetoothTaskManagerWin::AdapterState& state) OVERRIDE;
+ virtual void DiscoveryStarted(bool success) OVERRIDE;
+ virtual void DiscoveryStopped() OVERRIDE;
+ virtual void ScanningChanged(bool scanning) OVERRIDE;
+ virtual void DevicesDiscovered(
+ const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices)
+ OVERRIDE;
- BluetoothAdapterWin();
+ private:
+ friend class BluetoothAdapterFactory;
+ friend class BluetoothAdapterWinTest;
+
+ enum DiscoveryStatus {
+ NOT_DISCOVERING,
+ DISCOVERY_STARTING,
+ DISCOVERING,
+ DISCOVERY_STOPPING
+ };
+
+ explicit BluetoothAdapterWin(const InitCallback& init_callback);
virtual ~BluetoothAdapterWin();
+ void TrackDefaultAdapter();
+ void TrackTestAdapter(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner);
+
+ void MaybePostStartDiscoveryTask();
+ void MaybePostStopDiscoveryTask();
+
+ InitCallback init_callback_;
+ bool initialized_;
+ bool powered_;
+ DiscoveryStatus discovery_status_;
+ bool scanning_;
+
+ std::vector<std::pair<base::Closure, ErrorCallback> >
+ on_start_discovery_callbacks_;
+ std::vector<base::Closure> on_stop_discovery_callbacks_;
+ size_t num_discovery_listeners_;
+
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+ scoped_refptr<BluetoothTaskManagerWin> task_manager_;
+
+ base::ThreadChecker thread_checker_;
+
+ // List of observers interested in event notifications from us.
+ ObserverList<BluetoothAdapter::Observer> observers_;
+
// 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<BluetoothAdapterWin> weak_ptr_factory_;
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc
new file mode 100644
index 0000000..91887c4
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -0,0 +1,576 @@
+// 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/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/test_simple_task_runner.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_win.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kAdapterAddress[] = "Bluetooth Adapter Address";
+const char kAdapterName[] = "Bluetooth Adapter Name";
+
+
+void MakeDeviceState(const std::string& name,
+ const std::string& address,
+ device::BluetoothTaskManagerWin::DeviceState* state) {
+ state->name = name;
+ state->address = address;
+ state->bluetooth_class = 0;
+ state->authenticated = false;
+ state->connected = false;
+}
+
+class AdapterObserver : public device::BluetoothAdapter::Observer {
+ public:
+ AdapterObserver() {
+ Clear();
+ }
+
+ void Clear() {
+ num_present_changed_ = 0;
+ num_powered_changed_ = 0;
+ num_discovering_changed_ = 0;
+ num_scanning_changed_ = 0;
+ num_device_added_ = 0;
+ num_device_changed_ = 0;
+ num_device_removed_ = 0;
+ }
+
+ virtual void AdapterPresentChanged(
+ device::BluetoothAdapter* adapter, bool present) OVERRIDE {
+ num_present_changed_++;
+ }
+
+ virtual void AdapterPoweredChanged(
+ device::BluetoothAdapter* adapter, bool powered) OVERRIDE {
+ num_powered_changed_++;
+ }
+
+ virtual void AdapterDiscoveringChanged(
+ device::BluetoothAdapter* adapter, bool discovering) OVERRIDE {
+ num_discovering_changed_++;
+ }
+
+ virtual void AdapterScanningChanged(
+ device::BluetoothAdapter* adapter, bool scanning) OVERRIDE {
+ num_scanning_changed_++;
+ }
+
+ virtual void DeviceAdded(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_added_++;
+ }
+
+ virtual void DeviceChanged(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_changed_++;
+ }
+
+ virtual void DeviceRemoved(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE {
+ num_device_removed_++;
+ }
+
+ int num_present_changed() const {
+ return num_present_changed_;
+ }
+
+ int num_powered_changed() const {
+ return num_powered_changed_;
+ }
+
+ int num_discovering_changed() const {
+ return num_discovering_changed_;
+ }
+
+ int num_scanning_changed() const {
+ return num_scanning_changed_;
+ }
+
+ int num_device_added() const {
+ return num_device_added_;
+ }
+
+ int num_device_changed() const {
+ return num_device_changed_;
+ }
+
+ int num_device_removed() const {
+ return num_device_removed_;
+ }
+
+ private:
+ int num_present_changed_;
+ int num_powered_changed_;
+ int num_discovering_changed_;
+ int num_scanning_changed_;
+ int num_device_added_;
+ int num_device_changed_;
+ int num_device_removed_;
+};
+
+} // namespace
+
+namespace device {
+
+class BluetoothAdapterWinTest : public testing::Test {
+ public:
+ BluetoothAdapterWinTest()
+ : ui_task_runner_(new base::TestSimpleTaskRunner()),
+ bluetooth_task_runner_(new base::TestSimpleTaskRunner()),
+ adapter_(new BluetoothAdapterWin(
+ base::Bind(&BluetoothAdapterWinTest::RunInitCallback,
+ base::Unretained(this)))),
+ adapter_win_(static_cast<BluetoothAdapterWin*>(adapter_.get())),
+ init_callback_called_(false) {
+ adapter_win_->TrackTestAdapter(ui_task_runner_,
+ bluetooth_task_runner_);
+ }
+
+ virtual void SetUp() OVERRIDE {
+ adapter_win_->AddObserver(&adapter_observer_);
+ num_start_discovery_callbacks_ = 0;
+ num_start_discovery_error_callbacks_ = 0;
+ num_stop_discovery_callbacks_ = 0;
+ num_stop_discovery_error_callbacks_ = 0;
+ }
+
+ virtual void TearDown() OVERRIDE {
+ adapter_win_->RemoveObserver(&adapter_observer_);
+ }
+
+ void RunInitCallback() {
+ init_callback_called_ = true;
+ }
+
+ void IncrementNumStartDiscoveryCallbacks() {
+ num_start_discovery_callbacks_++;
+ }
+
+ void IncrementNumStartDiscoveryErrorCallbacks() {
+ num_start_discovery_error_callbacks_++;
+ }
+
+ void IncrementNumStopDiscoveryCallbacks() {
+ num_stop_discovery_callbacks_++;
+ }
+
+ void IncrementNumStopDiscoveryErrorCallbacks() {
+ num_stop_discovery_error_callbacks_++;
+ }
+
+ protected:
+ scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_;
+ scoped_refptr<BluetoothAdapter> adapter_;
+ BluetoothAdapterWin* adapter_win_;
+ AdapterObserver adapter_observer_;
+ bool init_callback_called_;
+ int num_start_discovery_callbacks_;
+ int num_start_discovery_error_callbacks_;
+ int num_stop_discovery_callbacks_;
+ int num_stop_discovery_error_callbacks_;
+};
+
+TEST_F(BluetoothAdapterWinTest, AdapterNotPresent) {
+ BluetoothTaskManagerWin::AdapterState state;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_FALSE(adapter_win_->IsPresent());
+}
+
+TEST_F(BluetoothAdapterWinTest, AdapterPresent) {
+ BluetoothTaskManagerWin::AdapterState state;
+ state.address = kAdapterAddress;
+ state.name = kAdapterName;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_TRUE(adapter_win_->IsPresent());
+}
+
+TEST_F(BluetoothAdapterWinTest, AdapterPresentChanged) {
+ BluetoothTaskManagerWin::AdapterState state;
+ state.address = kAdapterAddress;
+ state.name = kAdapterName;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_EQ(1, adapter_observer_.num_present_changed());
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_EQ(1, adapter_observer_.num_present_changed());
+ BluetoothTaskManagerWin::AdapterState empty_state;
+ adapter_win_->AdapterStateChanged(empty_state);
+ EXPECT_EQ(2, adapter_observer_.num_present_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, AdapterPoweredChanged) {
+ BluetoothTaskManagerWin::AdapterState state;
+ state.powered = true;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_EQ(1, adapter_observer_.num_powered_changed());
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_EQ(1, adapter_observer_.num_powered_changed());
+ state.powered = false;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_EQ(2, adapter_observer_.num_powered_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, AdapterInitialized) {
+ EXPECT_FALSE(adapter_win_->IsInitialized());
+ EXPECT_FALSE(init_callback_called_);
+ BluetoothTaskManagerWin::AdapterState state;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_TRUE(adapter_win_->IsInitialized());
+ EXPECT_TRUE(init_callback_called_);
+}
+
+TEST_F(BluetoothAdapterWinTest, SingleStartDiscovery) {
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->StartDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(0, num_start_discovery_callbacks_);
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_start_discovery_callbacks_);
+ EXPECT_EQ(1, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, SingleStartDiscoveryFailure) {
+ adapter_win_->StartDiscovering(
+ base::Closure(),
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
+ base::Unretained(this)));
+ adapter_win_->DiscoveryStarted(false);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_start_discovery_error_callbacks_);
+ EXPECT_EQ(0, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveries) {
+ bluetooth_task_runner_->ClearPendingTasks();
+ int num_discoveries = 5;
+ for (int i = 0; i < num_discoveries; i++) {
+ adapter_win_->StartDiscovering(
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+ }
+ EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(0, num_start_discovery_callbacks_);
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_EQ(num_discoveries, num_start_discovery_callbacks_);
+ EXPECT_EQ(1, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesFailure) {
+ int num_discoveries = 5;
+ for (int i = 0; i < num_discoveries; i++) {
+ adapter_win_->StartDiscovering(
+ base::Closure(),
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
+ base::Unretained(this)));
+ }
+ adapter_win_->DiscoveryStarted(false);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(num_discoveries, num_start_discovery_error_callbacks_);
+ EXPECT_EQ(0, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesAfterDiscovering) {
+ adapter_win_->StartDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_start_discovery_callbacks_);
+
+ bluetooth_task_runner_->ClearPendingTasks();
+ for (int i = 0; i < 5; i++) {
+ int num_start_discovery_callbacks = num_start_discovery_callbacks_;
+ adapter_win_->StartDiscovering(
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
+ EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
+ EXPECT_EQ(num_start_discovery_callbacks + 1,
+ num_start_discovery_callbacks_);
+ }
+ EXPECT_EQ(1, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, StartDiscoveryAfterDiscoveringFailure) {
+ adapter_win_->StartDiscovering(
+ base::Closure(),
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
+ base::Unretained(this)));
+ adapter_win_->DiscoveryStarted(false);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_start_discovery_error_callbacks_);
+
+ adapter_win_->StartDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_start_discovery_callbacks_);
+}
+
+TEST_F(BluetoothAdapterWinTest, SingleStopDiscovery) {
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->ClearPendingTasks();
+ adapter_win_->StopDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ EXPECT_EQ(0, num_stop_discovery_callbacks_);
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->DiscoveryStopped();
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(1, num_stop_discovery_callbacks_);
+ EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
+ EXPECT_EQ(2, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, MultipleStopDiscoveries) {
+ int num_discoveries = 5;
+ for (int i = 0; i < num_discoveries; i++) {
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ }
+ adapter_win_->DiscoveryStarted(true);
+ ui_task_runner_->ClearPendingTasks();
+ bluetooth_task_runner_->ClearPendingTasks();
+ for (int i = 0; i < num_discoveries - 1; i++) {
+ adapter_win_->StopDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(i + 1, num_stop_discovery_callbacks_);
+ }
+ adapter_win_->StopDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ adapter_win_->DiscoveryStopped();
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ EXPECT_EQ(num_discoveries, num_stop_discovery_callbacks_);
+ EXPECT_EQ(2, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest,
+ StartDiscoveryAndStartDiscoveryAndStopDiscoveries) {
+ adapter_win_->StartDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ adapter_win_->StartDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ ui_task_runner_->ClearPendingTasks();
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->StopDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
+ adapter_win_->StopDiscovering(
+ base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothAdapterWinTest,
+ StartDiscoveryAndStopDiscoveryAndStartDiscovery) {
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+ adapter_win_->StopDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStopped();
+ EXPECT_FALSE(adapter_->IsDiscovering());
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ EXPECT_TRUE(adapter_->IsDiscovering());
+}
+
+TEST_F(BluetoothAdapterWinTest, StartDiscoveryBeforeDiscoveryStopped) {
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->DiscoveryStarted(true);
+ adapter_win_->StopDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->DiscoveryStopped();
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothAdapterWinTest, StopDiscoveryWithoutStartDiscovery) {
+ adapter_win_->StopDiscovering(
+ base::Closure(),
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks,
+ base::Unretained(this)));
+ EXPECT_EQ(1, num_stop_discovery_error_callbacks_);
+}
+
+TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStarted) {
+ adapter_win_->StartDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ adapter_win_->StopDiscovering(
+ base::Closure(), BluetoothAdapter::ErrorCallback());
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->DiscoveryStarted(true);
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothAdapterWinTest, StartAndStopBeforeDiscoveryStarted) {
+ int num_expected_start_discoveries = 3;
+ int num_expected_stop_discoveries = 2;
+ for (int i = 0; i < num_expected_start_discoveries; i++) {
+ adapter_win_->StartDiscovering(
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ }
+ for (int i = 0; i < num_expected_stop_discoveries; i++) {
+ adapter_win_->StopDiscovering(
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ }
+ bluetooth_task_runner_->ClearPendingTasks();
+ adapter_win_->DiscoveryStarted(true);
+ EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(num_expected_start_discoveries, num_start_discovery_callbacks_);
+ EXPECT_EQ(num_expected_stop_discoveries, num_stop_discovery_callbacks_);
+}
+
+TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStartedAndFailed) {
+ adapter_win_->StartDiscovering(
+ base::Closure(),
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
+ base::Unretained(this)));
+ adapter_win_->StopDiscovering(
+ base::Bind(
+ &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
+ base::Unretained(this)),
+ BluetoothAdapter::ErrorCallback());
+ ui_task_runner_->ClearPendingTasks();
+ adapter_win_->DiscoveryStarted(false);
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(1, num_start_discovery_error_callbacks_);
+ EXPECT_EQ(1, num_stop_discovery_callbacks_);
+ EXPECT_EQ(0, adapter_observer_.num_discovering_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, ScanningChanged) {
+ adapter_win_->ScanningChanged(false);
+ EXPECT_EQ(0, adapter_observer_.num_scanning_changed());
+ adapter_win_->ScanningChanged(true);
+ EXPECT_EQ(1, adapter_observer_.num_scanning_changed());
+ adapter_win_->ScanningChanged(true);
+ EXPECT_EQ(1, adapter_observer_.num_scanning_changed());
+ adapter_win_->ScanningChanged(false);
+ EXPECT_EQ(2, adapter_observer_.num_scanning_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, ScanningFalseOnDiscoveryStopped) {
+ adapter_win_->ScanningChanged(true);
+ adapter_win_->DiscoveryStopped();
+ EXPECT_EQ(2, adapter_observer_.num_scanning_changed());
+}
+
+TEST_F(BluetoothAdapterWinTest, DevicesDiscovered) {
+ BluetoothTaskManagerWin::DeviceState* android_phone_state =
+ new BluetoothTaskManagerWin::DeviceState();
+ MakeDeviceState("phone", "android phone address", android_phone_state);
+ BluetoothTaskManagerWin::DeviceState* laptop_state =
+ new BluetoothTaskManagerWin::DeviceState();
+ MakeDeviceState("laptop", "laptop address", laptop_state);
+ BluetoothTaskManagerWin::DeviceState* iphone_state =
+ new BluetoothTaskManagerWin::DeviceState();
+ MakeDeviceState("phone", "iphone address", iphone_state);
+ ScopedVector<BluetoothTaskManagerWin::DeviceState> devices;
+ devices.push_back(android_phone_state);
+ devices.push_back(laptop_state);
+ devices.push_back(iphone_state);
+
+ adapter_win_->DevicesDiscovered(devices);
+ EXPECT_EQ(3, adapter_observer_.num_device_added());
+ adapter_observer_.Clear();
+
+ iphone_state->name = "apple phone";
+ adapter_win_->DevicesDiscovered(devices);
+ EXPECT_EQ(0, adapter_observer_.num_device_added());
+ EXPECT_EQ(1, adapter_observer_.num_device_changed());
+ EXPECT_EQ(0, adapter_observer_.num_device_removed());
+ adapter_observer_.Clear();
+
+ laptop_state->address = "notebook address";
+ laptop_state->connected = true;
+ adapter_win_->DevicesDiscovered(devices);
+ EXPECT_EQ(1, adapter_observer_.num_device_added());
+ EXPECT_EQ(0, adapter_observer_.num_device_changed());
+ EXPECT_EQ(1, adapter_observer_.num_device_removed());
+ adapter_observer_.Clear();
+
+ devices.clear();
+ adapter_win_->DevicesDiscovered(devices);
+
+ EXPECT_EQ(2, adapter_observer_.num_device_removed());
+ EXPECT_EQ(1, adapter_observer_.num_device_changed());
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc
index 378c6ce..a2249c5 100644
--- a/device/bluetooth/bluetooth_device.cc
+++ b/device/bluetooth/bluetooth_device.cc
@@ -4,17 +4,27 @@
#include "device/bluetooth/bluetooth_device.h"
+#include <string>
+
#include "base/utf_string_conversions.h"
-#include "grit/generated_resources.h"
+#include "device/bluetooth/bluetooth_utils.h"
+#include "grit/device_bluetooth_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace device {
+// static
+bool BluetoothDevice::IsUUIDValid(const std::string& uuid) {
+ return !bluetooth_utils::CanonicalUuid(uuid).empty();
+}
+
BluetoothDevice::BluetoothDevice()
: bluetooth_class_(0),
visible_(false),
bonded_(false),
- connected_(false) {
+ connected_(false),
+ connectable_(true),
+ connecting_(false) {
}
BluetoothDevice::~BluetoothDevice() {
@@ -167,4 +177,25 @@
return connected_;
}
+bool BluetoothDevice::IsConnectable() const {
+ return connectable_;
+}
+
+bool BluetoothDevice::IsConnecting() const {
+ return connecting_;
+}
+
+bool BluetoothDevice::ProvidesServiceWithUUID(
+ const std::string& uuid) const {
+ std::string canonical_uuid = bluetooth_utils::CanonicalUuid(uuid);
+ const BluetoothDevice::ServiceList& services = GetServices();
+ for (BluetoothDevice::ServiceList::const_iterator iter = services.begin();
+ iter != services.end();
+ ++iter) {
+ if (bluetooth_utils::CanonicalUuid(*iter) == canonical_uuid)
+ return true;
+ }
+ return false;
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index 90e420b..b7dc9e2 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -9,8 +9,9 @@
#include <vector>
#include "base/callback.h"
-#include "base/string16.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/string16.h"
namespace device {
@@ -52,6 +53,19 @@
DEVICE_KEYBOARD_MOUSE_COMBO
};
+ // Possible errors passed back to an error callback function in case of a
+ // failed call to Connect().
+ enum ConnectErrorCode {
+ ERROR_UNKNOWN,
+ ERROR_INPROGRESS,
+ ERROR_FAILED,
+ ERROR_AUTH_FAILED,
+ ERROR_AUTH_CANCELED,
+ ERROR_AUTH_REJECTED,
+ ERROR_AUTH_TIMEOUT,
+ ERROR_UNSUPPORTED_DEVICE
+ };
+
// Interface for observing changes from bluetooth devices.
class Observer {
public:
@@ -131,6 +145,10 @@
virtual void DismissDisplayOrConfirm() = 0;
};
+ // Returns true if uuid is in a a valid canonical format
+ // (see utils::CanonicalUuid).
+ static bool IsUUIDValid(const std::string& uuid);
+
virtual ~BluetoothDevice();
// Returns the Bluetooth of address the device. This should be used as
@@ -165,6 +183,15 @@
// and at least one service available for use.
virtual bool IsConnected() const;
+ // Indicates whether the bonded device accepts connections initiated from the
+ // adapter. This value is undefined for unbonded devices.
+ virtual bool IsConnectable() const;
+
+ // Indicates whether there is a call to Connect() ongoing. For this attribute,
+ // we consider a call is ongoing if none of the callbacks passed to Connect()
+ // were called after the corresponding call to Connect().
+ virtual bool IsConnecting() const;
+
// Returns the services (as UUID strings) that this device provides.
typedef std::vector<std::string> ServiceList;
virtual const ServiceList& GetServices() const = 0;
@@ -173,6 +200,11 @@
// is called, in the success case the callback is simply not called.
typedef base::Callback<void()> ErrorCallback;
+ // The ConnectErrorCallback is used for methods that can fail with an error,
+ // passed back as an error code argument to this callback.
+ // In the success case this callback is not called.
+ typedef base::Callback<void(enum ConnectErrorCode)> ConnectErrorCallback;
+
// Returns the services (as BluetoothServiceRecord objects) that this device
// provides.
typedef ScopedVector<BluetoothServiceRecord> ServiceRecordList;
@@ -180,9 +212,8 @@
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;
+ // Indicates whether this device provides the given service.
+ virtual bool ProvidesServiceWithUUID(const std::string& uuid) const;
// The ProvidesServiceCallback is used by ProvidesServiceWithName to indicate
// whether or not a matching service was found.
@@ -222,9 +253,12 @@
//
// If the request fails, |error_callback| will be called; otherwise,
// |callback| is called when the request is complete.
+ // After calling Connect, CancelPairing should be called to cancel the pairing
+ // process and release |pairing_delegate_| if user cancels the pairing and
+ // closes the pairing UI.
virtual void Connect(PairingDelegate* pairing_delegate,
const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ const ConnectErrorCallback& error_callback) = 0;
// Sends the PIN code |pincode| to the remote device during pairing.
//
@@ -246,7 +280,8 @@
// Rejects a pairing or connection request from a remote device.
virtual void RejectPairing() = 0;
- // Cancels a pairing or connection attempt to a remote device.
+ // Cancels a pairing or connection attempt to a remote device or release
+ // |pairing_deleage_| and |agent_|.
virtual void CancelPairing() = 0;
// Disconnects the device, terminating the low-level ACL connection
@@ -307,6 +342,16 @@
bool bonded_;
bool connected_;
+ // Indicates whether the device normally accepts connections initiated from
+ // the adapter once paired.
+ bool connectable_;
+
+ // Indicated whether the device is in a connecting status.
+ bool connecting_;
+
+ // The services (identified by UUIDs) that this device provides.
+ ServiceList service_uuids_;
+
private:
// Returns a localized string containing the device's bluetooth address and
// a device type for display when |name_| is empty.
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc
index 2a09cac..32f4d9f 100644
--- a/device/bluetooth/bluetooth_device_chromeos.cc
+++ b/device/bluetooth/bluetooth_device_chromeos.cc
@@ -28,6 +28,7 @@
#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_service_record_chromeos.h"
#include "device/bluetooth/bluetooth_socket_chromeos.h"
#include "device/bluetooth/bluetooth_utils.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
@@ -37,98 +38,113 @@
using device::BluetoothServiceRecord;
using device::BluetoothSocket;
+namespace {
+
+void DoNothingServiceRecordList(const BluetoothDevice::ServiceRecordList&) {}
+
+} // namespace
+
namespace chromeos {
-BluetoothDeviceChromeOs::BluetoothDeviceChromeOs(
- BluetoothAdapterChromeOs* adapter)
- : BluetoothDevice(),
- adapter_(adapter),
- pairing_delegate_(NULL),
- connecting_applications_counter_(0),
- weak_ptr_factory_(this) {
+BluetoothDeviceChromeOS::BluetoothDeviceChromeOS(
+ BluetoothAdapterChromeOS* adapter)
+ : BluetoothDevice(),
+ adapter_(adapter),
+ pairing_delegate_(NULL),
+ connecting_applications_counter_(0),
+ connecting_calls_(0),
+ service_records_loaded_(false),
+ weak_ptr_factory_(this) {
}
-BluetoothDeviceChromeOs::~BluetoothDeviceChromeOs() {
+BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() {
}
-bool BluetoothDeviceChromeOs::IsPaired() const {
+bool BluetoothDeviceChromeOS::IsPaired() const {
return !object_path_.value().empty();
}
const BluetoothDevice::ServiceList&
-BluetoothDeviceChromeOs::GetServices() const {
+BluetoothDeviceChromeOS::GetServices() const {
return service_uuids_;
}
-void BluetoothDeviceChromeOs::GetServiceRecords(
+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,
+ base::Bind(&BluetoothDeviceChromeOS::CollectServiceRecordsCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
- error_callback));
+ base::Bind(
+ &BluetoothDeviceChromeOS::OnGetServiceRecordsError,
+ 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(
+void BluetoothDeviceChromeOS::ProvidesServiceWithName(
const std::string& name,
const ProvidesServiceCallback& callback) {
GetServiceRecords(
- base::Bind(&BluetoothDeviceChromeOs::SearchServicesForNameCallback,
+ base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameCallback,
weak_ptr_factory_.GetWeakPtr(),
name,
callback),
- base::Bind(&BluetoothDeviceChromeOs::SearchServicesForNameErrorCallback,
+ base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
-bool BluetoothDeviceChromeOs::ExpectingPinCode() const {
+bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
return !pincode_callback_.is_null();
}
-bool BluetoothDeviceChromeOs::ExpectingPasskey() const {
+bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
return !passkey_callback_.is_null();
}
-bool BluetoothDeviceChromeOs::ExpectingConfirmation() const {
+bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
return !confirmation_callback_.is_null();
}
-void BluetoothDeviceChromeOs::Connect(PairingDelegate* pairing_delegate,
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
+void BluetoothDeviceChromeOS::Connect(
+ PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback) {
+ // This is safe because Connect() and its callbacks are called in the same
+ // thread.
+ connecting_calls_++;
+ connecting_ = !!connecting_calls_;
+ // Set the decrement to be issued when either callback is called.
+ base::Closure wrapped_callback = base::Bind(
+ &BluetoothDeviceChromeOS::OnConnectCallbackCalled,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback);
+ ConnectErrorCallback wrapped_error_callback = base::Bind(
+ &BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled,
+ weak_ptr_factory_.GetWeakPtr(),
+ error_callback);
+
if (IsPaired() || IsBonded() || IsConnected()) {
// Connection to already paired or connected device.
- ConnectApplications(callback, error_callback);
+ ConnectApplications(wrapped_callback, wrapped_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,
+ base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice,
weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback),
- base::Bind(&BluetoothDeviceChromeOs::ConnectErrorCallback,
+ wrapped_callback,
+ wrapped_error_callback),
+ base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError,
weak_ptr_factory_.GetWeakPtr(),
- error_callback));
+ wrapped_error_callback));
} else {
// Initiate high-security connection with pairing.
DCHECK(!pairing_delegate_);
@@ -153,24 +169,24 @@
agent_.reset(NULL);
}
- DVLOG(1) << "Pairing: " << address_;
+ VLOG(1) << "Pairing: " << address_;
DBusThreadManager::Get()->GetBluetoothAdapterClient()->
CreatePairedDevice(
adapter_->object_path_,
address_,
agent_path,
bluetooth_agent::kDisplayYesNoCapability,
- base::Bind(&BluetoothDeviceChromeOs::ConnectCallback,
+ base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice,
weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback),
- base::Bind(&BluetoothDeviceChromeOs::ConnectErrorCallback,
+ wrapped_callback,
+ wrapped_error_callback),
+ base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError,
weak_ptr_factory_.GetWeakPtr(),
- error_callback));
+ wrapped_error_callback));
}
}
-void BluetoothDeviceChromeOs::SetPinCode(const std::string& pincode) {
+void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
if (!agent_.get() || pincode_callback_.is_null())
return;
@@ -178,7 +194,7 @@
pincode_callback_.Reset();
}
-void BluetoothDeviceChromeOs::SetPasskey(uint32 passkey) {
+void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
if (!agent_.get() || passkey_callback_.is_null())
return;
@@ -186,7 +202,7 @@
passkey_callback_.Reset();
}
-void BluetoothDeviceChromeOs::ConfirmPairing() {
+void BluetoothDeviceChromeOS::ConfirmPairing() {
if (!agent_.get() || confirmation_callback_.is_null())
return;
@@ -194,7 +210,7 @@
confirmation_callback_.Reset();
}
-void BluetoothDeviceChromeOs::RejectPairing() {
+void BluetoothDeviceChromeOS::RejectPairing() {
if (!agent_.get())
return;
@@ -212,58 +228,73 @@
}
}
-void BluetoothDeviceChromeOs::CancelPairing() {
- if (!agent_.get())
- return;
+void BluetoothDeviceChromeOS::CancelPairing() {
+ bool have_callback = false;
+ if (agent_.get()) {
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(CANCELLED, "");
+ pincode_callback_.Reset();
+ have_callback = true;
+ }
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(CANCELLED, 0);
+ passkey_callback_.Reset();
+ have_callback = true;
+ }
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(CANCELLED);
+ confirmation_callback_.Reset();
+ have_callback = true;
+ }
+ }
- 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();
+ if (!have_callback) {
+ // User cancels the pairing process.
+ DBusThreadManager::Get()->GetBluetoothAdapterClient()->CancelDeviceCreation(
+ adapter_->object_path_,
+ address_,
+ base::Bind(&BluetoothDeviceChromeOS::OnCancelDeviceCreation,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ pairing_delegate_ = NULL;
+ agent_.reset();
}
}
-void BluetoothDeviceChromeOs::Disconnect(const base::Closure& callback,
+void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
const ErrorCallback& error_callback) {
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
Disconnect(object_path_,
- base::Bind(&BluetoothDeviceChromeOs::DisconnectCallback,
+ base::Bind(&BluetoothDeviceChromeOS::DisconnectCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
-void BluetoothDeviceChromeOs::Forget(const ErrorCallback& error_callback) {
+void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) {
DBusThreadManager::Get()->GetBluetoothAdapterClient()->
RemoveDevice(adapter_->object_path_,
object_path_,
- base::Bind(&BluetoothDeviceChromeOs::ForgetCallback,
+ base::Bind(&BluetoothDeviceChromeOS::ForgetCallback,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
}
-void BluetoothDeviceChromeOs::ConnectToService(const std::string& service_uuid,
+void BluetoothDeviceChromeOS::ConnectToService(const std::string& service_uuid,
const SocketCallback& callback) {
GetServiceRecords(
- base::Bind(&BluetoothDeviceChromeOs::GetServiceRecordsForConnectCallback,
+ base::Bind(&BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback,
weak_ptr_factory_.GetWeakPtr(),
service_uuid,
callback),
base::Bind(
- &BluetoothDeviceChromeOs::GetServiceRecordsForConnectErrorCallback,
+ &BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
-void BluetoothDeviceChromeOs::SetOutOfBandPairingData(
+void BluetoothDeviceChromeOS::SetOutOfBandPairingData(
const BluetoothOutOfBandPairingData& data,
const base::Closure& callback,
const ErrorCallback& error_callback) {
@@ -272,37 +303,37 @@
object_path_,
address(),
data,
- base::Bind(&BluetoothDeviceChromeOs::OnRemoteDataCallback,
+ base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
-void BluetoothDeviceChromeOs::ClearOutOfBandPairingData(
+void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
const base::Closure& callback,
const ErrorCallback& error_callback) {
DBusThreadManager::Get()->GetBluetoothOutOfBandClient()->
RemoveRemoteData(
object_path_,
address(),
- base::Bind(&BluetoothDeviceChromeOs::OnRemoteDataCallback,
+ base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
-void BluetoothDeviceChromeOs::SetObjectPath(
+void BluetoothDeviceChromeOS::SetObjectPath(
const dbus::ObjectPath& object_path) {
DCHECK(object_path_ == dbus::ObjectPath(""));
object_path_ = object_path;
}
-void BluetoothDeviceChromeOs::RemoveObjectPath() {
+void BluetoothDeviceChromeOS::RemoveObjectPath() {
DCHECK(object_path_ != dbus::ObjectPath(""));
object_path_ = dbus::ObjectPath("");
}
-void BluetoothDeviceChromeOs::Update(
+void BluetoothDeviceChromeOS::Update(
const BluetoothDeviceClient::Properties* properties,
bool update_state) {
std::string address = properties->address.value();
@@ -322,6 +353,13 @@
}
if (update_state) {
+ // When the device reconnects and we don't have any service records for it,
+ // try to update the cache or fail silently.
+ if (!service_records_loaded_ && !connected_ &&
+ properties->connected.value())
+ GetServiceRecords(base::Bind(&DoNothingServiceRecordList),
+ base::Bind(&base::DoNothing));
+
// 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();
@@ -329,11 +367,11 @@
}
}
-void BluetoothDeviceChromeOs::ConnectCallback(
+void BluetoothDeviceChromeOS::OnCreateDevice(
const base::Closure& callback,
- const ErrorCallback& error_callback,
+ const ConnectErrorCallback& error_callback,
const dbus::ObjectPath& device_path) {
- DVLOG(1) << "Connection successful: " << device_path.value();
+ VLOG(1) << "Connection successful: " << device_path.value();
if (object_path_.value().empty()) {
object_path_ = device_path;
} else {
@@ -351,25 +389,50 @@
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
GetProperties(object_path_)->trusted.Set(
true,
- base::Bind(&BluetoothDeviceChromeOs::OnSetTrusted,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
+ base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted,
+ weak_ptr_factory_.GetWeakPtr()));
- // Connect application-layer protocols.
- ConnectApplications(callback, error_callback);
+ // In parallel with the |trusted| property change, call GetServiceRecords to
+ // retrieve the SDP from the device and then, either on success or failure,
+ // call ConnectApplications.
+ GetServiceRecords(
+ base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecords,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback),
+ base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
}
-void BluetoothDeviceChromeOs::ConnectErrorCallback(
- const ErrorCallback& error_callback,
+void BluetoothDeviceChromeOS::OnCreateDeviceError(
+ const ConnectErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
- LOG(WARNING) << "Connection failed: " << address_
- << ": " << error_name << ": " << error_message;
- error_callback.Run();
+ // The default |error_code| is an unknown error.
+ ConnectErrorCode error_code = ERROR_UNKNOWN;
+
+ // Report any error in the log, even if we know the possible source of it.
+ LOG(WARNING) << "Connection failed (on CreatePairedDevice): "
+ << "\"" << name_ << "\" (" << address_ << "): "
+ << error_name << ": \"" << error_message << "\"";
+
+ // Determines the right error code from error_name, assuming the error name
+ // comes from CreatePairedDevice bluez function.
+ if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) {
+ error_code = ERROR_FAILED;
+ } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) {
+ error_code = ERROR_AUTH_FAILED;
+ } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) {
+ error_code = ERROR_AUTH_REJECTED;
+ } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) {
+ error_code = ERROR_AUTH_TIMEOUT;
+ }
+ error_callback.Run(error_code);
}
-void BluetoothDeviceChromeOs::CollectServiceRecordsCallback(
+void BluetoothDeviceChromeOS::CollectServiceRecordsCallback(
const ServiceRecordsCallback& callback,
const ErrorCallback& error_callback,
const dbus::ObjectPath& device_path,
@@ -380,48 +443,95 @@
return;
}
- ScopedVector<BluetoothServiceRecord> records;
+ // Update the cache. No other thread is executing a GetServiceRecords
+ // callback, so it is safe to delete the previous objects here.
+ service_records_.clear();
+ // TODO(deymo): Perhaps don't update the cache if the new SDP information is
+ // empty and we had something before. Some devices only answer this
+ // information while paired, and this callback could be called in any order if
+ // several calls to GetServiceRecords are made while initial pairing with the
+ // device. This requires more investigation.
for (BluetoothDeviceClient::ServiceMap::const_iterator i =
service_map.begin(); i != service_map.end(); ++i) {
- records.push_back(
- new BluetoothServiceRecord(address(), i->second));
+ service_records_.push_back(
+ new BluetoothServiceRecordChromeOS(address(), i->second));
}
- callback.Run(records);
+ service_records_loaded_ = true;
+
+ callback.Run(service_records_);
}
-void BluetoothDeviceChromeOs::OnSetTrusted(const base::Closure& callback,
- const ErrorCallback& error_callback,
- bool success) {
- if (success) {
- callback.Run();
+void BluetoothDeviceChromeOS::OnSetTrusted(bool success) {
+ LOG_IF(WARNING, !success) << "Failed to set device as trusted: " << address_;
+}
+
+void BluetoothDeviceChromeOS::OnInitialGetServiceRecords(
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback,
+ const ServiceRecordList& list) {
+ // Connect application-layer protocols.
+ ConnectApplications(callback, error_callback);
+}
+
+void BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError(
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback) {
+ // Ignore the error retrieving the service records and continue.
+ LOG(WARNING) << "Error retrieving SDP for " << address_ << " after pairing.";
+ // Connect application-layer protocols.
+ ConnectApplications(callback, error_callback);
+}
+
+void BluetoothDeviceChromeOS::OnGetServiceRecordsError(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback) {
+ if (service_records_loaded_) {
+ callback.Run(service_records_);
} else {
- LOG(WARNING) << "Failed to set device as trusted: " << address_;
error_callback.Run();
}
}
-void BluetoothDeviceChromeOs::ConnectApplications(
+void BluetoothDeviceChromeOS::OnConnectCallbackCalled(
+ const base::Closure& callback) {
+ // Update the connecting status.
+ connecting_calls_--;
+ connecting_ = !!connecting_calls_;
+ callback.Run();
+}
+
+void BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled(
+ const ConnectErrorCallback& error_callback,
+ enum ConnectErrorCode error_code) {
+ // Update the connecting status.
+ connecting_calls_--;
+ connecting_ = !!connecting_calls_;
+ error_callback.Run(error_code);
+}
+
+void BluetoothDeviceChromeOS::ConnectApplications(
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ const ConnectErrorCallback& error_callback) {
// Introspect the device object to determine supported applications.
DBusThreadManager::Get()->GetIntrospectableClient()->
Introspect(bluetooth_device::kBluetoothDeviceServiceName,
object_path_,
- base::Bind(&BluetoothDeviceChromeOs::OnIntrospect,
+ 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) {
+void BluetoothDeviceChromeOS::OnIntrospect(
+ const base::Closure& callback,
+ const ConnectErrorCallback& 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();
+ error_callback.Run(ERROR_UNKNOWN);
return;
}
@@ -441,11 +551,11 @@
// Supports Input interface.
DBusThreadManager::Get()->GetBluetoothInputClient()->
Connect(object_path_,
- base::Bind(&BluetoothDeviceChromeOs::OnConnect,
+ base::Bind(&BluetoothDeviceChromeOS::OnConnect,
weak_ptr_factory_.GetWeakPtr(),
callback,
*iter),
- base::Bind(&BluetoothDeviceChromeOs::OnConnectError,
+ base::Bind(&BluetoothDeviceChromeOS::OnConnectError,
weak_ptr_factory_.GetWeakPtr(),
error_callback, *iter));
}
@@ -460,11 +570,11 @@
callback.Run();
}
-void BluetoothDeviceChromeOs::OnConnect(const base::Closure& callback,
+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;
+ VLOG(1) << "Application connection successful: " << device_path.value()
+ << ": " << interface_name;
connecting_applications_counter_--;
// |callback| should only be called once, meaning it cannot be called before
@@ -478,33 +588,56 @@
}
}
-void BluetoothDeviceChromeOs::OnConnectError(
- const ErrorCallback& error_callback,
+void BluetoothDeviceChromeOS::OnConnectError(
+ const ConnectErrorCallback& 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();
+ // The default |error_code| is an unknown error.
+ ConnectErrorCode error_code = ERROR_UNKNOWN;
+
+ // Report any error in the log, even if we know the possible source of it.
+ LOG(WARNING) << "Connection failed (on Connect): "
+ << interface_name << ": "
+ << "\"" << name_ << "\" (" << address_ << "): "
+ << error_name << ": \"" << error_message << "\"";
+
+ // Determines the right error code from error_name, assuming the error name
+ // comes from Connect bluez function.
+ if (error_name == bluetooth_adapter::kErrorFailed) {
+ error_code = ERROR_FAILED;
+ } else if (error_name == bluetooth_adapter::kErrorInProgress) {
+ error_code = ERROR_INPROGRESS;
+ } else if (error_name == bluetooth_adapter::kErrorNotSupported) {
+ error_code = ERROR_UNSUPPORTED_DEVICE;
+ }
+
+ error_callback.Run(error_code);
}
-void BluetoothDeviceChromeOs::DisconnectCallback(
+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_;
+ VLOG(1) << "Disconnection successful: " << address_;
callback.Run();
} else {
- LOG(WARNING) << "Disconnection failed: " << address_;
- error_callback.Run();
+ if (connected_) {
+ LOG(WARNING) << "Disconnection failed: " << address_;
+ error_callback.Run();
+ } else {
+ VLOG(1) << "Disconnection failed on a already disconnected device: "
+ << address_;
+ callback.Run();
+ }
}
}
-void BluetoothDeviceChromeOs::ForgetCallback(
+void BluetoothDeviceChromeOS::ForgetCallback(
const ErrorCallback& error_callback,
const dbus::ObjectPath& adapter_path,
bool success) {
@@ -519,12 +652,19 @@
}
}
-void BluetoothDeviceChromeOs::SearchServicesForNameErrorCallback(
+void BluetoothDeviceChromeOS::OnCancelDeviceCreation(
+ const dbus::ObjectPath& adapter_path,
+ bool success) {
+ if (!success)
+ LOG(WARNING) << "CancelDeviceCreation failed: " << address_;
+}
+
+void BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback(
const ProvidesServiceCallback& callback) {
callback.Run(false);
}
-void BluetoothDeviceChromeOs::SearchServicesForNameCallback(
+void BluetoothDeviceChromeOS::SearchServicesForNameCallback(
const std::string& name,
const ProvidesServiceCallback& callback,
const ServiceRecordList& list) {
@@ -538,12 +678,12 @@
callback.Run(false);
}
-void BluetoothDeviceChromeOs::GetServiceRecordsForConnectErrorCallback(
+void BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback(
const SocketCallback& callback) {
callback.Run(NULL);
}
-void BluetoothDeviceChromeOs::GetServiceRecordsForConnectCallback(
+void BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback(
const std::string& service_uuid,
const SocketCallback& callback,
const ServiceRecordList& list) {
@@ -552,7 +692,7 @@
if ((*i)->uuid() == service_uuid) {
// If multiple service records are found, use the first one that works.
scoped_refptr<BluetoothSocket> socket(
- BluetoothSocketChromeOs::CreateBluetoothSocket(**i));
+ BluetoothSocketChromeOS::CreateBluetoothSocket(**i));
if (socket.get() != NULL) {
callback.Run(socket);
return;
@@ -562,7 +702,7 @@
callback.Run(NULL);
}
-void BluetoothDeviceChromeOs::OnRemoteDataCallback(
+void BluetoothDeviceChromeOS::OnRemoteDataCallback(
const base::Closure& callback,
const ErrorCallback& error_callback,
bool success) {
@@ -572,14 +712,14 @@
error_callback.Run();
}
-void BluetoothDeviceChromeOs::DisconnectRequested(
+void BluetoothDeviceChromeOS::DisconnectRequested(
const dbus::ObjectPath& object_path) {
DCHECK(object_path == object_path_);
}
-void BluetoothDeviceChromeOs::Release() {
+void BluetoothDeviceChromeOS::Release() {
DCHECK(agent_.get());
- DVLOG(1) << "Release: " << address_;
+ VLOG(1) << "Release: " << address_;
DCHECK(pairing_delegate_);
pairing_delegate_->DismissDisplayOrConfirm();
@@ -592,11 +732,11 @@
agent_.reset();
}
-void BluetoothDeviceChromeOs::RequestPinCode(
+void BluetoothDeviceChromeOS::RequestPinCode(
const dbus::ObjectPath& device_path,
const PinCodeCallback& callback) {
DCHECK(agent_.get());
- DVLOG(1) << "RequestPinCode: " << device_path.value();
+ VLOG(1) << "RequestPinCode: " << device_path.value();
DCHECK(pairing_delegate_);
DCHECK(pincode_callback_.is_null());
@@ -604,12 +744,12 @@
pairing_delegate_->RequestPinCode(this);
}
-void BluetoothDeviceChromeOs::RequestPasskey(
+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();
+ VLOG(1) << "RequestPasskey: " << device_path.value();
DCHECK(pairing_delegate_);
DCHECK(passkey_callback_.is_null());
@@ -617,35 +757,35 @@
pairing_delegate_->RequestPasskey(this);
}
-void BluetoothDeviceChromeOs::DisplayPinCode(
+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;
+ VLOG(1) << "DisplayPinCode: " << device_path.value() << " " << pincode;
DCHECK(pairing_delegate_);
pairing_delegate_->DisplayPinCode(this, pincode);
}
-void BluetoothDeviceChromeOs::DisplayPasskey(
+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;
+ VLOG(1) << "DisplayPasskey: " << device_path.value() << " " << passkey;
DCHECK(pairing_delegate_);
pairing_delegate_->DisplayPasskey(this, passkey);
}
-void BluetoothDeviceChromeOs::RequestConfirmation(
+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;
+ VLOG(1) << "RequestConfirmation: " << device_path.value() << " " << passkey;
DCHECK(pairing_delegate_);
DCHECK(confirmation_callback_.is_null());
@@ -653,7 +793,7 @@
pairing_delegate_->ConfirmPasskey(this, passkey);
}
-void BluetoothDeviceChromeOs::Authorize(const dbus::ObjectPath& device_path,
+void BluetoothDeviceChromeOS::Authorize(const dbus::ObjectPath& device_path,
const std::string& uuid,
const ConfirmationCallback& callback) {
DCHECK(agent_.get());
@@ -663,7 +803,7 @@
callback.Run(REJECTED);
}
-void BluetoothDeviceChromeOs::ConfirmModeChange(
+void BluetoothDeviceChromeOS::ConfirmModeChange(
Mode mode,
const ConfirmationCallback& callback) {
DCHECK(agent_.get());
@@ -672,9 +812,9 @@
callback.Run(REJECTED);
}
-void BluetoothDeviceChromeOs::Cancel() {
+void BluetoothDeviceChromeOS::Cancel() {
DCHECK(agent_.get());
- DVLOG(1) << "Cancel: " << address_;
+ VLOG(1) << "Cancel: " << address_;
DCHECK(pairing_delegate_);
pairing_delegate_->DismissDisplayOrConfirm();
@@ -682,9 +822,9 @@
// static
-BluetoothDeviceChromeOs* BluetoothDeviceChromeOs::Create(
- BluetoothAdapterChromeOs* adapter) {
- return new BluetoothDeviceChromeOs(adapter);
+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
index 4b2d3b5..32e8984 100644
--- a/device/bluetooth/bluetooth_device_chromeos.h
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -28,16 +28,16 @@
namespace chromeos {
-class BluetoothAdapterChromeOs;
+class BluetoothAdapterChromeOS;
-// The BluetoothDeviceChromeOs class is an implementation of BluetoothDevice
+// The BluetoothDeviceChromeOS class is an implementation of BluetoothDevice
// for Chrome OS platform.
-class BluetoothDeviceChromeOs
+class BluetoothDeviceChromeOS
: public device::BluetoothDevice,
public BluetoothDeviceClient::Observer,
public BluetoothAgentServiceProvider::Delegate {
public:
- virtual ~BluetoothDeviceChromeOs();
+ virtual ~BluetoothDeviceChromeOS();
// BluetoothDevice override
virtual bool IsPaired() const OVERRIDE;
@@ -45,7 +45,6 @@
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;
@@ -55,7 +54,7 @@
virtual void Connect(
device::BluetoothDevice::PairingDelegate* pairing_delegate,
const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
+ const ConnectErrorCallback& error_callback) OVERRIDE;
virtual void SetPinCode(const std::string& pincode) OVERRIDE;
virtual void SetPasskey(uint32 passkey) OVERRIDE;
virtual void ConfirmPairing() OVERRIDE;
@@ -77,10 +76,10 @@
const ErrorCallback& error_callback) OVERRIDE;
private:
- friend class BluetoothAdapterChromeOs;
+ friend class BluetoothAdapterChromeOS;
friend class device::MockBluetoothDevice;
- explicit BluetoothDeviceChromeOs(BluetoothAdapterChromeOs* adapter);
+ 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.
@@ -103,19 +102,19 @@
// 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);
+ void OnCreateDevice(const base::Closure& callback,
+ const ConnectErrorCallback& 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);
+ void OnCreateDeviceError(const ConnectErrorCallback& error_callback,
+ const std::string& error_name,
+ const std::string& error_message);
- // Called by BluetoothAdapterClient when a call to DiscoverServices()
+ // Called by BluetoothAdapterClient when a call to GetServiceRecords()
// completes. |callback| and |error_callback| are the callbacks provided to
// GetServiceRecords.
void CollectServiceRecordsCallback(
@@ -127,18 +126,44 @@
// 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);
+ // succeeded.
+ void OnSetTrusted(bool success);
+
+ // Called by BluetoothAdapterClient when a call to GetServiceRecords()
+ // fails. |callback| and |error_callback| are the callbacks provided to
+ // GetServiceRecords().
+ void OnGetServiceRecordsError(const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback);
+
+ // Called by BluetoothAdapterClient when the initial call to
+ // GetServiceRecords() after pairing completes. |callback| and
+ // |error_callback| are the callbacks provided to Connect().
+ void OnInitialGetServiceRecords(const base::Closure& callback,
+ const ConnectErrorCallback& error_callback,
+ const ServiceRecordList& list);
+
+ // Called by BluetoothAdapterClient when the initial call to
+ // GetServiceRecords() after pairing fails. |callback| and |error_callback|
+ // are the callbacks provided to Connect().
+ void OnInitialGetServiceRecordsError(
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback);
+
+ // Called by Connect() when it succeeds. The |callback| is the value passed to
+ // the Connect() call.
+ void OnConnectCallbackCalled(const base::Closure& callback);
+
+ // Called by Connect() when it fails. The |error_callback| is the value passed
+ // to the Connect() call.
+ void OnConnectErrorCallbackCalled(const ConnectErrorCallback& error_callback,
+ enum ConnectErrorCode error_code);
// 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);
+ const ConnectErrorCallback& error_callback);
// Called by IntrospectableClient when a call to Introspect() completes.
// |success| indicates whether or not the request succeeded, |callback| and
@@ -146,7 +171,7 @@
// |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 ConnectErrorCallback& error_callback,
const std::string& service_name,
const dbus::ObjectPath& device_path,
const std::string& xml_data, bool success);
@@ -164,7 +189,7 @@
// |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,
+ void OnConnectError(const ConnectErrorCallback& error_callback,
const std::string& interface_name,
const dbus::ObjectPath& device_path,
const std::string& error_name,
@@ -185,6 +210,11 @@
void ForgetCallback(const ErrorCallback& error_callback,
const dbus::ObjectPath& adapter_path, bool success);
+ // Called by BluetoothAdapterClient when a call to CancelDeviceCreation()
+ // completes, |success| indicates whether or not the request succeeded.
+ void OnCancelDeviceCreation(const dbus::ObjectPath& adapter_path,
+ bool success);
+
// Called if the call to GetServiceRecords from ProvidesServiceWithName fails.
void SearchServicesForNameErrorCallback(
const ProvidesServiceCallback& callback);
@@ -330,12 +360,12 @@
// the request failed before a reply was returned from the device.
virtual void Cancel() OVERRIDE;
- // Creates a new BluetoothDeviceChromeOs object bound to the adapter
+ // Creates a new BluetoothDeviceChromeOS object bound to the adapter
// |adapter|.
- static BluetoothDeviceChromeOs* Create(BluetoothAdapterChromeOs* adapter);
+ static BluetoothDeviceChromeOS* Create(BluetoothAdapterChromeOS* adapter);
// The adapter that owns this device instance.
- BluetoothAdapterChromeOs* adapter_;
+ BluetoothAdapterChromeOS* adapter_;
// The dbus object path of the device, will be empty if the device has only
// been discovered and not yet paired with.
@@ -363,11 +393,21 @@
// Used to keep track of pending application connection requests.
int connecting_applications_counter_;
+ // Used to keep track of ongoing calls to Connect().
+ int connecting_calls_;
+
+ // A service records cache.
+ ServiceRecordList service_records_;
+
+ // This says whether the |service_records_| cache is initialized. Note that an
+ // empty |service_records_| list can be a valid list.
+ bool service_records_loaded_;
+
// 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_;
+ base::WeakPtrFactory<BluetoothDeviceChromeOS> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceChromeOs);
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceChromeOS);
};
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_device_mac.h b/device/bluetooth/bluetooth_device_mac.h
new file mode 100644
index 0000000..d1f4b24
--- /dev/null
+++ b/device/bluetooth/bluetooth_device_mac.h
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_MAC_H_
+#define DEVICE_BLUETOOTH_BlUETOOTH_DEVICE_MAC_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+#ifdef __OBJC__
+@class IOBluetoothDevice;
+#else
+class IOBluetoothDevice;
+#endif
+
+namespace device {
+
+class BluetoothDeviceMac : public BluetoothDevice {
+ public:
+ explicit BluetoothDeviceMac(const IOBluetoothDevice* device);
+ virtual ~BluetoothDeviceMac();
+
+ // 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 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(
+ PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ConnectErrorCallback& 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 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 BluetoothAdapterMac;
+
+ // Computes the fingerprint that can be used to compare the devices.
+ static uint32 ComputeDeviceFingerprint(const IOBluetoothDevice* device);
+
+ uint32 device_fingerprint() const {
+ return device_fingerprint_;
+ }
+
+ // Used to compare the devices.
+ const uint32 device_fingerprint_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_MAC_H_
diff --git a/device/bluetooth/bluetooth_device_mac.mm b/device/bluetooth/bluetooth_device_mac.mm
new file mode 100644
index 0000000..d7ddb54
--- /dev/null
+++ b/device/bluetooth/bluetooth_device_mac.mm
@@ -0,0 +1,158 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_device_mac.h"
+
+#include <IOBluetooth/Bluetooth.h>
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+#import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/hash.h"
+#include "base/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
+#include "device/bluetooth/bluetooth_service_record_mac.h"
+
+// Replicate specific 10.7 SDK declarations for building with prior SDKs.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface IOBluetoothDevice (LionSDKDeclarations)
+- (NSString*)addressString;
+- (NSString*)name;
+- (unsigned int)classOfDevice;
+- (NSArray*)services;
+@end
+
+#endif // MAC_OS_X_VERSION_10_7
+
+namespace device {
+
+BluetoothDeviceMac::BluetoothDeviceMac(const IOBluetoothDevice* device)
+ : BluetoothDevice(),
+ device_fingerprint_(ComputeDeviceFingerprint(device)) {
+ name_ = base::SysNSStringToUTF8([device name]);
+ address_ = base::SysNSStringToUTF8([device addressString]);
+ bluetooth_class_ = [device classOfDevice];
+ connected_ = [device isConnected];
+ bonded_ = [device isPaired];
+ visible_ = true;
+}
+
+BluetoothDeviceMac::~BluetoothDeviceMac() {
+}
+
+bool BluetoothDeviceMac::IsPaired() const {
+ return bonded_;
+}
+
+const BluetoothDevice::ServiceList& BluetoothDeviceMac::GetServices() const {
+ return service_uuids_;
+}
+
+void BluetoothDeviceMac::GetServiceRecords(
+ const ServiceRecordsCallback& callback,
+ const ErrorCallback& error_callback) {
+}
+
+void BluetoothDeviceMac::ProvidesServiceWithName(
+ const std::string& name,
+ const ProvidesServiceCallback& callback) {
+}
+
+bool BluetoothDeviceMac::ExpectingPinCode() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceMac::ExpectingPasskey() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceMac::ExpectingConfirmation() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void BluetoothDeviceMac::Connect(
+ PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::SetPinCode(const std::string& pincode) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::SetPasskey(uint32 passkey) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::ConfirmPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::RejectPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::CancelPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::Disconnect(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::Forget(const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::ConnectToService(
+ const std::string& service_uuid,
+ const SocketCallback& callback) {
+}
+
+void BluetoothDeviceMac::SetOutOfBandPairingData(
+ const BluetoothOutOfBandPairingData& data,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceMac::ClearOutOfBandPairingData(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+// static
+uint32 BluetoothDeviceMac::ComputeDeviceFingerprint(
+ const IOBluetoothDevice* device) {
+ std::string device_string = base::StringPrintf("%s|%s|%u|%d|%d",
+ base::SysNSStringToUTF8([device name]).c_str(),
+ base::SysNSStringToUTF8([device addressString]).c_str(),
+ [device classOfDevice],
+ [device isConnected],
+ [device isPaired]);
+
+ for (IOBluetoothSDPServiceRecord* record in [device services]) {
+ base::StringAppendF(
+ &device_string,
+ "|%s|%u",
+ base::SysNSStringToUTF8([record getServiceName]).c_str(),
+ [[record attributes] count]);
+ }
+
+ return base::Hash(device_string);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index 5b6cd9c..c06693f 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -1,50 +1,89 @@
// 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.
-//
-// TODO(youngki): Implement this file.
#include "device/bluetooth/bluetooth_device_win.h"
#include <string>
+
#include "base/basictypes.h"
+#include "base/hash.h"
#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/stringprintf.h"
#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
+#include "device/bluetooth/bluetooth_service_record_win.h"
+#include "device/bluetooth/bluetooth_socket_win.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+
+namespace {
+
+const int kSdpBytesBufferSize = 1024;
+
+} // namespace
namespace device {
-BluetoothDeviceWin::BluetoothDeviceWin() : BluetoothDevice() {
+BluetoothDeviceWin::BluetoothDeviceWin(
+ const BluetoothTaskManagerWin::DeviceState& state)
+ : BluetoothDevice(), device_fingerprint_(ComputeDeviceFingerprint(state)) {
+ name_ = state.name;
+ address_ = state.address;
+ bluetooth_class_ = state.bluetooth_class;
+ connected_ = state.connected;
+ bonded_ = state.authenticated;
+
+ for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator
+ iter = state.service_record_states.begin();
+ iter != state.service_record_states.end();
+ ++iter) {
+ uint8 sdp_bytes_buffer[kSdpBytesBufferSize];
+ std::copy((*iter)->sdp_bytes.begin(),
+ (*iter)->sdp_bytes.end(),
+ sdp_bytes_buffer);
+ BluetoothServiceRecord* service_record = new BluetoothServiceRecordWin(
+ (*iter)->name,
+ (*iter)->address,
+ (*iter)->sdp_bytes.size(),
+ sdp_bytes_buffer);
+ service_record_list_.push_back(service_record);
+ service_uuids_.push_back(service_record->uuid());
+ }
}
BluetoothDeviceWin::~BluetoothDeviceWin() {
}
+void BluetoothDeviceWin::SetVisible(bool visible) {
+ visible_ = visible;
+}
+
bool BluetoothDeviceWin::IsPaired() const {
- NOTIMPLEMENTED();
return false;
}
const BluetoothDevice::ServiceList& BluetoothDeviceWin::GetServices() const {
- NOTIMPLEMENTED();
return service_uuids_;
}
void BluetoothDeviceWin::GetServiceRecords(
const ServiceRecordsCallback& callback,
const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
-}
-
-bool BluetoothDeviceWin::ProvidesServiceWithUUID(
- const std::string& uuid) const {
- NOTIMPLEMENTED();
- return false;
+ callback.Run(service_record_list_);
}
void BluetoothDeviceWin::ProvidesServiceWithName(
const std::string& name,
const ProvidesServiceCallback& callback) {
- NOTIMPLEMENTED();
+ for (ServiceRecordList::const_iterator iter = service_record_list_.begin();
+ iter != service_record_list_.end();
+ ++iter) {
+ if ((*iter)->name() == name) {
+ callback.Run(true);
+ return;
+ }
+ }
+ callback.Run(false);
}
bool BluetoothDeviceWin::ExpectingPinCode() const {
@@ -65,7 +104,7 @@
void BluetoothDeviceWin::Connect(
PairingDelegate* pairing_delegate,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ const ConnectErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
@@ -102,7 +141,19 @@
void BluetoothDeviceWin::ConnectToService(
const std::string& service_uuid,
const SocketCallback& callback) {
- NOTIMPLEMENTED();
+ for (ServiceRecordList::const_iterator iter = service_record_list_.begin();
+ iter != service_record_list_.end();
+ ++iter) {
+ if ((*iter)->uuid() == service_uuid) {
+ // If multiple service records are found, use the first one that works.
+ scoped_refptr<BluetoothSocket> socket(
+ BluetoothSocketWin::CreateBluetoothSocket(**iter));
+ if (socket.get() != NULL) {
+ callback.Run(socket);
+ return;
+ }
+ }
+ }
}
void BluetoothDeviceWin::SetOutOfBandPairingData(
@@ -118,4 +169,27 @@
NOTIMPLEMENTED();
}
+// static
+uint32 BluetoothDeviceWin::ComputeDeviceFingerprint(
+ const BluetoothTaskManagerWin::DeviceState& state) {
+ std::string device_string = base::StringPrintf("%s%s%u%s%s%s",
+ state.name.c_str(),
+ state.address.c_str(),
+ state.bluetooth_class,
+ state.visible ? "true" : "false",
+ state.connected ? "true" : "false",
+ state.authenticated ? "true" : "false");
+ for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator
+ iter = state.service_record_states.begin();
+ iter != state.service_record_states.end();
+ ++iter) {
+ base::StringAppendF(&device_string,
+ "%s%s%d",
+ (*iter)->name.c_str(),
+ (*iter)->address.c_str(),
+ (*iter)->sdp_bytes.size());
+ }
+ return base::Hash(device_string);
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h
index ee2048b..b1e9d80 100644
--- a/device/bluetooth/bluetooth_device_win.h
+++ b/device/bluetooth/bluetooth_device_win.h
@@ -6,23 +6,30 @@
#define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WIN_H_
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
namespace device {
+class BluetoothAdapterWin;
+
class BluetoothDeviceWin : public BluetoothDevice {
public:
- BluetoothDeviceWin();
+ explicit BluetoothDeviceWin(
+ const BluetoothTaskManagerWin::DeviceState& state);
virtual ~BluetoothDeviceWin();
+ void SetVisible(bool visible);
+
+ // 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;
@@ -32,7 +39,7 @@
virtual void Connect(
PairingDelegate* pairing_delegate,
const base::Closure& callback,
- const ErrorCallback& error_callback) OVERRIDE;
+ const ConnectErrorCallback& error_callback) OVERRIDE;
virtual void SetPinCode(const std::string& pincode) OVERRIDE;
virtual void SetPasskey(uint32 passkey) OVERRIDE;
virtual void ConfirmPairing() OVERRIDE;
@@ -54,8 +61,21 @@
const ErrorCallback& error_callback) OVERRIDE;
private:
- // The services (identified by UUIDs) that this device provides.
- std::vector<std::string> service_uuids_;
+ friend class BluetoothAdapterWin;
+
+ // Computes the fingerprint that can be used to compare the devices.
+ static uint32 ComputeDeviceFingerprint(
+ const BluetoothTaskManagerWin::DeviceState& state);
+
+ uint32 device_fingerprint() const {
+ return device_fingerprint_;
+ }
+
+ // Used to compare the devices.
+ uint32 device_fingerprint_;
+ ServiceRecordList service_record_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceWin);
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_device_win_unittest.cc b/device/bluetooth/bluetooth_device_win_unittest.cc
new file mode 100644
index 0000000..892f022
--- /dev/null
+++ b/device/bluetooth/bluetooth_device_win_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/string_number_conversions.h"
+#include "device/bluetooth/bluetooth_device_win.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kDeviceName[] = "Device";
+const char kDeviceAddress[] = "device address";
+
+const char kTestAudioSdpName[] = "Audio";
+const char kTestAudioSdpAddress[] = "01:02:03:0A:10:A0";
+const char kTestAudioSdpBytes[] =
+ "35510900000a00010001090001350319110a09000435103506190100090019350619001909"
+ "010209000535031910020900093508350619110d090102090100250c417564696f20536f75"
+ "726365090311090001";
+const char kTestAudioSdpUuid[] = "0000110a-0000-1000-8000-00805f9b34fb";
+
+const char kTestVideoSdpName[] = "Video";
+const char kTestVideoSdpAddress[] = "A0:10:0A:03:02:01";
+const char kTestVideoSdpBytes[] =
+ "354b0900000a000100030900013506191112191203090004350c3503190100350519000308"
+ "0b090005350319100209000935083506191108090100090100250d566f6963652047617465"
+ "776179";
+const char kTestVideoSdpUuid[] = "00001112-0000-1000-8000-00805f9b34fb";
+
+} // namespace
+
+namespace device {
+
+class BluetoothDeviceWinTest : public testing::Test {
+ public:
+ BluetoothDeviceWinTest()
+ : error_called_(false),
+ provides_service_with_name_(false) {
+ BluetoothTaskManagerWin::DeviceState device_state;
+ device_state.name = kDeviceName;
+ device_state.address = kDeviceAddress;
+
+ BluetoothTaskManagerWin::ServiceRecordState* audio_state =
+ new BluetoothTaskManagerWin::ServiceRecordState();
+ audio_state->name = kTestAudioSdpName;
+ audio_state->address = kTestAudioSdpAddress;
+ base::HexStringToBytes(kTestAudioSdpBytes, &audio_state->sdp_bytes);
+ device_state.service_record_states.push_back(audio_state);
+
+ BluetoothTaskManagerWin::ServiceRecordState* video_state =
+ new BluetoothTaskManagerWin::ServiceRecordState();
+ video_state->name = kTestVideoSdpName;
+ video_state->address = kTestVideoSdpAddress;
+ base::HexStringToBytes(kTestVideoSdpBytes, &video_state->sdp_bytes);
+ device_state.service_record_states.push_back(video_state);
+
+ device_.reset(new BluetoothDeviceWin(device_state));
+ }
+
+ void GetServiceRecords(
+ const BluetoothDevice::ServiceRecordList& service_record_list) {
+ service_records_ = &service_record_list;
+ }
+
+ void OnError() {
+ error_called_ = true;
+ }
+
+ void SetProvidesServiceWithName(bool provides_service_with_name) {
+ provides_service_with_name_ = provides_service_with_name;
+ }
+
+ protected:
+ scoped_ptr<BluetoothDevice> device_;
+ scoped_ptr<BluetoothDevice> empty_device_;
+ const BluetoothDevice::ServiceRecordList* service_records_;
+ bool error_called_;
+ bool provides_service_with_name_;
+};
+
+TEST_F(BluetoothDeviceWinTest, GetServices) {
+ const BluetoothDevice::ServiceList& service_list = device_->GetServices();
+
+ EXPECT_EQ(2, service_list.size());
+ EXPECT_STREQ(kTestAudioSdpUuid, service_list[0].c_str());
+ EXPECT_STREQ(kTestVideoSdpUuid, service_list[1].c_str());
+}
+
+TEST_F(BluetoothDeviceWinTest, GetServiceRecords) {
+ device_->GetServiceRecords(
+ base::Bind(&BluetoothDeviceWinTest::GetServiceRecords,
+ base::Unretained(this)),
+ BluetoothDevice::ErrorCallback());
+ ASSERT_TRUE(service_records_ != NULL);
+ EXPECT_EQ(2, service_records_->size());
+ EXPECT_STREQ(kTestAudioSdpUuid, (*service_records_)[0]->uuid().c_str());
+ EXPECT_STREQ(kTestVideoSdpUuid, (*service_records_)[1]->uuid().c_str());
+}
+
+TEST_F(BluetoothDeviceWinTest, ProvidesServiceWithName) {
+ device_->ProvidesServiceWithName(
+ kTestAudioSdpName,
+ base::Bind(&BluetoothDeviceWinTest::SetProvidesServiceWithName,
+ base::Unretained(this)));
+ EXPECT_TRUE(provides_service_with_name_);
+
+ device_->ProvidesServiceWithName(
+ kTestVideoSdpName,
+ base::Bind(&BluetoothDeviceWinTest::SetProvidesServiceWithName,
+ base::Unretained(this)));
+ EXPECT_TRUE(provides_service_with_name_);
+
+ device_->ProvidesServiceWithName(
+ "name that does not exist",
+ base::Bind(&BluetoothDeviceWinTest::SetProvidesServiceWithName,
+ base::Unretained(this)));
+ EXPECT_FALSE(provides_service_with_name_);
+}
+
+} // namespace device
\ No newline at end of file
diff --git a/device/bluetooth/bluetooth_init_win.cc b/device/bluetooth/bluetooth_init_win.cc
new file mode 100644
index 0000000..54d0b20
--- /dev/null
+++ b/device/bluetooth/bluetooth_init_win.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_init_win.h"
+
+#include "base/threading/thread_restrictions.h"
+
+namespace {
+
+// A frame-based exception handler filter function for a handler for exceptions
+// generated by the Visual C++ delay loader helper function.
+int FilterVisualCPPExceptions(DWORD exception_code) {
+ return HRESULT_FACILITY(exception_code) == FACILITY_VISUALCPP ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+
+} // namespace
+
+namespace device {
+namespace bluetooth_init_win {
+
+bool HasBluetoothStack() {
+ static enum {
+ HBS_UNKNOWN,
+ HBS_YES,
+ HBS_NO,
+ } has_bluetooth_stack = HBS_UNKNOWN;
+
+ if (has_bluetooth_stack == HBS_UNKNOWN) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ HRESULT hr = E_FAIL;
+ __try {
+ hr = __HrLoadAllImportsForDll("bthprops.cpl");
+ } __except(FilterVisualCPPExceptions(::GetExceptionCode())) {
+ hr = E_FAIL;
+ }
+ has_bluetooth_stack = SUCCEEDED(hr) ? HBS_YES : HBS_NO;
+ }
+
+ return has_bluetooth_stack == HBS_YES;
+}
+
+} // namespace bluetooth_init_win
+} // namespace device
\ No newline at end of file
diff --git a/device/bluetooth/bluetooth_init_win.h b/device/bluetooth/bluetooth_init_win.h
new file mode 100644
index 0000000..00fd186
--- /dev/null
+++ b/device/bluetooth/bluetooth_init_win.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_INIT_WIN_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_INIT_WIN_H_
+
+// windows.h needs to be included before BluetoothAPIs.h.
+#include <windows.h>
+
+#include <BluetoothAPIs.h>
+#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <delayimp.h>
+#include <ws2def.h>
+#include <ws2bth.h>
+
+#pragma comment(lib, "Bthprops.lib")
+
+namespace device {
+namespace bluetooth_init_win {
+
+// Returns true if the machine has a bluetooth stack available. The first call
+// to this function will involve file IO, so it should be done on an appropriate
+// thread. This function is not threadsafe.
+bool HasBluetoothStack();
+
+} // namespace bluetooth_init_win
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_INIT_WIN_H_
diff --git a/device/bluetooth/bluetooth_service_record.cc b/device/bluetooth/bluetooth_service_record.cc
index 0ea18d7..aa97373 100644
--- a/device/bluetooth/bluetooth_service_record.cc
+++ b/device/bluetooth/bluetooth_service_record.cc
@@ -4,119 +4,12 @@
#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);
- }
+BluetoothServiceRecord::BluetoothServiceRecord() {
}
-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_);
+BluetoothServiceRecord::~BluetoothServiceRecord() {
}
} // namespace device
diff --git a/device/bluetooth/bluetooth_service_record.h b/device/bluetooth/bluetooth_service_record.h
index e04d73a..eebdb6a 100644
--- a/device/bluetooth/bluetooth_service_record.h
+++ b/device/bluetooth/bluetooth_service_record.h
@@ -9,8 +9,6 @@
#include "base/basictypes.h"
-class XmlReader;
-
namespace device {
// BluetoothServiceRecord represents an SDP service record.
@@ -19,38 +17,51 @@
// that have been necessary so far.
class BluetoothServiceRecord {
public:
- BluetoothServiceRecord(
- const std::string& address,
- const std::string& xml_data);
+ virtual ~BluetoothServiceRecord();
- // The human-readable name of this service.
- const std::string& name() const { return name_; }
+ // 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 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_; }
+ // 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_; }
+ // Indicates if this service supports HID.
+ bool SupportsHid() const { return supports_hid_; }
- // 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_; }
+ // For HID services, returns the HIDReconnectInitiate attribute. For non-HID
+ // or unknown services defaults to true.
+ bool hid_reconnect_initiate() const { return hid_reconnect_initiate_; }
- private:
- void ExtractChannels(XmlReader* reader);
- void ExtractUuid(XmlReader* reader);
+ // For HID services, returns the HIDNormallyConnectable attribute. For non-HID
+ // or unknown services defaults to true.
+ bool hid_normally_connectable() const { return hid_normally_connectable_; }
+
+ // 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_; }
+
+ protected:
+ BluetoothServiceRecord();
std::string address_;
std::string name_;
std::string uuid_;
+ bool supports_hid_;
+ bool hid_reconnect_initiate_;
+ bool hid_normally_connectable_;
+
bool supports_rfcomm_;
uint8 rfcomm_channel_;
+ private:
DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecord);
};
diff --git a/device/bluetooth/bluetooth_service_record_chromeos.cc b/device/bluetooth/bluetooth_service_record_chromeos.cc
new file mode 100644
index 0000000..b7ab878
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_chromeos.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_service_record_chromeos.h"
+
+#include <bluetooth/bluetooth.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* kBooleanNode = "boolean";
+static const char* kSequenceNode = "sequence";
+static const char* kTextNode = "text";
+static const char* kUint8Node = "uint8";
+static const char* kUuidNode = "uuid";
+
+static const char* kIdAttribute = "id";
+static const char* kValueAttribute = "value";
+static const char* kValueTrue = "true";
+
+static const char* kHidNormallyConnectableId = "0x020d";
+static const char* kHidReconnectInitiateId = "0x0205";
+static const char* kProtocolDescriptorListId = "0x0004";
+static const char* kSdpNameId = "0x0100";
+static const char* kServiceClassUuidId = "0x0001";
+
+static const char* kProtocolRfcommUuid = "0x0003";
+static const char* kProtocolHidpUuid = "0x0011";
+
+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;
+}
+
+bool ExtractBooleanValue(XmlReader* reader, bool* value_out) {
+ if (AdvanceToTag(reader, kBooleanNode)) {
+ std::string str_value;
+ if (!reader->NodeAttribute(kValueAttribute, &str_value))
+ return false;
+ *value_out = str_value == kValueTrue;
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+namespace chromeos {
+
+BluetoothServiceRecordChromeOS::BluetoothServiceRecordChromeOS(
+ const std::string& address,
+ const std::string& xml_data) {
+ address_ = address;
+ supports_rfcomm_ = false;
+ supports_hid_ = false;
+
+ // For HID services the default is false when the attribute is not present.
+ hid_reconnect_initiate_ = false;
+ hid_normally_connectable_ = 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)) {
+ ExtractProtocolDescriptors(&reader);
+ }
+ } else if (id == kServiceClassUuidId) {
+ if (AdvanceToTag(&reader, kSequenceNode)) {
+ ExtractServiceClassUuid(&reader);
+ }
+ } else if (id == kHidNormallyConnectableId) {
+ ExtractBooleanValue(&reader, &hid_normally_connectable_);
+ } else if (id == kHidReconnectInitiateId) {
+ ExtractBooleanValue(&reader, &hid_reconnect_initiate_);
+ }
+ }
+ // We don't care about anything else here, so find the closing tag
+ AdvanceToTag(&reader, kAttributeNode);
+ }
+ if (!supports_hid_) {
+ // For non-HID services the default is true.
+ hid_normally_connectable_ = true;
+ hid_reconnect_initiate_ = true;
+ }
+}
+
+void BluetoothServiceRecordChromeOS::GetBluetoothAddress(
+ bdaddr_t* out_address) const {
+ std::string numbers_only;
+ for (int i = 0; i < 6; ++i)
+ numbers_only += address_.substr(i * 3, 2);
+
+ std::vector<uint8> address_bytes;
+ base::HexStringToBytes(numbers_only, &address_bytes);
+ for (int i = 0; i < 6; ++i)
+ out_address->b[5 - i] = address_bytes[i];
+}
+
+void BluetoothServiceRecordChromeOS::ExtractProtocolDescriptors(
+ XmlReader* reader) {
+ const int start_depth = reader->Depth();
+ // The ProtocolDescriptorList can have one or more sequence of sequence of
+ // stack, where each stack starts with an UUID and the remaining tags (if
+ // present) are protocol-specific.
+ do {
+ if (reader->NodeName() == kSequenceNode) {
+ if (AdvanceToTag(reader, kUuidNode)) {
+ std::string protocolUuid;
+ if (reader->NodeAttribute(kValueAttribute, &protocolUuid)) {
+ // Per protocol parameters parsing.
+ if (protocolUuid == kProtocolRfcommUuid) {
+ 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;
+ }
+ }
+ }
+ }
+ } else if (protocolUuid == kProtocolHidpUuid) {
+ supports_hid_ = true;
+ }
+ }
+ }
+ }
+ } while (AdvanceToTag(reader, kSequenceNode) &&
+ reader->Depth() != start_depth);
+}
+
+void BluetoothServiceRecordChromeOS::ExtractServiceClassUuid(
+ 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 chromeos
diff --git a/device/bluetooth/bluetooth_service_record_chromeos.h b/device/bluetooth/bluetooth_service_record_chromeos.h
new file mode 100644
index 0000000..5d0ce9b
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_chromeos.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_CHROMEOS_H_
+
+#include <bluetooth/bluetooth.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+
+class XmlReader;
+
+namespace chromeos {
+
+// BluetoothServiceRecordChromeOS is an implementation of BluetoothServiceRecord
+// for the ChromeOS platform.
+class BluetoothServiceRecordChromeOS : public device::BluetoothServiceRecord {
+ public:
+ BluetoothServiceRecordChromeOS(const std::string& address,
+ const std::string& xml_data);
+
+ void GetBluetoothAddress(bdaddr_t* out_address) const;
+
+ private:
+ void ExtractProtocolDescriptors(XmlReader* reader);
+ void ExtractServiceClassUuid(XmlReader* reader);
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecordChromeOS);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_service_record_chromeos_unittest.cc b/device/bluetooth/bluetooth_service_record_chromeos_unittest.cc
new file mode 100644
index 0000000..df4bab7
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_chromeos_unittest.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 <bluetooth/bluetooth.h>
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "device/bluetooth/bluetooth_service_record_chromeos.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const char* kAddress = "01:02:03:0A:10:A0";
+static const char* kCustomUuid = "01234567-89ab-cdef-0123-456789abcdef";
+static const char* kSerialUuid = "00001101-0000-1000-8000-00805f9b34fb";
+
+} // namespace
+
+namespace chromeos {
+
+class BluetoothServiceRecordChromeOSTest : public testing::Test {
+ public:
+ base::FilePath GetTestDataFilePath(const char* file) {
+ base::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(BluetoothServiceRecordChromeOSTest, RfcommService) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("rfcomm.xml"), &xml_data);
+
+ BluetoothServiceRecordChromeOS 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(BluetoothServiceRecordChromeOSTest, ShortUuid) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("short_uuid.xml"), &xml_data);
+ BluetoothServiceRecordChromeOS 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);
+ BluetoothServiceRecordChromeOS medium_uuid_service_record(kAddress, xml_data);
+ EXPECT_EQ(kSerialUuid, medium_uuid_service_record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordChromeOSTest, CleanUuid) {
+ std::string xml_data;
+ file_util::ReadFileToString(GetTestDataFilePath("uppercase_uuid.xml"),
+ &xml_data);
+ BluetoothServiceRecordChromeOS service_record(kAddress, xml_data);
+ EXPECT_EQ(kCustomUuid, service_record.uuid());
+
+ xml_data.clear();
+ file_util::ReadFileToString(GetTestDataFilePath("invalid_uuid.xml"),
+ &xml_data);
+ BluetoothServiceRecordChromeOS invalid_service_record(kAddress, xml_data);
+ EXPECT_EQ("", invalid_service_record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordChromeOSTest, BluetoothAddress) {
+ BluetoothServiceRecordChromeOS service_record(kAddress, "");
+ bdaddr_t bluetooth_address;
+ service_record.GetBluetoothAddress(&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]);
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_service_record_mac.h b/device/bluetooth/bluetooth_service_record_mac.h
new file mode 100644
index 0000000..13eb56b
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_mac.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_MAC_H_
+
+#include "device/bluetooth/bluetooth_service_record.h"
+
+#ifdef __OBJC__
+@class IOBluetoothDevice;
+@class IOBluetoothSDPServiceRecord;
+#else
+class IOBluetoothDevice;
+class IOBluetoothSDPServiceRecord;
+#endif
+
+namespace device {
+
+class BluetoothServiceRecordMac : public BluetoothServiceRecord {
+ public:
+ explicit BluetoothServiceRecordMac(IOBluetoothSDPServiceRecord* record);
+ virtual ~BluetoothServiceRecordMac();
+
+ IOBluetoothDevice* GetIOBluetoothDevice() const {
+ return device_;
+ }
+
+ private:
+ IOBluetoothDevice* device_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecordMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_MAC_H_
diff --git a/device/bluetooth/bluetooth_service_record_mac.mm b/device/bluetooth/bluetooth_service_record_mac.mm
new file mode 100644
index 0000000..3410351
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_mac.mm
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_service_record_mac.h"
+
+#include <IOBluetooth/Bluetooth.h>
+#import <IOBluetooth/IOBluetoothUtilities.h>
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+#import <IOBluetooth/objc/IOBluetoothSDPDataElement.h>
+#import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
+#import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace {
+
+void ExtractUuid(IOBluetoothSDPDataElement* service_class_data,
+ std::string* uuid) {
+ NSArray* inner_elements = [service_class_data getArrayValue];
+ IOBluetoothSDPUUID* sdp_uuid = nil;
+ for (IOBluetoothSDPDataElement* inner_element in inner_elements) {
+ if ([inner_element getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) {
+ sdp_uuid = [[inner_element getUUIDValue] getUUIDWithLength:16];
+ break;
+ }
+ }
+ if (sdp_uuid != nil) {
+ const uint8* uuid_bytes = reinterpret_cast<const uint8*>([sdp_uuid bytes]);
+ *uuid = base::StringPrintf(
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3],
+ uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7],
+ uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11],
+ uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]);
+ }
+}
+
+} // namespace
+
+namespace device {
+
+BluetoothServiceRecordMac::BluetoothServiceRecordMac(
+ IOBluetoothSDPServiceRecord* record)
+ : BluetoothServiceRecord() {
+ name_ = base::SysNSStringToUTF8([record getServiceName]);
+ device_ = [[record device] retain];
+ address_ = base::SysNSStringToUTF8(IOBluetoothNSStringFromDeviceAddress(
+ [device_ getAddress]));
+
+ // TODO(youngki): Extract these values from |record|.
+ supports_hid_ = false;
+ hid_reconnect_initiate_ = false;
+ hid_normally_connectable_ = false;
+
+ supports_rfcomm_ =
+ [record getRFCOMMChannelID:&rfcomm_channel_] == kIOReturnSuccess;
+
+ const BluetoothSDPServiceAttributeID service_class_id = 1;
+
+ IOBluetoothSDPDataElement* service_class_data =
+ [record getAttributeDataElement:service_class_id];
+ if ([service_class_data getTypeDescriptor] ==
+ kBluetoothSDPDataElementTypeDataElementSequence) {
+ ExtractUuid(service_class_data, &uuid_);
+ }
+}
+
+BluetoothServiceRecordMac::~BluetoothServiceRecordMac() {
+ [device_ release];
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_service_record_mac_unittest.mm b/device/bluetooth/bluetooth_service_record_mac_unittest.mm
new file mode 100644
index 0000000..8cfb46f
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_mac_unittest.mm
@@ -0,0 +1,152 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_service_record_mac.h"
+
+#import <IOBluetooth/objc/IOBluetoothSDPDataElement.h>
+#import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
+#import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const BluetoothSDPServiceAttributeID kServiceClassIDAttributeId = 0x0001;
+const BluetoothSDPServiceAttributeID kProtocolDescriptorListAttributeId =
+ 0x0004;
+const BluetoothSDPServiceAttributeID kServiceNameAttributeId = 0x0100;
+
+const uint8 kRfcommChannel = 0x0c;
+const char kServiceName[] = "Headset Audio Gateway";
+
+const char kExpectedRfcommUuid[] = "01234567-89ab-cdef-0123-456789abcdef";
+const char kExpectedSerialUuid[] = "00001101-0000-1000-8000-00805f9b34fb";
+
+const int kMaxUuidSize = 16;
+
+} // namespace
+
+namespace device {
+
+class BluetoothServiceRecordMacTest : public testing::Test {
+ public:
+
+ IOBluetoothSDPUUID* ConvertUuid(const char* uuid_hex_char, size_t uuid_size) {
+ std::vector<uint8> uuid_bytes_vector;
+ uint8 uuid_buffer[kMaxUuidSize];
+ base::HexStringToBytes(uuid_hex_char, &uuid_bytes_vector);
+ std::copy(uuid_bytes_vector.begin(),
+ uuid_bytes_vector.end(),
+ uuid_buffer);
+ return [IOBluetoothSDPUUID uuidWithBytes:uuid_buffer length:uuid_size];
+ }
+
+ IOBluetoothSDPDataElement* GetServiceClassId(IOBluetoothSDPUUID* uuid) {
+ IOBluetoothSDPDataElement* uuid_element =
+ [IOBluetoothSDPDataElement withElementValue:uuid];
+ return [IOBluetoothSDPDataElement
+ withElementValue:[NSArray arrayWithObject:uuid_element]];
+ }
+
+ IOBluetoothSDPDataElement* GetProtocolDescriptorList(bool supports_rfcomm) {
+ NSMutableArray* protocol_descriptor_list_sequence = [NSMutableArray array];
+
+ const uint8 l2cap_uuid_bytes[] = { 0x01, 0x00 };
+
+ IOBluetoothSDPUUID* l2cap_uuid =
+ [IOBluetoothSDPUUID uuidWithBytes:l2cap_uuid_bytes length:2];
+ [protocol_descriptor_list_sequence
+ addObject:[NSArray arrayWithObject:l2cap_uuid]];
+
+ if (supports_rfcomm) {
+ const uint8 rfcomm_uuid_bytes[] = { 0x00, 0x03 };
+ IOBluetoothSDPUUID* rfcomm_uuid =
+ [IOBluetoothSDPUUID uuidWithBytes:rfcomm_uuid_bytes length:2];
+ NSNumber* rfcomm_channel =
+ [NSNumber numberWithUnsignedChar:kRfcommChannel];
+ [protocol_descriptor_list_sequence
+ addObject:[NSArray
+ arrayWithObjects:rfcomm_uuid, rfcomm_channel, nil]];
+ }
+
+ return [IOBluetoothSDPDataElement
+ withElementValue:protocol_descriptor_list_sequence];
+ }
+
+ IOBluetoothSDPDataElement* GetServiceName(const std::string& service_name) {
+ return [IOBluetoothSDPDataElement
+ withElementValue:base::SysUTF8ToNSString(service_name)];
+ }
+
+ IOBluetoothSDPServiceRecord* GetServiceRecord(
+ IOBluetoothSDPUUID* uuid, bool supports_rfcomm) {
+ NSMutableDictionary* service_attrs = [NSMutableDictionary dictionary];
+
+ if (uuid != nil) {
+ [service_attrs
+ setObject:GetServiceClassId(uuid)
+ forKey:[NSNumber numberWithInt:kServiceClassIDAttributeId]];
+ }
+ [service_attrs
+ setObject:GetProtocolDescriptorList(supports_rfcomm)
+ forKey:[NSNumber numberWithInt:kProtocolDescriptorListAttributeId]];
+ [service_attrs
+ setObject:GetServiceName(kServiceName)
+ forKey:[NSNumber numberWithInt:kServiceNameAttributeId]];
+
+ return [IOBluetoothSDPServiceRecord withServiceDictionary:service_attrs
+ device:nil];
+ }
+};
+
+TEST_F(BluetoothServiceRecordMacTest, RfcommService) {
+ const char rfcomm_uuid_bytes[] = "0123456789abcdef0123456789abcdef";
+ IOBluetoothSDPUUID* rfcomm_uuid =
+ ConvertUuid(rfcomm_uuid_bytes, sizeof(rfcomm_uuid_bytes) / 2);
+
+ BluetoothServiceRecordMac record(GetServiceRecord(rfcomm_uuid, true));
+ EXPECT_EQ(kServiceName, record.name());
+ EXPECT_TRUE(record.SupportsRfcomm());
+ EXPECT_EQ(kRfcommChannel, record.rfcomm_channel());
+ EXPECT_EQ(kExpectedRfcommUuid, record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordMacTest, ShortUuid) {
+ const char short_uuid_bytes[] = "1101";
+ IOBluetoothSDPUUID* short_uuid =
+ ConvertUuid(short_uuid_bytes, sizeof(short_uuid_bytes) / 2);
+
+ BluetoothServiceRecordMac record(GetServiceRecord(short_uuid, false));
+ EXPECT_EQ(kExpectedSerialUuid, record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordMacTest, MediumUuid) {
+ const char medium_uuid_bytes[] = "00001101";
+ IOBluetoothSDPUUID* medium_uuid =
+ ConvertUuid(medium_uuid_bytes, sizeof(medium_uuid_bytes) / 2);
+
+ BluetoothServiceRecordMac record(GetServiceRecord(medium_uuid, false));
+ EXPECT_EQ(kExpectedSerialUuid, record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordMacTest, UpperCaseUuid) {
+ const char upper_case_uuid_bytes[] = "0123456789ABCDEF0123456789ABCDEF";
+ IOBluetoothSDPUUID* upper_case_uuid =
+ ConvertUuid(upper_case_uuid_bytes, sizeof(upper_case_uuid_bytes) / 2);
+
+ BluetoothServiceRecordMac record(GetServiceRecord(upper_case_uuid, false));
+ EXPECT_EQ(kExpectedRfcommUuid, record.uuid());
+}
+
+TEST_F(BluetoothServiceRecordMacTest, InvalidUuid) {
+ BluetoothServiceRecordMac record(GetServiceRecord(nil, false));
+ EXPECT_EQ("", record.uuid());
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_service_record_unittest.cc b/device/bluetooth/bluetooth_service_record_unittest.cc
deleted file mode 100644
index b59474f..0000000
--- a/device/bluetooth/bluetooth_service_record_unittest.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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_service_record_win.cc b/device/bluetooth/bluetooth_service_record_win.cc
new file mode 100644
index 0000000..a09b335
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_win.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_service_record_win.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/stringprintf.h"
+#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_utils.h"
+
+namespace {
+
+const uint16 kProtocolDescriptorListId = 4;
+const uint16 kRfcommUuid = 3;
+const uint16 kUuidId = 1;
+
+bool AdvanceToSdpType(const SDP_ELEMENT_DATA& sequence_data,
+ SDP_TYPE type,
+ HBLUETOOTH_CONTAINER_ELEMENT* element,
+ SDP_ELEMENT_DATA* sdp_data) {
+ while (ERROR_SUCCESS == BluetoothSdpGetContainerElementData(
+ sequence_data.data.sequence.value,
+ sequence_data.data.sequence.length,
+ element,
+ sdp_data)) {
+ if (sdp_data->type == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ExtractChannels(const SDP_ELEMENT_DATA& protocol_descriptor_list_data,
+ bool* supports_rfcomm,
+ uint8* rfcomm_channel) {
+ HBLUETOOTH_CONTAINER_ELEMENT sequence_element = NULL;
+ SDP_ELEMENT_DATA sequence_data;
+ while (AdvanceToSdpType(protocol_descriptor_list_data,
+ SDP_TYPE_SEQUENCE,
+ &sequence_element,
+ &sequence_data)) {
+ HBLUETOOTH_CONTAINER_ELEMENT inner_sequence_element = NULL;
+ SDP_ELEMENT_DATA inner_sequence_data;
+ if (AdvanceToSdpType(sequence_data,
+ SDP_TYPE_UUID,
+ &inner_sequence_element,
+ &inner_sequence_data) &&
+ inner_sequence_data.data.uuid32 == kRfcommUuid &&
+ AdvanceToSdpType(sequence_data,
+ SDP_TYPE_UINT,
+ &inner_sequence_element,
+ &inner_sequence_data) &&
+ inner_sequence_data.specificType == SDP_ST_UINT8) {
+ *rfcomm_channel = inner_sequence_data.data.uint8;
+ *supports_rfcomm = true;
+ }
+ }
+}
+
+void ExtractUuid(const SDP_ELEMENT_DATA& uuid_data, std::string* uuid) {
+ HBLUETOOTH_CONTAINER_ELEMENT inner_uuid_element = NULL;
+ SDP_ELEMENT_DATA inner_uuid_data;
+ if (AdvanceToSdpType(uuid_data,
+ SDP_TYPE_UUID,
+ &inner_uuid_element,
+ &inner_uuid_data)) {
+ if (inner_uuid_data.specificType == SDP_ST_UUID16) {
+ std::string uuid_hex =
+ base::StringPrintf("%04x", inner_uuid_data.data.uuid16);
+ *uuid = device::bluetooth_utils::CanonicalUuid(uuid_hex);
+ } else if (inner_uuid_data.specificType == SDP_ST_UUID32) {
+ std::string uuid_hex =
+ base::StringPrintf("%08x", inner_uuid_data.data.uuid32);
+ *uuid = device::bluetooth_utils::CanonicalUuid(uuid_hex);
+ } else if (inner_uuid_data.specificType == SDP_ST_UUID128) {
+ *uuid = base::StringPrintf(
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ inner_uuid_data.data.uuid128.Data1,
+ inner_uuid_data.data.uuid128.Data2,
+ inner_uuid_data.data.uuid128.Data3,
+ inner_uuid_data.data.uuid128.Data4[0],
+ inner_uuid_data.data.uuid128.Data4[1],
+ inner_uuid_data.data.uuid128.Data4[2],
+ inner_uuid_data.data.uuid128.Data4[3],
+ inner_uuid_data.data.uuid128.Data4[4],
+ inner_uuid_data.data.uuid128.Data4[5],
+ inner_uuid_data.data.uuid128.Data4[6],
+ inner_uuid_data.data.uuid128.Data4[7]);
+ } else {
+ uuid->clear();
+ }
+ }
+}
+
+BTH_ADDR ConvertToBthAddr(const std::string& address) {
+ BTH_ADDR bth_addr = 0;
+ std::string numbers_only;
+ for (int i = 0; i < 6; ++i) {
+ numbers_only += address.substr(i * 3, 2);
+ }
+
+ std::vector<uint8> address_bytes;
+ base::HexStringToBytes(numbers_only, &address_bytes);
+ int byte_position = 0;
+ for (std::vector<uint8>::reverse_iterator iter = address_bytes.rbegin();
+ iter != address_bytes.rend();
+ ++iter) {
+ bth_addr += *iter * pow(256.0, byte_position);
+ byte_position++;
+ }
+ return bth_addr;
+}
+
+} // namespace
+
+namespace device {
+
+BluetoothServiceRecordWin::BluetoothServiceRecordWin(
+ const std::string& name,
+ const std::string& address,
+ uint64 blob_size,
+ uint8* blob_data) : bth_addr_(ConvertToBthAddr(address)) {
+ name_ = name;
+ address_ = address;
+ supports_rfcomm_ = false;
+ SDP_ELEMENT_DATA protocol_descriptor_list_data;
+ if (ERROR_SUCCESS == BluetoothSdpGetAttributeValue(
+ blob_data,
+ blob_size,
+ kProtocolDescriptorListId,
+ &protocol_descriptor_list_data)) {
+ ExtractChannels(protocol_descriptor_list_data,
+ &supports_rfcomm_,
+ &rfcomm_channel_);
+ }
+ SDP_ELEMENT_DATA uuid_data;
+ if (ERROR_SUCCESS == BluetoothSdpGetAttributeValue(
+ blob_data,
+ blob_size,
+ kUuidId,
+ &uuid_data)) {
+ ExtractUuid(uuid_data, &uuid_);
+ }
+}
+
+} // namespace device
\ No newline at end of file
diff --git a/device/bluetooth/bluetooth_service_record_win.h b/device/bluetooth/bluetooth_service_record_win.h
new file mode 100644
index 0000000..b9f0331
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_win.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_WIN_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_WIN_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+
+namespace device {
+
+class BluetoothServiceRecordWin : public BluetoothServiceRecord {
+ public:
+ BluetoothServiceRecordWin(const std::string& name,
+ const std::string& address,
+ uint64 blob_size,
+ uint8* blob_data);
+
+ BTH_ADDR bth_addr() const {
+ return bth_addr_;
+ }
+
+ private:
+ BTH_ADDR bth_addr_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecordWin);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SERVICE_RECORD_WIN_H_
diff --git a/device/bluetooth/bluetooth_service_record_win_unittest.cc b/device/bluetooth/bluetooth_service_record_win_unittest.cc
new file mode 100644
index 0000000..5f5c03e
--- /dev/null
+++ b/device/bluetooth/bluetooth_service_record_win_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "device/bluetooth/bluetooth_service_record_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestNoRfcommSdpBytes[] =
+ "35510900000a00010001090001350319110a09000435103506190100090019350619001909"
+ "010209000535031910020900093508350619110d090102090100250c417564696f20536f75"
+ "726365090311090001";
+const int kTestNoRfcommSdpBytesSize = sizeof(kTestNoRfcommSdpBytes) / 2;
+const char kTestNoRfcommSdpUuid[] = "0000110a-0000-1000-8000-00805f9b34fb";
+
+const char kTestRfcommSdpBytes[] =
+ "354b0900000a000100030900013506191112191203090004350c3503190100350519000308"
+ "0b090005350319100209000935083506191108090100090100250d566f6963652047617465"
+ "776179";
+const int kTestRfcommSdpBytesSize = sizeof(kTestRfcommSdpBytes) / 2;
+const char kTestRfcommSdpUuid[] = "00001112-0000-1000-8000-00805f9b34fb";
+const int kTestRfcommChannel = 11;
+
+} // namespace
+
+namespace device {
+
+class BluetoothServiceRecordWinTest : public testing::Test {
+ protected:
+ void ConvertSdpBytes(const char* sdp_hex_char, uint8* sdp_bytes_array) {
+ std::vector<uint8> sdp_bytes_vector;
+ base::HexStringToBytes(sdp_hex_char, &sdp_bytes_vector);
+ std::copy(sdp_bytes_vector.begin(),
+ sdp_bytes_vector.end(),
+ sdp_bytes_array);
+ }
+};
+
+TEST_F(BluetoothServiceRecordWinTest, NoRfcommSdp) {
+ uint8 sdp_bytes_array[kTestNoRfcommSdpBytesSize];
+ ConvertSdpBytes(kTestNoRfcommSdpBytes, sdp_bytes_array);
+ BluetoothServiceRecordWin service_record("NoRfcommSdp",
+ "01:02:03:0A:10:A0",
+ kTestNoRfcommSdpBytesSize,
+ sdp_bytes_array);
+ EXPECT_STREQ(kTestNoRfcommSdpUuid, service_record.uuid().c_str());
+ EXPECT_FALSE(service_record.SupportsRfcomm());
+}
+
+
+TEST_F(BluetoothServiceRecordWinTest, RfcommSdp) {
+ uint8 sdp_bytes_array[kTestRfcommSdpBytesSize];
+ ConvertSdpBytes(kTestRfcommSdpBytes, sdp_bytes_array);
+ BluetoothServiceRecordWin service_record("RfcommSdp",
+ "01:02:03:0A:10:A0",
+ kTestRfcommSdpBytesSize,
+ sdp_bytes_array);
+ EXPECT_STREQ(kTestRfcommSdpUuid, service_record.uuid().c_str());
+ EXPECT_TRUE(service_record.SupportsRfcomm());
+ EXPECT_EQ(kTestRfcommChannel, service_record.rfcomm_channel());
+}
+
+TEST_F(BluetoothServiceRecordWinTest, BthAddr) {
+ uint8 sdp_bytes_array[kTestRfcommSdpBytesSize];
+ ConvertSdpBytes(kTestRfcommSdpBytes, sdp_bytes_array);
+ BluetoothServiceRecordWin service_record("Sdp",
+ "01:02:03:0A:10:A0",
+ kTestRfcommSdpBytesSize,
+ sdp_bytes_array);
+ EXPECT_EQ(1108152553632, service_record.bth_addr());
+}
+
+} // namespace device
\ No newline at end of file
diff --git a/device/bluetooth/bluetooth_socket.h b/device/bluetooth/bluetooth_socket.h
index b444110..6ae349e 100644
--- a/device/bluetooth/bluetooth_socket.h
+++ b/device/bluetooth/bluetooth_socket.h
@@ -5,8 +5,17 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_H_
+#include <string>
+
#include "base/memory/ref_counted.h"
+namespace net {
+
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+
+} // namespace net
+
namespace device {
// BluetoothSocket represents a socket to a specific service on a
@@ -15,10 +24,17 @@
// 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;
+ // Receives data from the socket and stores it in |buffer|. It returns whether
+ // the reception has been successful. If it fails, the caller can get the
+ // error message through |GetLastErrorMessage()|.
+ virtual bool Receive(net::GrowableIOBuffer* buffer) = 0;
+
+ // Sends |buffer| to the socket. It returns whether the sending has been
+ // successful. If it fails, the caller can get the error message through
+ // |GetLastErrorMessage()|.
+ virtual bool Send(net::DrainableIOBuffer* buffer) = 0;
+
+ virtual std::string GetLastErrorMessage() const = 0;
protected:
friend class base::RefCounted<BluetoothSocket>;
diff --git a/device/bluetooth/bluetooth_socket_chromeos.cc b/device/bluetooth/bluetooth_socket_chromeos.cc
index 7e75a9d..c4781df 100644
--- a/device/bluetooth/bluetooth_socket_chromeos.cc
+++ b/device/bluetooth/bluetooth_socket_chromeos.cc
@@ -4,54 +4,54 @@
#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 <string>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
#include "base/logging.h"
-#include "device/bluetooth/bluetooth_service_record.h"
+#include "base/safe_strerror_posix.h"
+#include "device/bluetooth/bluetooth_service_record_chromeos.h"
#include "device/bluetooth/bluetooth_utils.h"
+#include "net/base/io_buffer.h"
using device::BluetoothServiceRecord;
using device::BluetoothSocket;
namespace chromeos {
-BluetoothSocketChromeOs::BluetoothSocketChromeOs(
- const std::string& address, int fd)
- : address_(address),
- fd_(fd) {
+BluetoothSocketChromeOS::BluetoothSocketChromeOS(int fd) : fd_(fd) {
}
-BluetoothSocketChromeOs::~BluetoothSocketChromeOs() {
+BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
close(fd_);
}
// static
-scoped_refptr<BluetoothSocket> BluetoothSocketChromeOs::CreateBluetoothSocket(
+scoped_refptr<BluetoothSocket> BluetoothSocketChromeOS::CreateBluetoothSocket(
const BluetoothServiceRecord& service_record) {
- BluetoothSocketChromeOs* bluetooth_socket = NULL;
+ 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);
+ const BluetoothServiceRecordChromeOS* service_record_chromeos =
+ static_cast<const BluetoothServiceRecordChromeOS*>(&service_record);
+ service_record_chromeos->GetBluetoothAddress(&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);
+ bluetooth_socket = new BluetoothSocketChromeOS(socket_fd);
} else {
LOG(ERROR) << "Failed to connect bluetooth socket "
<< "(" << service_record.address() << "): "
@@ -61,11 +61,44 @@
}
// TODO(bryeung): add support for L2CAP sockets as well.
- return scoped_refptr<BluetoothSocketChromeOs>(bluetooth_socket);
+ return scoped_refptr<BluetoothSocketChromeOS>(bluetooth_socket);
}
-int BluetoothSocketChromeOs::fd() const {
- return fd_;
+bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer* buffer) {
+ buffer->SetCapacity(1024);
+ ssize_t bytes_read;
+ do {
+ if (buffer->RemainingCapacity() == 0)
+ buffer->SetCapacity(buffer->capacity() * 2);
+ bytes_read = read(fd_, buffer, buffer->RemainingCapacity());
+ if (bytes_read > 0)
+ buffer->set_offset(buffer->offset() + bytes_read);
+ } while (bytes_read > 0);
+
+ if (bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+ error_message_ = safe_strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer* buffer) {
+ ssize_t bytes_written;
+ do {
+ bytes_written = write(fd_, buffer, buffer->BytesRemaining());
+ if (bytes_written > 0)
+ buffer->DidConsume(bytes_written);
+ } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
+
+ if (bytes_written < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+ error_message_ = safe_strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+std::string BluetoothSocketChromeOS::GetLastErrorMessage() const {
+ return error_message_;
}
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_socket_chromeos.h b/device/bluetooth/bluetooth_socket_chromeos.h
index 0685830..d9e89fa 100644
--- a/device/bluetooth/bluetooth_socket_chromeos.h
+++ b/device/bluetooth/bluetooth_socket_chromeos.h
@@ -16,28 +16,37 @@
} // namespace device
+namespace net {
+
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+
+} // namespace net
+
namespace chromeos {
// This class is an implementation of BluetoothSocket class for Chrome OS
// platform.
-class BluetoothSocketChromeOs : public device::BluetoothSocket {
+class BluetoothSocketChromeOS : public device::BluetoothSocket {
public:
static scoped_refptr<device::BluetoothSocket> CreateBluetoothSocket(
const device::BluetoothServiceRecord& service_record);
// BluetoothSocket override
- virtual int fd() const OVERRIDE;
+ virtual bool Receive(net::GrowableIOBuffer* buffer) OVERRIDE;
+ virtual bool Send(net::DrainableIOBuffer* buffer) OVERRIDE;
+ virtual std::string GetLastErrorMessage() const OVERRIDE;
protected:
- virtual ~BluetoothSocketChromeOs();
+ virtual ~BluetoothSocketChromeOS();
private:
- BluetoothSocketChromeOs(const std::string& address, int fd);
+ BluetoothSocketChromeOS(int fd);
- const std::string address_;
const int fd_;
+ std::string error_message_;
- DISALLOW_COPY_AND_ASSIGN(BluetoothSocketChromeOs);
+ DISALLOW_COPY_AND_ASSIGN(BluetoothSocketChromeOS);
};
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_socket_mac.h b/device/bluetooth/bluetooth_socket_mac.h
new file mode 100644
index 0000000..5689a42
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket_mac.h
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_socket.h"
+
+#ifdef __OBJC__
+@class BluetoothRFCOMMChannelDelegate;
+@class IOBluetoothRFCOMMChannel;
+#else
+class BluetoothRFCOMMChannelDelegate;
+class IOBluetoothRFCOMMChannel;
+#endif
+
+namespace net {
+
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+
+} // namespace net
+
+namespace device {
+
+class BluetoothServiceRecord;
+
+// This class is an implementation of BluetoothSocket class for OSX platform.
+class BluetoothSocketMac : public BluetoothSocket {
+ public:
+ static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
+ const BluetoothServiceRecord& service_record);
+
+ // BluetoothSocket override
+ virtual bool Receive(net::GrowableIOBuffer* buffer) OVERRIDE;
+ virtual bool Send(net::DrainableIOBuffer* buffer) OVERRIDE;
+ virtual std::string GetLastErrorMessage() const OVERRIDE;
+
+ // called by BluetoothRFCOMMChannelDelegate.
+ void OnDataReceived(IOBluetoothRFCOMMChannel* rfcomm_channel,
+ void* data,
+ size_t length);
+
+ protected:
+ virtual ~BluetoothSocketMac();
+
+ private:
+ explicit BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel);
+
+ void ResetIncomingDataBuffer();
+
+ IOBluetoothRFCOMMChannel* rfcomm_channel_;
+ BluetoothRFCOMMChannelDelegate* delegate_;
+ scoped_refptr<net::GrowableIOBuffer> incoming_data_buffer_;
+ std::string error_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothSocketMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
new file mode 100644
index 0000000..83b30a8
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket_mac.mm
@@ -0,0 +1,141 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_socket_mac.h"
+
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+#import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h>
+
+#include <limits>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/stringprintf.h"
+#include "device/bluetooth/bluetooth_service_record.h"
+#include "device/bluetooth/bluetooth_service_record_mac.h"
+#include "net/base/io_buffer.h"
+
+@interface BluetoothRFCOMMChannelDelegate
+ : NSObject <IOBluetoothRFCOMMChannelDelegate> {
+ @private
+ device::BluetoothSocketMac* socket_; // weak
+}
+
+- (id)initWithSocket:(device::BluetoothSocketMac*)socket;
+
+@end
+
+@implementation BluetoothRFCOMMChannelDelegate
+
+- (id)initWithSocket:(device::BluetoothSocketMac*)socket {
+ if ((self = [super init]))
+ socket_ = socket;
+
+ return self;
+}
+
+- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
+ data:(void*)dataPointer
+ length:(size_t)dataLength {
+ socket_->OnDataReceived(rfcommChannel, dataPointer, dataLength);
+}
+
+@end
+
+namespace device {
+
+BluetoothSocketMac::BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel)
+ : rfcomm_channel_(rfcomm_channel),
+ delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) {
+ [rfcomm_channel_ setDelegate:delegate_];
+ ResetIncomingDataBuffer();
+}
+
+BluetoothSocketMac::~BluetoothSocketMac() {
+ [rfcomm_channel_ release];
+ [delegate_ release];
+}
+
+// static
+scoped_refptr<BluetoothSocket> BluetoothSocketMac::CreateBluetoothSocket(
+ const BluetoothServiceRecord& service_record) {
+ BluetoothSocketMac* bluetooth_socket = NULL;
+ if (service_record.SupportsRfcomm()) {
+ const BluetoothServiceRecordMac* service_record_mac =
+ static_cast<const BluetoothServiceRecordMac*>(&service_record);
+ IOBluetoothDevice* device = service_record_mac->GetIOBluetoothDevice();
+ IOBluetoothRFCOMMChannel* rfcomm_channel;
+ IOReturn status =
+ [device openRFCOMMChannelAsync:&rfcomm_channel
+ withChannelID:service_record.rfcomm_channel()
+ delegate:nil];
+ if (status == kIOReturnSuccess) {
+ bluetooth_socket = new BluetoothSocketMac(rfcomm_channel);
+ } else {
+ LOG(ERROR) << "Failed to connect bluetooth socket ("
+ << service_record.address() << "): (" << status << ")";
+ }
+ }
+ // TODO(youngki): add support for L2CAP sockets as well.
+
+ return scoped_refptr<BluetoothSocketMac>(bluetooth_socket);
+}
+
+bool BluetoothSocketMac::Receive(net::GrowableIOBuffer* buffer) {
+ CHECK(buffer->offset() == 0);
+ int length = incoming_data_buffer_->offset();
+ if (length > 0) {
+ buffer->SetCapacity(length);
+ memcpy(buffer->data(), incoming_data_buffer_->StartOfBuffer(), length);
+ buffer->set_offset(length);
+
+ ResetIncomingDataBuffer();
+ }
+ return true;
+}
+
+bool BluetoothSocketMac::Send(net::DrainableIOBuffer* buffer) {
+ int bytes_written = buffer->BytesRemaining();
+ IOReturn status = [rfcomm_channel_ writeAsync:buffer->data()
+ length:bytes_written
+ refcon:nil];
+ if (status != kIOReturnSuccess) {
+ error_message_ = base::StringPrintf(
+ "Failed to send data. IOReturn code: %u", status);
+ return false;
+ }
+
+ buffer->DidConsume(bytes_written);
+ return true;
+}
+
+std::string BluetoothSocketMac::GetLastErrorMessage() const {
+ return error_message_;
+}
+
+void BluetoothSocketMac::OnDataReceived(
+ IOBluetoothRFCOMMChannel* rfcomm_channel, void* data, size_t length) {
+ DCHECK(rfcomm_channel_ == rfcomm_channel);
+ CHECK_LT(length, static_cast<size_t>(std::numeric_limits<int>::max()));
+ int data_size = static_cast<int>(length);
+ if (incoming_data_buffer_->RemainingCapacity() < data_size) {
+ int additional_capacity =
+ std::max(data_size, incoming_data_buffer_->capacity());
+ CHECK_LT(
+ additional_capacity,
+ std::numeric_limits<int>::max() - incoming_data_buffer_->capacity());
+ incoming_data_buffer_->SetCapacity(
+ incoming_data_buffer_->capacity() + additional_capacity);
+ }
+ memcpy(incoming_data_buffer_->data(), data, data_size);
+ incoming_data_buffer_->set_offset(
+ incoming_data_buffer_->offset() + data_size);
+}
+
+void BluetoothSocketMac::ResetIncomingDataBuffer() {
+ incoming_data_buffer_ = new net::GrowableIOBuffer();
+ incoming_data_buffer_->SetCapacity(1024);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_socket_win.cc b/device/bluetooth/bluetooth_socket_win.cc
index ab83a1f..01b8eee 100644
--- a/device/bluetooth/bluetooth_socket_win.cc
+++ b/device/bluetooth/bluetooth_socket_win.cc
@@ -1,24 +1,115 @@
// 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.
-//
-// TODO(youngki): Implement this file.
#include "device/bluetooth/bluetooth_socket_win.h"
+#include <string>
+
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/sys_string_conversions.h"
+#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_service_record_win.h"
+#include "net/base/io_buffer.h"
+#include "net/base/winsock_init.h"
+
+namespace {
+
+std::string FormatErrorMessage(DWORD error_code) {
+ TCHAR error_msg[1024];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ error_code,
+ 0,
+ error_msg,
+ 1024,
+ NULL);
+ return base::SysWideToUTF8(error_msg);
+}
+
+} // namespace
namespace device {
-BluetoothSocketWin::BluetoothSocketWin() {
+BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) {
}
BluetoothSocketWin::~BluetoothSocketWin() {
+ closesocket(fd_);
}
-int BluetoothSocketWin::fd() const {
- NOTIMPLEMENTED();
- return -1;
+// static
+scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket(
+ const BluetoothServiceRecord& service_record) {
+ BluetoothSocketWin* bluetooth_socket = NULL;
+ if (service_record.SupportsRfcomm()) {
+ net::EnsureWinsockInit();
+ SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
+ SOCKADDR_BTH sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.addressFamily = AF_BTH;
+ sa.port = service_record.rfcomm_channel();
+ const BluetoothServiceRecordWin* service_record_win =
+ static_cast<const BluetoothServiceRecordWin*>(&service_record);
+ sa.btAddr = service_record_win->bth_addr();
+
+ int status = connect(socket_fd,
+ reinterpret_cast<SOCKADDR *>(&sa),
+ sizeof(sa));
+ DWORD error_code = WSAGetLastError();
+ if (status == 0 || error_code == WSAEINPROGRESS) {
+ bluetooth_socket =
+ new BluetoothSocketWin(socket_fd);
+ } else {
+ LOG(ERROR) << "Failed to connect bluetooth socket "
+ << "(" << service_record.address() << "): "
+ << "(" << error_code << ")" << FormatErrorMessage(error_code);
+ closesocket(socket_fd);
+ }
+ }
+ // TODO(youngki) add support for L2CAP sockets as well.
+
+ return scoped_refptr<BluetoothSocketWin>(bluetooth_socket);
+}
+
+bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) {
+ buffer->SetCapacity(1024);
+ int bytes_read;
+ do {
+ if (buffer->RemainingCapacity() == 0)
+ buffer->SetCapacity(buffer->capacity() * 2);
+ bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0);
+ if (bytes_read > 0)
+ buffer->set_offset(buffer->offset() + bytes_read);
+ } while (bytes_read > 0);
+
+ DWORD error_code = WSAGetLastError();
+ if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) {
+ error_message_ = FormatErrorMessage(error_code);
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) {
+ int bytes_written;
+ do {
+ bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0);
+ if (bytes_written > 0)
+ buffer->DidConsume(bytes_written);
+ } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
+
+ DWORD error_code = WSAGetLastError();
+ if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) {
+ error_message_ = FormatErrorMessage(error_code);
+ return false;
+ }
+ return true;
+}
+
+std::string BluetoothSocketWin::GetLastErrorMessage() const {
+ return error_message_;
}
} // namespace device
diff --git a/device/bluetooth/bluetooth_socket_win.h b/device/bluetooth/bluetooth_socket_win.h
index e9fe120..41713e7 100644
--- a/device/bluetooth/bluetooth_socket_win.h
+++ b/device/bluetooth/bluetooth_socket_win.h
@@ -5,18 +5,46 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_WIN_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_WIN_H_
+#include <WinSock2.h>
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
#include "device/bluetooth/bluetooth_socket.h"
+namespace net {
+
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+
+} // namespace net
+
namespace device {
+class BluetoothServiceRecord;
+
+// This class is an implementation of BluetoothSocket class for Windows
+// platform.
class BluetoothSocketWin : public BluetoothSocket {
public:
+ static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
+ const BluetoothServiceRecord& service_record);
+
// BluetoothSocket override
- virtual int fd() const OVERRIDE;
+ virtual bool Receive(net::GrowableIOBuffer* buffer) OVERRIDE;
+ virtual bool Send(net::DrainableIOBuffer* buffer) OVERRIDE;
+ virtual std::string GetLastErrorMessage() const OVERRIDE;
+
+ protected:
+ virtual ~BluetoothSocketWin();
private:
- BluetoothSocketWin();
- virtual ~BluetoothSocketWin();
+ explicit BluetoothSocketWin(SOCKET fd);
+
+ const SOCKET fd_;
+ std::string error_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothSocketWin);
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
new file mode 100644
index 0000000..b747f3b
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -0,0 +1,420 @@
+// 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_task_manager_win.h"
+
+#include <winsock2.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/stringprintf.h"
+#include "base/sys_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/win/scoped_handle.h"
+#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_service_record_win.h"
+#include "net/base/winsock_init.h"
+
+namespace {
+
+const int kNumThreadsInWorkerPool = 3;
+const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
+const int kMaxNumDeviceAddressChar = 127;
+const int kServiceDiscoveryResultBufferSize = 5000;
+const int kMaxDeviceDiscoveryTimeout = 48;
+
+// Populates bluetooth adapter state using adapter_handle.
+void GetAdapterState(HANDLE adapter_handle,
+ device::BluetoothTaskManagerWin::AdapterState* state) {
+ std::string name;
+ std::string address;
+ bool powered = false;
+ BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
+ if (adapter_handle &&
+ ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
+ &adapter_info)) {
+ name = base::SysWideToUTF8(adapter_info.szName);
+ address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
+ adapter_info.address.rgBytes[5],
+ adapter_info.address.rgBytes[4],
+ adapter_info.address.rgBytes[3],
+ adapter_info.address.rgBytes[2],
+ adapter_info.address.rgBytes[1],
+ adapter_info.address.rgBytes[0]);
+ powered = !!BluetoothIsConnectable(adapter_handle);
+ }
+ state->name = name;
+ state->address = address;
+ state->powered = powered;
+}
+
+void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
+ device::BluetoothTaskManagerWin::DeviceState* state) {
+ state->name = base::SysWideToUTF8(device_info.szName);
+ state->address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
+ device_info.Address.rgBytes[5],
+ device_info.Address.rgBytes[4],
+ device_info.Address.rgBytes[3],
+ device_info.Address.rgBytes[2],
+ device_info.Address.rgBytes[1],
+ device_info.Address.rgBytes[0]);
+ state->bluetooth_class = device_info.ulClassofDevice;
+ state->visible = true;
+ state->connected = !!device_info.fConnected;
+ state->authenticated = !!device_info.fAuthenticated;
+}
+
+} // namespace
+
+namespace device {
+
+// static
+const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
+
+BluetoothTaskManagerWin::BluetoothTaskManagerWin(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
+ : ui_task_runner_(ui_task_runner),
+ discovering_(false) {
+}
+
+BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
+}
+
+void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
+ DCHECK(observer);
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ observers_.AddObserver(observer);
+}
+
+void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
+ DCHECK(observer);
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ observers_.RemoveObserver(observer);
+}
+
+void BluetoothTaskManagerWin::Initialize() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool,
+ kBluetoothThreadName);
+ InitializeWithBluetoothTaskRunner(
+ worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
+ worker_pool_->GetSequenceToken(),
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+}
+
+void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
+ scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ bluetooth_task_runner_ = bluetooth_task_runner;
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
+}
+
+void BluetoothTaskManagerWin::StartPolling() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+
+ if (device::bluetooth_init_win::HasBluetoothStack()) {
+ PollAdapter();
+ } else {
+ // IF the bluetooth stack is not available, we still send an empty state
+ // to BluetoothAdapter so that it is marked initialized, but the adapter
+ // will not be present.
+ AdapterState* state = new AdapterState();
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
+ this,
+ base::Owned(state)));
+ }
+}
+
+void BluetoothTaskManagerWin::Shutdown() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ if (worker_pool_)
+ worker_pool_->Shutdown();
+}
+
+void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
+ bool powered,
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::SetPowered,
+ this,
+ powered,
+ callback,
+ error_callback));
+}
+
+void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
+}
+
+void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
+}
+
+void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ AdapterStateChanged(*state));
+}
+
+void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ DiscoveryStarted(success));
+}
+
+void BluetoothTaskManagerWin::OnDiscoveryStopped() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ DiscoveryStopped());
+}
+
+void BluetoothTaskManagerWin::OnScanningChanged(bool scanning) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ ScanningChanged(scanning));
+}
+
+void BluetoothTaskManagerWin::OnDevicesDiscovered(
+ const ScopedVector<DeviceState>* devices) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ DevicesDiscovered(*devices));
+}
+
+void BluetoothTaskManagerWin::PollAdapter() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+
+ // Skips updating the adapter info if the adapter is in discovery mode.
+ if (!discovering_) {
+ const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
+ { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
+ if (adapter_handle_)
+ adapter_handle_.Close();
+ HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
+ &adapter_param, adapter_handle_.Receive());
+
+ if (handle) {
+ GetKnownDevices();
+ BluetoothFindRadioClose(handle);
+ }
+ PostAdapterStateToUi();
+ }
+
+ // Re-poll.
+ bluetooth_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::PollAdapter,
+ this),
+ base::TimeDelta::FromMilliseconds(kPollIntervalMs));
+}
+
+void BluetoothTaskManagerWin::PostAdapterStateToUi() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ AdapterState* state = new AdapterState();
+ GetAdapterState(adapter_handle_, state);
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
+ this,
+ base::Owned(state)));
+}
+
+void BluetoothTaskManagerWin::SetPowered(
+ bool powered,
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback) {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ bool success = false;
+ if (adapter_handle_) {
+ if (!powered)
+ BluetoothEnableDiscovery(adapter_handle_, false);
+ success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
+ }
+
+ if (success) {
+ PostAdapterStateToUi();
+ ui_task_runner_->PostTask(FROM_HERE, callback);
+ } else {
+ ui_task_runner_->PostTask(FROM_HERE, error_callback);
+ }
+}
+
+void BluetoothTaskManagerWin::StartDiscovery() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
+ this,
+ !!adapter_handle_));
+ if (!adapter_handle_)
+ return;
+ discovering_ = true;
+
+ DiscoverDevices(1);
+}
+
+void BluetoothTaskManagerWin::StopDiscovery() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ discovering_ = false;
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+}
+
+void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ if (!discovering_ || !adapter_handle_) {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+ return;
+ }
+
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnScanningChanged, this, true));
+
+ ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
+ SearchDevices(timeout, false, device_list);
+ if (device_list->empty()) {
+ delete device_list;
+ } else {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnScanningChanged, this, false));
+ DiscoverServices(device_list);
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
+ this,
+ base::Owned(device_list)));
+ }
+
+ if (timeout < kMaxDeviceDiscoveryTimeout) {
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::DiscoverDevices,
+ this,
+ timeout + 1));
+ } else {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+ discovering_ = false;
+ }
+}
+
+void BluetoothTaskManagerWin::GetKnownDevices() {
+ ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
+ SearchDevices(1, true, device_list);
+ if (device_list->empty()) {
+ delete device_list;
+ return;
+ }
+ DiscoverServices(device_list);
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
+ this,
+ base::Owned(device_list)));
+}
+
+void BluetoothTaskManagerWin::SearchDevices(
+ int timeout,
+ bool search_cached_devices_only,
+ ScopedVector<DeviceState>* device_list) {
+ BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = {
+ sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),
+ 1, // return authenticated devices
+ 1, // return remembered devices
+ search_cached_devices_only ? 0 : 1, // return unknown devices
+ 1, // return connected devices
+ search_cached_devices_only ? 0 : 1, // issue a new inquiry
+ timeout, // timeout for the inquiry in increments of 1.28 seconds
+ adapter_handle_
+ };
+
+ BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 };
+ // Issues a device inquiry and waits for |timeout| * 1.28 seconds.
+ HBLUETOOTH_DEVICE_FIND handle =
+ BluetoothFindFirstDevice(&device_search_params, &device_info);
+ if (handle) {
+ do {
+ DeviceState* device_state = new DeviceState();
+ GetDeviceState(device_info, device_state);
+ device_list->push_back(device_state);
+ } while (BluetoothFindNextDevice(handle, &device_info));
+
+ BluetoothFindDeviceClose(handle);
+ }
+}
+
+void BluetoothTaskManagerWin::DiscoverServices(
+ ScopedVector<DeviceState>* device_list) {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+ net::EnsureWinsockInit();
+ for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
+ iter != device_list->end();
+ ++iter) {
+ const std::string device_address = (*iter)->address;
+ ScopedVector<ServiceRecordState>* service_record_states =
+ &(*iter)->service_record_states;
+ WSAQUERYSET sdp_query;
+ ZeroMemory(&sdp_query, sizeof(sdp_query));
+ sdp_query.dwSize = sizeof(sdp_query);
+ GUID protocol = L2CAP_PROTOCOL_UUID;
+ sdp_query.lpServiceClassId = &protocol;
+ sdp_query.dwNameSpace = NS_BTH;
+ wchar_t device_address_context[kMaxNumDeviceAddressChar];
+ std::size_t length =
+ base::SysUTF8ToWide("(" + device_address + ")").copy(
+ device_address_context, kMaxNumDeviceAddressChar);
+ device_address_context[length] = NULL;
+ sdp_query.lpszContext = device_address_context;
+ HANDLE sdp_handle;
+ if (ERROR_SUCCESS !=
+ WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) {
+ return;
+ }
+ char sdp_buffer[kServiceDiscoveryResultBufferSize];
+ LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
+ DWORD sdp_buffer_size = sizeof(sdp_buffer);
+ while (ERROR_SUCCESS == WSALookupServiceNext(sdp_handle,
+ LUP_RETURN_ALL,
+ &sdp_buffer_size,
+ sdp_result_data)) {
+ ServiceRecordState* service_record_state = new ServiceRecordState();
+ service_record_state->name =
+ base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
+ service_record_state->address = device_address;
+ for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
+ service_record_state->sdp_bytes.push_back(
+ sdp_result_data->lpBlob->pBlobData[i]);
+ }
+ service_record_states->push_back(service_record_state);
+ }
+ WSALookupServiceEnd(sdp_handle);
+ }
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_task_manager_win.h b/device/bluetooth/bluetooth_task_manager_win.h
new file mode 100644
index 0000000..3608667
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win.h
@@ -0,0 +1,157 @@
+// 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_TASK_MANAGER_WIN_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "base/win/scoped_handle.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+class SequencedWorkerPool;
+
+} // namespace base
+
+namespace device {
+
+// Manages the blocking Bluetooth tasks using |SequencedWorkerPool|. It runs
+// bluetooth tasks using |SequencedWorkerPool| and informs its observers of
+// bluetooth adapter state changes and any other bluetooth device inquiry
+// result.
+//
+// It delegates the blocking Windows API calls to |bluetooth_task_runner_|'s
+// message loop, and receives responses via methods like OnAdapterStateChanged
+// posted to UI thread.
+class BluetoothTaskManagerWin
+ : public base::RefCountedThreadSafe<BluetoothTaskManagerWin> {
+ public:
+ struct AdapterState {
+ std::string name;
+ std::string address;
+ bool powered;
+ };
+
+ struct ServiceRecordState {
+ std::string name;
+ std::string address;
+ std::vector<uint8> sdp_bytes;
+ };
+
+ struct DeviceState {
+ std::string name;
+ std::string address;
+ uint32 bluetooth_class;
+ bool visible;
+ bool connected;
+ bool authenticated;
+ ScopedVector<ServiceRecordState> service_record_states;
+ };
+
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ virtual void AdapterStateChanged(const AdapterState& state) {}
+ virtual void DiscoveryStarted(bool success) {}
+ virtual void DiscoveryStopped() {}
+ virtual void ScanningChanged(bool scanning) {}
+ virtual void DevicesDiscovered(const ScopedVector<DeviceState>& devices) {}
+ };
+
+ explicit BluetoothTaskManagerWin(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void Initialize();
+ void InitializeWithBluetoothTaskRunner(
+ scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner);
+ void Shutdown();
+
+ void PostSetPoweredBluetoothTask(
+ bool powered,
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback);
+ void PostStartDiscoveryTask();
+ void PostStopDiscoveryTask();
+
+ private:
+ friend class base::RefCountedThreadSafe<BluetoothTaskManagerWin>;
+ friend class BluetoothTaskManagerWinTest;
+
+ static const int kPollIntervalMs;
+
+ virtual ~BluetoothTaskManagerWin();
+
+ // Notify all Observers of updated AdapterState. Should only be called on the
+ // UI thread.
+ void OnAdapterStateChanged(const AdapterState* state);
+ void OnDiscoveryStarted(bool success);
+ void OnDiscoveryStopped();
+ void OnScanningChanged(bool scanning);
+ void OnDevicesDiscovered(const ScopedVector<DeviceState>* devices);
+
+ // Called on BluetoothTaskRunner.
+ void StartPolling();
+ void PollAdapter();
+ void PostAdapterStateToUi();
+ void SetPowered(bool powered,
+ const base::Closure& callback,
+ const BluetoothAdapter::ErrorCallback& error_callback);
+
+ // Starts discovery. Once the discovery starts, it issues a discovery inquiry
+ // with a short timeout, then issues more inquiries with greater timeout
+ // values. The discovery finishes when StopDiscovery() is called or timeout
+ // has reached its maximum value.
+ void StartDiscovery();
+ void StopDiscovery();
+
+ // Issues a device inquiry that runs for |timeout| * 1.28 seconds.
+ // This posts itself again with |timeout| + 1 until |timeout| reaches the
+ // maximum value or stop discovery call is received.
+ void DiscoverDevices(int timeout);
+
+ // Fetch already known device information. Similar to |StartDiscovery|, except
+ // this function does not issue a discovery inquiry. Instead it gets the
+ // device info cached in the adapter.
+ void GetKnownDevices();
+
+ // Sends a device search API call to the adapter.
+ void SearchDevices(int timeout,
+ bool search_cached_devices_only,
+ ScopedVector<DeviceState>* device_list);
+
+ // Discover services for the devices in |device_list|.
+ void DiscoverServices(ScopedVector<DeviceState>* device_list);
+
+ // UI task runner reference.
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+
+ scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner_;
+
+ // List of observers interested in event notifications.
+ ObserverList<Observer> observers_;
+
+ // Adapter handle owned by bluetooth task runner.
+ base::win::ScopedHandle adapter_handle_;
+
+ // indicates whether the adapter is in discovery mode or not.
+ bool discovering_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothTaskManagerWin);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_
diff --git a/device/bluetooth/bluetooth_task_manager_win_unittest.cc b/device/bluetooth/bluetooth_task_manager_win_unittest.cc
new file mode 100644
index 0000000..87a3ef5
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win_unittest.cc
@@ -0,0 +1,171 @@
+// 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/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/test_pending_task.h"
+#include "base/test/test_simple_task_runner.h"
+#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class BluetoothTaskObserver : public device::BluetoothTaskManagerWin::Observer {
+ public:
+ BluetoothTaskObserver() {
+ Clear();
+ }
+
+ virtual ~BluetoothTaskObserver() {
+ }
+
+ virtual void AdapterStateChanged(
+ const device::BluetoothTaskManagerWin::AdapterState& state) OVERRIDE {
+ num_adapter_state_changed_++;
+ }
+
+ virtual void DiscoveryStarted(bool success) OVERRIDE {
+ num_discovery_started_++;
+ }
+
+ virtual void DiscoveryStopped() OVERRIDE {
+ num_discovery_stopped_++;
+ }
+
+ virtual void ScanningChanged(bool scanning) OVERRIDE {
+ num_scanning_changed_++;
+ }
+
+ virtual void DevicesDiscovered(
+ const ScopedVector<device::BluetoothTaskManagerWin::DeviceState>&
+ devices) OVERRIDE {
+ num_devices_discovered_++;
+ }
+
+ void Clear() {
+ num_adapter_state_changed_ = 0;
+ num_discovery_started_ = 0;
+ num_discovery_stopped_ = 0;
+ num_scanning_changed_ = 0;
+ num_devices_discovered_ = 0;
+ }
+
+ int num_adapter_state_changed() const {
+ return num_adapter_state_changed_;
+ }
+
+ int num_discovery_started() const {
+ return num_discovery_started_;
+ }
+
+ int num_discovery_stopped() const {
+ return num_discovery_stopped_;
+ }
+
+ int num_scanning_changed() const {
+ return num_scanning_changed_;
+ }
+
+ int num_devices_discovered() const {
+ return num_devices_discovered_;
+ }
+
+ private:
+ int num_adapter_state_changed_;
+ int num_discovery_started_;
+ int num_discovery_stopped_;
+ int num_scanning_changed_;
+ int num_devices_discovered_;
+};
+
+} // namespace
+
+namespace device {
+
+class BluetoothTaskManagerWinTest : public testing::Test {
+ public:
+ BluetoothTaskManagerWinTest()
+ : ui_task_runner_(new base::TestSimpleTaskRunner()),
+ bluetooth_task_runner_(new base::TestSimpleTaskRunner()),
+ task_manager_(new BluetoothTaskManagerWin(ui_task_runner_)),
+ has_bluetooth_stack_(device::bluetooth_init_win::HasBluetoothStack()) {
+ task_manager_->InitializeWithBluetoothTaskRunner(bluetooth_task_runner_);
+ }
+
+ virtual void SetUp() {
+ task_manager_->AddObserver(&observer_);
+ }
+
+ virtual void TearDown() {
+ task_manager_->RemoveObserver(&observer_);
+ }
+
+ int GetPollingIntervalMs() const {
+ return BluetoothTaskManagerWin::kPollIntervalMs;
+ }
+
+ protected:
+ scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_;
+ scoped_refptr<BluetoothTaskManagerWin> task_manager_;
+ BluetoothTaskObserver observer_;
+ const bool has_bluetooth_stack_;
+};
+
+TEST_F(BluetoothTaskManagerWinTest, StartPolling) {
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothTaskManagerWinTest, PollAdapterIfBluetoothStackIsAvailable) {
+ bluetooth_task_runner_->RunPendingTasks();
+ int num_expected_pending_tasks = has_bluetooth_stack_ ? 1 : 0;
+ EXPECT_EQ(num_expected_pending_tasks,
+ bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothTaskManagerWinTest, Polling) {
+ if (!has_bluetooth_stack_)
+ return;
+
+ int num_polls = 5;
+
+ for (int i = 0; i < num_polls; i++) {
+ bluetooth_task_runner_->RunPendingTasks();
+ }
+
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(num_polls, observer_.num_adapter_state_changed());
+}
+
+TEST_F(BluetoothTaskManagerWinTest, SetPowered) {
+ if (!has_bluetooth_stack_)
+ return;
+
+ bluetooth_task_runner_->ClearPendingTasks();
+ base::Closure closure;
+ task_manager_->PostSetPoweredBluetoothTask(true, closure, closure);
+
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+ bluetooth_task_runner_->RunPendingTasks();
+ EXPECT_TRUE(ui_task_runner_->GetPendingTasks().size() >= 1);
+}
+
+TEST_F(BluetoothTaskManagerWinTest, Discovery) {
+ if (!has_bluetooth_stack_)
+ return;
+
+ bluetooth_task_runner_->RunPendingTasks();
+ bluetooth_task_runner_->ClearPendingTasks();
+ task_manager_->PostStartDiscoveryTask();
+ bluetooth_task_runner_->RunPendingTasks();
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(1, observer_.num_discovery_started());
+ task_manager_->PostStopDiscoveryTask();
+ bluetooth_task_runner_->RunPendingTasks();
+ ui_task_runner_->RunPendingTasks();
+ EXPECT_EQ(1, observer_.num_discovery_stopped());
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_utils.cc b/device/bluetooth/bluetooth_utils.cc
index 6d06409..1e7b827 100644
--- a/device/bluetooth/bluetooth_utils.cc
+++ b/device/bluetooth/bluetooth_utils.cc
@@ -6,12 +6,8 @@
#include <vector>
-#if defined(OS_CHROMEOS)
-#include <bluetooth/bluetooth.h>
-#endif
-
+#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/string_number_conversions.h"
#include "base/string_util.h"
namespace {
@@ -23,35 +19,6 @@
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 "";
diff --git a/device/bluetooth/bluetooth_utils.h b/device/bluetooth/bluetooth_utils.h
index f796d5d..0995160 100644
--- a/device/bluetooth/bluetooth_utils.h
+++ b/device/bluetooth/bluetooth_utils.h
@@ -7,22 +7,11 @@
#include <string>
-#if defined(OS_CHROMEOS)
-#include <bluetooth/bluetooth.h>
-#endif
+#include "base/basictypes.h"
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.
diff --git a/device/bluetooth/bluetooth_utils_unittest.cc b/device/bluetooth/bluetooth_utils_unittest.cc
index 0e05f8e..46d5f34 100644
--- a/device/bluetooth/bluetooth_utils_unittest.cc
+++ b/device/bluetooth/bluetooth_utils_unittest.cc
@@ -2,35 +2,12 @@
// 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 "base/basictypes.h"
#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",
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h
index 33f7afb..7d76a2b 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.h
+++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -24,6 +24,7 @@
MOCK_METHOD2(AdapterPresentChanged, void(BluetoothAdapter*, bool));
MOCK_METHOD2(AdapterPoweredChanged, void(BluetoothAdapter*, bool));
MOCK_METHOD2(AdapterDiscoveringChanged, void(BluetoothAdapter*, bool));
+ MOCK_METHOD2(AdapterScanningChanged, void(BluetoothAdapter*, bool));
MOCK_METHOD2(DeviceAdded, void(BluetoothAdapter*, BluetoothDevice*));
MOCK_METHOD2(DeviceChanged, void(BluetoothAdapter*, BluetoothDevice*));
MOCK_METHOD2(DeviceRemoved, void(BluetoothAdapter*, BluetoothDevice*));
@@ -33,6 +34,7 @@
MOCK_METHOD1(AddObserver, void(BluetoothAdapter::Observer*));
MOCK_METHOD1(RemoveObserver, void(BluetoothAdapter::Observer*));
+ MOCK_CONST_METHOD0(IsInitialized, bool());
MOCK_CONST_METHOD0(IsPresent, bool());
MOCK_CONST_METHOD0(IsPowered, bool());
MOCK_METHOD3(SetPowered,
@@ -40,9 +42,12 @@
const base::Closure& callback,
const ErrorCallback& error_callback));
MOCK_CONST_METHOD0(IsDiscovering, bool());
- MOCK_METHOD3(SetDiscovering,
- void(bool discovering,
- const base::Closure& callback,
+ MOCK_CONST_METHOD0(IsScanning, bool());
+ MOCK_METHOD2(StartDiscovering,
+ void(const base::Closure& callback,
+ const ErrorCallback& error_callback));
+ MOCK_METHOD2(StopDiscovering,
+ void(const base::Closure& callback,
const ErrorCallback& error_callback));
MOCK_CONST_METHOD0(GetDevices, BluetoothAdapter::ConstDeviceList());
MOCK_METHOD1(GetDevice, BluetoothDevice*(const std::string& address));
diff --git a/device/bluetooth/test/mock_bluetooth_device.cc b/device/bluetooth/test/mock_bluetooth_device.cc
index f2f358d..6762e04 100644
--- a/device/bluetooth/test/mock_bluetooth_device.cc
+++ b/device/bluetooth/test/mock_bluetooth_device.cc
@@ -2,9 +2,10 @@
// 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_device.h"
+
#include "base/utf_string_conversions.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
-#include "device/bluetooth/test/mock_bluetooth_device.h"
namespace device {
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
index e917a30..56ca4c2 100644
--- a/device/bluetooth/test/mock_bluetooth_device.h
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -46,7 +46,8 @@
MOCK_METHOD3(Connect,
void(BluetoothDevice::PairingDelegate* pairnig_delegate,
const base::Closure& callback,
- const BluetoothDevice::ErrorCallback& error_callback));
+ const BluetoothDevice::ConnectErrorCallback&
+ error_callback));
MOCK_METHOD1(SetPinCode, void(const std::string&));
MOCK_METHOD1(SetPasskey, void(uint32));
MOCK_METHOD0(ConfirmPairing, void());
diff --git a/device/bluetooth/test/mock_bluetooth_socket.cc b/device/bluetooth/test/mock_bluetooth_socket.cc
new file mode 100644
index 0000000..3c11518
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_socket.cc
@@ -0,0 +1,12 @@
+// 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_socket.h"
+
+namespace device {
+
+MockBluetoothSocket::MockBluetoothSocket() {}
+MockBluetoothSocket::~MockBluetoothSocket() {}
+
+} // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_socket.h b/device/bluetooth/test/mock_bluetooth_socket.h
new file mode 100644
index 0000000..8b5e142
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_socket.h
@@ -0,0 +1,35 @@
+// 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_SOCKET_H_
+#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_SOCKET_H_
+
+#include <string>
+
+#include "device/bluetooth/bluetooth_socket.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace net {
+
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+
+} // namespace net
+
+namespace device {
+
+class MockBluetoothSocket : public BluetoothSocket {
+ public:
+ MockBluetoothSocket();
+ MOCK_METHOD1(Receive, bool(net::GrowableIOBuffer*));
+ MOCK_METHOD1(Send, bool(net::DrainableIOBuffer*));
+ MOCK_CONST_METHOD0(GetLastErrorMessage, std::string());
+
+ protected:
+ virtual ~MockBluetoothSocket();
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_SOCKET_H_
diff --git a/device/device.gyp b/device/device.gyp
index bcf73d5..f3de857 100644
--- a/device/device.gyp
+++ b/device/device.gyp
@@ -11,33 +11,54 @@
'target_name': 'device_bluetooth',
'type': 'static_library',
'dependencies': [
- '../chrome/chrome_resources.gyp:chrome_strings',
- '../third_party/libxml/libxml.gyp:libxml',
- '../ui/ui.gyp:ui'
+ 'device_bluetooth_strings.gyp:device_bluetooth_strings',
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../net/net.gyp:net',
+ '../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_chromeos_experimental.cc',
+ 'bluetooth/bluetooth_adapter_chromeos_experimental.h',
'bluetooth/bluetooth_adapter_factory.cc',
'bluetooth/bluetooth_adapter_factory.h',
+ 'bluetooth/bluetooth_adapter_mac.h',
+ 'bluetooth/bluetooth_adapter_mac.mm',
'bluetooth/bluetooth_adapter_win.cc',
'bluetooth/bluetooth_adapter_win.h',
'bluetooth/bluetooth_device.cc',
'bluetooth/bluetooth_device.h',
'bluetooth/bluetooth_device_chromeos.cc',
'bluetooth/bluetooth_device_chromeos.h',
+ 'bluetooth/bluetooth_device_mac.h',
+ 'bluetooth/bluetooth_device_mac.mm',
'bluetooth/bluetooth_device_win.cc',
'bluetooth/bluetooth_device_win.h',
+ 'bluetooth/bluetooth_init_win.cc',
+ 'bluetooth/bluetooth_init_win.h',
'bluetooth/bluetooth_out_of_band_pairing_data.h',
'bluetooth/bluetooth_service_record.cc',
'bluetooth/bluetooth_service_record.h',
+ 'bluetooth/bluetooth_service_record_chromeos.cc',
+ 'bluetooth/bluetooth_service_record_chromeos.h',
+ 'bluetooth/bluetooth_service_record_mac.h',
+ 'bluetooth/bluetooth_service_record_mac.mm',
+ 'bluetooth/bluetooth_service_record_win.cc',
+ 'bluetooth/bluetooth_service_record_win.h',
'bluetooth/bluetooth_socket.h',
'bluetooth/bluetooth_socket_chromeos.cc',
'bluetooth/bluetooth_socket_chromeos.h',
+ 'bluetooth/bluetooth_socket_mac.h',
+ 'bluetooth/bluetooth_socket_mac.mm',
'bluetooth/bluetooth_socket_win.cc',
'bluetooth/bluetooth_socket_win.h',
+ 'bluetooth/bluetooth_task_manager_win.cc',
+ 'bluetooth/bluetooth_task_manager_win.h',
'bluetooth/bluetooth_utils.cc',
'bluetooth/bluetooth_utils.h',
],
@@ -49,6 +70,26 @@
'../dbus/dbus.gyp:dbus',
]
}],
+ ['OS=="win"', {
+ 'all_dependent_settings': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'DelayLoadDLLs': [
+ # Despite MSDN stating that Bthprops.dll contains the
+ # symbols declared by bthprops.lib, they actually reside here:
+ 'Bthprops.cpl',
+ ],
+ },
+ },
+ },
+ }],
+ ['OS=="mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/IOBluetooth.framework',
+ ],
+ },
+ }],
],
},
{
@@ -63,30 +104,71 @@
'bluetooth/test/mock_bluetooth_adapter.h',
'bluetooth/test/mock_bluetooth_device.cc',
'bluetooth/test/mock_bluetooth_device.h',
+ 'bluetooth/test/mock_bluetooth_socket.cc',
+ 'bluetooth/test/mock_bluetooth_socket.h',
],
'include_dirs': [
'..',
],
},
{
+ 'target_name': 'device_usb',
+ 'type': 'static_library',
+ 'sources': [
+ 'usb/usb_ids.cc',
+ 'usb/usb_ids.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'generate_usb_ids',
+ 'variables': {
+ 'usb_ids_path%': '<(DEPTH)/third_party/usb_ids/usb.ids',
+ 'usb_ids_py_path': '<(DEPTH)/tools/usb_ids/usb_ids.py',
+ },
+ 'inputs': [
+ '<(usb_ids_path)',
+ '<(usb_ids_py_path)',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/device/usb/usb_ids_gen.cc',
+ ],
+ 'action': [
+ 'python',
+ '<(usb_ids_py_path)',
+ '-i', '<(usb_ids_path)',
+ '-o', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ {
'target_name': 'device_unittests',
'type': '<(gtest_target_type)',
'dependencies': [
'device_bluetooth',
'device_bluetooth_mocks',
+ 'device_usb',
'../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_devices_chromeos_unittest.cc',
- 'bluetooth/bluetooth_service_record_unittest.cc',
+ 'bluetooth/bluetooth_adapter_mac_unittest.mm',
+ 'bluetooth/bluetooth_adapter_win_unittest.cc',
+ 'bluetooth/bluetooth_device_win_unittest.cc',
+ 'bluetooth/bluetooth_service_record_chromeos_unittest.cc',
+ 'bluetooth/bluetooth_service_record_mac_unittest.mm',
+ 'bluetooth/bluetooth_service_record_win_unittest.cc',
+ 'bluetooth/bluetooth_task_manager_win_unittest.cc',
'bluetooth/bluetooth_utils_unittest.cc',
- 'test/device_test_suite.cc',
- 'test/device_test_suite.h',
'test/run_all_unittests.cc',
+ 'usb/usb_ids_unittest.cc',
],
'conditions': [
['chromeos==1', {
@@ -96,7 +178,72 @@
'../dbus/dbus.gyp:dbus',
]
}],
+ ['OS=="mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/IOBluetooth.framework',
+ ],
+ },
+ }],
+ ['os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', {
+ 'conditions': [
+ ['linux_use_tcmalloc == 1', {
+ 'dependencies': [
+ '../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ }],
],
},
],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'targets': [
+ {
+ # Protobuf compiler / generator for the MtpFileEntry and
+ # MtpFileEntries protocol buffers.
+ 'target_name': 'mtp_file_entry_proto',
+ 'type': 'static_library',
+ 'sources': [
+ '../third_party/cros_system_api/dbus/mtp_file_entry.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '../third_party/cros_system_api/dbus',
+ 'proto_out_dir': 'device/media_transfer_protocol',
+ },
+ 'includes': ['../build/protoc.gypi'],
+ },
+ {
+ # Protobuf compiler / generator for the MtpStorageInfo protocol
+ # buffer.
+ 'target_name': 'mtp_storage_info_proto',
+ 'type': 'static_library',
+ 'sources': [
+ '../third_party/cros_system_api/dbus/mtp_storage_info.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '../third_party/cros_system_api/dbus',
+ 'proto_out_dir': 'device/media_transfer_protocol',
+ },
+ 'includes': ['../build/protoc.gypi'],
+ },
+ {
+ 'target_name': 'device_media_transfer_protocol',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../build/linux/system.gyp:dbus',
+ 'mtp_file_entry_proto',
+ 'mtp_storage_info_proto',
+ ],
+ 'sources': [
+ 'media_transfer_protocol/media_transfer_protocol_daemon_client.cc',
+ 'media_transfer_protocol/media_transfer_protocol_daemon_client.h',
+ 'media_transfer_protocol/media_transfer_protocol_manager.cc',
+ 'media_transfer_protocol/media_transfer_protocol_manager.h',
+ ],
+ },
+ ],
+ }],
+ ],
}
diff --git a/device/device_bluetooth_strings.grd b/device/device_bluetooth_strings.grd
new file mode 100644
index 0000000..6d54815
--- /dev/null
+++ b/device/device_bluetooth_strings.grd
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+This file contains the strings for device_bluetooth.
+-->
+
+<grit base_dir="." latest_public_release="0" current_release="1"
+ source_lang_id="en" enc_check="möl">
+ <outputs>
+ <output filename="grit/device_bluetooth_strings.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="device_bluetooth_strings_am.pak" type="data_package" lang="am" />
+ <output filename="device_bluetooth_strings_ar.pak" type="data_package" lang="ar" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_ast.pak" type="data_package" lang="ast" />
+ </if>
+ <output filename="device_bluetooth_strings_bg.pak" type="data_package" lang="bg" />
+ <output filename="device_bluetooth_strings_bn.pak" type="data_package" lang="bn" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_bs.pak" type="data_package" lang="bs" />
+ </if>
+ <output filename="device_bluetooth_strings_ca.pak" type="data_package" lang="ca" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
+ </if>
+ <output filename="device_bluetooth_strings_cs.pak" type="data_package" lang="cs" />
+ <output filename="device_bluetooth_strings_da.pak" type="data_package" lang="da" />
+ <output filename="device_bluetooth_strings_de.pak" type="data_package" lang="de" />
+ <output filename="device_bluetooth_strings_el.pak" type="data_package" lang="el" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_en-AU.pak" type="data_package" lang="en-AU" />
+ </if>
+ <output filename="device_bluetooth_strings_en-GB.pak" type="data_package" lang="en-GB" />
+ <output filename="device_bluetooth_strings_en-US.pak" type="data_package" lang="en" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_eo.pak" type="data_package" lang="eo" />
+ </if>
+ <output filename="device_bluetooth_strings_es.pak" type="data_package" lang="es" />
+ <output filename="device_bluetooth_strings_es-419.pak" type="data_package" lang="es-419" />
+ <output filename="device_bluetooth_strings_et.pak" type="data_package" lang="et" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_eu.pak" type="data_package" lang="eu" />
+ </if>
+ <output filename="device_bluetooth_strings_fa.pak" type="data_package" lang="fa" />
+ <output filename="device_bluetooth_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
+ <output filename="device_bluetooth_strings_fi.pak" type="data_package" lang="fi" />
+ <output filename="device_bluetooth_strings_fil.pak" type="data_package" lang="fil" />
+ <output filename="device_bluetooth_strings_fr.pak" type="data_package" lang="fr" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_gl.pak" type="data_package" lang="gl" />
+ </if>
+ <output filename="device_bluetooth_strings_gu.pak" type="data_package" lang="gu" />
+ <output filename="device_bluetooth_strings_he.pak" type="data_package" lang="he" />
+ <output filename="device_bluetooth_strings_hi.pak" type="data_package" lang="hi" />
+ <output filename="device_bluetooth_strings_hr.pak" type="data_package" lang="hr" />
+ <output filename="device_bluetooth_strings_hu.pak" type="data_package" lang="hu" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_hy.pak" type="data_package" lang="hy" />
+ <output filename="device_bluetooth_strings_ia.pak" type="data_package" lang="ia" />
+ </if>
+ <output filename="device_bluetooth_strings_id.pak" type="data_package" lang="id" />
+ <output filename="device_bluetooth_strings_it.pak" type="data_package" lang="it" />
+ <output filename="device_bluetooth_strings_ja.pak" type="data_package" lang="ja" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_ka.pak" type="data_package" lang="ka" />
+ </if>
+ <output filename="device_bluetooth_strings_kn.pak" type="data_package" lang="kn" />
+ <output filename="device_bluetooth_strings_ko.pak" type="data_package" lang="ko" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_ku.pak" type="data_package" lang="ku" />
+ <output filename="device_bluetooth_strings_kw.pak" type="data_package" lang="kw" />
+ </if>
+ <output filename="device_bluetooth_strings_lt.pak" type="data_package" lang="lt" />
+ <output filename="device_bluetooth_strings_lv.pak" type="data_package" lang="lv" />
+ <output filename="device_bluetooth_strings_ml.pak" type="data_package" lang="ml" />
+ <output filename="device_bluetooth_strings_mr.pak" type="data_package" lang="mr" />
+ <output filename="device_bluetooth_strings_ms.pak" type="data_package" lang="ms" />
+ <output filename="device_bluetooth_strings_nl.pak" type="data_package" lang="nl" />
+ <!-- The translation console uses 'no' for Norwegian Bokmål. It should
+ be 'nb'. -->
+ <output filename="device_bluetooth_strings_nb.pak" type="data_package" lang="no" />
+ <output filename="device_bluetooth_strings_pl.pak" type="data_package" lang="pl" />
+ <output filename="device_bluetooth_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
+ <output filename="device_bluetooth_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
+ <output filename="device_bluetooth_strings_ro.pak" type="data_package" lang="ro" />
+ <output filename="device_bluetooth_strings_ru.pak" type="data_package" lang="ru" />
+ <output filename="device_bluetooth_strings_sk.pak" type="data_package" lang="sk" />
+ <output filename="device_bluetooth_strings_sl.pak" type="data_package" lang="sl" />
+ <output filename="device_bluetooth_strings_sr.pak" type="data_package" lang="sr" />
+ <output filename="device_bluetooth_strings_sv.pak" type="data_package" lang="sv" />
+ <output filename="device_bluetooth_strings_sw.pak" type="data_package" lang="sw" />
+ <output filename="device_bluetooth_strings_ta.pak" type="data_package" lang="ta" />
+ <output filename="device_bluetooth_strings_te.pak" type="data_package" lang="te" />
+ <output filename="device_bluetooth_strings_th.pak" type="data_package" lang="th" />
+ <output filename="device_bluetooth_strings_tr.pak" type="data_package" lang="tr" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="device_bluetooth_strings_ug.pak" type="data_package" lang="ug" />
+ </if>
+ <output filename="device_bluetooth_strings_uk.pak" type="data_package" lang="uk" />
+ <output filename="device_bluetooth_strings_vi.pak" type="data_package" lang="vi" />
+ <output filename="device_bluetooth_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
+ <output filename="device_bluetooth_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
+ </outputs>
+ <translations>
+ <file path="strings/device_bluetooth_strings_am.xtb" lang="am" />
+ <file path="strings/device_bluetooth_strings_ar.xtb" lang="ar" />
+ <file path="strings/device_bluetooth_strings_bg.xtb" lang="bg" />
+ <file path="strings/device_bluetooth_strings_bn.xtb" lang="bn" />
+ <file path="strings/device_bluetooth_strings_ca.xtb" lang="ca" />
+ <file path="strings/device_bluetooth_strings_cs.xtb" lang="cs" />
+ <file path="strings/device_bluetooth_strings_da.xtb" lang="da" />
+ <file path="strings/device_bluetooth_strings_de.xtb" lang="de" />
+ <file path="strings/device_bluetooth_strings_el.xtb" lang="el" />
+ <file path="strings/device_bluetooth_strings_en-GB.xtb" lang="en-GB" />
+ <file path="strings/device_bluetooth_strings_es.xtb" lang="es" />
+ <file path="strings/device_bluetooth_strings_es-419.xtb" lang="es-419" />
+ <file path="strings/device_bluetooth_strings_et.xtb" lang="et" />
+ <file path="strings/device_bluetooth_strings_fa.xtb" lang="fa" />
+ <file path="strings/device_bluetooth_strings_fi.xtb" lang="fi" />
+ <file path="strings/device_bluetooth_strings_fil.xtb" lang="fil" />
+ <file path="strings/device_bluetooth_strings_fr.xtb" lang="fr" />
+ <file path="strings/device_bluetooth_strings_gu.xtb" lang="gu" />
+ <file path="strings/device_bluetooth_strings_hi.xtb" lang="hi" />
+ <file path="strings/device_bluetooth_strings_hr.xtb" lang="hr" />
+ <file path="strings/device_bluetooth_strings_hu.xtb" lang="hu" />
+ <file path="strings/device_bluetooth_strings_id.xtb" lang="id" />
+ <file path="strings/device_bluetooth_strings_it.xtb" lang="it" />
+ <!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
+ <file path="strings/device_bluetooth_strings_iw.xtb" lang="he" />
+ <file path="strings/device_bluetooth_strings_ja.xtb" lang="ja" />
+ <file path="strings/device_bluetooth_strings_kn.xtb" lang="kn" />
+ <file path="strings/device_bluetooth_strings_ko.xtb" lang="ko" />
+ <file path="strings/device_bluetooth_strings_lt.xtb" lang="lt" />
+ <file path="strings/device_bluetooth_strings_lv.xtb" lang="lv" />
+ <file path="strings/device_bluetooth_strings_ml.xtb" lang="ml" />
+ <file path="strings/device_bluetooth_strings_mr.xtb" lang="mr" />
+ <file path="strings/device_bluetooth_strings_ms.xtb" lang="ms" />
+ <file path="strings/device_bluetooth_strings_nl.xtb" lang="nl" />
+ <file path="strings/device_bluetooth_strings_no.xtb" lang="no" />
+ <file path="strings/device_bluetooth_strings_pl.xtb" lang="pl" />
+ <file path="strings/device_bluetooth_strings_pt-BR.xtb" lang="pt-BR" />
+ <file path="strings/device_bluetooth_strings_pt-PT.xtb" lang="pt-PT" />
+ <file path="strings/device_bluetooth_strings_ro.xtb" lang="ro" />
+ <file path="strings/device_bluetooth_strings_ru.xtb" lang="ru" />
+ <file path="strings/device_bluetooth_strings_sk.xtb" lang="sk" />
+ <file path="strings/device_bluetooth_strings_sl.xtb" lang="sl" />
+ <file path="strings/device_bluetooth_strings_sr.xtb" lang="sr" />
+ <file path="strings/device_bluetooth_strings_sv.xtb" lang="sv" />
+ <file path="strings/device_bluetooth_strings_sw.xtb" lang="sw" />
+ <file path="strings/device_bluetooth_strings_ta.xtb" lang="ta" />
+ <file path="strings/device_bluetooth_strings_te.xtb" lang="te" />
+ <file path="strings/device_bluetooth_strings_th.xtb" lang="th" />
+ <file path="strings/device_bluetooth_strings_tr.xtb" lang="tr" />
+ <file path="strings/device_bluetooth_strings_uk.xtb" lang="uk" />
+ <file path="strings/device_bluetooth_strings_vi.xtb" lang="vi" />
+ <file path="strings/device_bluetooth_strings_zh-CN.xtb" lang="zh-CN" />
+ <file path="strings/device_bluetooth_strings_zh-TW.xtb" lang="zh-TW" />
+ </translations>
+ <release seq="1" allow_pseudo="false">
+ <messages fallback_to_english="true">
+ <message name="IDS_BLUETOOTH_DEVICE_UNKNOWN" desc="Text to identify Bluetooth devices of unknown or unsupported class.">
+ Unknown or Unsupported Device (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_COMPUTER" desc="Text to identify Bluetooth devices of the computer class.">
+ Computer (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_PHONE" desc="Text to identify Bluetooth devices of the phone class.">
+ Phone (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_MODEM" desc="Text to identify Bluetooth devices of the modem class.">
+ Modem (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_AUDIO" desc="Text to identify Bluetooth devices of the audio class.">
+ Audio (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_CAR_AUDIO" desc="Text to identify Bluetooth devices of the car audio class.">
+ Car audio (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_VIDEO" desc="Text to identify Bluetooth devices of the video class.">
+ Video (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_JOYSTICK" desc="Text to identify Bluetooth devices of the joystick class.">
+ Joystick (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_GAMEPAD" desc="Text to identify Bluetooth devices of the gamepad class.">
+ Gamepad (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_KEYBOARD" desc="Text to identify Bluetooth devices of the keyboard class.">
+ Keyboard (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_TABLET" desc="Text to identify Bluetooth devices of the tablet class.">
+ Tablet (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_MOUSE" desc="Text to identify Bluetooth devices of the mouse class.">
+ Mouse (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ <message name="IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO" desc="Text to identify Bluetooth devices of both keyboard and mouse class.">
+ Keyboard/Mouse (<ph name="ADDRESS">$1<ex>12:34:56:78:9A:BC</ex></ph>)
+ </message>
+ </messages>
+ </release>
+</grit>
+
diff --git a/device/device_bluetooth_strings.gyp b/device/device_bluetooth_strings.gyp
new file mode 100644
index 0000000..3794f55
--- /dev/null
+++ b/device/device_bluetooth_strings.gyp
@@ -0,0 +1,31 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome',
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'device_bluetooth_strings',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'device_bluetooth_strings',
+ 'variables': {
+ 'grit_grd_file': 'device_bluetooth_strings.grd',
+ 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/device_bluetooth_strings',
+ },
+ 'includes': [ '../build/grit_action.gypi' ],
+ },
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/device_bluetooth_strings',
+ ],
+ },
+ },
+ ],
+}
diff --git a/device/media_transfer_protocol/DEPS b/device/media_transfer_protocol/DEPS
new file mode 100644
index 0000000..b9845a3
--- /dev/null
+++ b/device/media_transfer_protocol/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ # The media transfer protocol daemon uses D-Bus.
+ "+dbus",
+ "+chromeos/dbus",
+ "+third_party/cros_system_api/dbus",
+]
diff --git a/device/media_transfer_protocol/OWNERS b/device/media_transfer_protocol/OWNERS
new file mode 100644
index 0000000..8cada85
--- /dev/null
+++ b/device/media_transfer_protocol/OWNERS
@@ -0,0 +1,2 @@
+satorux@chromium.org
+thestig@chromium.org
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
new file mode 100644
index 0000000..52e8e63
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
@@ -0,0 +1,489 @@
+// 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/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace device {
+
+namespace {
+
+const char kInvalidResponseMsg[] = "Invalid Response: ";
+
+// The MediaTransferProtocolDaemonClient implementation.
+class MediaTransferProtocolDaemonClientImpl
+ : public MediaTransferProtocolDaemonClient {
+ public:
+ explicit MediaTransferProtocolDaemonClientImpl(dbus::Bus* bus)
+ : proxy_(bus->GetObjectProxy(
+ mtpd::kMtpdServiceName,
+ dbus::ObjectPath(mtpd::kMtpdServicePath))),
+ weak_ptr_factory_(this) {
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void EnumerateStorages(const EnumerateStoragesCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kEnumerateStorages);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void GetStorageInfo(const std::string& storage_name,
+ const GetStorageInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetStorageInfo);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(storage_name);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ storage_name,
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(storage_name);
+ DCHECK_EQ(mtpd::kReadOnlyMode, mode);
+ writer.AppendString(mtpd::kReadOnlyMode);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void CloseStorage(const std::string& handle,
+ const CloseStorageCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCloseStorage);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void ReadDirectoryByPath(
+ const std::string& handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kReadDirectoryByPath);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendString(path);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void ReadDirectoryById(
+ const std::string& handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kReadDirectoryById);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendUint32(file_id);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void ReadFileChunkByPath(
+ const std::string& handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kReadFileChunkByPath);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendString(path);
+ writer.AppendUint32(offset);
+ writer.AppendUint32(bytes_to_read);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void ReadFileChunkById(const std::string& handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kReadFileChunkById);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendUint32(file_id);
+ writer.AppendUint32(offset);
+ writer.AppendUint32(bytes_to_read);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void GetFileInfoByPath(const std::string& handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kGetFileInfoByPath);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendString(path);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void GetFileInfoById(const std::string& handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfoById);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendUint32(file_id);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // MediaTransferProtocolDaemonClient override.
+ virtual void SetUpConnections(
+ const MTPStorageEventHandler& handler) OVERRIDE {
+ static const SignalEventTuple kSignalEventTuples[] = {
+ { mtpd::kMTPStorageAttached, true },
+ { mtpd::kMTPStorageDetached, false },
+ };
+ const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
+
+ for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
+ proxy_->ConnectToSignal(
+ mtpd::kMtpdInterface,
+ kSignalEventTuples[i].signal_name,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal,
+ weak_ptr_factory_.GetWeakPtr(),
+ handler,
+ kSignalEventTuples[i].is_attach),
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ }
+
+ private:
+ // A struct to contain a pair of signal name and attachment event type.
+ // Used by SetUpConnections.
+ struct SignalEventTuple {
+ const char *signal_name;
+ bool is_attach;
+ };
+
+ // Handles the result of EnumerateStorages and calls |callback| or
+ // |error_callback|.
+ void OnEnumerateStorages(const EnumerateStoragesCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ dbus::MessageReader reader(response);
+ std::vector<std::string> storage_names;
+ if (!reader.PopArrayOfStrings(&storage_names)) {
+ LOG(ERROR) << kInvalidResponseMsg << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(storage_names);
+ }
+
+ // Handles the result of GetStorageInfo and calls |callback| or
+ // |error_callback|.
+ void OnGetStorageInfo(const std::string& storage_name,
+ const GetStorageInfoCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+
+ dbus::MessageReader reader(response);
+ MtpStorageInfo protobuf;
+ if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
+ LOG(ERROR) << kInvalidResponseMsg << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(protobuf);
+ }
+
+ // Handles the result of OpenStorage and calls |callback| or |error_callback|.
+ void OnOpenStorage(const OpenStorageCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ dbus::MessageReader reader(response);
+ std::string handle;
+ if (!reader.PopString(&handle)) {
+ LOG(ERROR) << kInvalidResponseMsg << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(handle);
+ }
+
+ // Handles the result of CloseStorage and calls |callback| or
+ // |error_callback|.
+ void OnCloseStorage(const CloseStorageCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ callback.Run();
+ }
+
+ // Handles the result of ReadDirectoryByPath/Id and calls |callback| or
+ // |error_callback|.
+ void OnReadDirectory(const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+
+ std::vector<MtpFileEntry> file_entries;
+ dbus::MessageReader reader(response);
+ MtpFileEntries entries_protobuf;
+ if (!reader.PopArrayOfBytesAsProto(&entries_protobuf)) {
+ LOG(ERROR) << kInvalidResponseMsg << response->ToString();
+ error_callback.Run();
+ return;
+ }
+
+ for (int i = 0; i < entries_protobuf.file_entries_size(); ++i)
+ file_entries.push_back(entries_protobuf.file_entries(i));
+ callback.Run(file_entries);
+ }
+
+ // Handles the result of ReadFileChunkByPath/Id and calls |callback| or
+ // |error_callback|.
+ void OnReadFile(const ReadFileCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+
+ uint8* data_bytes = NULL;
+ size_t data_length = 0;
+ dbus::MessageReader reader(response);
+ if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) {
+ error_callback.Run();
+ return;
+ }
+ std::string data(reinterpret_cast<const char*>(data_bytes), data_length);
+ callback.Run(data);
+ }
+
+ // Handles the result of GetFileInfoByPath/Id and calls |callback| or
+ // |error_callback|.
+ void OnGetFileInfo(const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+
+ dbus::MessageReader reader(response);
+ MtpFileEntry protobuf;
+ if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
+ LOG(ERROR) << kInvalidResponseMsg << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(protobuf);
+ }
+
+ // Handles MTPStorageAttached/Dettached signals and calls |handler|.
+ void OnMTPStorageSignal(MTPStorageEventHandler handler,
+ bool is_attach,
+ dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ std::string storage_name;
+ if (!reader.PopString(&storage_name)) {
+ LOG(ERROR) << "Invalid signal: " << signal->ToString();
+ return;
+ }
+ DCHECK(!storage_name.empty());
+ handler.Run(is_attach, storage_name);
+ }
+
+
+ // Handles the result of signal connection setup.
+ void OnSignalConnected(const std::string& interface,
+ const std::string& signal,
+ bool succeeded) {
+ LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
+ << signal << " failed.";
+ }
+
+ dbus::ObjectProxy* proxy_;
+
+ // 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<MediaTransferProtocolDaemonClientImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl);
+};
+
+// A stub implementaion of MediaTransferProtocolDaemonClient.
+class MediaTransferProtocolDaemonClientStubImpl
+ : public MediaTransferProtocolDaemonClient {
+ public:
+ MediaTransferProtocolDaemonClientStubImpl() {}
+ virtual ~MediaTransferProtocolDaemonClientStubImpl() {}
+
+ virtual void EnumerateStorages(
+ const EnumerateStoragesCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void GetStorageInfo(
+ const std::string& storage_name,
+ const GetStorageInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void CloseStorage(const std::string& handle,
+ const CloseStorageCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void ReadDirectoryByPath(
+ const std::string& handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void ReadDirectoryById(
+ const std::string& handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void ReadFileChunkByPath(
+ const std::string& handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 length,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void ReadFileChunkById(
+ const std::string& handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 length,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void GetFileInfoByPath(
+ const std::string& handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void GetFileInfoById(const std::string& handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {}
+ virtual void SetUpConnections(
+ const MTPStorageEventHandler& handler) OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientStubImpl);
+};
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// MediaTransferProtocolDaemonClient
+
+MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
+
+MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
+
+// static
+MediaTransferProtocolDaemonClient*
+MediaTransferProtocolDaemonClient::Create(dbus::Bus* bus, bool is_stub) {
+ if (is_stub)
+ return new MediaTransferProtocolDaemonClientStubImpl();
+ return new MediaTransferProtocolDaemonClientImpl(bus);
+}
+
+} // namespace device
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
new file mode 100644
index 0000000..bba9794
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -0,0 +1,180 @@
+// 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.
+
+// Client code to talk to the Media Transfer Protocol daemon. The MTP daemon is
+// responsible for communicating with PTP / MTP capable devices like cameras
+// and smartphones.
+
+#ifndef DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
+#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "build/build_config.h"
+
+#if !defined(OS_LINUX)
+#error "Only used on Linux and ChromeOS"
+#endif
+
+class MtpFileEntry;
+class MtpStorageInfo;
+
+namespace dbus {
+class Bus;
+}
+
+namespace device {
+
+// A class to make the actual DBus calls for mtpd service.
+// This class only makes calls, result/error handling should be done
+// by callbacks.
+class MediaTransferProtocolDaemonClient {
+ public:
+ // A callback to be called when DBus method call fails.
+ typedef base::Callback<void()> ErrorCallback;
+
+ // A callback to handle the result of EnumerateAutoMountableDevices.
+ // The argument is the enumerated storage names.
+ typedef base::Callback<void(const std::vector<std::string>& storage_names)
+ > EnumerateStoragesCallback;
+
+ // A callback to handle the result of GetStorageInfo.
+ // The argument is the information about the specified storage.
+ typedef base::Callback<void(const MtpStorageInfo& storage_info)
+ > GetStorageInfoCallback;
+
+ // A callback to handle the result of OpenStorage.
+ // The argument is the returned handle.
+ typedef base::Callback<void(const std::string& handle)> OpenStorageCallback;
+
+ // A callback to handle the result of CloseStorage.
+ typedef base::Callback<void()> CloseStorageCallback;
+
+ // A callback to handle the result of ReadDirectoryByPath/Id.
+ // The argument is a vector of file entries.
+ typedef base::Callback<void(const std::vector<MtpFileEntry>& file_entries)
+ > ReadDirectoryCallback;
+
+ // A callback to handle the result of ReadFileChunkByPath/Id.
+ // The argument is a string containing the file data.
+ typedef base::Callback<void(const std::string& data)> ReadFileCallback;
+
+ // A callback to handle the result of GetFileInfoByPath/Id.
+ // The argument is a file entry.
+ typedef base::Callback<void(const MtpFileEntry& file_entry)
+ > GetFileInfoCallback;
+
+ // A callback to handle storage attach/detach events.
+ // The first argument is true for attach, false for detach.
+ // The second argument is the storage name.
+ typedef base::Callback<void(bool is_attach,
+ const std::string& storage_name)
+ > MTPStorageEventHandler;
+
+ virtual ~MediaTransferProtocolDaemonClient();
+
+ // Calls EnumerateStorages method. |callback| is called after the
+ // method call succeeds, otherwise, |error_callback| is called.
+ virtual void EnumerateStorages(
+ const EnumerateStoragesCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetStorageInfo method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ virtual void GetStorageInfo(const std::string& storage_name,
+ const GetStorageInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls OpenStorage method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // OpenStorage returns a handle in |callback|.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls CloseStorage method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // |handle| comes from a OpenStorageCallback.
+ virtual void CloseStorage(const std::string& handle,
+ const CloseStorageCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadDirectoryByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ virtual void ReadDirectoryByPath(const std::string& handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadDirectoryById method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ virtual void ReadDirectoryById(const std::string& handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadFileChunkByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |bytes_to_read| cannot exceed 1 MiB.
+ virtual void ReadFileChunkByPath(const std::string& handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // TODO(thestig) Remove this in the near future if we don't see anyone using
+ // it.
+ // Calls ReadFilePathById method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ // |bytes_to_read| cannot exceed 1 MiB.
+ virtual void ReadFileChunkById(const std::string& handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetFileInfoByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ virtual void GetFileInfoByPath(const std::string& handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetFileInfoById method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ virtual void GetFileInfoById(const std::string& handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Registers given callback for events.
+ // |storage_event_handler| is called when a mtp storage attach or detach
+ // signal is received.
+ virtual void SetUpConnections(const MTPStorageEventHandler& handler) = 0;
+
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, set |is_stub| to false.
+ static MediaTransferProtocolDaemonClient* Create(dbus::Bus* bus,
+ bool is_stub);
+
+ protected:
+ // Create() should be used instead.
+ MediaTransferProtocolDaemonClient();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClient);
+};
+
+} // namespace device
+
+#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.cc b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
new file mode 100644
index 0000000..bbd13b3
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
@@ -0,0 +1,465 @@
+// 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/media_transfer_protocol/media_transfer_protocol_manager.h"
+
+#include <map>
+#include <queue>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_checker.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
+#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#else
+#include "dbus/bus.h"
+#endif
+
+namespace device {
+
+namespace {
+
+MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL;
+
+// The MediaTransferProtocolManager implementation.
+class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
+ public:
+ MediaTransferProtocolManagerImpl(
+ scoped_refptr<base::MessageLoopProxy> loop_proxy)
+ : weak_ptr_factory_(this) {
+ dbus::Bus* bus = NULL;
+#if defined(OS_CHROMEOS)
+ DCHECK(!loop_proxy.get());
+ chromeos::DBusThreadManager* dbus_thread_manager =
+ chromeos::DBusThreadManager::Get();
+ bus = dbus_thread_manager->GetSystemBus();
+ if (!bus)
+ return;
+#else
+ DCHECK(loop_proxy.get());
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ options.connection_type = dbus::Bus::PRIVATE;
+ options.dbus_task_runner = loop_proxy;
+ session_bus_ = new dbus::Bus(options);
+ bus = session_bus_.get();
+#endif
+
+ DCHECK(bus);
+ mtp_client_.reset(
+ MediaTransferProtocolDaemonClient::Create(bus, false /* not stub */));
+
+ // Set up signals and start initializing |storage_info_map_|.
+ mtp_client_->SetUpConnections(
+ base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+ mtp_client_->EnumerateStorages(
+ base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+
+ virtual ~MediaTransferProtocolManagerImpl() {
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void AddObserver(Observer* observer) OVERRIDE {
+ observers_.AddObserver(observer);
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {
+ observers_.RemoveObserver(observer);
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual const std::vector<std::string> GetStorages() const OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ std::vector<std::string> storages;
+ for (StorageInfoMap::const_iterator it = storage_info_map_.begin();
+ it != storage_info_map_.end();
+ ++it) {
+ storages.push_back(it->first);
+ }
+ return storages;
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual const MtpStorageInfo* GetStorageInfo(
+ const std::string& storage_name) const OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name);
+ if (it == storage_info_map_.end())
+ return NULL;
+ return &it->second;
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(storage_info_map_, storage_name)) {
+ callback.Run("", true);
+ return;
+ }
+ open_storage_callbacks_.push(callback);
+ mtp_client_->OpenStorage(
+ storage_name,
+ mode,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void CloseStorage(const std::string& storage_handle,
+ const CloseStorageCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(true);
+ return;
+ }
+ close_storage_callbacks_.push(std::make_pair(callback, storage_handle));
+ mtp_client_->CloseStorage(
+ storage_handle,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadDirectoryByPath(
+ const std::string& storage_handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::vector<MtpFileEntry>(), true);
+ return;
+ }
+ read_directory_callbacks_.push(callback);
+ mtp_client_->ReadDirectoryByPath(
+ storage_handle,
+ path,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadDirectoryById(
+ const std::string& storage_handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::vector<MtpFileEntry>(), true);
+ return;
+ }
+ read_directory_callbacks_.push(callback);
+ mtp_client_->ReadDirectoryById(
+ storage_handle,
+ file_id,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadFileChunkByPath(const std::string& storage_handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::string(), true);
+ return;
+ }
+ read_file_callbacks_.push(callback);
+ mtp_client_->ReadFileChunkByPath(
+ storage_handle, path, offset, count,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadFileChunkById(const std::string& storage_handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::string(), true);
+ return;
+ }
+ read_file_callbacks_.push(callback);
+ mtp_client_->ReadFileChunkById(
+ storage_handle, file_id, offset, count,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual void GetFileInfoByPath(const std::string& storage_handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(MtpFileEntry(), true);
+ return;
+ }
+ get_file_info_callbacks_.push(callback);
+ mtp_client_->GetFileInfoByPath(
+ storage_handle,
+ path,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual void GetFileInfoById(const std::string& storage_handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback) OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(MtpFileEntry(), true);
+ return;
+ }
+ get_file_info_callbacks_.push(callback);
+ mtp_client_->GetFileInfoById(
+ storage_handle,
+ file_id,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ private:
+ // Map of storage names to storage info.
+ typedef std::map<std::string, MtpStorageInfo> StorageInfoMap;
+ // Callback queues - DBus communication is in-order, thus callbacks are
+ // received in the same order as the requests.
+ typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue;
+ // (callback, handle)
+ typedef std::queue<std::pair<CloseStorageCallback, std::string>
+ > CloseStorageCallbackQueue;
+ typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue;
+ typedef std::queue<ReadFileCallback> ReadFileCallbackQueue;
+ typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue;
+
+ void OnStorageChanged(bool is_attach, const std::string& storage_name) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (is_attach) {
+ mtp_client_->GetStorageInfo(
+ storage_name,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ return;
+ }
+
+ // Detach case.
+ StorageInfoMap::iterator it = storage_info_map_.find(storage_name);
+ if (it == storage_info_map_.end()) {
+ // This might happen during initialization when |storage_info_map_| has
+ // not been fully populated yet?
+ return;
+ }
+ storage_info_map_.erase(it);
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ StorageChanged(false /* detach */, storage_name));
+ }
+
+ void OnEnumerateStorages(const std::vector<std::string>& storage_names) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ for (size_t i = 0; i < storage_names.size(); ++i) {
+ mtp_client_->GetStorageInfo(
+ storage_names[i],
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+ }
+
+ void OnGetStorageInfo(const MtpStorageInfo& storage_info) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ const std::string& storage_name = storage_info.storage_name();
+ if (ContainsKey(storage_info_map_, storage_name)) {
+ // This should not happen, since MediaTransferProtocolManagerImpl should
+ // only call EnumerateStorages() once, which populates |storage_info_map_|
+ // with the already-attached devices.
+ // After that, all incoming signals are either for new storage
+ // attachments, which should not be in |storage_info_map_|, or for
+ // storage detachements, which do not add to |storage_info_map_|.
+ NOTREACHED();
+ return;
+ }
+
+ // New storage. Add it and let the observers know.
+ storage_info_map_.insert(std::make_pair(storage_name, storage_info));
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ StorageChanged(true /* is attach */, storage_name));
+ }
+
+ void OnOpenStorage(const std::string& handle) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, handle)) {
+ handles_.insert(handle);
+ open_storage_callbacks_.front().Run(handle, false);
+ } else {
+ NOTREACHED();
+ open_storage_callbacks_.front().Run("", true);
+ }
+ open_storage_callbacks_.pop();
+ }
+
+ void OnOpenStorageError() {
+ open_storage_callbacks_.front().Run("", true);
+ open_storage_callbacks_.pop();
+ }
+
+ void OnCloseStorage() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ const std::string& handle = close_storage_callbacks_.front().second;
+ if (ContainsKey(handles_, handle)) {
+ handles_.erase(handle);
+ close_storage_callbacks_.front().first.Run(false);
+ } else {
+ NOTREACHED();
+ close_storage_callbacks_.front().first.Run(true);
+ }
+ close_storage_callbacks_.pop();
+ }
+
+ void OnCloseStorageError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ close_storage_callbacks_.front().first.Run(true);
+ close_storage_callbacks_.pop();
+ }
+
+ void OnReadDirectory(const std::vector<MtpFileEntry>& file_entries) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ read_directory_callbacks_.front().Run(file_entries, false);
+ read_directory_callbacks_.pop();
+ }
+
+ void OnReadDirectoryError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(), true);
+ read_directory_callbacks_.pop();
+ }
+
+ void OnReadFile(const std::string& data) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ read_file_callbacks_.front().Run(data, false);
+ read_file_callbacks_.pop();
+ }
+
+ void OnReadFileError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ read_file_callbacks_.front().Run(std::string(), true);
+ read_file_callbacks_.pop();
+ }
+
+ void OnGetFileInfo(const MtpFileEntry& entry) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ get_file_info_callbacks_.front().Run(entry, false);
+ get_file_info_callbacks_.pop();
+ }
+
+ void OnGetFileInfoError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ get_file_info_callbacks_.front().Run(MtpFileEntry(), true);
+ get_file_info_callbacks_.pop();
+ }
+
+ // Mtpd DBus client.
+ scoped_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
+
+#if !defined(OS_CHROMEOS)
+ // And a D-Bus session for talking to mtpd.
+ scoped_refptr<dbus::Bus> session_bus_;
+#endif
+
+ // Device attachment / detachment observers.
+ ObserverList<Observer> observers_;
+
+ base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
+
+ // Everything below is only accessed on the UI thread.
+
+ // Map to keep track of attached storages by name.
+ StorageInfoMap storage_info_map_;
+
+ // Set of open storage handles.
+ std::set<std::string> handles_;
+
+ // Queued callbacks.
+ OpenStorageCallbackQueue open_storage_callbacks_;
+ CloseStorageCallbackQueue close_storage_callbacks_;
+ ReadDirectoryCallbackQueue read_directory_callbacks_;
+ ReadFileCallbackQueue read_file_callbacks_;
+ GetFileInfoCallbackQueue get_file_info_callbacks_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
+};
+
+} // namespace
+
+// static
+void MediaTransferProtocolManager::Initialize(
+ scoped_refptr<base::MessageLoopProxy> loop_proxy) {
+ if (g_media_transfer_protocol_manager) {
+ LOG(WARNING) << "MediaTransferProtocolManager was already initialized";
+ return;
+ }
+ g_media_transfer_protocol_manager =
+ new MediaTransferProtocolManagerImpl(loop_proxy);
+ VLOG(1) << "MediaTransferProtocolManager initialized";
+}
+
+// static
+void MediaTransferProtocolManager::Shutdown() {
+ if (!g_media_transfer_protocol_manager) {
+ LOG(WARNING) << "MediaTransferProtocolManager::Shutdown() called with "
+ << "NULL manager";
+ return;
+ }
+ delete g_media_transfer_protocol_manager;
+ g_media_transfer_protocol_manager = NULL;
+ VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
+}
+
+// static
+MediaTransferProtocolManager* MediaTransferProtocolManager::GetInstance() {
+ return g_media_transfer_protocol_manager;
+}
+
+} // namespace device
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.h b/device/media_transfer_protocol/media_transfer_protocol_manager.h
new file mode 100644
index 0000000..8751325
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.h
@@ -0,0 +1,152 @@
+// 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_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
+#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+
+#if !defined(OS_LINUX)
+#error "Only used on Linux and ChromeOS"
+#endif
+
+class MtpFileEntry;
+class MtpStorageInfo;
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace device {
+
+// This class handles the interaction with mtpd.
+// Other classes can add themselves as observers.
+class MediaTransferProtocolManager {
+ public:
+ // A callback to handle the result of OpenStorage.
+ // The first argument is the returned handle.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::string& handle,
+ bool error)> OpenStorageCallback;
+
+ // A callback to handle the result of CloseStorage.
+ // The argument is true if there was an error.
+ typedef base::Callback<void(bool error)> CloseStorageCallback;
+
+ // A callback to handle the result of ReadDirectoryByPath/Id.
+ // The first argument is a vector of file entries.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::vector<MtpFileEntry>& file_entries,
+ bool error)> ReadDirectoryCallback;
+
+ // A callback to handle the result of ReadFileChunkByPath/Id.
+ // The first argument is a string containing the file data.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::string& data,
+ bool error)> ReadFileCallback;
+
+ // A callback to handle the result of GetFileInfoByPath/Id.
+ // The first argument is a file entry.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const MtpFileEntry& file_entry,
+ bool error)> GetFileInfoCallback;
+
+ // Implement this interface to be notified about MTP storage
+ // attachment / detachment events.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // A function called after a MTP storage has been attached / detached.
+ virtual void StorageChanged(bool is_attached,
+ const std::string& storage_name) = 0;
+ };
+
+ virtual ~MediaTransferProtocolManager() {}
+
+ // Adds an observer.
+ virtual void AddObserver(Observer* observer) = 0;
+
+ // Removes an observer.
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Returns a vector of available MTP storages.
+ virtual const std::vector<std::string> GetStorages() const = 0;
+
+ // On success, returns the the metadata for |storage_name|.
+ // Otherwise returns NULL.
+ virtual const MtpStorageInfo* GetStorageInfo(
+ const std::string& storage_name) const = 0;
+
+ // Opens |storage_name| in |mode| and runs |callback|.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) = 0;
+
+ // Close |storage_handle| and runs |callback|.
+ virtual void CloseStorage(const std::string& storage_handle,
+ const CloseStorageCallback& callback) = 0;
+
+ // Reads directory entries from |path| on |storage_handle| and runs
+ // |callback|.
+ virtual void ReadDirectoryByPath(const std::string& storage_handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Reads directory entries from |file_id| on |storage_handle| and runs
+ // |callback|.
+ virtual void ReadDirectoryById(const std::string& storage_handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Reads file data from |path| on |storage_handle| and runs |callback|.
+ // Reads |count| bytes of data starting at |offset|.
+ virtual void ReadFileChunkByPath(const std::string& storage_handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) = 0;
+
+ // Reads file data from |file_id| on |storage_handle| and runs |callback|.
+ // Reads |count| bytes of data starting at |offset|.
+ virtual void ReadFileChunkById(const std::string& storage_handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) = 0;
+
+ // Gets the file metadata for |path| on |storage_handle| and runs |callback|.
+ virtual void GetFileInfoByPath(const std::string& storage_handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback) = 0;
+
+ // Gets the file metadata for |file_id| on |storage_handle| and runs
+ // |callback|.
+ virtual void GetFileInfoById(const std::string& storage_handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback) = 0;
+
+ // Creates the global MediaTransferProtocolManager instance.
+ // On Linux, |loop_proxy| specifies the message loop proxy to process
+ // asynchronous operations.
+ // On ChromeOS, |loop_proxy| is set to NULL because ChromeOS already has a
+ // dedicated message loop proxy.
+ static void Initialize(scoped_refptr<base::MessageLoopProxy> loop_proxy);
+
+ // Destroys the global MediaTransferProtocolManager instance if it exists.
+ static void Shutdown();
+
+ // Returns a pointer to the global MediaTransferProtocolManager instance.
+ // Initialize() should already have been called.
+ static MediaTransferProtocolManager* GetInstance();
+};
+
+} // namespace device
+
+#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
diff --git a/device/strings/device_bluetooth_strings_am.xtb b/device/strings/device_bluetooth_strings_am.xtb
new file mode 100644
index 0000000..6c985cb
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_am.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ar.xtb b/device/strings/device_bluetooth_strings_ar.xtb
new file mode 100644
index 0000000..e8b5562
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ar.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_bg.xtb b/device/strings/device_bluetooth_strings_bg.xtb
new file mode 100644
index 0000000..ebab473
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_bg.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_bn.xtb b/device/strings/device_bluetooth_strings_bn.xtb
new file mode 100644
index 0000000..a66cc1f
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_bn.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bn">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ca.xtb b/device/strings/device_bluetooth_strings_ca.xtb
new file mode 100644
index 0000000..1438d89
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ca.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_cs.xtb b/device/strings/device_bluetooth_strings_cs.xtb
new file mode 100644
index 0000000..2d95130
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_cs.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_da.xtb b/device/strings/device_bluetooth_strings_da.xtb
new file mode 100644
index 0000000..751fa4a
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_da.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_de.xtb b/device/strings/device_bluetooth_strings_de.xtb
new file mode 100644
index 0000000..91de7f5
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_de.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_el.xtb b/device/strings/device_bluetooth_strings_el.xtb
new file mode 100644
index 0000000..6e5e7d8
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_el.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_en-GB.xtb b/device/strings/device_bluetooth_strings_en-GB.xtb
new file mode 100644
index 0000000..0fb2133
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_en-GB.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_es-419.xtb b/device/strings/device_bluetooth_strings_es-419.xtb
new file mode 100644
index 0000000..2fe4770
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_es-419.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_es.xtb b/device/strings/device_bluetooth_strings_es.xtb
new file mode 100644
index 0000000..64022ec
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_es.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_et.xtb b/device/strings/device_bluetooth_strings_et.xtb
new file mode 100644
index 0000000..5244dfd
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_et.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="et">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_fa.xtb b/device/strings/device_bluetooth_strings_fa.xtb
new file mode 100644
index 0000000..18626f8
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_fa.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fa">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_fi.xtb b/device/strings/device_bluetooth_strings_fi.xtb
new file mode 100644
index 0000000..4691cd5
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_fi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_fil.xtb b/device/strings/device_bluetooth_strings_fil.xtb
new file mode 100644
index 0000000..443630e
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_fil.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_fr.xtb b/device/strings/device_bluetooth_strings_fr.xtb
new file mode 100644
index 0000000..63026a3
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_fr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_gu.xtb b/device/strings/device_bluetooth_strings_gu.xtb
new file mode 100644
index 0000000..7d8a4df
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_gu.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="gu">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_hi.xtb b/device/strings/device_bluetooth_strings_hi.xtb
new file mode 100644
index 0000000..a6ddd5d
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_hi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_hr.xtb b/device/strings/device_bluetooth_strings_hr.xtb
new file mode 100644
index 0000000..26f99d0
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_hr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_hu.xtb b/device/strings/device_bluetooth_strings_hu.xtb
new file mode 100644
index 0000000..7ef9a5e
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_hu.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_id.xtb b/device/strings/device_bluetooth_strings_id.xtb
new file mode 100644
index 0000000..aa34783
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_id.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_it.xtb b/device/strings/device_bluetooth_strings_it.xtb
new file mode 100644
index 0000000..a6ac8d4
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_it.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_iw.xtb b/device/strings/device_bluetooth_strings_iw.xtb
new file mode 100644
index 0000000..86b5533
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_iw.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="iw">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ja.xtb b/device/strings/device_bluetooth_strings_ja.xtb
new file mode 100644
index 0000000..23139e6
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ja.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_kn.xtb b/device/strings/device_bluetooth_strings_kn.xtb
new file mode 100644
index 0000000..cc3643a
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_kn.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="kn">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ko.xtb b/device/strings/device_bluetooth_strings_ko.xtb
new file mode 100644
index 0000000..e0fc370
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ko.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_lt.xtb b/device/strings/device_bluetooth_strings_lt.xtb
new file mode 100644
index 0000000..5804ae2
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_lt.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_lv.xtb b/device/strings/device_bluetooth_strings_lv.xtb
new file mode 100644
index 0000000..a0a1c47
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_lv.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ml.xtb b/device/strings/device_bluetooth_strings_ml.xtb
new file mode 100644
index 0000000..f7db315
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ml.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ml">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_mr.xtb b/device/strings/device_bluetooth_strings_mr.xtb
new file mode 100644
index 0000000..098d29c
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_mr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="mr">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ms.xtb b/device/strings/device_bluetooth_strings_ms.xtb
new file mode 100644
index 0000000..1fb470a
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ms.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ms">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_nl.xtb b/device/strings/device_bluetooth_strings_nl.xtb
new file mode 100644
index 0000000..e782410
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_nl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_no.xtb b/device/strings/device_bluetooth_strings_no.xtb
new file mode 100644
index 0000000..913638b
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_no.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_pl.xtb b/device/strings/device_bluetooth_strings_pl.xtb
new file mode 100644
index 0000000..4519e3d
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_pl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_pt-BR.xtb b/device/strings/device_bluetooth_strings_pt-BR.xtb
new file mode 100644
index 0000000..e95eb56
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_pt-BR.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_pt-PT.xtb b/device/strings/device_bluetooth_strings_pt-PT.xtb
new file mode 100644
index 0000000..1dcf557
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_pt-PT.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ro.xtb b/device/strings/device_bluetooth_strings_ro.xtb
new file mode 100644
index 0000000..9e43493
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ro.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ru.xtb b/device/strings/device_bluetooth_strings_ru.xtb
new file mode 100644
index 0000000..c4a621b
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ru.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_sk.xtb b/device/strings/device_bluetooth_strings_sk.xtb
new file mode 100644
index 0000000..00750d3
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_sk.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_sl.xtb b/device/strings/device_bluetooth_strings_sl.xtb
new file mode 100644
index 0000000..489b7e4
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_sl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_sr.xtb b/device/strings/device_bluetooth_strings_sr.xtb
new file mode 100644
index 0000000..38f6f35
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_sr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_sv.xtb b/device/strings/device_bluetooth_strings_sv.xtb
new file mode 100644
index 0000000..ddea3dc
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_sv.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_sw.xtb b/device/strings/device_bluetooth_strings_sw.xtb
new file mode 100644
index 0000000..b775088
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_sw.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sw">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_ta.xtb b/device/strings/device_bluetooth_strings_ta.xtb
new file mode 100644
index 0000000..ef90687
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_ta.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ta">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_te.xtb b/device/strings/device_bluetooth_strings_te.xtb
new file mode 100644
index 0000000..48c714b
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_te.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="te">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_th.xtb b/device/strings/device_bluetooth_strings_th.xtb
new file mode 100644
index 0000000..fae3196
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_th.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_tr.xtb b/device/strings/device_bluetooth_strings_tr.xtb
new file mode 100644
index 0000000..9a29951
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_tr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_uk.xtb b/device/strings/device_bluetooth_strings_uk.xtb
new file mode 100644
index 0000000..f0db52c
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_uk.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_vi.xtb b/device/strings/device_bluetooth_strings_vi.xtb
new file mode 100644
index 0000000..b2957da
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_vi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_zh-CN.xtb b/device/strings/device_bluetooth_strings_zh-CN.xtb
new file mode 100644
index 0000000..26e8b40
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_zh-CN.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+</translationbundle>
diff --git a/device/strings/device_bluetooth_strings_zh-TW.xtb b/device/strings/device_bluetooth_strings_zh-TW.xtb
new file mode 100644
index 0000000..935ef48
--- /dev/null
+++ b/device/strings/device_bluetooth_strings_zh-TW.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+</translationbundle>
diff --git a/device/test/device_test_suite.cc b/device/test/device_test_suite.cc
deleted file mode 100644
index 6556076..0000000
--- a/device/test/device_test_suite.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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
deleted file mode 100644
index 15059ab..0000000
--- a/device/test/device_test_suite.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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
index 36e6e51..f4b4fc8 100644
--- a/device/test/run_all_unittests.cc
+++ b/device/test/run_all_unittests.cc
@@ -2,9 +2,8 @@
// 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"
+#include "base/test/test_suite.h"
int main(int argc, char **argv) {
- return content::UnitTestTestSuite(new DeviceTestSuite(argc, argv)).Run();
+ return base::TestSuite(argc, argv).Run();
}
diff --git a/device/usb/OWNERS b/device/usb/OWNERS
new file mode 100644
index 0000000..2ffd61a
--- /dev/null
+++ b/device/usb/OWNERS
@@ -0,0 +1,2 @@
+gdk@chromium.org
+bryeung@chromium.org
diff --git a/device/usb/usb_ids.cc b/device/usb/usb_ids.cc
new file mode 100644
index 0000000..fbb5b7e
--- /dev/null
+++ b/device/usb/usb_ids.cc
@@ -0,0 +1,58 @@
+// 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/usb/usb_ids.h"
+
+#include <stdlib.h>
+
+#include "base/basictypes.h"
+
+namespace device {
+
+namespace {
+
+static int CompareVendors(const void* a, const void* b) {
+ const UsbVendor* vendor_a = static_cast<const UsbVendor*>(a);
+ const UsbVendor* vendor_b = static_cast<const UsbVendor*>(b);
+ return vendor_a->id - vendor_b->id;
+}
+
+static int CompareProducts(const void* a, const void* b) {
+ const UsbProduct* product_a = static_cast<const UsbProduct*>(a);
+ const UsbProduct* product_b = static_cast<const UsbProduct*>(b);
+ return product_a->id - product_b->id;
+}
+
+} // namespace
+
+const UsbVendor* UsbIds::FindVendor(uint16_t vendor_id) {
+ const UsbVendor key = {vendor_id, NULL, 0, NULL};
+ void* result = bsearch(&key, vendors_, vendor_size_, sizeof(vendors_[0]),
+ &CompareVendors);
+ if (!result)
+ return NULL;
+ return static_cast<const UsbVendor*>(result);
+}
+
+const char* UsbIds::GetVendorName(uint16_t vendor_id) {
+ const UsbVendor* vendor = FindVendor(vendor_id);
+ if (!vendor)
+ return NULL;
+ return vendor->name;
+}
+
+const char* UsbIds::GetProductName(uint16_t vendor_id, uint16_t product_id) {
+ const UsbVendor* vendor = FindVendor(vendor_id);
+ if (!vendor)
+ return NULL;
+
+ const UsbProduct key = {product_id, NULL};
+ void* result = bsearch(&key, vendor->products, vendor->product_size,
+ sizeof(vendor->products[0]), &CompareProducts);
+ if (!result)
+ return NULL;
+ return static_cast<const UsbProduct*>(result)->name;
+}
+
+} // namespace device
diff --git a/device/usb/usb_ids.h b/device/usb/usb_ids.h
new file mode 100644
index 0000000..2f6b950
--- /dev/null
+++ b/device/usb/usb_ids.h
@@ -0,0 +1,58 @@
+// 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_USB_USB_IDS_H_
+#define DEVICE_USB_USB_IDS_H_
+
+#include <stdint.h>
+
+#include "base/basictypes.h"
+
+namespace device {
+
+struct UsbProduct {
+ const uint16_t id;
+ const char* name;
+};
+
+struct UsbVendor {
+ const uint16_t id;
+ const char* name;
+ const size_t product_size;
+ const UsbProduct* products;
+};
+
+// UsbIds provides a static mapping from a vendor ID to a name, as well as a
+// mapping from a vendor/product ID pair to a product name.
+class UsbIds {
+ public:
+ // Gets the name of the vendor who owns |vendor_id|. Returns NULL if the
+ // specified |vendor_id| does not exist.
+ static const char* GetVendorName(uint16_t vendor_id);
+
+ // Gets the name of a product belonging to a specific vendor. If either
+ // |vendor_id| refers to a vendor that does not exist, or |vendor_id| is valid
+ // but |product_id| refers to a product that does not exist, this method
+ // returns NULL.
+ static const char* GetProductName(uint16_t vendor_id, uint16_t product_id);
+
+ private:
+ UsbIds();
+ ~UsbIds();
+
+ // Finds the static UsbVendor associated with |vendor_id|. Returns NULL if no
+ // such vendor exists.
+ static const UsbVendor* FindVendor(uint16_t vendor_id);
+
+ // These fields are defined in a generated file. See device/device.gyp for
+ // more information on how they are generated.
+ static const size_t vendor_size_;
+ static const UsbVendor vendors_[];
+
+ DISALLOW_COPY_AND_ASSIGN(UsbIds);
+};
+
+} // namespace device
+
+#endif // DEVICE_USB_USB_IDS_H_
diff --git a/device/usb/usb_ids_unittest.cc b/device/usb/usb_ids_unittest.cc
new file mode 100644
index 0000000..decce1e
--- /dev/null
+++ b/device/usb/usb_ids_unittest.cc
@@ -0,0 +1,31 @@
+// 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 "device/usb/usb_ids.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const uint16_t kGoogleVendorId = 0x18d1;
+static const uint16_t kNexusSProductId = 0x4e21;
+
+} // namespace
+
+namespace device {
+
+TEST(UsbIdsTest, GetVendorName) {
+ EXPECT_EQ(NULL, UsbIds::GetVendorName(0));
+ EXPECT_EQ(std::string("Google Inc."), UsbIds::GetVendorName(kGoogleVendorId));
+}
+
+TEST(UsbIdsTest, GetProductName) {
+ EXPECT_EQ(NULL, UsbIds::GetProductName(0, 0));
+ EXPECT_EQ(NULL, UsbIds::GetProductName(kGoogleVendorId, 0));
+ EXPECT_EQ(std::string("Nexus S"), UsbIds::GetProductName(kGoogleVendorId,
+ kNexusSProductId));
+}
+
+} // namespace device