From e069a45ceb26f426aae38a1f0e88d7d6e447b6cc Mon Sep 17 00:00:00 2001 From: gogerald Date: Fri, 26 Feb 2016 07:36:09 -0800 Subject: Implement BluetoothRemoteGattServiceWin and related unit tests This CL implements BluetoothRemoteGattServiceWin and related unit tests. BUG=579202 Review URL: https://codereview.chromium.org/1690133002 Cr-Commit-Position: refs/heads/master@{#377893} --- device/bluetooth/BUILD.gn | 2 + device/bluetooth/bluetooth.gyp | 2 + device/bluetooth/bluetooth_adapter_win.cc | 13 +- device/bluetooth/bluetooth_adapter_win.h | 7 + device/bluetooth/bluetooth_device_win.cc | 2 +- .../bluetooth/bluetooth_gatt_service_unittest.cc | 107 ++++++++++-- device/bluetooth/bluetooth_low_energy_win.cc | 46 +++++- device/bluetooth/bluetooth_low_energy_win.h | 15 +- device/bluetooth/bluetooth_low_energy_win_fake.cc | 180 ++++++++++++++++----- device/bluetooth/bluetooth_low_energy_win_fake.h | 37 ++++- .../bluetooth_remote_gatt_characteristic_win.cc | 166 +++++++++++++++++++ .../bluetooth_remote_gatt_characteristic_win.h | 74 +++++++++ .../bluetooth/bluetooth_remote_gatt_service_win.cc | 171 ++++++++++++++++++-- .../bluetooth/bluetooth_remote_gatt_service_win.h | 69 +++++++- device/bluetooth/bluetooth_task_manager_win.cc | 120 +++++++++++--- device/bluetooth/bluetooth_task_manager_win.h | 26 +++ device/bluetooth/test/bluetooth_test.h | 8 + device/bluetooth/test/bluetooth_test_win.cc | 163 +++++++++++++++++-- device/bluetooth/test/bluetooth_test_win.h | 10 ++ 19 files changed, 1107 insertions(+), 111 deletions(-) create mode 100644 device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc create mode 100644 device/bluetooth/bluetooth_remote_gatt_characteristic_win.h (limited to 'device') diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn index 0fb13c8..167fe30 100644 --- a/device/bluetooth/BUILD.gn +++ b/device/bluetooth/BUILD.gn @@ -89,6 +89,8 @@ component("bluetooth") { "bluetooth_low_energy_win.h", "bluetooth_remote_gatt_characteristic_android.cc", "bluetooth_remote_gatt_characteristic_android.h", + "bluetooth_remote_gatt_characteristic_win.cc", + "bluetooth_remote_gatt_characteristic_win.h", "bluetooth_remote_gatt_descriptor_android.cc", "bluetooth_remote_gatt_descriptor_android.h", "bluetooth_remote_gatt_service_android.cc", diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp index 8aaad96..59eacfd 100644 --- a/device/bluetooth/bluetooth.gyp +++ b/device/bluetooth/bluetooth.gyp @@ -91,6 +91,8 @@ 'bluetooth_low_energy_win.h', 'bluetooth_remote_gatt_characteristic_android.cc', 'bluetooth_remote_gatt_characteristic_android.h', + 'bluetooth_remote_gatt_characteristic_win.cc', + 'bluetooth_remote_gatt_characteristic_win.h', 'bluetooth_remote_gatt_descriptor_android.cc', 'bluetooth_remote_gatt_descriptor_android.h', 'bluetooth_remote_gatt_service_android.cc', diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc index 68f7812..8206c91 100644 --- a/device/bluetooth/bluetooth_adapter_win.cc +++ b/device/bluetooth/bluetooth_adapter_win.cc @@ -43,8 +43,8 @@ BluetoothAdapterWin::BluetoothAdapterWin(const InitCallback& init_callback) powered_(false), discovery_status_(NOT_DISCOVERING), num_discovery_listeners_(0), - weak_ptr_factory_(this) { -} + force_update_device_for_test_(false), + weak_ptr_factory_(this) {} BluetoothAdapterWin::~BluetoothAdapterWin() { if (task_manager_.get()) { @@ -284,10 +284,15 @@ void BluetoothAdapterWin::DevicesPolled( static_cast(iter->second); if (!device_win->IsEqual(*device_state)) { device_win->Update(*device_state); - FOR_EACH_OBSERVER(BluetoothAdapter::Observer, - observers_, + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, DeviceChanged(this, device_win)); } + // Above IsEqual returns true if device name, address, status and services + // (primary services of BLE device) are the same. However, in BLE tests, + // we may simulate characteristic, descriptor and secondary GATT service + // after device has been initialized. + if (force_update_device_for_test_) + device_win->Update(*device_state); } } } diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h index 26c895b..bb8f16b 100644 --- a/device/bluetooth/bluetooth_adapter_win.h +++ b/device/bluetooth/bluetooth_adapter_win.h @@ -93,6 +93,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin return socket_thread_; } + scoped_refptr GetWinBluetoothTaskManager() { + return task_manager_; + } + protected: // BluetoothAdapter: void RemovePairingDelegateInternal( @@ -153,6 +157,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin base::ThreadChecker thread_checker_; + // Flag indicating a device update must be forced in DevicesPolled. + bool force_update_device_for_test_; + // 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 weak_ptr_factory_; diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc index 310aa9d..561b5a7 100644 --- a/device/bluetooth/bluetooth_device_win.cc +++ b/device/bluetooth/bluetooth_device_win.cc @@ -357,7 +357,7 @@ void BluetoothDeviceWin::UpdateGattServices( } } for (const auto& service : to_be_removed_services) { - gatt_services_.erase(service); + gatt_services_.take_and_erase(service); } // Update previously discovered services. for (auto gatt_service : gatt_services_) { diff --git a/device/bluetooth/bluetooth_gatt_service_unittest.cc b/device/bluetooth/bluetooth_gatt_service_unittest.cc index ed01bf8..bd108ed 100644 --- a/device/bluetooth/bluetooth_gatt_service_unittest.cc +++ b/device/bluetooth/bluetooth_gatt_service_unittest.cc @@ -6,21 +6,24 @@ #include "build/build_config.h" #include "device/bluetooth/bluetooth_gatt_characteristic.h" +#include "device/bluetooth/test/test_bluetooth_adapter_observer.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_ANDROID) #include "device/bluetooth/test/bluetooth_test_android.h" #elif defined(OS_MACOSX) #include "device/bluetooth/test/bluetooth_test_mac.h" +#elif defined(OS_WIN) +#include "device/bluetooth/test/bluetooth_test_win.h" #endif namespace device { -#if defined(OS_ANDROID) || defined(OS_MACOSX) +#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) class BluetoothGattServiceTest : public BluetoothTest {}; #endif -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) TEST_F(BluetoothGattServiceTest, GetIdentifier) { InitWithFakeAdapter(); StartLowEnergyDiscoverySession(); @@ -56,9 +59,9 @@ TEST_F(BluetoothGattServiceTest, GetIdentifier) { EXPECT_NE(service3->GetIdentifier(), service4->GetIdentifier()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) TEST_F(BluetoothGattServiceTest, GetUUID) { InitWithFakeAdapter(); StartLowEnergyDiscoverySession(); @@ -78,9 +81,9 @@ TEST_F(BluetoothGattServiceTest, GetUUID) { EXPECT_EQ(uuid, device->GetGattServices()[0]->GetUUID()); EXPECT_EQ(uuid, device->GetGattServices()[1]->GetUUID()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) TEST_F(BluetoothGattServiceTest, GetCharacteristics_FindNone) { InitWithFakeAdapter(); StartLowEnergyDiscoverySession(); @@ -97,9 +100,9 @@ TEST_F(BluetoothGattServiceTest, GetCharacteristics_FindNone) { EXPECT_EQ(0u, service->GetCharacteristics().size()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) TEST_F(BluetoothGattServiceTest, GetCharacteristics_and_GetCharacteristic) { InitWithFakeAdapter(); StartLowEnergyDiscoverySession(); @@ -145,6 +148,92 @@ TEST_F(BluetoothGattServiceTest, GetCharacteristics_and_GetCharacteristic) { EXPECT_EQ(service->GetCharacteristic(char_id1), service->GetCharacteristic(char_id1)); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) + +#if defined(OS_WIN) +TEST_F(BluetoothGattServiceTest, GetCharacteristic_CharacteristicRemoved) { + InitWithFakeAdapter(); + StartLowEnergyDiscoverySession(); + BluetoothDevice* device = DiscoverLowEnergyDevice(3); + device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED), + GetConnectErrorCallback(Call::NOT_EXPECTED)); + SimulateGattConnection(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Simulate a service, with several Characteristics: + std::vector services; + services.push_back("00000000-0000-1000-8000-00805f9b34fb"); + SimulateGattServicesDiscovered(device, services); + BluetoothGattService* service = device->GetGattServices()[0]; + std::string characteristic_uuid1 = "11111111-0000-1000-8000-00805f9b34fb"; + std::string characteristic_uuid2 = "22222222-0000-1000-8000-00805f9b34fb"; + std::string characteristic_uuid3 = characteristic_uuid2; // Duplicate UUID. + std::string characteristic_uuid4 = "33333333-0000-1000-8000-00805f9b34fb"; + SimulateGattCharacteristic(service, characteristic_uuid1, /* properties */ 0); + SimulateGattCharacteristic(service, characteristic_uuid2, /* properties */ 0); + SimulateGattCharacteristic(service, characteristic_uuid3, /* properties */ 0); + SimulateGattCharacteristic(service, characteristic_uuid4, /* properties */ 0); + + // Simulate remove of characteristics one by one. + EXPECT_EQ(4u, service->GetCharacteristics().size()); + std::string removed_char = service->GetCharacteristics()[0]->GetIdentifier(); + SimulateGattCharacteristicRemoved(service, + service->GetCharacteristic(removed_char)); + EXPECT_EQ(1, observer.gatt_characteristic_removed_count()); + EXPECT_FALSE(service->GetCharacteristic(removed_char)); + EXPECT_EQ(3u, service->GetCharacteristics().size()); + removed_char = service->GetCharacteristics()[0]->GetIdentifier(); + SimulateGattCharacteristicRemoved(service, + service->GetCharacteristic(removed_char)); + EXPECT_EQ(2, observer.gatt_characteristic_removed_count()); + EXPECT_FALSE(service->GetCharacteristic(removed_char)); + EXPECT_EQ(2u, service->GetCharacteristics().size()); + removed_char = service->GetCharacteristics()[0]->GetIdentifier(); + SimulateGattCharacteristicRemoved(service, + service->GetCharacteristic(removed_char)); + EXPECT_EQ(3, observer.gatt_characteristic_removed_count()); + EXPECT_FALSE(service->GetCharacteristic(removed_char)); + EXPECT_EQ(1u, service->GetCharacteristics().size()); + removed_char = service->GetCharacteristics()[0]->GetIdentifier(); + SimulateGattCharacteristicRemoved(service, + service->GetCharacteristic(removed_char)); + EXPECT_EQ(4, observer.gatt_characteristic_removed_count()); + EXPECT_FALSE(service->GetCharacteristic(removed_char)); + EXPECT_EQ(0u, service->GetCharacteristics().size()); + + EXPECT_EQ(4, observer.gatt_service_changed_count()); +} +#endif // defined(OS_WIN) + +#if defined(OS_WIN) +TEST_F(BluetoothGattServiceTest, SimulateGattServiceRemove) { + InitWithFakeAdapter(); + StartLowEnergyDiscoverySession(); + BluetoothDevice* device = DiscoverLowEnergyDevice(3); + device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED), + GetConnectErrorCallback(Call::NOT_EXPECTED)); + SimulateGattConnection(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Simulate two primary GATT services. + std::vector services; + services.push_back("00000000-0000-1000-8000-00805f9b34fb"); + services.push_back("01010101-0101-1000-8000-00805f9b34fb"); + SimulateGattServicesDiscovered(device, services); + EXPECT_EQ(2u, device->GetGattServices().size()); + + // Simulate remove of a primary service. + BluetoothGattService* service1 = device->GetGattServices()[0]; + BluetoothGattService* service2 = device->GetGattServices()[1]; + std::string removed_service = service1->GetIdentifier(); + SimulateGattServiceRemoved(device->GetGattService(removed_service)); + EXPECT_EQ(1, observer.gatt_service_removed_count()); + EXPECT_EQ(1u, device->GetGattServices().size()); + EXPECT_FALSE(device->GetGattService(removed_service)); + EXPECT_EQ(device->GetGattServices()[0], service2); +} +#endif // defined(OS_WIN) } // namespace device diff --git a/device/bluetooth/bluetooth_low_energy_win.cc b/device/bluetooth/bluetooth_low_energy_win.cc index 29932b9..1e985b5 100644 --- a/device/bluetooth/bluetooth_low_energy_win.cc +++ b/device/bluetooth/bluetooth_low_energy_win.cc @@ -650,10 +650,6 @@ BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { } -bool IsBluetoothLowEnergySupported() { - return base::win::GetVersion() >= base::win::VERSION_WIN8; -} - bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( const std::string& instance_id, BLUETOOTH_ADDRESS* btha, @@ -682,6 +678,10 @@ void BluetoothLowEnergyWrapper::SetInstanceForTest( BluetoothLowEnergyWrapper::BluetoothLowEnergyWrapper() {} BluetoothLowEnergyWrapper::~BluetoothLowEnergyWrapper() {} +bool BluetoothLowEnergyWrapper::IsBluetoothLowEnergySupported() { + return base::win::GetVersion() >= base::win::VERSION_WIN8; +} + bool BluetoothLowEnergyWrapper::EnumerateKnownBluetoothLowEnergyDevices( ScopedVector* devices, std::string* error) { @@ -719,5 +719,43 @@ bool BluetoothLowEnergyWrapper::EnumerateKnownBluetoothLowEnergyServices( return CollectBluetoothLowEnergyDeviceServices(device_path, services, error); } +HRESULT BluetoothLowEnergyWrapper::ReadCharacteristicsOfAService( + base::FilePath& service_path, + const PBTH_LE_GATT_SERVICE service, + scoped_ptr* out_included_characteristics, + USHORT* out_counts) { + base::File file(service_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!file.IsValid()) + return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED); + + USHORT required_length = 0; + HRESULT hr = BluetoothGATTGetCharacteristics(file.GetPlatformFile(), service, + 0, NULL, &required_length, + BLUETOOTH_GATT_FLAG_NONE); + if (hr != HRESULT_FROM_WIN32(ERROR_MORE_DATA)) + return hr; + + out_included_characteristics->reset( + new BTH_LE_GATT_CHARACTERISTIC[required_length]); + USHORT actual_length = required_length; + hr = BluetoothGATTGetCharacteristics( + file.GetPlatformFile(), service, actual_length, + out_included_characteristics->get(), &required_length, + BLUETOOTH_GATT_FLAG_NONE); + if (SUCCEEDED(hr) && required_length != actual_length) { + LOG(ERROR) << "Retrieved charactersitics is not equal to expected" + << " actual_length " << actual_length << " required_length " + << required_length; + hr = HRESULT_FROM_WIN32(ERROR_INVALID_USER_BUFFER); + } + *out_counts = actual_length; + + if (FAILED(hr)) { + out_included_characteristics->reset(nullptr); + *out_counts = 0; + } + return hr; +} + } // namespace win } // namespace device diff --git a/device/bluetooth/bluetooth_low_energy_win.h b/device/bluetooth/bluetooth_low_energy_win.h index 9d92435..a2bae9e 100644 --- a/device/bluetooth/bluetooth_low_energy_win.h +++ b/device/bluetooth/bluetooth_low_energy_win.h @@ -74,9 +74,6 @@ class DEVICE_BLUETOOTH_EXPORT DevicePropertyValue { DISALLOW_COPY_AND_ASSIGN(DevicePropertyValue); }; -// Returns true only on Windows platforms supporting Bluetooth Low Energy. -bool DEVICE_BLUETOOTH_EXPORT IsBluetoothLowEnergySupported(); - struct DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyServiceInfo { BluetoothLowEnergyServiceInfo(); ~BluetoothLowEnergyServiceInfo(); @@ -113,6 +110,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyWrapper { static void DeleteInstance(); static void SetInstanceForTest(BluetoothLowEnergyWrapper* instance); + // Returns true only on Windows platforms supporting Bluetooth Low Energy. + virtual bool IsBluetoothLowEnergySupported(); + // Enumerates the list of known (i.e. already paired) Bluetooth LE devices on // this machine. In case of error, returns false and sets |error| with an // error message describing the problem. @@ -144,6 +144,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyWrapper { ScopedVector* services, std::string* error); + // Reads characteristics of |service| with service device path |service_path|. + // The result will be stored in |*out_included_characteristics| and + // |*out_counts|. + virtual HRESULT ReadCharacteristicsOfAService( + base::FilePath& service_path, + const PBTH_LE_GATT_SERVICE service, + scoped_ptr* out_included_characteristics, + USHORT* out_counts); + protected: BluetoothLowEnergyWrapper(); virtual ~BluetoothLowEnergyWrapper(); diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.cc b/device/bluetooth/bluetooth_low_energy_win_fake.cc index 6750323..bc1d2b5 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.cc +++ b/device/bluetooth/bluetooth_low_energy_win_fake.cc @@ -5,6 +5,7 @@ #include "device/bluetooth/bluetooth_low_energy_win_fake.h" #include "base/strings/stringprintf.h" +#include "device/bluetooth/bluetooth_low_energy_defs_win.h" namespace { const char kPlatformNotSupported[] = @@ -29,6 +30,10 @@ BLEGattDescriptor::~BLEGattDescriptor() {} BluetoothLowEnergyWrapperFake::BluetoothLowEnergyWrapperFake() {} BluetoothLowEnergyWrapperFake::~BluetoothLowEnergyWrapperFake() {} +bool BluetoothLowEnergyWrapperFake::IsBluetoothLowEnergySupported() { + return true; +} + bool BluetoothLowEnergyWrapperFake::EnumerateKnownBluetoothLowEnergyDevices( ScopedVector* devices, std::string* error) { @@ -81,16 +86,16 @@ bool BluetoothLowEnergyWrapperFake::EnumerateKnownBluetoothLowEnergyServices( base::string16 device_address = ExtractDeviceAddressFromDevicePath(device_path.value()); - base::string16 service_attribute_handle = - ExtractServiceAttributeHandleFromDevicePath(device_path.value()); + std::vector service_attribute_handles = + ExtractServiceAttributeHandlesFromDevicePath(device_path.value()); BLEDevicesMap::iterator it_d = simulated_devices_.find( std::string(device_address.begin(), device_address.end())); CHECK(it_d != simulated_devices_.end()); - // |service_attribute_handle| is empty means |device_path| is a BLE device + // |service_attribute_handles| is empty means |device_path| is a BLE device // path, otherwise it is a BLE GATT service device path. - if (service_attribute_handle.empty()) { + if (service_attribute_handles.empty()) { // Return all primary services for BLE device. for (auto& primary_service : it_d->second->primary_services) { BluetoothLowEnergyServiceInfo* service_info = @@ -102,21 +107,52 @@ bool BluetoothLowEnergyWrapperFake::EnumerateKnownBluetoothLowEnergyServices( } } else { // Return corresponding GATT service for BLE GATT service device. - BLEGattServicesMap::iterator it_s = - it_d->second->primary_services.find(std::string( - service_attribute_handle.begin(), service_attribute_handle.end())); - CHECK(it_s != it_d->second->primary_services.end()); + BLEGattService* target_service = + GetSimulatedGattService(it_d->second.get(), service_attribute_handles); BluetoothLowEnergyServiceInfo* service_info = new BluetoothLowEnergyServiceInfo(); - service_info->uuid = it_s->second->service_info->ServiceUuid; + service_info->uuid = target_service->service_info->ServiceUuid; service_info->attribute_handle = - it_s->second->service_info->AttributeHandle; + target_service->service_info->AttributeHandle; services->push_back(service_info); } return true; } +HRESULT BluetoothLowEnergyWrapperFake::ReadCharacteristicsOfAService( + base::FilePath& service_path, + const PBTH_LE_GATT_SERVICE service, + scoped_ptr* out_included_characteristics, + USHORT* out_counts) { + base::string16 device_address = + ExtractDeviceAddressFromDevicePath(service_path.value()); + const std::vector service_att_handles = + ExtractServiceAttributeHandlesFromDevicePath(service_path.value()); + BLEGattService* target_service = GetSimulatedGattService( + GetSimulatedBLEDevice( + std::string(device_address.begin(), device_address.end())), + service_att_handles); + if (target_service == nullptr) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + + std::size_t number_of_included_characteristic = + target_service->included_characteristics.size(); + if (number_of_included_characteristic) { + *out_counts = (USHORT)number_of_included_characteristic; + out_included_characteristics->reset( + new BTH_LE_GATT_CHARACTERISTIC[number_of_included_characteristic]); + std::size_t i = 0; + for (const auto& cha : target_service->included_characteristics) { + out_included_characteristics->get()[i] = + *(cha.second->characteristic_info); + i++; + } + return S_OK; + } + return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); +} + BLEDevice* BluetoothLowEnergyWrapperFake::SimulateBLEDevice( std::string device_name, BLUETOOTH_ADDRESS device_address) { @@ -134,9 +170,18 @@ BLEDevice* BluetoothLowEnergyWrapperFake::SimulateBLEDevice( return device; } +BLEDevice* BluetoothLowEnergyWrapperFake::GetSimulatedBLEDevice( + std::string device_address) { + BLEDevicesMap::iterator it_d = simulated_devices_.find(device_address); + if (it_d == simulated_devices_.end()) + return nullptr; + return it_d->second.get(); +} + BLEGattService* BluetoothLowEnergyWrapperFake::SimulateBLEGattService( BLEDevice* device, - std::string uuid) { + BLEGattService* parent_service, + const BTH_LE_UUID& uuid) { CHECK(device); BLEGattService* service = new BLEGattService(); @@ -145,19 +190,79 @@ BLEGattService* BluetoothLowEnergyWrapperFake::SimulateBLEGattService( BluetoothAddressToCanonicalString(device->device_info->address); service_info->AttributeHandle = GenerateAUniqueAttributeHandle(string_device_address); - service_info->ServiceUuid = CanonicalStringToBTH_LE_UUID(uuid); + service_info->ServiceUuid = uuid; service->service_info.reset(service_info); - device->primary_services[std::to_string(service_info->AttributeHandle)] = - make_scoped_ptr(service); + + if (parent_service) { + parent_service + ->included_services[std::to_string(service_info->AttributeHandle)] = + make_scoped_ptr(service); + } else { + device->primary_services[std::to_string(service_info->AttributeHandle)] = + make_scoped_ptr(service); + } return service; } -BLEDevice* BluetoothLowEnergyWrapperFake::GetSimulatedBLEDevice( - std::string device_address) { - BLEDevicesMap::iterator it_d = simulated_devices_.find(device_address); - if (it_d == simulated_devices_.end()) +void BluetoothLowEnergyWrapperFake::SimulateBLEGattServiceRemoved( + BLEDevice* device, + BLEGattService* parent_service, + std::string attribute_handle) { + if (parent_service) { + parent_service->included_services.erase(attribute_handle); + } else { + device->primary_services.erase(attribute_handle); + } +} + +BLEGattService* BluetoothLowEnergyWrapperFake::GetSimulatedGattService( + BLEDevice* device, + const std::vector& chain_of_att_handle) { + // First, find the root primary service. + BLEGattServicesMap::iterator it_s = + device->primary_services.find(chain_of_att_handle[0]); + if (it_s == device->primary_services.end()) return nullptr; - return it_d->second.get(); + + // Iteratively follow the chain of included service attribute handles to find + // the target service. + for (std::size_t i = 1; i < chain_of_att_handle.size(); i++) { + std::string included_att_handle = std::string( + chain_of_att_handle[i].begin(), chain_of_att_handle[i].end()); + BLEGattServicesMap::iterator it_i = + it_s->second->included_services.find(included_att_handle); + if (it_i == it_s->second->included_services.end()) + return nullptr; + it_s = it_i; + } + return it_s->second.get(); +} + +BLEGattCharacteristic* +BluetoothLowEnergyWrapperFake::SimulateBLEGattCharacterisc( + std::string device_address, + BLEGattService* parent_service, + const BTH_LE_GATT_CHARACTERISTIC& characteristic) { + CHECK(parent_service); + + BLEGattCharacteristic* win_characteristic = new BLEGattCharacteristic(); + PBTH_LE_GATT_CHARACTERISTIC win_characteristic_info = + new BTH_LE_GATT_CHARACTERISTIC[1]; + *win_characteristic_info = characteristic; + (win_characteristic->characteristic_info).reset(win_characteristic_info); + win_characteristic->characteristic_info->AttributeHandle = + GenerateAUniqueAttributeHandle(device_address); + parent_service->included_characteristics[std::to_string( + win_characteristic->characteristic_info->AttributeHandle)] = + make_scoped_ptr(win_characteristic); + return win_characteristic; +} + +void BluetoothLowEnergyWrapperFake::SimulateBLEGattCharacteriscRemove( + BLEGattService* parent_service, + std::string attribute_handle) { + CHECK(parent_service); + parent_service->included_characteristics.erase(attribute_handle); } USHORT BluetoothLowEnergyWrapperFake::GenerateAUniqueAttributeHandle( @@ -206,33 +311,34 @@ base::string16 BluetoothLowEnergyWrapperFake::GenerateBLEGattServiceDevicePath( base::string16 BluetoothLowEnergyWrapperFake::ExtractDeviceAddressFromDevicePath( base::string16 path) { - std::size_t found = path.find('/'); + std::size_t found = path.find_first_of('/'); if (found != base::string16::npos) { return path.substr(0, found); } return path; } -base::string16 -BluetoothLowEnergyWrapperFake::ExtractServiceAttributeHandleFromDevicePath( +std::vector +BluetoothLowEnergyWrapperFake::ExtractServiceAttributeHandlesFromDevicePath( base::string16 path) { std::size_t found = path.find('/'); if (found == base::string16::npos) - return base::string16(); - return path.substr(found + 1); -} - -BTH_LE_UUID BluetoothLowEnergyWrapperFake::CanonicalStringToBTH_LE_UUID( - std::string uuid) { - BTH_LE_UUID win_uuid; - // Only short UUIDs (4 hex digits) have beened used in BluetoothTest right - // now. Need fix after using long UUIDs. - win_uuid.IsShortUuid = true; - unsigned int data[1]; - int result = sscanf_s(uuid.c_str(), "%04x", &data[0]); - CHECK(result == 1); - win_uuid.Value.ShortUuid = data[0]; - return win_uuid; + return std::vector(); + + std::vector chain_of_att_handle; + while (true) { + std::size_t next_found = path.find(path, found + 1); + if (next_found == base::string16::npos) + break; + base::string16 att_handle = path.substr(found + 1, next_found); + chain_of_att_handle.push_back( + std::string(att_handle.begin(), att_handle.end())); + found = next_found; + } + base::string16 att_handle = path.substr(found + 1); + chain_of_att_handle.push_back( + std::string(att_handle.begin(), att_handle.end())); + return chain_of_att_handle; } std::string BluetoothLowEnergyWrapperFake::BluetoothAddressToCanonicalString( diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.h b/device/bluetooth/bluetooth_low_energy_win_fake.h index a4da0c7..b069daa 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.h +++ b/device/bluetooth/bluetooth_low_energy_win_fake.h @@ -68,6 +68,7 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { BluetoothLowEnergyWrapperFake(); ~BluetoothLowEnergyWrapperFake() override; + bool IsBluetoothLowEnergySupported() override; bool EnumerateKnownBluetoothLowEnergyDevices( ScopedVector* devices, std::string* error) override; @@ -78,11 +79,38 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { const base::FilePath& device_path, ScopedVector* services, std::string* error) override; + HRESULT ReadCharacteristicsOfAService( + base::FilePath& service_path, + const PBTH_LE_GATT_SERVICE service, + scoped_ptr* out_included_characteristics, + USHORT* out_counts) override; BLEDevice* SimulateBLEDevice(std::string device_name, BLUETOOTH_ADDRESS device_address); BLEDevice* GetSimulatedBLEDevice(std::string device_address); - BLEGattService* SimulateBLEGattService(BLEDevice* device, std::string uuid); + + // Note: |parent_service| may be nullptr to indicate a primary service. + BLEGattService* SimulateBLEGattService(BLEDevice* device, + BLEGattService* parent_service, + const BTH_LE_UUID& uuid); + + // Note: |parent_service| may be nullptr to indicate a primary service. + void SimulateBLEGattServiceRemoved(BLEDevice* device, + BLEGattService* parent_service, + std::string attribute_handle); + + // Note: |chain_of_att_handle| contains the attribute handles of the services + // in order from primary service to target service. The last item in + // |chain_of_att_handle| is the target service's attribute handle. + BLEGattService* GetSimulatedGattService( + BLEDevice* device, + const std::vector& chain_of_att_handle); + BLEGattCharacteristic* SimulateBLEGattCharacterisc( + std::string device_address, + BLEGattService* parent_service, + const BTH_LE_GATT_CHARACTERISTIC& characteristic); + void SimulateBLEGattCharacteriscRemove(BLEGattService* parent_service, + std::string attribute_handle); private: // Generate an unique attribute handle on |device_address|. @@ -102,18 +130,15 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { // GenerateBLEDevicePath or GenerateBLEGattServiceDevicePath. base::string16 ExtractDeviceAddressFromDevicePath(base::string16 path); - // Extract service attribute handle from the |path| generated by + // Extract service attribute handles from the |path| generated by // GenerateBLEGattServiceDevicePath. - base::string16 ExtractServiceAttributeHandleFromDevicePath( + std::vector ExtractServiceAttributeHandlesFromDevicePath( base::string16 path); // The canonical BLE device address string format is the // BluetoothDevice::CanonicalizeAddress. std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha); - // The canonical UUID string format is device::BluetoothUUID.value(). - BTH_LE_UUID CanonicalStringToBTH_LE_UUID(std::string uuid); - // Table to store allocated attribute handle for a device. BLEAttributeHandleTable attribute_handle_table_; BLEDevicesMap simulated_devices_; diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc new file mode 100644 index 0000000..8f2a6d8 --- /dev/null +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc @@ -0,0 +1,166 @@ +// Copyright 2016 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_characteristic_win.h" + +#include "device/bluetooth/bluetooth_adapter_win.h" +#include "device/bluetooth/bluetooth_remote_gatt_service_win.h" +#include "device/bluetooth/bluetooth_task_manager_win.h" + +namespace device { + +BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin( + BluetoothRemoteGattServiceWin* parent_service, + BTH_LE_GATT_CHARACTERISTIC* characteristic_info, + scoped_refptr& ui_task_runner) + : parent_service_(parent_service), + characteristic_info_(characteristic_info), + ui_task_runner_(ui_task_runner), + weak_ptr_factory_(this) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(parent_service_); + DCHECK(characteristic_info_); + + adapter_ = static_cast( + parent_service_->GetDevice()->GetAdapter()); + DCHECK(adapter_); + task_manager_ = adapter_->GetWinBluetoothTaskManager(); + DCHECK(task_manager_); + + characteristic_uuid_ = task_manager_->BluetoothLowEnergyUuidToBluetoothUuid( + characteristic_info_->CharacteristicUuid); + characteristic_identifier_ = + parent_service_->GetIdentifier() + + std::to_string(characteristic_info_->AttributeHandle); + Update(); +} + +BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + adapter_->NotifyGattCharacteristicRemoved(this); +} + +std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const { + return characteristic_identifier_; +} + +BluetoothUUID BluetoothRemoteGattCharacteristicWin::GetUUID() const { + return characteristic_uuid_; +} + +bool BluetoothRemoteGattCharacteristicWin::IsLocal() const { + return false; +} + +std::vector& BluetoothRemoteGattCharacteristicWin::GetValue() const { + NOTIMPLEMENTED(); + return const_cast&>(characteristic_value_); +} + +BluetoothGattService* BluetoothRemoteGattCharacteristicWin::GetService() const { + return parent_service_; +} + +BluetoothGattCharacteristic::Properties +BluetoothRemoteGattCharacteristicWin::GetProperties() const { + BluetoothGattCharacteristic::Properties properties = PROPERTY_NONE; + + if (characteristic_info_->IsBroadcastable) + properties = properties | PROPERTY_BROADCAST; + if (characteristic_info_->IsReadable) + properties = properties | PROPERTY_READ; + if (characteristic_info_->IsWritableWithoutResponse) + properties = properties | PROPERTY_WRITE_WITHOUT_RESPONSE; + if (characteristic_info_->IsWritable) + properties = properties | PROPERTY_WRITE; + if (characteristic_info_->IsNotifiable) + properties = properties | PROPERTY_NOTIFY; + if (characteristic_info_->IsIndicatable) + properties = properties | PROPERTY_INDICATE; + if (characteristic_info_->IsSignedWritable) + properties = properties | PROPERTY_AUTHENTICATED_SIGNED_WRITES; + if (characteristic_info_->HasExtendedProperties) + properties = properties | PROPERTY_EXTENDED_PROPERTIES; + + // TODO(crbug.com/589304): Information about PROPERTY_RELIABLE_WRITE and + // PROPERTY_WRITABLE_AUXILIARIES is not available in characteristic_info_ + // (BTH_LE_GATT_CHARACTERISTIC). + + return properties; +} + +BluetoothGattCharacteristic::Permissions +BluetoothRemoteGattCharacteristicWin::GetPermissions() const { + BluetoothGattCharacteristic::Permissions permissions = PERMISSION_NONE; + + if (characteristic_info_->IsReadable) + permissions = permissions | PERMISSION_READ; + if (characteristic_info_->IsWritable) + permissions = permissions | PERMISSION_WRITE; + + return permissions; +} + +bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const { + NOTIMPLEMENTED(); + return false; +} + +std::vector +BluetoothRemoteGattCharacteristicWin::GetDescriptors() const { + NOTIMPLEMENTED(); + return std::vector(); +} + +BluetoothGattDescriptor* BluetoothRemoteGattCharacteristicWin::GetDescriptor( + const std::string& identifier) const { + NOTIMPLEMENTED(); + return nullptr; +} + +bool BluetoothRemoteGattCharacteristicWin::AddDescriptor( + BluetoothGattDescriptor* descriptor) { + NOTIMPLEMENTED(); + return false; +} + +bool BluetoothRemoteGattCharacteristicWin::UpdateValue( + const std::vector& value) { + NOTIMPLEMENTED(); + return false; +} + +void BluetoothRemoteGattCharacteristicWin::StartNotifySession( + const NotifySessionCallback& callback, + const ErrorCallback& error_callback) { + NOTIMPLEMENTED(); + error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); +} + +void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( + const ValueCallback& callback, + const ErrorCallback& error_callback) { + NOTIMPLEMENTED(); + error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); +} + +void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic( + const std::vector& new_value, + const base::Closure& callback, + const ErrorCallback& error_callback) { + NOTIMPLEMENTED(); + error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); +} + +void BluetoothRemoteGattCharacteristicWin::Update() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + NOTIMPLEMENTED(); +} + +uint16_t BluetoothRemoteGattCharacteristicWin::GetAttributeHandle() const { + return characteristic_info_->AttributeHandle; +} + +} // namespace device. diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h new file mode 100644 index 0000000..f397363 --- /dev/null +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h @@ -0,0 +1,74 @@ +// Copyright 2016 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_CHARACTERISTIC_WIN_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_WIN_H_ + +#include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" +#include "device/bluetooth/bluetooth_gatt_characteristic.h" +#include "device/bluetooth/bluetooth_low_energy_defs_win.h" + +namespace device { + +class BluetoothAdapterWin; +class BluetoothRemoteGattServiceWin; +class BluetoothTaskManagerWin; + +// The BluetoothRemoteGattCharacteristicWin class implements +// BluetoothGattCharacteristic for remote GATT services on Windows 8 and later. +class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWin + : public BluetoothGattCharacteristic { + public: + BluetoothRemoteGattCharacteristicWin( + BluetoothRemoteGattServiceWin* parent_service, + BTH_LE_GATT_CHARACTERISTIC* characteristic_info, + scoped_refptr& ui_task_runner); + ~BluetoothRemoteGattCharacteristicWin() override; + + // Override BluetoothGattCharacteristic interfaces. + std::string GetIdentifier() const override; + BluetoothUUID GetUUID() const override; + bool IsLocal() const override; + std::vector& GetValue() const override; + BluetoothGattService* GetService() const override; + Properties GetProperties() const override; + Permissions GetPermissions() const override; + bool IsNotifying() const override; + std::vector GetDescriptors() const override; + BluetoothGattDescriptor* GetDescriptor( + const std::string& identifier) const override; + bool AddDescriptor(BluetoothGattDescriptor* descriptor) override; + bool UpdateValue(const std::vector& value) override; + void StartNotifySession(const NotifySessionCallback& callback, + const ErrorCallback& error_callback) override; + void ReadRemoteCharacteristic(const ValueCallback& callback, + const ErrorCallback& error_callback) override; + void WriteRemoteCharacteristic(const std::vector& new_value, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + + // Update included descriptors. + void Update(); + uint16_t GetAttributeHandle() const; + + private: + BluetoothAdapterWin* adapter_; + BluetoothRemoteGattServiceWin* parent_service_; + scoped_refptr task_manager_; + + // Characteristic info from OS and used to interact with OS. + scoped_ptr characteristic_info_; + scoped_refptr ui_task_runner_; + BluetoothUUID characteristic_uuid_; + std::vector characteristic_value_; + std::string characteristic_identifier_; + + base::WeakPtrFactory weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattCharacteristicWin); +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_WIN_H_ diff --git a/device/bluetooth/bluetooth_remote_gatt_service_win.cc b/device/bluetooth/bluetooth_remote_gatt_service_win.cc index 7021703..19064eb 100644 --- a/device/bluetooth/bluetooth_remote_gatt_service_win.cc +++ b/device/bluetooth/bluetooth_remote_gatt_service_win.cc @@ -4,7 +4,14 @@ #include "device/bluetooth/bluetooth_remote_gatt_service_win.h" +#include "base/bind.h" +#include "device/bluetooth/bluetooth_adapter_win.h" +#include "device/bluetooth/bluetooth_device_win.h" +#include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" +#include "device/bluetooth/bluetooth_task_manager_win.h" + namespace device { + BluetoothRemoteGattServiceWin::BluetoothRemoteGattServiceWin( BluetoothDeviceWin* device, base::FilePath service_path, @@ -19,7 +26,10 @@ BluetoothRemoteGattServiceWin::BluetoothRemoteGattServiceWin( service_attribute_handle_(service_attribute_handle), is_primary_(is_primary), parent_service_(parent_service), - ui_task_runner_(ui_task_runner) { + ui_task_runner_(ui_task_runner), + discovery_complete_notified_(false), + included_characteristics_discovered_(false), + weak_ptr_factory_(this) { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); DCHECK(!service_path_.empty()); DCHECK(service_uuid_.IsValid()); @@ -27,18 +37,24 @@ BluetoothRemoteGattServiceWin::BluetoothRemoteGattServiceWin( DCHECK(device_); if (!is_primary_) DCHECK(parent_service_); + + adapter_ = static_cast(device_->GetAdapter()); + DCHECK(adapter_); + task_manager_ = adapter_->GetWinBluetoothTaskManager(); + DCHECK(task_manager_); + service_identifier_ = device_->GetIdentifier() + "/" + service_uuid_.value() + + "_" + std::to_string(service_attribute_handle_); Update(); } -BluetoothRemoteGattServiceWin::~BluetoothRemoteGattServiceWin() {} +BluetoothRemoteGattServiceWin::~BluetoothRemoteGattServiceWin() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + adapter_->NotifyGattServiceRemoved(this); +} std::string BluetoothRemoteGattServiceWin::GetIdentifier() const { - std::string identifier = - service_uuid_.value() + "_" + std::to_string(service_attribute_handle_); - if (is_primary_) - return device_->GetIdentifier() + "/" + identifier; - else - return parent_service_->GetIdentifier() + "/" + identifier; + return service_identifier_; } BluetoothUUID BluetoothRemoteGattServiceWin::GetUUID() const { @@ -59,19 +75,25 @@ BluetoothDevice* BluetoothRemoteGattServiceWin::GetDevice() const { std::vector BluetoothRemoteGattServiceWin::GetCharacteristics() const { - NOTIMPLEMENTED(); - return std::vector(); + std::vector has_characteristics; + for (const auto& c : included_characteristics_) + has_characteristics.push_back(c.second.get()); + return has_characteristics; } std::vector BluetoothRemoteGattServiceWin::GetIncludedServices() const { NOTIMPLEMENTED(); + // TODO(crbug.com/590008): Needs implementation. return std::vector(); } BluetoothGattCharacteristic* BluetoothRemoteGattServiceWin::GetCharacteristic( const std::string& identifier) const { - NOTIMPLEMENTED(); + GattCharacteristicsMap::const_iterator it = + included_characteristics_.find(identifier); + if (it != included_characteristics_.end()) + return it->second.get(); return nullptr; } @@ -101,13 +123,134 @@ void BluetoothRemoteGattServiceWin::Unregister( error_callback.Run(); } +void BluetoothRemoteGattServiceWin::GattCharacteristicDiscoveryComplete( + BluetoothRemoteGattCharacteristicWin* characteristic) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(included_characteristics_.find(characteristic->GetIdentifier()) != + included_characteristics_.end()); + + discovery_completed_included_charateristics_.insert( + characteristic->GetIdentifier()); + adapter_->NotifyGattCharacteristicAdded(characteristic); + NotifyGattDiscoveryCompleteForServiceIfNecessary(); +} + void BluetoothRemoteGattServiceWin::Update() { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); - NOTIMPLEMENTED(); + + task_manager_->PostGetGattIncludedCharacteristics( + service_path_, service_uuid_, service_attribute_handle_, + base::Bind(&BluetoothRemoteGattServiceWin::OnGetIncludedCharacteristics, + weak_ptr_factory_.GetWeakPtr())); +} + +void BluetoothRemoteGattServiceWin::OnGetIncludedCharacteristics( + scoped_ptr characteristics, + uint16_t num, + HRESULT hr) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + UpdateIncludedCharacteristics(characteristics.get(), num); + included_characteristics_discovered_ = true; + NotifyGattDiscoveryCompleteForServiceIfNecessary(); +} + +void BluetoothRemoteGattServiceWin::UpdateIncludedCharacteristics( + PBTH_LE_GATT_CHARACTERISTIC characteristics, + uint16_t num) { + if (num == 0) { + if (included_characteristics_.size() > 0) { + ClearIncludedCharacteristics(); + adapter_->NotifyGattServiceChanged(this); + } + return; + } + + // First, remove characteristics that no longer exist. + std::vector to_be_removed; + for (const auto& c : included_characteristics_) { + if (!DoesCharacteristicExist(characteristics, num, c.second.get())) + to_be_removed.push_back(c.second->GetIdentifier()); + } + for (const auto& id : to_be_removed) { + RemoveIncludedCharacteristic(id); + } + + // Update previously known characteristics. + for (auto& c : included_characteristics_) + c.second->Update(); + + // Return if no new characteristics have been added. + if (included_characteristics_.size() == num) + return; + + // Add new characteristics. + for (uint16_t i = 0; i < num; i++) { + if (!IsCharacteristicDiscovered(characteristics[i].CharacteristicUuid, + characteristics[i].AttributeHandle)) { + PBTH_LE_GATT_CHARACTERISTIC info = new BTH_LE_GATT_CHARACTERISTIC(); + *info = characteristics[i]; + BluetoothRemoteGattCharacteristicWin* characteristic_object = + new BluetoothRemoteGattCharacteristicWin(this, info, ui_task_runner_); + included_characteristics_[characteristic_object->GetIdentifier()] = + make_scoped_ptr(characteristic_object); + } + } + + if (included_characteristics_discovered_) + adapter_->NotifyGattServiceChanged(this); +} + +void BluetoothRemoteGattServiceWin:: + NotifyGattDiscoveryCompleteForServiceIfNecessary() { + if (discovery_completed_included_charateristics_.size() == + included_characteristics_.size() && + included_characteristics_discovered_ && !discovery_complete_notified_) { + adapter_->NotifyGattDiscoveryComplete(this); + discovery_complete_notified_ = true; + } +} + +bool BluetoothRemoteGattServiceWin::IsCharacteristicDiscovered( + BTH_LE_UUID& uuid, + uint16_t attribute_handle) { + BluetoothUUID bt_uuid = + BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(uuid); + for (const auto& c : included_characteristics_) { + if (bt_uuid == c.second->GetUUID() && + attribute_handle == c.second->GetAttributeHandle()) { + return true; + } + } + return false; +} + +bool BluetoothRemoteGattServiceWin::DoesCharacteristicExist( + PBTH_LE_GATT_CHARACTERISTIC characteristics, + uint16_t num, + BluetoothRemoteGattCharacteristicWin* characteristic) { + for (uint16_t i = 0; i < num; i++) { + BluetoothUUID uuid = + BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid( + characteristics[i].CharacteristicUuid); + if (characteristic->GetUUID() == uuid && + characteristic->GetAttributeHandle() == + characteristics[i].AttributeHandle) { + return true; + } + } + return false; +} + +void BluetoothRemoteGattServiceWin::RemoveIncludedCharacteristic( + std::string identifier) { + discovery_completed_included_charateristics_.erase(identifier); + included_characteristics_.erase(identifier); } -uint16_t BluetoothRemoteGattServiceWin::GetAttributeHandle() { - return service_attribute_handle_; +void BluetoothRemoteGattServiceWin::ClearIncludedCharacteristics() { + discovery_completed_included_charateristics_.clear(); + included_characteristics_.clear(); } } // namespace device. diff --git a/device/bluetooth/bluetooth_remote_gatt_service_win.h b/device/bluetooth/bluetooth_remote_gatt_service_win.h index 218bc90..ada0c83d 100644 --- a/device/bluetooth/bluetooth_remote_gatt_service_win.h +++ b/device/bluetooth/bluetooth_remote_gatt_service_win.h @@ -5,12 +5,21 @@ #ifndef DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_SERVICE_WIN_H_ #define DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_SERVICE_WIN_H_ +#include + #include "base/files/file.h" -#include "device/bluetooth/bluetooth_device_win.h" +#include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" #include "device/bluetooth/bluetooth_gatt_service.h" +#include "device/bluetooth/bluetooth_low_energy_defs_win.h" namespace device { +class BluetoothAdapterWin; +class BluetoothDeviceWin; +class BluetoothRemoteGattCharacteristicWin; +class BluetoothTaskManagerWin; + // The BluetoothRemoteGattServiceWin class implements BluetoothGattService // for remote GATT services on Windows 8 and later. class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattServiceWin @@ -43,11 +52,42 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattServiceWin void Unregister(const base::Closure& callback, const ErrorCallback& error_callback) override; + // Notify |characteristic| discovery complete, |characteristic| is the + // included characteritic of this service. + void GattCharacteristicDiscoveryComplete( + BluetoothRemoteGattCharacteristicWin* characteristic); + // Update included services and characteristics. void Update(); - uint16_t GetAttributeHandle(); + uint16_t GetAttributeHandle() const { return service_attribute_handle_; } private: + void OnGetIncludedCharacteristics( + scoped_ptr characteristics, + uint16_t num, + HRESULT hr); + void UpdateIncludedCharacteristics( + PBTH_LE_GATT_CHARACTERISTIC characteristics, + uint16_t num); + + // Sends GattDiscoveryCompleteForService notification if necessary. + void NotifyGattDiscoveryCompleteForServiceIfNecessary(); + + // Checks if the characteristic with |uuid| and |attribute_handle| has already + // been discovered as included characteristic. + bool IsCharacteristicDiscovered(BTH_LE_UUID& uuid, uint16_t attribute_handle); + + // Checks if |characteristic| still exists in this service according to newly + // retreived |num| of included |characteristics|. + static bool DoesCharacteristicExist( + PBTH_LE_GATT_CHARACTERISTIC characteristics, + uint16_t num, + BluetoothRemoteGattCharacteristicWin* characteristic); + + void RemoveIncludedCharacteristic(std::string identifier); + void ClearIncludedCharacteristics(); + + BluetoothAdapterWin* adapter_; BluetoothDeviceWin* device_; base::FilePath service_path_; BluetoothUUID service_uuid_; @@ -55,7 +95,32 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattServiceWin bool is_primary_; BluetoothRemoteGattServiceWin* parent_service_; scoped_refptr ui_task_runner_; + std::string service_identifier_; + + // BluetoothTaskManagerWin to handle asynchronously Bluetooth IO and platform + // dependent operations. + scoped_refptr task_manager_; + + // The key of GattCharacteristicsMap is the identifier of + // BluetoothRemoteGattCharacteristicWin instance. + typedef std::unordered_map> + GattCharacteristicsMap; + GattCharacteristicsMap included_characteristics_; + + // The element of the set is the identifier of + // BluetoothRemoteGattCharacteristicWin instance. + std::set discovery_completed_included_charateristics_; + + // Flag indicates if discovery complete notification has been send out to + // avoid duplicate notification. + bool discovery_complete_notified_; + + // Flag indicates if asynchronous discovery of included characteristic has + // completed. + bool included_characteristics_discovered_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattServiceWin); }; diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc index 1f9364d..1ccc013 100644 --- a/device/bluetooth/bluetooth_task_manager_win.cc +++ b/device/bluetooth/bluetooth_task_manager_win.cc @@ -19,7 +19,6 @@ #include "device/bluetooth/bluetooth_classic_win.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_init_win.h" -#include "device/bluetooth/bluetooth_low_energy_win.h" #include "device/bluetooth/bluetooth_service_record_win.h" #include "net/base/winsock_init.h" @@ -53,27 +52,42 @@ std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) { return result; } -device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid( - const BTH_LE_UUID& bth_le_uuid) { - if (bth_le_uuid.IsShortUuid) { - std::string uuid_hex = - base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); - return device::BluetoothUUID(uuid_hex); +bool BluetoothUUIDToWinBLEUUID(const device::BluetoothUUID& uuid, + BTH_LE_UUID* out_win_uuid) { + if (!uuid.IsValid()) + return false; + + if (uuid.format() == device::BluetoothUUID::kFormat16Bit) { + out_win_uuid->IsShortUuid = true; + unsigned int data = 0; + int result = sscanf_s(uuid.value().c_str(), "%04x", &data); + if (result != 1) + return false; + out_win_uuid->Value.ShortUuid = data; } else { - return device::BluetoothUUID( - base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - bth_le_uuid.Value.LongUuid.Data1, - bth_le_uuid.Value.LongUuid.Data2, - bth_le_uuid.Value.LongUuid.Data3, - bth_le_uuid.Value.LongUuid.Data4[0], - bth_le_uuid.Value.LongUuid.Data4[1], - bth_le_uuid.Value.LongUuid.Data4[2], - bth_le_uuid.Value.LongUuid.Data4[3], - bth_le_uuid.Value.LongUuid.Data4[4], - bth_le_uuid.Value.LongUuid.Data4[5], - bth_le_uuid.Value.LongUuid.Data4[6], - bth_le_uuid.Value.LongUuid.Data4[7])); + out_win_uuid->IsShortUuid = false; + unsigned int data[11]; + int result = + sscanf_s(uuid.value().c_str(), + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", &data[0], + &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], + &data[7], &data[8], &data[9], &data[10]); + if (result != 11) + return false; + out_win_uuid->Value.LongUuid.Data1 = data[0]; + out_win_uuid->Value.LongUuid.Data2 = data[1]; + out_win_uuid->Value.LongUuid.Data3 = data[2]; + out_win_uuid->Value.LongUuid.Data4[0] = data[3]; + out_win_uuid->Value.LongUuid.Data4[1] = data[4]; + out_win_uuid->Value.LongUuid.Data4[2] = data[5]; + out_win_uuid->Value.LongUuid.Data4[3] = data[6]; + out_win_uuid->Value.LongUuid.Data4[4] = data[7]; + out_win_uuid->Value.LongUuid.Data4[5] = data[8]; + out_win_uuid->Value.LongUuid.Data4[6] = data[9]; + out_win_uuid->Value.LongUuid.Data4[7] = data[10]; } + + return true; } // Populates bluetooth adapter state using adapter_handle. @@ -149,6 +163,27 @@ BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { win::BluetoothClassicWrapper::DeleteInstance(); } +BluetoothUUID BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid( + const BTH_LE_UUID& bth_le_uuid) { + if (bth_le_uuid.IsShortUuid) { + std::string uuid_hex = + base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); + return BluetoothUUID(uuid_hex); + } else { + return BluetoothUUID(base::StringPrintf( + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + bth_le_uuid.Value.LongUuid.Data1, bth_le_uuid.Value.LongUuid.Data2, + bth_le_uuid.Value.LongUuid.Data3, bth_le_uuid.Value.LongUuid.Data4[0], + bth_le_uuid.Value.LongUuid.Data4[1], + bth_le_uuid.Value.LongUuid.Data4[2], + bth_le_uuid.Value.LongUuid.Data4[3], + bth_le_uuid.Value.LongUuid.Data4[4], + bth_le_uuid.Value.LongUuid.Data4[5], + bth_le_uuid.Value.LongUuid.Data4[6], + bth_le_uuid.Value.LongUuid.Data4[7])); + } +} + void BluetoothTaskManagerWin::AddObserver(Observer* observer) { DCHECK(observer); DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); @@ -481,8 +516,10 @@ bool BluetoothTaskManagerWin::SearchClassicDevices( bool BluetoothTaskManagerWin::SearchLowEnergyDevices( ScopedVector* device_list) { - if (!win::IsBluetoothLowEnergySupported()) + if (!win::BluetoothLowEnergyWrapper::GetInstance() + ->IsBluetoothLowEnergySupported()) { return true; // Bluetooth LE not supported is not an error. + } ScopedVector btle_devices; std::string error; @@ -643,8 +680,10 @@ int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker( bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices( const base::FilePath& device_path, ScopedVector* service_record_states) { - if (!win::IsBluetoothLowEnergySupported()) + if (!win::BluetoothLowEnergyWrapper::GetInstance() + ->IsBluetoothLowEnergySupported()) { return true; // Bluetooth LE not supported is not an error. + } std::string error; ScopedVector services; @@ -727,4 +766,41 @@ bool BluetoothTaskManagerWin::SearchForGattServiceDevicePaths( return true; } +void BluetoothTaskManagerWin::GetGattIncludedCharacteristics( + base::FilePath service_path, + BluetoothUUID uuid, + uint16_t attribute_handle, + const GetGattIncludedCharacteristicsCallback& callback) { + HRESULT hr = S_OK; + scoped_ptr win_characteristics_info; + uint16_t number_of_charateristics = 0; + + BTH_LE_GATT_SERVICE win_service; + if (BluetoothUUIDToWinBLEUUID(uuid, &(win_service.ServiceUuid))) { + win_service.AttributeHandle = attribute_handle; + hr = win::BluetoothLowEnergyWrapper::GetInstance() + ->ReadCharacteristicsOfAService(service_path, &win_service, + &win_characteristics_info, + &number_of_charateristics); + } else { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + } + + ui_task_runner_->PostTask( + FROM_HERE, base::Bind(callback, base::Passed(&win_characteristics_info), + number_of_charateristics, hr)); +} + +void BluetoothTaskManagerWin::PostGetGattIncludedCharacteristics( + const base::FilePath& service_path, + const BluetoothUUID& uuid, + uint16_t attribute_handle, + const GetGattIncludedCharacteristicsCallback& callback) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::GetGattIncludedCharacteristics, this, + service_path, uuid, attribute_handle, callback)); +} + } // namespace device diff --git a/device/bluetooth/bluetooth_task_manager_win.h b/device/bluetooth/bluetooth_task_manager_win.h index 56ecbef..354a579 100644 --- a/device/bluetooth/bluetooth_task_manager_win.h +++ b/device/bluetooth/bluetooth_task_manager_win.h @@ -18,6 +18,7 @@ #include "base/win/scoped_handle.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_export.h" +#include "device/bluetooth/bluetooth_low_energy_win.h" namespace base { @@ -103,6 +104,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin explicit BluetoothTaskManagerWin( scoped_refptr ui_task_runner); + static BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid( + const BTH_LE_UUID& bth_le_uuid); + void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -118,6 +122,21 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin void PostStartDiscoveryTask(); void PostStopDiscoveryTask(); + // Callbacks of asynchronous operations of GATT service. + typedef base::Callback< + void(scoped_ptr, uint16_t, HRESULT)> + GetGattIncludedCharacteristicsCallback; + + // Get all included characteristics of a given service. The service is + // uniquely identified by its |uuid| and |attribute_handle| with service + // device |service_path|. The result is returned asynchronously through + // |callback|. + void PostGetGattIncludedCharacteristics( + const base::FilePath& service_path, + const BluetoothUUID& uuid, + uint16_t attribute_handle, + const GetGattIncludedCharacteristicsCallback& callback); + private: friend class base::RefCountedThreadSafe; friend class BluetoothTaskManagerWinTest; @@ -208,6 +227,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin const std::string device_address, ScopedVector* service_record_states); + // GATT service related functions. + void GetGattIncludedCharacteristics( + base::FilePath device_path, + BluetoothUUID uuid, + uint16_t attribute_handle, + const GetGattIncludedCharacteristicsCallback& callback); + // UI task runner reference. scoped_refptr ui_task_runner_; diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h index 5e34d90..5570ca1 100644 --- a/device/bluetooth/test/bluetooth_test.h +++ b/device/bluetooth/test/bluetooth_test.h @@ -113,6 +113,9 @@ class BluetoothTestBase : public testing::Test { BluetoothDevice* device, const std::vector& uuids) {} + // Simulates remove of a |service|. + virtual void SimulateGattServiceRemoved(BluetoothGattService* service) {} + // Simulates failure to discover services. virtual void SimulateGattServicesDiscoveryError(BluetoothDevice* device) {} @@ -121,6 +124,11 @@ class BluetoothTestBase : public testing::Test { const std::string& uuid, int properties) {} + // Simulates remove of a |characteristic| from |service|. + virtual void SimulateGattCharacteristicRemoved( + BluetoothGattService* service, + BluetoothGattCharacteristic* characteristic) {} + // Remembers |characteristic|'s platform specific object to be used in a // subsequent call to methods such as SimulateGattCharacteristicRead that // accept a nullptr value to select this remembered characteristic. This diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc index 7a8f8f8..b9cbe48 100644 --- a/device/bluetooth/test/bluetooth_test_win.cc +++ b/device/bluetooth/test/bluetooth_test_win.cc @@ -8,6 +8,8 @@ #include "base/strings/sys_string_conversions.h" #include "device/bluetooth/bluetooth_adapter_win.h" #include "device/bluetooth/bluetooth_low_energy_win.h" +#include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" +#include "device/bluetooth/bluetooth_remote_gatt_service_win.h" namespace { @@ -25,16 +27,56 @@ BLUETOOTH_ADDRESS CanonicalStringToBLUETOOTH_ADDRESS( return win_addr; } +// The canonical UUID string format is device::BluetoothUUID.value(). +BTH_LE_UUID CanonicalStringToBTH_LE_UUID(std::string uuid) { + BTH_LE_UUID win_uuid = {0}; + if (uuid.size() == 4) { + win_uuid.IsShortUuid = TRUE; + unsigned int data[1]; + int result = sscanf_s(uuid.c_str(), "%04x", &data[0]); + CHECK(result == 1); + win_uuid.Value.ShortUuid = data[0]; + } else if (uuid.size() == 36) { + win_uuid.IsShortUuid = FALSE; + unsigned int data[11]; + int result = sscanf_s( + uuid.c_str(), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], + &data[7], &data[8], &data[9], &data[10]); + CHECK(result == 11); + win_uuid.Value.LongUuid.Data1 = data[0]; + win_uuid.Value.LongUuid.Data2 = data[1]; + win_uuid.Value.LongUuid.Data3 = data[2]; + win_uuid.Value.LongUuid.Data4[0] = data[3]; + win_uuid.Value.LongUuid.Data4[1] = data[4]; + win_uuid.Value.LongUuid.Data4[2] = data[5]; + win_uuid.Value.LongUuid.Data4[3] = data[6]; + win_uuid.Value.LongUuid.Data4[4] = data[7]; + win_uuid.Value.LongUuid.Data4[5] = data[8]; + win_uuid.Value.LongUuid.Data4[6] = data[9]; + win_uuid.Value.LongUuid.Data4[7] = data[10]; + } else { + CHECK(false); + } + + return win_uuid; +} + } // namespace namespace device { BluetoothTestWin::BluetoothTestWin() : ui_task_runner_(new base::TestSimpleTaskRunner()), - bluetooth_task_runner_(new base::TestSimpleTaskRunner()) {} + bluetooth_task_runner_(new base::TestSimpleTaskRunner()), + adapter_win_(nullptr), + fake_bt_classic_wrapper_(nullptr), + fake_bt_le_wrapper_(nullptr) {} BluetoothTestWin::~BluetoothTestWin() {} bool BluetoothTestWin::PlatformSupportsLowEnergy() { - return win::IsBluetoothLowEnergySupported(); + if (fake_bt_le_wrapper_) + return fake_bt_le_wrapper_->IsBluetoothLowEnergySupported(); + return true; } void BluetoothTestWin::AdapterInitCallback() {} @@ -110,12 +152,16 @@ BluetoothDevice* BluetoothTestWin::DiscoverLowEnergyDevice(int device_ordinal) { win::BLEDevice* simulated_device = fake_bt_le_wrapper_->SimulateBLEDevice( device_name, CanonicalStringToBLUETOOTH_ADDRESS(device_address)); if (simulated_device != nullptr) { - if (!service_uuid_1.empty()) - fake_bt_le_wrapper_->SimulateBLEGattService(simulated_device, - service_uuid_1); - if (!service_uuid_2.empty()) - fake_bt_le_wrapper_->SimulateBLEGattService(simulated_device, - service_uuid_2); + if (!service_uuid_1.empty()) { + fake_bt_le_wrapper_->SimulateBLEGattService( + simulated_device, nullptr, + CanonicalStringToBTH_LE_UUID(service_uuid_1)); + } + if (!service_uuid_2.empty()) { + fake_bt_le_wrapper_->SimulateBLEGattService( + simulated_device, nullptr, + CanonicalStringToBTH_LE_UUID(service_uuid_2)); + } } bluetooth_task_runner_->RunPendingTasks(); ui_task_runner_->RunPendingTasks(); @@ -148,10 +194,109 @@ void BluetoothTestWin::SimulateGattServicesDiscovered( CHECK(simulated_device); for (auto uuid : uuids) { - fake_bt_le_wrapper_->SimulateBLEGattService(simulated_device, uuid); + fake_bt_le_wrapper_->SimulateBLEGattService( + simulated_device, nullptr, CanonicalStringToBTH_LE_UUID(uuid)); } bluetooth_task_runner_->RunPendingTasks(); ui_task_runner_->RunPendingTasks(); } + +void BluetoothTestWin::SimulateGattServiceRemoved( + BluetoothGattService* service) { + std::string device_address = service->GetDevice()->GetAddress(); + win::BLEDevice* target_device = + fake_bt_le_wrapper_->GetSimulatedBLEDevice(device_address); + CHECK(target_device); + + BluetoothRemoteGattServiceWin* win_service = + static_cast(service); + std::string service_att_handle = + std::to_string(win_service->GetAttributeHandle()); + fake_bt_le_wrapper_->SimulateBLEGattServiceRemoved(target_device, nullptr, + service_att_handle); + + ForceRefreshDevice(); +} + +void BluetoothTestWin::SimulateGattCharacteristic(BluetoothGattService* service, + const std::string& uuid, + int properties) { + std::string device_address = service->GetDevice()->GetAddress(); + win::BLEDevice* target_device = + fake_bt_le_wrapper_->GetSimulatedBLEDevice(device_address); + CHECK(target_device); + win::BLEGattService* target_service = + GetSimulatedService(target_device, service); + CHECK(target_service); + + BTH_LE_GATT_CHARACTERISTIC win_cha_info; + win_cha_info.CharacteristicUuid = CanonicalStringToBTH_LE_UUID(uuid); + if (properties & BluetoothGattCharacteristic::PROPERTY_BROADCAST) + win_cha_info.IsBroadcastable = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_READ) + win_cha_info.IsReadable = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE) + win_cha_info.IsWritableWithoutResponse = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_WRITE) + win_cha_info.IsWritable = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_NOTIFY) + win_cha_info.IsNotifiable = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_INDICATE) + win_cha_info.IsIndicatable = TRUE; + if (properties & + BluetoothGattCharacteristic::PROPERTY_AUTHENTICATED_SIGNED_WRITES) + win_cha_info.IsSignedWritable = TRUE; + if (properties & BluetoothGattCharacteristic::PROPERTY_EXTENDED_PROPERTIES) + win_cha_info.HasExtendedProperties = TRUE; + fake_bt_le_wrapper_->SimulateBLEGattCharacterisc( + device_address, target_service, win_cha_info); + + ForceRefreshDevice(); +} + +void BluetoothTestWin::SimulateGattCharacteristicRemoved( + BluetoothGattService* service, + BluetoothGattCharacteristic* characteristic) { + CHECK(service); + CHECK(characteristic); + + std::string device_address = service->GetDevice()->GetAddress(); + win::BLEGattService* target_service = GetSimulatedService( + fake_bt_le_wrapper_->GetSimulatedBLEDevice(device_address), service); + CHECK(target_service); + + std::string characteristic_att_handle = std::to_string( + static_cast(characteristic) + ->GetAttributeHandle()); + fake_bt_le_wrapper_->SimulateBLEGattCharacteriscRemove( + target_service, characteristic_att_handle); + + ForceRefreshDevice(); +} + +win::BLEGattService* BluetoothTestWin::GetSimulatedService( + win::BLEDevice* device, + BluetoothGattService* service) { + CHECK(device); + CHECK(service); + + std::vector chain_of_att_handles; + BluetoothRemoteGattServiceWin* win_service = + static_cast(service); + chain_of_att_handles.insert( + chain_of_att_handles.begin(), + std::to_string(win_service->GetAttributeHandle())); + win::BLEGattService* simulated_service = + fake_bt_le_wrapper_->GetSimulatedGattService(device, + chain_of_att_handles); + CHECK(simulated_service); + return simulated_service; +} + +void BluetoothTestWin::ForceRefreshDevice() { + adapter_win_->force_update_device_for_test_ = true; + bluetooth_task_runner_->RunPendingTasks(); + ui_task_runner_->RunPendingTasks(); +} } diff --git a/device/bluetooth/test/bluetooth_test_win.h b/device/bluetooth/test/bluetooth_test_win.h index eeeb068..f159235 100644 --- a/device/bluetooth/test/bluetooth_test_win.h +++ b/device/bluetooth/test/bluetooth_test_win.h @@ -34,6 +34,13 @@ class BluetoothTestWin : public BluetoothTestBase { void SimulateGattServicesDiscovered( BluetoothDevice* device, const std::vector& uuids) override; + void SimulateGattServiceRemoved(BluetoothGattService* service) override; + void SimulateGattCharacteristic(BluetoothGattService* service, + const std::string& uuid, + int properties) override; + void SimulateGattCharacteristicRemoved( + BluetoothGattService* service, + BluetoothGattCharacteristic* characteristic) override; private: scoped_refptr ui_task_runner_; @@ -44,6 +51,9 @@ class BluetoothTestWin : public BluetoothTestBase { win::BluetoothLowEnergyWrapperFake* fake_bt_le_wrapper_; void AdapterInitCallback(); + win::BLEGattService* GetSimulatedService(win::BLEDevice* device, + BluetoothGattService* service); + void ForceRefreshDevice(); }; // Defines common test fixture name. Use TEST_F(BluetoothTest, YourTestName). -- cgit v1.1