diff options
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; |