summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-11 08:20:12 +0000
committerarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-11 08:20:12 +0000
commit2a46ef5d4a8fb7037def587b7927cd359561b296 (patch)
tree3972c42ee200f2ca0e2f6f8ef013ea4bb8e82d2d
parentb5e5a42df4b992425cb8692d418dfc1aca1bc316 (diff)
downloadchromium_src-2a46ef5d4a8fb7037def587b7927cd359561b296.zip
chromium_src-2a46ef5d4a8fb7037def587b7927cd359561b296.tar.gz
chromium_src-2a46ef5d4a8fb7037def587b7927cd359561b296.tar.bz2
device/bluetooth: Add chromeos::BluetoothRemoteGattDescriptorChromeOS.
Added the chromeos::BluetoothRemoteGattDescriptorChromeOS class which implements a remote instance of device::BluetoothGattDescriptor for the Chrome OS platform. BUG=360266,340529 TEST=device_unittests Review URL: https://codereview.chromium.org/234443005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263194 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc20
-rw-r--r--chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h1
-rw-r--r--chromeos/dbus/fake_bluetooth_gatt_descriptor_client.cc115
-rw-r--r--chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h39
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_gatt_chromeos_unittest.cc266
-rw-r--r--device/bluetooth/bluetooth_gatt_descriptor.cc3
-rw-r--r--device/bluetooth/bluetooth_gatt_descriptor.h30
-rw-r--r--device/bluetooth/bluetooth_gatt_service.h8
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc86
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h23
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.cc148
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h85
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_service_chromeos.cc16
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_service_chromeos.h5
15 files changed, 801 insertions, 46 deletions
diff --git a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
index 55784a9..dbbdcc3 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
@@ -8,6 +8,8 @@
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/time/time.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
@@ -207,12 +209,28 @@ void FakeBluetoothGattCharacteristicClient::ExposeHeartRateCharacteristics(
// be handled by BlueZ, automatically set up notifications for now.
ScheduleHeartRateMeasurementValueChange();
- // TODO(armansito): Add descriptors.
+ // Expose CCC descriptor for Heart Rate Measurement characteristic.
+ FakeBluetoothGattDescriptorClient* descriptor_client =
+ static_cast<FakeBluetoothGattDescriptorClient*>(
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient());
+ dbus::ObjectPath ccc_path(descriptor_client->ExposeDescriptor(
+ dbus::ObjectPath(heart_rate_measurement_path_),
+ FakeBluetoothGattDescriptorClient::
+ kClientCharacteristicConfigurationUUID));
+ DCHECK(ccc_path.IsValid());
+ heart_rate_measurement_ccc_desc_path_ = ccc_path.value();
}
void FakeBluetoothGattCharacteristicClient::HideHeartRateCharacteristics() {
VLOG(2) << "Hiding fake Heart Rate characteristics.";
+ // Hide the descriptors.
+ FakeBluetoothGattDescriptorClient* descriptor_client =
+ static_cast<FakeBluetoothGattDescriptorClient*>(
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient());
+ descriptor_client->HideDescriptor(
+ dbus::ObjectPath(heart_rate_measurement_ccc_desc_path_));
+
// Notify the observers before deleting the properties structures so that they
// can be accessed from the observer method.
NotifyCharacteristicRemoved(dbus::ObjectPath(heart_rate_measurement_path_));
diff --git a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h
index bd3d126..1ae77cb 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h
+++ b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h
@@ -110,6 +110,7 @@ class CHROMEOS_EXPORT FakeBluetoothGattCharacteristicClient
// Object paths of the exposed characteristics. If a characteristic is not
// exposed, these will be empty.
std::string heart_rate_measurement_path_;
+ std::string heart_rate_measurement_ccc_desc_path_;
std::string body_sensor_location_path_;
std::string heart_rate_control_point_path_;
diff --git a/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.cc b/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.cc
index f0846a8..4bb5255 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.cc
@@ -4,10 +4,18 @@
#include "chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h"
+#include "base/bind.h"
+#include "base/logging.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
+const char FakeBluetoothGattDescriptorClient::
+ kClientCharacteristicConfigurationPathComponent[] = "desc0000";
+const char FakeBluetoothGattDescriptorClient::
+ kClientCharacteristicConfigurationUUID[] =
+ "00002902-0000-1000-8000-00805f9b34fb";
+
FakeBluetoothGattDescriptorClient::Properties::Properties(
const PropertyChangedCallback& callback)
: BluetoothGattDescriptorClient::Properties(
@@ -23,7 +31,7 @@ void FakeBluetoothGattDescriptorClient::Properties::Get(
dbus::PropertyBase* property,
dbus::PropertySet::GetCallback callback) {
VLOG(1) << "Get " << property->name();
- callback.Run(false);
+ callback.Run(true);
}
void FakeBluetoothGattDescriptorClient::Properties::GetAll() {
@@ -33,14 +41,24 @@ void FakeBluetoothGattDescriptorClient::Properties::GetAll() {
void FakeBluetoothGattDescriptorClient::Properties::Set(
dbus::PropertyBase* property,
dbus::PropertySet::SetCallback callback) {
- VLOG(1) << "Get " << property->name();
- callback.Run(false);
+ VLOG(1) << "Set " << property->name();
+ if (property->name() != value.name()) {
+ callback.Run(false);
+ return;
+ }
// TODO(armansito): Setting the "Value" property should be allowed based
// on permissions.
+ if (uuid.value() != kClientCharacteristicConfigurationUUID) {
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ property->ReplaceValueWithSetValue();
}
-FakeBluetoothGattDescriptorClient::FakeBluetoothGattDescriptorClient() {
+FakeBluetoothGattDescriptorClient::FakeBluetoothGattDescriptorClient()
+ : weak_ptr_factory_(this) {
}
FakeBluetoothGattDescriptorClient::~FakeBluetoothGattDescriptorClient() {
@@ -59,13 +77,98 @@ void FakeBluetoothGattDescriptorClient::RemoveObserver(Observer* observer) {
std::vector<dbus::ObjectPath>
FakeBluetoothGattDescriptorClient::GetDescriptors() {
- return std::vector<dbus::ObjectPath>();
+ std::vector<dbus::ObjectPath> descriptors;
+ for (PropertiesMap::const_iterator iter = properties_.begin();
+ iter != properties_.end(); ++iter) {
+ descriptors.push_back(iter->first);
+ }
+ return descriptors;
}
FakeBluetoothGattDescriptorClient::Properties*
FakeBluetoothGattDescriptorClient::GetProperties(
const dbus::ObjectPath& object_path) {
- return NULL;
+ PropertiesMap::const_iterator iter = properties_.find(object_path);
+ if (iter == properties_.end())
+ return NULL;
+ return iter->second;
+}
+
+dbus::ObjectPath FakeBluetoothGattDescriptorClient::ExposeDescriptor(
+ const dbus::ObjectPath& characteristic_path,
+ const std::string& uuid) {
+ if (uuid != kClientCharacteristicConfigurationUUID) {
+ VLOG(2) << "Unsupported UUID: " << uuid;
+ return dbus::ObjectPath();
+ }
+
+ // CCC descriptor is the only one supported at the moment.
+ DCHECK(characteristic_path.IsValid());
+ dbus::ObjectPath object_path(
+ characteristic_path.value() + "/" +
+ kClientCharacteristicConfigurationPathComponent);
+ DCHECK(object_path.IsValid());
+ PropertiesMap::const_iterator iter = properties_.find(object_path);
+ if (iter != properties_.end()) {
+ VLOG(1) << "Descriptor already exposed: " << object_path.value();
+ return dbus::ObjectPath();
+ }
+
+ Properties* properties = new Properties(base::Bind(
+ &FakeBluetoothGattDescriptorClient::OnPropertyChanged,
+ weak_ptr_factory_.GetWeakPtr(),
+ object_path));
+ properties_[object_path] = properties;
+ properties->uuid.ReplaceValue(uuid);
+ properties->characteristic.ReplaceValue(characteristic_path);
+
+ std::vector<uint8> value;
+ value.push_back(0); // Notifications/Indications disabled.
+ value.push_back(0);
+ properties->value.ReplaceValue(value);
+
+ NotifyDescriptorAdded(object_path);
+
+ return object_path;
+}
+
+void FakeBluetoothGattDescriptorClient::HideDescriptor(
+ const dbus::ObjectPath& descriptor_path) {
+ PropertiesMap::iterator iter = properties_.find(descriptor_path);
+ if (iter == properties_.end()) {
+ VLOG(1) << "Descriptor not exposed: " << descriptor_path.value();
+ return;
+ }
+
+ NotifyDescriptorRemoved(descriptor_path);
+
+ delete iter->second;
+ properties_.erase(iter);
+}
+
+void FakeBluetoothGattDescriptorClient::OnPropertyChanged(
+ const dbus::ObjectPath& object_path,
+ const std::string& property_name) {
+ VLOG(2) << "Descriptor property changed: " << object_path.value()
+ << ": " << property_name;
+
+ FOR_EACH_OBSERVER(BluetoothGattDescriptorClient::Observer, observers_,
+ GattDescriptorPropertyChanged(object_path, property_name));
+
+ // TODO(armansito): Implement CCC behavior (enable/disable notifications
+ // or indications characteristics).
+}
+
+void FakeBluetoothGattDescriptorClient::NotifyDescriptorAdded(
+ const dbus::ObjectPath& object_path) {
+ FOR_EACH_OBSERVER(BluetoothGattDescriptorClient::Observer, observers_,
+ GattDescriptorAdded(object_path));
+}
+
+void FakeBluetoothGattDescriptorClient::NotifyDescriptorRemoved(
+ const dbus::ObjectPath& object_path) {
+ FOR_EACH_OBSERVER(BluetoothGattDescriptorClient::Observer, observers_,
+ GattDescriptorRemoved(object_path));
}
} // namespace chromeos
diff --git a/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h b/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h
index dd9f7af..3676983 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h
+++ b/chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h
@@ -5,9 +5,14 @@
#ifndef CHROMEOS_DBUS_FAKE_BLUETOOTH_GATT_DESCRIPTOR_CLIENT_H_
#define CHROMEOS_DBUS_FAKE_BLUETOOTH_GATT_DESCRIPTOR_CLIENT_H_
+#include <map>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/dbus/bluetooth_gatt_descriptor_client.h"
+#include "dbus/object_path.h"
namespace chromeos {
@@ -42,13 +47,43 @@ class CHROMEOS_EXPORT FakeBluetoothGattDescriptorClient
virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
OVERRIDE;
+ // Makes the descriptor with the UUID |uuid| visible under the characteristic
+ // with object path |characteristic_path|. Descriptor object paths are
+ // hierarchical to their characteristics. |uuid| must belong to a descriptor
+ // for which there is a constant defined below, otherwise this method has no
+ // effect. Returns the object path of the created descriptor. In the no-op
+ // case, returns an invalid path.
+ dbus::ObjectPath ExposeDescriptor(const dbus::ObjectPath& characteristic_path,
+ const std::string& uuid);
+ void HideDescriptor(const dbus::ObjectPath& descriptor_path);
+
+ // Object path components and UUIDs of GATT characteristic descriptors.
+ static const char kClientCharacteristicConfigurationPathComponent[];
+ static const char kClientCharacteristicConfigurationUUID[];
+
private:
- // TODO(armansito): Add simulated descriptors, once BlueZ's behavior is
- // better defined.
+ // Property callback passed when we create Properties structures.
+ void OnPropertyChanged(const dbus::ObjectPath& object_path,
+ const std::string& property_name);
+
+ // Notifies observers.
+ void NotifyDescriptorAdded(const dbus::ObjectPath& object_path);
+ void NotifyDescriptorRemoved(const dbus::ObjectPath& object_path);
+
+ // Mapping from object paths to Properties structures.
+ typedef std::map<dbus::ObjectPath, Properties*> PropertiesMap;
+ PropertiesMap properties_;
// List of observers interested in event notifications from us.
ObserverList<Observer> observers_;
+ // Weak pointer factory for generating 'this' pointers that might live longer
+ // than we do.
+ // 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<FakeBluetoothGattDescriptorClient>
+ weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(FakeBluetoothGattDescriptorClient);
};
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index 43357be..68a9dfd 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -62,6 +62,8 @@
'bluetooth_profile_win.h',
'bluetooth_remote_gatt_characteristic_chromeos.cc',
'bluetooth_remote_gatt_characteristic_chromeos.h',
+ 'bluetooth_remote_gatt_descriptor_chromeos.cc',
+ 'bluetooth_remote_gatt_descriptor_chromeos.h',
'bluetooth_remote_gatt_service_chromeos.cc',
'bluetooth_remote_gatt_service_chromeos.h',
'bluetooth_service_record.cc',
diff --git a/device/bluetooth/bluetooth_gatt_chromeos_unittest.cc b/device/bluetooth/bluetooth_gatt_chromeos_unittest.cc
index 68c01ed..a3294fb 100644
--- a/device/bluetooth/bluetooth_gatt_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_gatt_chromeos_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "chromeos/dbus/fake_bluetooth_adapter_client.h"
#include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
#include "chromeos/dbus/fake_bluetooth_device_client.h"
@@ -16,6 +17,7 @@
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
+#include "device/bluetooth/bluetooth_gatt_descriptor.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +25,7 @@
using device::BluetoothAdapter;
using device::BluetoothDevice;
using device::BluetoothGattCharacteristic;
+using device::BluetoothGattDescriptor;
using device::BluetoothGattService;
using device::BluetoothUUID;
@@ -244,6 +247,8 @@ class BluetoothGattChromeOSTest : public testing::Test {
new FakeBluetoothGattServiceClient;
fake_bluetooth_gatt_characteristic_client_ =
new FakeBluetoothGattCharacteristicClient;
+ fake_bluetooth_gatt_descriptor_client_ =
+ new FakeBluetoothGattDescriptorClient;
fake_dbus_thread_manager->SetBluetoothDeviceClient(
scoped_ptr<BluetoothDeviceClient>(
fake_bluetooth_device_client_));
@@ -255,7 +260,7 @@ class BluetoothGattChromeOSTest : public testing::Test {
fake_bluetooth_gatt_characteristic_client_));
fake_dbus_thread_manager->SetBluetoothGattDescriptorClient(
scoped_ptr<BluetoothGattDescriptorClient>(
- new FakeBluetoothGattDescriptorClient));
+ fake_bluetooth_gatt_descriptor_client_));
fake_dbus_thread_manager->SetBluetoothAdapterClient(
scoped_ptr<BluetoothAdapterClient>(new FakeBluetoothAdapterClient));
fake_dbus_thread_manager->SetBluetoothInputClient(
@@ -265,12 +270,7 @@ class BluetoothGattChromeOSTest : public testing::Test {
new FakeBluetoothAgentManagerClient));
DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
- device::BluetoothAdapterFactory::GetAdapter(
- base::Bind(&BluetoothGattChromeOSTest::AdapterCallback,
- base::Unretained(this)));
- ASSERT_TRUE(adapter_.get() != NULL);
- ASSERT_TRUE(adapter_->IsInitialized());
- ASSERT_TRUE(adapter_->IsPresent());
+ GetAdapter();
adapter_->SetPowered(
true,
@@ -284,6 +284,15 @@ class BluetoothGattChromeOSTest : public testing::Test {
DBusThreadManager::Shutdown();
}
+ void GetAdapter() {
+ device::BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothGattChromeOSTest::AdapterCallback,
+ base::Unretained(this)));
+ ASSERT_TRUE(adapter_.get() != NULL);
+ ASSERT_TRUE(adapter_->IsInitialized());
+ ASSERT_TRUE(adapter_->IsPresent());
+ }
+
void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
adapter_ = adapter;
}
@@ -308,6 +317,7 @@ class BluetoothGattChromeOSTest : public testing::Test {
FakeBluetoothGattServiceClient* fake_bluetooth_gatt_service_client_;
FakeBluetoothGattCharacteristicClient*
fake_bluetooth_gatt_characteristic_client_;
+ FakeBluetoothGattDescriptorClient* fake_bluetooth_gatt_descriptor_client_;
scoped_refptr<BluetoothAdapter> adapter_;
int success_callback_count_;
@@ -348,6 +358,7 @@ TEST_F(BluetoothGattChromeOSTest, GattServiceAddedAndRemoved) {
EXPECT_FALSE(service->IsLocal());
EXPECT_TRUE(service->IsPrimary());
EXPECT_EQ(service, device->GetGattServices()[0]);
+ EXPECT_EQ(service, device->GetGattService(service->GetIdentifier()));
EXPECT_EQ(observer.last_gatt_service_uuid_, service->GetUUID());
@@ -436,8 +447,9 @@ TEST_F(BluetoothGattChromeOSTest, GattCharacteristicAddedAndRemoved) {
base::MessageLoop::current()->Run();
// 3 characteristics should appear. Only 1 of the characteristics sends
- // value changed signals.
- EXPECT_EQ(3, service_observer.gatt_service_changed_count_);
+ // value changed signals. Service changed should be fired once for
+ // descriptor added.
+ EXPECT_EQ(4, service_observer.gatt_service_changed_count_);
EXPECT_EQ(3, service_observer.gatt_characteristic_added_count_);
EXPECT_EQ(0, service_observer.gatt_characteristic_removed_count_);
EXPECT_EQ(1, service_observer.gatt_characteristic_value_changed_count_);
@@ -445,7 +457,7 @@ TEST_F(BluetoothGattChromeOSTest, GattCharacteristicAddedAndRemoved) {
// Hide the characteristics. 3 removed signals should be received.
fake_bluetooth_gatt_characteristic_client_->HideHeartRateCharacteristics();
- EXPECT_EQ(6, service_observer.gatt_service_changed_count_);
+ EXPECT_EQ(8, service_observer.gatt_service_changed_count_);
EXPECT_EQ(3, service_observer.gatt_characteristic_added_count_);
EXPECT_EQ(3, service_observer.gatt_characteristic_removed_count_);
EXPECT_EQ(1, service_observer.gatt_characteristic_value_changed_count_);
@@ -454,7 +466,7 @@ TEST_F(BluetoothGattChromeOSTest, GattCharacteristicAddedAndRemoved) {
// Re-expose the heart rate characteristics.
fake_bluetooth_gatt_characteristic_client_->ExposeHeartRateCharacteristics(
fake_bluetooth_gatt_service_client_->GetHeartRateServicePath());
- EXPECT_EQ(9, service_observer.gatt_service_changed_count_);
+ EXPECT_EQ(12, service_observer.gatt_service_changed_count_);
EXPECT_EQ(6, service_observer.gatt_characteristic_added_count_);
EXPECT_EQ(3, service_observer.gatt_characteristic_removed_count_);
EXPECT_EQ(2, service_observer.gatt_characteristic_value_changed_count_);
@@ -462,12 +474,159 @@ TEST_F(BluetoothGattChromeOSTest, GattCharacteristicAddedAndRemoved) {
// Hide the service. All characteristics should disappear.
fake_bluetooth_gatt_service_client_->HideHeartRateService();
- EXPECT_EQ(12, service_observer.gatt_service_changed_count_);
+ EXPECT_EQ(16, service_observer.gatt_service_changed_count_);
EXPECT_EQ(6, service_observer.gatt_characteristic_added_count_);
EXPECT_EQ(6, service_observer.gatt_characteristic_removed_count_);
EXPECT_EQ(2, service_observer.gatt_characteristic_value_changed_count_);
}
+TEST_F(BluetoothGattChromeOSTest, GattDescriptorAddedAndRemoved) {
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kLowEnergyAddress);
+ ASSERT_TRUE(device);
+
+ TestDeviceObserver observer(adapter_, device);
+
+ // Expose the fake Heart Rate service. This will asynchronously expose
+ // characteristics.
+ fake_bluetooth_gatt_service_client_->ExposeHeartRateService(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ ASSERT_EQ(1, observer.gatt_service_added_count_);
+
+ BluetoothGattService* service =
+ device->GetGattService(observer.last_gatt_service_id_);
+
+ TestGattServiceObserver service_observer(adapter_, device, service);
+ EXPECT_EQ(0, service_observer.gatt_service_changed_count_);
+ EXPECT_TRUE(service->GetCharacteristics().empty());
+
+ // Run the message loop so that the characteristics appear.
+ base::MessageLoop::current()->Run();
+ EXPECT_EQ(4, service_observer.gatt_service_changed_count_);
+
+ // Only the Heart Rate Measurement characteristic has a descriptor.
+ BluetoothGattCharacteristic* characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetBodySensorLocationPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_TRUE(characteristic->GetDescriptors().empty());
+
+ characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetHeartRateControlPointPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_TRUE(characteristic->GetDescriptors().empty());
+
+ characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetHeartRateMeasurementPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_EQ(1U, characteristic->GetDescriptors().size());
+
+ BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0];
+ EXPECT_FALSE(descriptor->IsLocal());
+ EXPECT_EQ(BluetoothGattDescriptor::kClientCharacteristicConfigurationUuid,
+ descriptor->GetUUID());
+
+ // Hide the descriptor.
+ fake_bluetooth_gatt_descriptor_client_->HideDescriptor(
+ dbus::ObjectPath(descriptor->GetIdentifier()));
+ EXPECT_TRUE(characteristic->GetDescriptors().empty());
+ EXPECT_EQ(5, service_observer.gatt_service_changed_count_);
+
+ // Expose the descriptor again.
+ fake_bluetooth_gatt_descriptor_client_->ExposeDescriptor(
+ dbus::ObjectPath(characteristic->GetIdentifier()),
+ FakeBluetoothGattDescriptorClient::
+ kClientCharacteristicConfigurationUUID);
+ EXPECT_EQ(6, service_observer.gatt_service_changed_count_);
+ EXPECT_EQ(1U, characteristic->GetDescriptors().size());
+
+ descriptor = characteristic->GetDescriptors()[0];
+ EXPECT_FALSE(descriptor->IsLocal());
+ EXPECT_EQ(BluetoothGattDescriptor::kClientCharacteristicConfigurationUuid,
+ descriptor->GetUUID());
+}
+
+TEST_F(BluetoothGattChromeOSTest, AdapterAddedAfterGattService) {
+ // This unit test tests that all remote GATT objects are created for D-Bus
+ // objects that were already exposed.
+ adapter_ = NULL;
+ EXPECT_EQ(NULL, device::BluetoothAdapterFactory::MaybeGetAdapter().get());
+
+ // Create the fake D-Bus objects.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ fake_bluetooth_gatt_service_client_->ExposeHeartRateService(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ while (!fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible())
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(fake_bluetooth_gatt_service_client_->IsHeartRateVisible());
+ ASSERT_TRUE(fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible());
+
+ // Create the adapter. This should create all the GATT objects.
+ GetAdapter();
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kLowEnergyAddress);
+ ASSERT_TRUE(device);
+ EXPECT_EQ(1U, device->GetGattServices().size());
+
+ BluetoothGattService* service = device->GetGattServices()[0];
+ ASSERT_TRUE(service);
+ EXPECT_FALSE(service->IsLocal());
+ EXPECT_TRUE(service->IsPrimary());
+ EXPECT_EQ(
+ BluetoothUUID(FakeBluetoothGattServiceClient::kHeartRateServiceUUID),
+ service->GetUUID());
+ EXPECT_EQ(service, device->GetGattServices()[0]);
+ EXPECT_EQ(service, device->GetGattService(service->GetIdentifier()));
+ EXPECT_FALSE(service->IsLocal());
+ EXPECT_EQ(3U, service->GetCharacteristics().size());
+
+ BluetoothGattCharacteristic* characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetBodySensorLocationPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_EQ(
+ BluetoothUUID(FakeBluetoothGattCharacteristicClient::
+ kBodySensorLocationUUID),
+ characteristic->GetUUID());
+ EXPECT_FALSE(characteristic->IsLocal());
+ EXPECT_TRUE(characteristic->GetDescriptors().empty());
+
+ characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetHeartRateControlPointPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_EQ(
+ BluetoothUUID(FakeBluetoothGattCharacteristicClient::
+ kHeartRateControlPointUUID),
+ characteristic->GetUUID());
+ EXPECT_FALSE(characteristic->IsLocal());
+ EXPECT_TRUE(characteristic->GetDescriptors().empty());
+
+ characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetHeartRateMeasurementPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_EQ(
+ BluetoothUUID(FakeBluetoothGattCharacteristicClient::
+ kHeartRateMeasurementUUID),
+ characteristic->GetUUID());
+ EXPECT_FALSE(characteristic->IsLocal());
+ EXPECT_EQ(1U, characteristic->GetDescriptors().size());
+
+ BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0];
+ ASSERT_TRUE(descriptor);
+ EXPECT_EQ(BluetoothGattDescriptor::kClientCharacteristicConfigurationUuid,
+ descriptor->GetUUID());
+ EXPECT_FALSE(descriptor->IsLocal());
+}
+
TEST_F(BluetoothGattChromeOSTest, GattCharacteristicValue) {
fake_bluetooth_device_client_->CreateDevice(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
@@ -618,4 +777,87 @@ TEST_F(BluetoothGattChromeOSTest, GattCharacteristicValue) {
service_observer.last_gatt_characteristic_id_);
}
+TEST_F(BluetoothGattChromeOSTest, GattDescriptorValue) {
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kLowEnergyAddress);
+ ASSERT_TRUE(device);
+
+ TestDeviceObserver observer(adapter_, device);
+
+ // Expose the fake Heart Rate service. This will asynchronously expose
+ // characteristics.
+ fake_bluetooth_gatt_service_client_->ExposeHeartRateService(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath));
+ ASSERT_EQ(1, observer.gatt_service_added_count_);
+
+ BluetoothGattService* service =
+ device->GetGattService(observer.last_gatt_service_id_);
+
+ TestGattServiceObserver service_observer(adapter_, device, service);
+ EXPECT_EQ(0, service_observer.gatt_service_changed_count_);
+ EXPECT_TRUE(service->GetCharacteristics().empty());
+
+ // Run the message loop so that the characteristics appear.
+ base::MessageLoop::current()->Run();
+ EXPECT_EQ(4, service_observer.gatt_service_changed_count_);
+
+ // Only the Heart Rate Measurement characteristic has a descriptor.
+ BluetoothGattCharacteristic* characteristic = service->GetCharacteristic(
+ fake_bluetooth_gatt_characteristic_client_->
+ GetHeartRateMeasurementPath().value());
+ ASSERT_TRUE(characteristic);
+ EXPECT_EQ(1U, characteristic->GetDescriptors().size());
+
+ BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0];
+ EXPECT_FALSE(descriptor->IsLocal());
+ EXPECT_EQ(BluetoothGattDescriptor::kClientCharacteristicConfigurationUuid,
+ descriptor->GetUUID());
+
+ std::vector<uint8> desc_value;
+ desc_value.push_back(0);
+ desc_value.push_back(0);
+ EXPECT_TRUE(ValuesEqual(desc_value, descriptor->GetValue()));
+
+ EXPECT_EQ(0, success_callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(last_read_value_.empty());
+
+ // Read value.
+ descriptor->ReadRemoteDescriptor(
+ base::Bind(&BluetoothGattChromeOSTest::ValueCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothGattChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(1, success_callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue()));
+
+ // Write value.
+ desc_value[0] = 0x03;
+ descriptor->WriteRemoteDescriptor(
+ desc_value,
+ base::Bind(&BluetoothGattChromeOSTest::SuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothGattChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(2, success_callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_FALSE(ValuesEqual(last_read_value_, descriptor->GetValue()));
+ EXPECT_TRUE(ValuesEqual(desc_value, descriptor->GetValue()));
+
+ // Read new value.
+ descriptor->ReadRemoteDescriptor(
+ base::Bind(&BluetoothGattChromeOSTest::ValueCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothGattChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ EXPECT_EQ(3, success_callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue()));
+ EXPECT_TRUE(ValuesEqual(desc_value, descriptor->GetValue()));
+}
+
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_gatt_descriptor.cc b/device/bluetooth/bluetooth_gatt_descriptor.cc
index 692e258..3af5a9f 100644
--- a/device/bluetooth/bluetooth_gatt_descriptor.cc
+++ b/device/bluetooth/bluetooth_gatt_descriptor.cc
@@ -30,7 +30,8 @@ BluetoothGattDescriptor::~BluetoothGattDescriptor() {
// static
BluetoothGattDescriptor* BluetoothGattDescriptor::Create(
const BluetoothUUID& uuid,
- const std::vector<uint8>& value) {
+ const std::vector<uint8>& value,
+ BluetoothGattCharacteristic::Permissions permissions) {
LOG(ERROR) << "Creating local GATT characteristic descriptors currently not "
<< "supported.";
return NULL;
diff --git a/device/bluetooth/bluetooth_gatt_descriptor.h b/device/bluetooth/bluetooth_gatt_descriptor.h
index d8860fe..56161e1 100644
--- a/device/bluetooth/bluetooth_gatt_descriptor.h
+++ b/device/bluetooth/bluetooth_gatt_descriptor.h
@@ -9,12 +9,11 @@
#include "base/basictypes.h"
#include "base/callback.h"
+#include "device/bluetooth/bluetooth_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace device {
-class BluetoothGattCharacteristic;
-
// BluetoothGattDescriptor represents a local or remote GATT characteristic
// descriptor. A GATT characteristic descriptor provides further information
// about a characteristic's value. They can be used to describe the
@@ -106,7 +105,7 @@ class BluetoothGattDescriptor {
static const BluetoothUUID kCharacteristicAggregateFormatUuid;
// The ErrorCallback is used by methods to asynchronously report errors.
- typedef base::Callback<void(const std::string&)> ErrorCallback;
+ typedef base::Closure ErrorCallback;
// The ValueCallback is used to return the value of a remote characteristic
// descriptor upon a read request.
@@ -128,8 +127,17 @@ class BluetoothGattDescriptor {
// |kCharacteristicPresentationFormat| are supported for locally hosted
// descriptors. This method will return NULL if |uuid| is any one of the
// unsupported predefined descriptor UUIDs.
- static BluetoothGattDescriptor* Create(const BluetoothUUID& uuid,
- const std::vector<uint8>& value);
+ static BluetoothGattDescriptor* Create(
+ const BluetoothUUID& uuid,
+ const std::vector<uint8>& value,
+ BluetoothGattCharacteristic::Permissions permissions);
+
+ // Identifier used to uniquely identify a GATT descriptorobject. This is
+ // different from the descriptor UUID: while multiple descriptors with the
+ // same UUID can exist on a Bluetooth device, the identifier returned from
+ // this method is unique among all descriptors of a device. The contents of
+ // the identifier are platform specific.
+ virtual std::string GetIdentifier() const = 0;
// The Bluetooth-specific UUID of the characteristic descriptor.
virtual BluetoothUUID GetUUID() const = 0;
@@ -148,6 +156,9 @@ class BluetoothGattDescriptor {
// descriptor belongs to.
virtual BluetoothGattCharacteristic* GetCharacteristic() const = 0;
+ // Returns the bitmask of characteristic descriptor attribute permissions.
+ virtual BluetoothGattCharacteristic::Permissions GetPermissions() const = 0;
+
// Sends a read request to a remote characteristic descriptor to read its
// value. |callback| is called to return the read value on success and
// |error_callback| is called for failures.
@@ -155,12 +166,11 @@ class BluetoothGattDescriptor {
const ErrorCallback& error_callback) = 0;
// Sends a write request to a remote characteristic descriptor, to modify the
- // value of the descriptor starting at offset |offset| with the new value
- // |new_value|. |callback| is called to signal success and |error_callback|
- // for failures. This method only applies to remote descriptors and will fail
- // for those that are locally hosted.
+ // value of the descriptor with the new value |new_value|. |callback| is
+ // called to signal success and |error_callback| for failures. This method
+ // only applies to remote descriptors and will fail for those that are locally
+ // hosted.
virtual void WriteRemoteDescriptor(
- int offset,
const std::vector<uint8>& new_value,
const base::Closure& callback,
const ErrorCallback& error_callback) = 0;
diff --git a/device/bluetooth/bluetooth_gatt_service.h b/device/bluetooth/bluetooth_gatt_service.h
index aabcfad..94b7e30 100644
--- a/device/bluetooth/bluetooth_gatt_service.h
+++ b/device/bluetooth/bluetooth_gatt_service.h
@@ -136,10 +136,10 @@ class BluetoothGattService {
// should read all GATT characteristic and descriptors objects and do any
// necessary set up required for a changed service. This method may be
// called several times, especially when the service is discovered for the
- // first time. It will be called for each characteristic that is discovered
- // or removed. Hence this method should be used to check whether or not all
- // characteristics of a service have been discovered that correspond to the
- // profile implemented by the Observer.
+ // first time. It will be called for each characteristic and characteristic
+ // descriptor that is discovered or removed. Hence this method should be
+ // used to check whether or not all characteristics of a service have been
+ // discovered that correspond to the profile implemented by the Observer.
virtual void GattServiceChanged(BluetoothGattService* service) {}
// Called when the remote GATT characteristic |characteristic| belonging to
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc
index fc751b5..a2b28a1 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc
@@ -8,6 +8,7 @@
#include "base/strings/stringprintf.h"
#include "chromeos/dbus/bluetooth_gatt_characteristic_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
namespace chromeos {
@@ -35,10 +36,28 @@ BluetoothRemoteGattCharacteristicChromeOS::
weak_ptr_factory_(this) {
VLOG(1) << "Creating remote GATT characteristic with identifier: "
<< GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ AddObserver(this);
+
+ // Add all known GATT characteristic descriptors.
+ const std::vector<dbus::ObjectPath>& gatt_descs =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetDescriptors();
+ for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin();
+ iter != gatt_descs.end(); ++iter)
+ GattDescriptorAdded(*iter);
}
BluetoothRemoteGattCharacteristicChromeOS::
~BluetoothRemoteGattCharacteristicChromeOS() {
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ RemoveObserver(this);
+
+ // Clean up all the descriptors. There isn't much point in notifying service
+ // observers for each descriptor that gets removed, so just delete them.
+ for (DescriptorMap::iterator iter = descriptors_.begin();
+ iter != descriptors_.end(); ++iter)
+ delete iter->second;
}
std::string BluetoothRemoteGattCharacteristicChromeOS::GetIdentifier() const {
@@ -88,8 +107,11 @@ BluetoothRemoteGattCharacteristicChromeOS::GetPermissions() const {
std::vector<device::BluetoothGattDescriptor*>
BluetoothRemoteGattCharacteristicChromeOS::GetDescriptors() const {
- // TODO(armansito): Return the actual descriptors here.
- return std::vector<device::BluetoothGattDescriptor*>();
+ std::vector<device::BluetoothGattDescriptor*> descriptors;
+ for (DescriptorMap::const_iterator iter = descriptors_.begin();
+ iter != descriptors_.end(); ++iter)
+ descriptors.push_back(iter->second);
+ return descriptors;
}
bool BluetoothRemoteGattCharacteristicChromeOS::AddDescriptor(
@@ -146,6 +168,66 @@ void BluetoothRemoteGattCharacteristicChromeOS::WriteRemoteCharacteristic(
callback, error_callback));
}
+void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded(
+ const dbus::ObjectPath& object_path) {
+ if (descriptors_.find(object_path) != descriptors_.end()) {
+ VLOG(1) << "Remote GATT characteristic descriptor already exists: "
+ << object_path.value();
+ return;
+ }
+
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path);
+ DCHECK(properties);
+ if (properties->characteristic.value() != object_path_) {
+ VLOG(2) << "Remote GATT descriptor does not belong to this characteristic.";
+ return;
+ }
+
+ VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: "
+ << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
+
+ BluetoothRemoteGattDescriptorChromeOS* descriptor =
+ new BluetoothRemoteGattDescriptorChromeOS(this, object_path);
+ descriptors_[object_path] = descriptor;
+ DCHECK(descriptor->GetIdentifier() == object_path.value());
+ DCHECK(descriptor->GetUUID().IsValid());
+ DCHECK(service_);
+ service_->NotifyServiceChanged();
+}
+
+void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorRemoved(
+ const dbus::ObjectPath& object_path) {
+ DescriptorMap::iterator iter = descriptors_.find(object_path);
+ if (iter == descriptors_.end()) {
+ VLOG(2) << "Unknown descriptor removed: " << object_path.value();
+ return;
+ }
+
+ VLOG(1) << "Removing remote GATT descriptor from characteristic: "
+ << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
+
+ BluetoothRemoteGattDescriptorChromeOS* descriptor = iter->second;
+ DCHECK(descriptor->object_path() == object_path);
+ descriptors_.erase(iter);
+ delete descriptor;
+
+ DCHECK(service_);
+ service_->NotifyServiceChanged();
+}
+
+void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorPropertyChanged(
+ const dbus::ObjectPath& object_path,
+ const std::string& property_name) {
+ DescriptorMap::const_iterator iter = descriptors_.find(object_path);
+ if (iter == descriptors_.end())
+ return;
+
+ VLOG(1) << "GATT descriptor property changed: " << object_path.value()
+ << ", property: " << property_name;
+}
+
void BluetoothRemoteGattCharacteristicChromeOS::OnGetValue(
const ValueCallback& callback,
const ErrorCallback& error_callback,
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h
index 3d66f29..1a4f045 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h
@@ -5,10 +5,12 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_CHROMEOS_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_CHROMEOS_H_
+#include <map>
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
+#include "chromeos/dbus/bluetooth_gatt_descriptor_client.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_uuid.h"
@@ -22,13 +24,15 @@ class BluetoothGattService;
namespace chromeos {
+class BluetoothRemoteGattDescriptorChromeOS;
class BluetoothRemoteGattServiceChromeOS;
// The BluetoothRemoteGattCharacteristicChromeOS class implements
// BluetoothGattCharacteristic for remote GATT characteristics on the Chrome OS
// platform.
class BluetoothRemoteGattCharacteristicChromeOS
- : public device::BluetoothGattCharacteristic {
+ : public device::BluetoothGattCharacteristic,
+ public BluetoothGattDescriptorClient::Observer {
public:
// device::BluetoothGattCharacteristic overrides.
virtual std::string GetIdentifier() const OVERRIDE;
@@ -62,6 +66,15 @@ class BluetoothRemoteGattCharacteristicChromeOS
const dbus::ObjectPath& object_path);
virtual ~BluetoothRemoteGattCharacteristicChromeOS();
+ // BluetoothGattDescriptorClient::Observer overrides.
+ virtual void GattDescriptorAdded(
+ const dbus::ObjectPath& object_path) OVERRIDE;
+ virtual void GattDescriptorRemoved(
+ const dbus::ObjectPath& object_path) OVERRIDE;
+ virtual void GattDescriptorPropertyChanged(
+ const dbus::ObjectPath& object_path,
+ const std::string& property_name) OVERRIDE;
+
// Called by dbus:: on completion of the request to get the characteristic
// value.
void OnGetValue(const ValueCallback& callback,
@@ -80,6 +93,14 @@ class BluetoothRemoteGattCharacteristicChromeOS
// The GATT service this GATT characteristic belongs to.
BluetoothRemoteGattServiceChromeOS* service_;
+ // Mapping from GATT descriptor object paths to descriptor objects owned by
+ // this characteristic. Since the Chrome OS implementation uses object paths
+ // as unique identifiers, we also use this mapping to return descriptors by
+ // identifier.
+ typedef std::map<dbus::ObjectPath, BluetoothRemoteGattDescriptorChromeOS*>
+ DescriptorMap;
+ DescriptorMap descriptors_;
+
// 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<BluetoothRemoteGattCharacteristicChromeOS>
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.cc
new file mode 100644
index 0000000..0027173
--- /dev/null
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.cc
@@ -0,0 +1,148 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chromeos/dbus/bluetooth_gatt_descriptor_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
+
+namespace chromeos {
+
+namespace {
+
+// Stream operator for logging vector<uint8>.
+std::ostream& operator<<(std::ostream& out, const std::vector<uint8> bytes) {
+ out << "[";
+ for (std::vector<uint8>::const_iterator iter = bytes.begin();
+ iter != bytes.end(); ++iter) {
+ out << base::StringPrintf("%02X", *iter);
+ }
+ return out << "]";
+}
+
+} // namespace
+
+BluetoothRemoteGattDescriptorChromeOS::BluetoothRemoteGattDescriptorChromeOS(
+ BluetoothRemoteGattCharacteristicChromeOS* characteristic,
+ const dbus::ObjectPath& object_path)
+ : object_path_(object_path),
+ characteristic_(characteristic),
+ weak_ptr_factory_(this) {
+ VLOG(1) << "Creating remote GATT descriptor with identifier: "
+ << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
+}
+
+BluetoothRemoteGattDescriptorChromeOS::
+ ~BluetoothRemoteGattDescriptorChromeOS() {
+}
+
+std::string BluetoothRemoteGattDescriptorChromeOS::GetIdentifier() const {
+ return object_path_.value();
+}
+
+device::BluetoothUUID BluetoothRemoteGattDescriptorChromeOS::GetUUID() const {
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path_);
+ DCHECK(properties);
+ return device::BluetoothUUID(properties->uuid.value());
+}
+
+bool BluetoothRemoteGattDescriptorChromeOS::IsLocal() const {
+ return false;
+}
+
+const std::vector<uint8>&
+BluetoothRemoteGattDescriptorChromeOS::GetValue() const {
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path_);
+ DCHECK(properties);
+ return properties->value.value();
+}
+
+device::BluetoothGattCharacteristic*
+BluetoothRemoteGattDescriptorChromeOS::GetCharacteristic() const {
+ return characteristic_;
+}
+
+device::BluetoothGattCharacteristic::Permissions
+BluetoothRemoteGattDescriptorChromeOS::GetPermissions() const {
+ // TODO(armansito): Once BlueZ defines the permissions, return the correct
+ // values here.
+ return device::BluetoothGattCharacteristic::kPermissionNone;
+}
+
+void BluetoothRemoteGattDescriptorChromeOS::ReadRemoteDescriptor(
+ const ValueCallback& callback,
+ const ErrorCallback& error_callback) {
+ VLOG(1) << "Sending GATT characteristic descriptor read request to "
+ << "descriptor: " << GetIdentifier() << ", UUID: "
+ << GetUUID().canonical_value();
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path_);
+ DCHECK(properties);
+ properties->value.Get(
+ base::Bind(&BluetoothRemoteGattDescriptorChromeOS::OnGetValue,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback, error_callback));
+}
+
+void BluetoothRemoteGattDescriptorChromeOS::WriteRemoteDescriptor(
+ const std::vector<uint8>& new_value,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ VLOG(1) << "Sending GATT characteristic descriptor write request to "
+ << "characteristic: " << GetIdentifier() << ", UUID: "
+ << GetUUID().canonical_value() << ", with value: "
+ << new_value << ".";
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path_);
+ DCHECK(properties);
+ properties->value.Set(
+ new_value,
+ base::Bind(&BluetoothRemoteGattDescriptorChromeOS::OnSetValue,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback, error_callback));
+}
+
+void BluetoothRemoteGattDescriptorChromeOS::OnGetValue(
+ const ValueCallback& callback,
+ const ErrorCallback& error_callback,
+ bool success) {
+ if (!success) {
+ VLOG(1) << "Failed to read the value from the remote descriptor.";
+ error_callback.Run();
+ return;
+ }
+
+ VLOG(1) << "Read value of remote descriptor.";
+ BluetoothGattDescriptorClient::Properties* properties =
+ DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
+ GetProperties(object_path_);
+ DCHECK(properties);
+ callback.Run(properties->value.value());
+}
+
+void BluetoothRemoteGattDescriptorChromeOS::OnSetValue(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success) {
+ if (!success) {
+ VLOG(1) << "Failed to write the value of remote descriptor.";
+ error_callback.Run();
+ return;
+ }
+
+ VLOG(1) << "Wrote value of remote descriptor.";
+ callback.Run();
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h b/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h
new file mode 100644
index 0000000..129daea
--- /dev/null
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_DESCRIPTOR_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_DESCRIPTOR_CHROMEOS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_gatt_descriptor.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace device {
+
+class BluetoothGattCharacteristic;
+
+} // namespace device
+
+namespace chromeos {
+
+class BluetoothRemoteGattCharacteristicChromeOS;
+
+// The BluetoothRemoteGattDescriptorChromeOS class implements
+// BluetoothGattDescriptor for remote GATT characteristic descriptors on the
+// Chrome OS platform.
+class BluetoothRemoteGattDescriptorChromeOS
+ : public device::BluetoothGattDescriptor {
+ public:
+ // device::BluetoothGattDescriptor overrides.
+ virtual std::string GetIdentifier() const OVERRIDE;
+ virtual device::BluetoothUUID GetUUID() const OVERRIDE;
+ virtual bool IsLocal() const OVERRIDE;
+ virtual const std::vector<uint8>& GetValue() const OVERRIDE;
+ virtual device::BluetoothGattCharacteristic*
+ GetCharacteristic() const OVERRIDE;
+ virtual device::BluetoothGattCharacteristic::Permissions
+ GetPermissions() const OVERRIDE;
+ virtual void ReadRemoteDescriptor(
+ const ValueCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+ virtual void WriteRemoteDescriptor(
+ const std::vector<uint8>& new_value,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
+
+ // Object path of the underlying D-Bus characteristic.
+ const dbus::ObjectPath& object_path() const { return object_path_; }
+
+ private:
+ friend class BluetoothRemoteGattCharacteristicChromeOS;
+
+ BluetoothRemoteGattDescriptorChromeOS(
+ BluetoothRemoteGattCharacteristicChromeOS* characteristic,
+ const dbus::ObjectPath& object_path);
+ virtual ~BluetoothRemoteGattDescriptorChromeOS();
+
+ // Called by dbus:: on completion of the request to get the descriptor value.
+ void OnGetValue(const ValueCallback& callback,
+ const ErrorCallback& error_callback,
+ bool success);
+
+ // Called by dbus:: on completion of the request to set the descriptor value.
+ void OnSetValue(const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ bool success);
+
+ // Object path of the D-Bus descriptor object.
+ dbus::ObjectPath object_path_;
+
+ // The GATT characteristic this descriptor belongs to.
+ BluetoothRemoteGattCharacteristicChromeOS* characteristic_;
+
+ // 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<BluetoothRemoteGattDescriptorChromeOS> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattDescriptorChromeOS);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_DESCRIPTOR_CHROMEOS_H_
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_chromeos.cc b/device/bluetooth/bluetooth_remote_gatt_service_chromeos.cc
index dae8808..ab37c96 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_chromeos.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service_chromeos.cc
@@ -39,7 +39,7 @@ BluetoothRemoteGattServiceChromeOS::BluetoothRemoteGattServiceChromeOS(
AddObserver(this);
// Add all known GATT characteristics.
- const std::vector<dbus::ObjectPath> gatt_chars =
+ const std::vector<dbus::ObjectPath>& gatt_chars =
DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
GetCharacteristics();
for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_chars.begin();
@@ -154,11 +154,15 @@ void BluetoothRemoteGattServiceChromeOS::Unregister(
error_callback.Run();
}
+void BluetoothRemoteGattServiceChromeOS::NotifyServiceChanged() {
+ FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
+ GattServiceChanged(this));
+}
+
void BluetoothRemoteGattServiceChromeOS::GattServicePropertyChanged(
const dbus::ObjectPath& object_path,
const std::string& property_name){
- FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
- GattServiceChanged(this));
+ NotifyServiceChanged();
}
void BluetoothRemoteGattServiceChromeOS::GattCharacteristicAdded(
@@ -189,8 +193,7 @@ void BluetoothRemoteGattServiceChromeOS::GattCharacteristicAdded(
FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
GattCharacteristicAdded(this, characteristic));
- FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
- GattServiceChanged(this));
+ NotifyServiceChanged();
}
void BluetoothRemoteGattServiceChromeOS::GattCharacteristicRemoved(
@@ -210,8 +213,7 @@ void BluetoothRemoteGattServiceChromeOS::GattCharacteristicRemoved(
FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
GattCharacteristicRemoved(this, characteristic));
- FOR_EACH_OBSERVER(device::BluetoothGattService::Observer, observers_,
- GattServiceChanged(this));
+ NotifyServiceChanged();
delete characteristic;
}
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_chromeos.h b/device/bluetooth/bluetooth_remote_gatt_service_chromeos.h
index cfb00c6..1316d0a 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_chromeos.h
+++ b/device/bluetooth/bluetooth_remote_gatt_service_chromeos.h
@@ -62,6 +62,11 @@ class BluetoothRemoteGattServiceChromeOS
// Object path of the underlying service.
const dbus::ObjectPath& object_path() const { return object_path_; }
+ // Notifies its observers that the GATT service has changed. This is mainly
+ // used by BluetoothRemoteGattCharacteristicChromeOS instances to notify
+ // service observers when characteristic descriptors get added and removed.
+ void NotifyServiceChanged();
+
private:
friend class BluetoothDeviceChromeOS;