summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authorgogerald <gogerald@chromium.org>2016-02-26 07:36:09 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-26 15:37:17 +0000
commite069a45ceb26f426aae38a1f0e88d7d6e447b6cc (patch)
treec4e1f9ad8a438ca2abcd22fc47e5185c5ee6efa8 /device
parent920e3f0cb63252e35a01ccea4abe1492f164eef1 (diff)
downloadchromium_src-e069a45ceb26f426aae38a1f0e88d7d6e447b6cc.zip
chromium_src-e069a45ceb26f426aae38a1f0e88d7d6e447b6cc.tar.gz
chromium_src-e069a45ceb26f426aae38a1f0e88d7d6e447b6cc.tar.bz2
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}
Diffstat (limited to 'device')
-rw-r--r--device/bluetooth/BUILD.gn2
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_adapter_win.cc13
-rw-r--r--device/bluetooth/bluetooth_adapter_win.h7
-rw-r--r--device/bluetooth/bluetooth_device_win.cc2
-rw-r--r--device/bluetooth/bluetooth_gatt_service_unittest.cc107
-rw-r--r--device/bluetooth/bluetooth_low_energy_win.cc46
-rw-r--r--device/bluetooth/bluetooth_low_energy_win.h15
-rw-r--r--device/bluetooth/bluetooth_low_energy_win_fake.cc180
-rw-r--r--device/bluetooth/bluetooth_low_energy_win_fake.h37
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc166
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_win.h74
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_service_win.cc171
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_service_win.h69
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.cc120
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.h26
-rw-r--r--device/bluetooth/test/bluetooth_test.h8
-rw-r--r--device/bluetooth/test/bluetooth_test_win.cc163
-rw-r--r--device/bluetooth/test/bluetooth_test_win.h10
19 files changed, 1107 insertions, 111 deletions
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<BluetoothDeviceWin*>(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<BluetoothTaskManagerWin> 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<BluetoothAdapterWin> 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<std::string> 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<std::string> 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<BluetoothLowEnergyDeviceInfo>* 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<BTH_LE_GATT_CHARACTERISTIC>* 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<BluetoothLowEnergyServiceInfo>* 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<BTH_LE_GATT_CHARACTERISTIC>* 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<BluetoothLowEnergyDeviceInfo>* 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<std::string> 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<BTH_LE_GATT_CHARACTERISTIC>* out_included_characteristics,
+ USHORT* out_counts) {
+ base::string16 device_address =
+ ExtractDeviceAddressFromDevicePath(service_path.value());
+ const std::vector<std::string> 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<std::string>& 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<std::string>
+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::string>();
+
+ std::vector<std::string> 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<BluetoothLowEnergyDeviceInfo>* devices,
std::string* error) override;
@@ -78,11 +79,38 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper {
const base::FilePath& device_path,
ScopedVector<BluetoothLowEnergyServiceInfo>* services,
std::string* error) override;
+ HRESULT ReadCharacteristicsOfAService(
+ base::FilePath& service_path,
+ const PBTH_LE_GATT_SERVICE service,
+ scoped_ptr<BTH_LE_GATT_CHARACTERISTIC>* 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<std::string>& 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<std::string> 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<base::SequencedTaskRunner>& 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<BluetoothAdapterWin*>(
+ 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<uint8_t>& BluetoothRemoteGattCharacteristicWin::GetValue() const {
+ NOTIMPLEMENTED();
+ return const_cast<std::vector<uint8_t>&>(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<BluetoothGattDescriptor*>
+BluetoothRemoteGattCharacteristicWin::GetDescriptors() const {
+ NOTIMPLEMENTED();
+ return std::vector<BluetoothGattDescriptor*>();
+}
+
+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<uint8_t>& 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<uint8_t>& 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<base::SequencedTaskRunner>& ui_task_runner);
+ ~BluetoothRemoteGattCharacteristicWin() override;
+
+ // Override BluetoothGattCharacteristic interfaces.
+ std::string GetIdentifier() const override;
+ BluetoothUUID GetUUID() const override;
+ bool IsLocal() const override;
+ std::vector<uint8_t>& GetValue() const override;
+ BluetoothGattService* GetService() const override;
+ Properties GetProperties() const override;
+ Permissions GetPermissions() const override;
+ bool IsNotifying() const override;
+ std::vector<BluetoothGattDescriptor*> GetDescriptors() const override;
+ BluetoothGattDescriptor* GetDescriptor(
+ const std::string& identifier) const override;
+ bool AddDescriptor(BluetoothGattDescriptor* descriptor) override;
+ bool UpdateValue(const std::vector<uint8_t>& 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<uint8_t>& 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<BluetoothTaskManagerWin> task_manager_;
+
+ // Characteristic info from OS and used to interact with OS.
+ scoped_ptr<BTH_LE_GATT_CHARACTERISTIC> characteristic_info_;
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+ BluetoothUUID characteristic_uuid_;
+ std::vector<uint8_t> characteristic_value_;
+ std::string characteristic_identifier_;
+
+ base::WeakPtrFactory<BluetoothRemoteGattCharacteristicWin> 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<BluetoothAdapterWin*>(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<BluetoothGattCharacteristic*>
BluetoothRemoteGattServiceWin::GetCharacteristics() const {
- NOTIMPLEMENTED();
- return std::vector<BluetoothGattCharacteristic*>();
+ std::vector<BluetoothGattCharacteristic*> has_characteristics;
+ for (const auto& c : included_characteristics_)
+ has_characteristics.push_back(c.second.get());
+ return has_characteristics;
}
std::vector<BluetoothGattService*>
BluetoothRemoteGattServiceWin::GetIncludedServices() const {
NOTIMPLEMENTED();
+ // TODO(crbug.com/590008): Needs implementation.
return std::vector<BluetoothGattService*>();
}
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<BTH_LE_GATT_CHARACTERISTIC> 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<std::string> 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 <set>
+
#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<BTH_LE_GATT_CHARACTERISTIC> 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<base::SequencedTaskRunner> ui_task_runner_;
+ std::string service_identifier_;
+
+ // BluetoothTaskManagerWin to handle asynchronously Bluetooth IO and platform
+ // dependent operations.
+ scoped_refptr<BluetoothTaskManagerWin> task_manager_;
+
+ // The key of GattCharacteristicsMap is the identifier of
+ // BluetoothRemoteGattCharacteristicWin instance.
+ typedef std::unordered_map<std::string,
+ scoped_ptr<BluetoothRemoteGattCharacteristicWin>>
+ GattCharacteristicsMap;
+ GattCharacteristicsMap included_characteristics_;
+
+ // The element of the set is the identifier of
+ // BluetoothRemoteGattCharacteristicWin instance.
+ std::set<std::string> 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<BluetoothRemoteGattServiceWin> 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<DeviceState>* device_list) {
- if (!win::IsBluetoothLowEnergySupported())
+ if (!win::BluetoothLowEnergyWrapper::GetInstance()
+ ->IsBluetoothLowEnergySupported()) {
return true; // Bluetooth LE not supported is not an error.
+ }
ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
std::string error;
@@ -643,8 +680,10 @@ int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
const base::FilePath& device_path,
ScopedVector<ServiceRecordState>* 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<win::BluetoothLowEnergyServiceInfo> 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<BTH_LE_GATT_CHARACTERISTIC> 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<base::SequencedTaskRunner> 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<BTH_LE_GATT_CHARACTERISTIC>, 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<BluetoothTaskManagerWin>;
friend class BluetoothTaskManagerWinTest;
@@ -208,6 +227,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin
const std::string device_address,
ScopedVector<ServiceRecordState>* 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<base::SequencedTaskRunner> 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<std::string>& 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<BluetoothRemoteGattServiceWin*>(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<BluetoothRemoteGattCharacteristicWin*>(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<std::string> chain_of_att_handles;
+ BluetoothRemoteGattServiceWin* win_service =
+ static_cast<BluetoothRemoteGattServiceWin*>(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<std::string>& 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<base::TestSimpleTaskRunner> 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).