Merge from Chromium at DEPS revision r167172

This commit was generated by merge_to_master.py.

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