Commit 20f64257 authored by Jan Wilken Doerrie's avatar Jan Wilken Doerrie Committed by Commit Bot

[Bluetooth][WinRT] Implement Obtaining Gatt Descriptors

This change implements obtainining Remote Gatt Descriptors for WinRT by
hooking up the appropriate logic into GattDiscovererWinrt. Furthermore,
appropriate tests are enabled.

Bug: 821766
Change-Id: I20475478367c2ab6b18940b4271de70ec138f676
Reviewed-on: https://chromium-review.googlesource.com/1156392
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579830}
parent 5ce63686
......@@ -25,23 +25,28 @@ using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDescriptorsResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceService;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattCharacteristic3;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattCharacteristicsResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceService;
IGattDescriptorsResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceService3;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
using ABI::Windows::Foundation::Collections::IVectorView;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IReference;
using ABI::Windows::Foundation::Collections::IVectorView;
using Microsoft::WRL::ComPtr;
template <typename IGattResult>
......@@ -149,6 +154,15 @@ BluetoothGattDiscovererWinrt::GetCharacteristics(
: nullptr;
}
const BluetoothGattDiscovererWinrt::GattDescriptorList*
BluetoothGattDiscovererWinrt::GetDescriptors(
uint16_t characteristic_attribute_handle) const {
auto iter =
characteristic_to_descriptors_map_.find(characteristic_attribute_handle);
return iter != characteristic_to_descriptors_map_.end() ? &iter->second
: nullptr;
}
void BluetoothGattDiscovererWinrt::OnGetGattServices(
ComPtr<IGattDeviceServicesResult> services_result) {
if (!CheckCommunicationStatus(services_result.Get())) {
......@@ -170,6 +184,7 @@ void BluetoothGattDiscovererWinrt::OnGetGattServices(
return;
}
num_services_ = gatt_services_.size();
for (const auto& gatt_service : gatt_services_) {
uint16_t service_attribute_handle;
hr = gatt_service->get_AttributeHandle(&service_attribute_handle);
......@@ -233,9 +248,80 @@ void BluetoothGattDiscovererWinrt::OnGetCharacteristics(
DCHECK(!base::ContainsKey(service_to_characteristics_map_,
service_attribute_handle));
if (!GetAsVector(
characteristics.Get(),
&service_to_characteristics_map_[service_attribute_handle])) {
auto& characteristics_list =
service_to_characteristics_map_[service_attribute_handle];
if (!GetAsVector(characteristics.Get(), &characteristics_list)) {
std::move(callback_).Run(false);
return;
}
num_characteristics_ += characteristics_list.size();
for (const auto& gatt_characteristic : characteristics_list) {
uint16_t characteristic_attribute_handle;
hr = gatt_characteristic->get_AttributeHandle(
&characteristic_attribute_handle);
if (FAILED(hr)) {
VLOG(2) << "Getting AttributeHandle failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
ComPtr<IGattCharacteristic3> gatt_characteristic_3;
hr = gatt_characteristic.As(&gatt_characteristic_3);
if (FAILED(hr)) {
VLOG(2) << "Obtaining IGattCharacteristic3 failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
ComPtr<IAsyncOperation<GattDescriptorsResult*>> get_descriptors_op;
hr = gatt_characteristic_3->GetDescriptorsAsync(&get_descriptors_op);
if (FAILED(hr)) {
VLOG(2) << "GattCharacteristic::GetDescriptorsAsync() failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
hr = PostAsyncResults(
std::move(get_descriptors_op),
base::BindOnce(&BluetoothGattDiscovererWinrt::OnGetDescriptors,
weak_ptr_factory_.GetWeakPtr(),
characteristic_attribute_handle));
if (FAILED(hr)) {
VLOG(2) << "PostAsyncResults failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
}
}
RunCallbackIfDone();
}
void BluetoothGattDiscovererWinrt::OnGetDescriptors(
uint16_t characteristic_attribute_handle,
ComPtr<IGattDescriptorsResult> descriptors_result) {
if (!CheckCommunicationStatus(descriptors_result.Get())) {
std::move(callback_).Run(false);
return;
}
ComPtr<IVectorView<GattDescriptor*>> descriptors;
HRESULT hr = descriptors_result->get_Descriptors(&descriptors);
if (FAILED(hr)) {
VLOG(2) << "Getting Descriptors failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
DCHECK(!base::ContainsKey(characteristic_to_descriptors_map_,
characteristic_attribute_handle));
if (!GetAsVector(descriptors.Get(), &characteristic_to_descriptors_map_
[characteristic_attribute_handle])) {
std::move(callback_).Run(false);
return;
}
......@@ -245,8 +331,10 @@ void BluetoothGattDiscovererWinrt::OnGetCharacteristics(
void BluetoothGattDiscovererWinrt::RunCallbackIfDone() {
DCHECK(callback_);
if (service_to_characteristics_map_.size() == gatt_services_.size())
if (service_to_characteristics_map_.size() == num_services_ &&
characteristic_to_descriptors_map_.size() == num_characteristics_) {
std::move(callback_).Run(true);
}
}
} // namespace device
......@@ -38,16 +38,24 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattDiscovererWinrt {
using GattCharacteristicList = std::vector<
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattCharacteristic>>;
using GattDescriptorList = std::vector<
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>>;
BluetoothGattDiscovererWinrt(
Microsoft::WRL::ComPtr<
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> ble_device);
~BluetoothGattDiscovererWinrt();
// Note: In order to avoid running |callback| multiple times on errors,
// clients are expected to synchronously destroy the GattDiscoverer after
// |callback| has been invoked for the first time.
void StartGattDiscovery(GattDiscoveryCallback callback);
const GattServiceList& GetGattServices() const;
const GattCharacteristicList* GetCharacteristics(
uint16_t service_attribute_handle) const;
const GattDescriptorList* GetDescriptors(
uint16_t characteristic_attribute_handle) const;
private:
void OnGetGattServices(
......@@ -61,6 +69,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattDiscovererWinrt {
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattCharacteristicsResult> characteristics_result);
void OnGetDescriptors(
uint16_t characteristic_attribute_handle,
Microsoft::WRL::ComPtr<
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDescriptorsResult> descriptors_result);
void RunCallbackIfDone();
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice>
......@@ -70,6 +84,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattDiscovererWinrt {
GattServiceList gatt_services_;
base::flat_map<uint16_t, GattCharacteristicList>
service_to_characteristics_map_;
base::flat_map<uint16_t, GattDescriptorList>
characteristic_to_descriptors_map_;
size_t num_services_ = 0;
size_t num_characteristics_ = 0;
THREAD_CHECKER(thread_checker_);
......
......@@ -169,6 +169,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristic
virtual bool WriteWithoutResponse(base::span<const uint8_t> value);
protected:
using DescriptorMap =
base::flat_map<std::string,
std::unique_ptr<BluetoothRemoteGattDescriptor>>;
BluetoothRemoteGattCharacteristic();
// Writes to the Client Characteristic Configuration descriptor to enable
......@@ -206,8 +210,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristic
// Descriptors owned by the chracteristic. The descriptors' identifiers serve
// as keys.
base::flat_map<std::string, std::unique_ptr<BluetoothRemoteGattDescriptor>>
descriptors_;
DescriptorMap descriptors_;
private:
friend class BluetoothGattNotifySession;
......
......@@ -3013,11 +3013,15 @@ TEST_F(BluetoothRemoteGattCharacteristicTest,
#define MAYBE_GetDescriptors_FindNone DISABLED_GetDescriptors_FindNone
#endif
#if defined(OS_WIN)
TEST_P(BluetoothRemoteGattCharacteristicTestWin32Only,
GetDescriptors_FindNone) {
TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, GetDescriptors_FindNone) {
#else
TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_GetDescriptors_FindNone) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
}
ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
EXPECT_EQ(0u, characteristic1_->GetDescriptors().size());
......@@ -3030,12 +3034,17 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_GetDescriptors_FindNone) {
DISABLED_GetDescriptors_and_GetDescriptor
#endif
#if defined(OS_WIN)
TEST_P(BluetoothRemoteGattCharacteristicTestWin32Only,
TEST_P(BluetoothRemoteGattCharacteristicTestWinrt,
GetDescriptors_and_GetDescriptor) {
#else
TEST_F(BluetoothRemoteGattCharacteristicTest,
MAYBE_GetDescriptors_and_GetDescriptor) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
}
ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
// Add several Descriptors:
......@@ -3047,6 +3056,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest,
SimulateGattDescriptor(characteristic1_, uuid2.canonical_value());
SimulateGattDescriptor(characteristic2_, uuid3.canonical_value());
SimulateGattDescriptor(characteristic2_, uuid4.canonical_value());
base::RunLoop().RunUntilIdle();
// Verify that GetDescriptor can retrieve descriptors again by ID,
// and that the same Descriptor is returned when searched by ID.
......@@ -3084,10 +3094,15 @@ TEST_F(BluetoothRemoteGattCharacteristicTest,
#define MAYBE_GetDescriptorsByUUID DISABLED_GetDescriptorsByUUID
#endif
#if defined(OS_WIN)
TEST_P(BluetoothRemoteGattCharacteristicTestWin32Only, GetDescriptorsByUUID) {
TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, GetDescriptorsByUUID) {
#else
TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_GetDescriptorsByUUID) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
}
ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
// Add several Descriptors:
......@@ -3098,6 +3113,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_GetDescriptorsByUUID) {
SimulateGattDescriptor(characteristic1_, id2.canonical_value());
SimulateGattDescriptor(characteristic2_, id3.canonical_value());
SimulateGattDescriptor(characteristic2_, id3.canonical_value());
base::RunLoop().RunUntilIdle();
EXPECT_NE(characteristic2_->GetDescriptorsByUUID(id3).at(0)->GetIdentifier(),
characteristic2_->GetDescriptorsByUUID(id3).at(1)->GetIdentifier());
......
......@@ -12,6 +12,8 @@
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/winrt_storage_util.h"
#include "device/bluetooth/bluetooth_gatt_discoverer_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/event_utils_winrt.h"
......@@ -256,6 +258,33 @@ void BluetoothRemoteGattCharacteristicWinrt::WriteRemoteCharacteristic(
std::make_unique<PendingWriteCallbacks>(callback, error_callback);
}
void BluetoothRemoteGattCharacteristicWinrt::UpdateDescriptors(
BluetoothGattDiscovererWinrt* gatt_discoverer) {
const auto* gatt_descriptors =
gatt_discoverer->GetDescriptors(attribute_handle_);
DCHECK(gatt_descriptors);
// Instead of clearing out |descriptors_| and creating each descriptor
// from scratch, we create a new map and move already existing descriptors
// into it in order to preserve pointer stability.
DescriptorMap descriptors;
for (const auto& gatt_descriptor : *gatt_descriptors) {
auto descriptor =
BluetoothRemoteGattDescriptorWinrt::Create(this, gatt_descriptor.Get());
if (!descriptor)
continue;
std::string identifier = descriptor->GetIdentifier();
auto iter = descriptors_.find(identifier);
if (iter != descriptors_.end())
descriptors.emplace(std::move(*iter));
else
descriptors.emplace(std::move(identifier), std::move(descriptor));
}
std::swap(descriptors, descriptors_);
}
bool BluetoothRemoteGattCharacteristicWinrt::WriteWithoutResponse(
base::span<const uint8_t> value) {
if (!(GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE))
......@@ -345,10 +374,11 @@ BluetoothRemoteGattCharacteristicWinrt::BluetoothRemoteGattCharacteristicWinrt(
characteristic_(std::move(characteristic)),
uuid_(std::move(uuid)),
properties_(properties),
attribute_handle_(attribute_handle),
identifier_(base::StringPrintf("%s/%s_%04x",
service_->GetIdentifier().c_str(),
uuid_.value().c_str(),
attribute_handle)),
attribute_handle_)),
weak_ptr_factory_(this) {}
void BluetoothRemoteGattCharacteristicWinrt::OnReadValue(
......
......@@ -23,6 +23,7 @@
namespace device {
class BluetoothRemoteGattDescriptor;
class BluetoothGattDiscovererWinrt;
class BluetoothRemoteGattService;
class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWinrt
......@@ -51,6 +52,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWinrt
const ErrorCallback& error_callback) override;
bool WriteWithoutResponse(base::span<const uint8_t> value) override;
void UpdateDescriptors(BluetoothGattDiscovererWinrt* gatt_discoverer);
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattCharacteristic*
GetCharacteristicForTesting();
......@@ -107,6 +110,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWinrt
characteristic_;
BluetoothUUID uuid_;
Properties properties_;
uint16_t attribute_handle_;
std::string identifier_;
std::vector<uint8_t> value_;
std::unique_ptr<PendingReadCallbacks> pending_read_callbacks_;
......
......@@ -22,7 +22,12 @@
namespace device {
class BluetoothRemoteGattDescriptorTest : public BluetoothTest {
class BluetoothRemoteGattDescriptorTest :
#if defined(OS_WIN)
public BluetoothTestWinrt {
#else
public BluetoothTest {
#endif
public:
// Creates adapter_, device_, service_, characteristic_,
// descriptor1_, & descriptor2_.
......@@ -59,12 +64,21 @@ class BluetoothRemoteGattDescriptorTest : public BluetoothTest {
BluetoothRemoteGattDescriptor* descriptor2_ = nullptr;
};
#if defined(OS_WIN)
using BluetoothRemoteGattDescriptorTestWinrtOnly =
BluetoothRemoteGattDescriptorTest;
#endif
#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_GetIdentifier GetIdentifier
#else
#define MAYBE_GetIdentifier DISABLED_GetIdentifier
#endif
#if defined(OS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrtOnly, GetIdentifier) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetIdentifier) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -102,6 +116,7 @@ TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetIdentifier) {
SimulateGattCharacteristic(service2, kTestUUIDDeviceName, /* properties */ 0);
SimulateGattCharacteristic(service3, kTestUUIDDeviceName, /* properties */ 0);
SimulateGattCharacteristic(service3, kTestUUIDDeviceName, /* properties */ 0);
base::RunLoop().RunUntilIdle();
BluetoothRemoteGattCharacteristic* char1 = service1->GetCharacteristics()[0];
BluetoothRemoteGattCharacteristic* char2 = service1->GetCharacteristics()[1];
BluetoothRemoteGattCharacteristic* char3 = service2->GetCharacteristics()[0];
......@@ -117,6 +132,7 @@ TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetIdentifier) {
SimulateGattDescriptor(char4, kTestUUIDCharacteristicUserDescription);
SimulateGattDescriptor(char5, kTestUUIDCharacteristicUserDescription);
SimulateGattDescriptor(char6, kTestUUIDCharacteristicUserDescription);
base::RunLoop().RunUntilIdle();
BluetoothRemoteGattDescriptor* desc1 = char1->GetDescriptors()[0];
BluetoothRemoteGattDescriptor* desc2 = char2->GetDescriptors()[0];
BluetoothRemoteGattDescriptor* desc3 = char3->GetDescriptors()[0];
......@@ -151,7 +167,11 @@ TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetIdentifier) {
#else
#define MAYBE_GetUUID DISABLED_GetUUID
#endif
#if defined(OS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrtOnly, GetUUID) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetUUID) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -170,6 +190,7 @@ TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetUUID) {
SimulateGattCharacteristic(service, kTestUUIDDeviceName,
/* properties */ 0);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, service->GetCharacteristics().size());
BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristics()[0];
......@@ -181,6 +202,7 @@ TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetUUID) {
kTestUUIDCharacteristicUserDescription);
SimulateGattDescriptor(characteristic,
kTestUUIDClientCharacteristicConfiguration);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, characteristic->GetDescriptors().size());
BluetoothRemoteGattDescriptor* descriptor1 =
characteristic->GetDescriptors()[0];
......@@ -904,4 +926,11 @@ TEST_F(BluetoothRemoteGattDescriptorTest, ReadRemoteDescriptor_NSNumber) {
}
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
INSTANTIATE_TEST_CASE_P(
/* no prefix */,
BluetoothRemoteGattDescriptorTestWinrtOnly,
::testing::Values(true));
#endif // defined(OS_WIN)
} // namespace device
......@@ -4,25 +4,57 @@
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
#include <utility>
#include "base/logging.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
namespace device {
BluetoothRemoteGattDescriptorWinrt::BluetoothRemoteGattDescriptorWinrt() =
default;
namespace {
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDescriptor;
using Microsoft::WRL::ComPtr;
} // namespace
// static
std::unique_ptr<BluetoothRemoteGattDescriptorWinrt>
BluetoothRemoteGattDescriptorWinrt::Create(
BluetoothRemoteGattCharacteristic* characteristic,
ComPtr<IGattDescriptor> descriptor) {
DCHECK(descriptor);
GUID guid;
HRESULT hr = descriptor->get_Uuid(&guid);
if (FAILED(hr)) {
VLOG(2) << "Getting UUID failed: " << logging::SystemErrorCodeToString(hr);
return nullptr;
}
uint16_t attribute_handle;
hr = descriptor->get_AttributeHandle(&attribute_handle);
if (FAILED(hr)) {
VLOG(2) << "Getting AttributeHandle failed: "
<< logging::SystemErrorCodeToString(hr);
return nullptr;
}
return base::WrapUnique(new BluetoothRemoteGattDescriptorWinrt(
characteristic, std::move(descriptor), BluetoothUUID(guid),
attribute_handle));
}
BluetoothRemoteGattDescriptorWinrt::~BluetoothRemoteGattDescriptorWinrt() =
default;
std::string BluetoothRemoteGattDescriptorWinrt::GetIdentifier() const {
NOTIMPLEMENTED();
return std::string();
return identifier_;
}
BluetoothUUID BluetoothRemoteGattDescriptorWinrt::GetUUID() const {
NOTIMPLEMENTED();
return BluetoothUUID();
return uuid_;
}
BluetoothGattCharacteristic::Permissions
......@@ -38,8 +70,7 @@ const std::vector<uint8_t>& BluetoothRemoteGattDescriptorWinrt::GetValue()
BluetoothRemoteGattCharacteristic*
BluetoothRemoteGattDescriptorWinrt::GetCharacteristic() const {
NOTIMPLEMENTED();
return nullptr;
return characteristic_;
}
void BluetoothRemoteGattDescriptorWinrt::ReadRemoteDescriptor(
......@@ -55,4 +86,19 @@ void BluetoothRemoteGattDescriptorWinrt::WriteRemoteDescriptor(
NOTIMPLEMENTED();
}
BluetoothRemoteGattDescriptorWinrt::BluetoothRemoteGattDescriptorWinrt(
BluetoothRemoteGattCharacteristic* characteristic,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>
descriptor,
BluetoothUUID uuid,
uint16_t attribute_handle)
: characteristic_(characteristic),
descriptor_(std::move(descriptor)),
uuid_(std::move(uuid)),
identifier_(base::StringPrintf("%s/%s_%04x",
characteristic_->GetIdentifier().c_str(),
uuid_.value().c_str(),
attribute_handle)) {}
} // namespace device
......@@ -5,8 +5,12 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_DESCRIPTOR_WINRT_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_DESCRIPTOR_WINRT_H_
#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <wrl/client.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
......@@ -15,15 +19,18 @@
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace device {
class BluetoothUUID;
class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattDescriptorWinrt
: public BluetoothRemoteGattDescriptor {
public:
BluetoothRemoteGattDescriptorWinrt();
static std::unique_ptr<BluetoothRemoteGattDescriptorWinrt> Create(
BluetoothRemoteGattCharacteristic* characteristic,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>
descriptor);
~BluetoothRemoteGattDescriptorWinrt() override;
// BluetoothGattDescriptor:
......@@ -41,6 +48,21 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattDescriptorWinrt
const ErrorCallback& error_callback) override;
private:
BluetoothRemoteGattDescriptorWinrt(
BluetoothRemoteGattCharacteristic* characteristic,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>
descriptor,
BluetoothUUID uuid,
uint16_t attribute_handle);
// Weak. This object is owned by |characteristic_|.
BluetoothRemoteGattCharacteristic* characteristic_;
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>
descriptor_;
BluetoothUUID uuid_;
std::string identifier_;
std::vector<uint8_t> value_;
DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattDescriptorWinrt);
......
......@@ -91,10 +91,16 @@ void BluetoothRemoteGattServiceWinrt::UpdateCharacteristics(
std::string identifier = characteristic->GetIdentifier();
auto iter = characteristics_.find(identifier);
if (iter != characteristics_.end())
characteristics.emplace(std::move(*iter));
else
characteristics.emplace(std::move(identifier), std::move(characteristic));
if (iter != characteristics_.end()) {
iter = characteristics.emplace(std::move(*iter)).first;
} else {
iter = characteristics
.emplace(std::move(identifier), std::move(characteristic))
.first;
}
static_cast<BluetoothRemoteGattCharacteristicWinrt*>(iter->second.get())
->UpdateDescriptors(gatt_discoverer);
}
std::swap(characteristics, characteristics_);
......
......@@ -813,6 +813,19 @@ void BluetoothTestWinrt::SimulateGattCharacteristicWriteError(
->SimulateGattCharacteristicWriteError(error_code);
}
void BluetoothTestWinrt::SimulateGattDescriptor(
BluetoothRemoteGattCharacteristic* characteristic,
const std::string& uuid) {
if (!GetParam() || !PlatformSupportsLowEnergy())
return BluetoothTestWin::SimulateGattDescriptor(characteristic, uuid);
auto* const ble_device = static_cast<TestBluetoothDeviceWinrt*>(
characteristic->GetService()->GetDevice())
->ble_device();
DCHECK(ble_device);
ble_device->SimulateGattDescriptor(characteristic, uuid);
}
void BluetoothTestWinrt::DeleteDevice(BluetoothDevice* device) {
(!GetParam() || !PlatformSupportsLowEnergy())
? BluetoothTestWin::DeleteDevice(device)
......
......@@ -147,6 +147,8 @@ class BluetoothTestWinrt : public BluetoothTestWin,
void SimulateGattCharacteristicWriteError(
BluetoothRemoteGattCharacteristic* characteristic,
BluetoothRemoteGattService::GattErrorCode error_code) override;
void SimulateGattDescriptor(BluetoothRemoteGattCharacteristic* characteristic,
const std::string& uuid) override;
void DeleteDevice(BluetoothDevice* device) override;
void OnFakeBluetoothDeviceConnectGattCalled();
......
......@@ -15,6 +15,7 @@
#include "base/win/async_operation.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
#include "device/bluetooth/test/bluetooth_test_win.h"
#include "device/bluetooth/test/fake_gatt_characteristic_winrt.h"
#include "device/bluetooth/test/fake_gatt_device_service_winrt.h"
#include "device/bluetooth/test/fake_gatt_device_services_result_winrt.h"
......@@ -198,8 +199,11 @@ void FakeBluetoothLEDeviceWinrt::SimulateGattDisconnection() {
void FakeBluetoothLEDeviceWinrt::SimulateGattServicesDiscovered(
const std::vector<std::string>& uuids) {
for (const auto& uuid : uuids) {
// Attribute handles need to be unique for a given BLE device. Increasing by
// a large number ensures enough address space for the contained
// characteristics and descriptors.
fake_services_.push_back(Make<FakeGattDeviceServiceWinrt>(
bluetooth_test_winrt_, uuid, service_attribute_handle_++));
bluetooth_test_winrt_, uuid, service_attribute_handle_ += 0x0400));
}
DCHECK(gatt_services_callback_);
......@@ -241,6 +245,23 @@ void FakeBluetoothLEDeviceWinrt::SimulateGattCharacteristic(
.Run(Make<FakeGattDeviceServicesResultWinrt>(fake_services_));
}
void FakeBluetoothLEDeviceWinrt::SimulateGattDescriptor(
BluetoothRemoteGattCharacteristic* characteristic,
const std::string& uuid) {
// Simulate the fake descriptor on the GATT service and trigger a GATT
// re-scan via GattServicesChanged().
auto* const fake_characteristic = static_cast<FakeGattCharacteristicWinrt*>(
static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
->GetCharacteristicForTesting());
DCHECK(fake_characteristic);
fake_characteristic->SimulateGattDescriptor(uuid);
SimulateGattServicesChanged();
DCHECK(gatt_services_callback_);
std::move(gatt_services_callback_)
.Run(Make<FakeGattDeviceServicesResultWinrt>(fake_services_));
}
void FakeBluetoothLEDeviceWinrt::SimulateGattServicesChanged() {
DCHECK(gatt_services_changed_handler_);
gatt_services_changed_handler_->Invoke(this, nullptr);
......
......@@ -112,6 +112,8 @@ class FakeBluetoothLEDeviceWinrt
void SimulateGattCharacteristic(BluetoothRemoteGattService* service,
const std::string& uuid,
int properties);
void SimulateGattDescriptor(BluetoothRemoteGattCharacteristic* characteristic,
const std::string& uuid);
void SimulateGattServicesDiscoveryError();
private:
......
......@@ -13,6 +13,8 @@
#include "base/win/winrt_storage_util.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/test/bluetooth_test_win.h"
#include "device/bluetooth/test/fake_gatt_descriptor_winrt.h"
#include "device/bluetooth/test/fake_gatt_descriptors_result_winrt.h"
#include "device/bluetooth/test/fake_gatt_read_result_winrt.h"
#include "device/bluetooth/test/fake_gatt_write_result_winrt.h"
......@@ -69,7 +71,8 @@ FakeGattCharacteristicWinrt::FakeGattCharacteristicWinrt(
: bluetooth_test_winrt_(bluetooth_test_winrt),
properties_(static_cast<GattCharacteristicProperties>(properties)),
uuid_(BluetoothUUID::GetCanonicalValueAsGUID(uuid)),
attribute_handle_(attribute_handle) {}
attribute_handle_(attribute_handle),
last_descriptor_attribute_handle_(attribute_handle) {}
FakeGattCharacteristicWinrt::~FakeGattCharacteristicWinrt() = default;
......@@ -173,7 +176,13 @@ HRESULT FakeGattCharacteristicWinrt::remove_ValueChanged(
HRESULT FakeGattCharacteristicWinrt::GetDescriptorsAsync(
IAsyncOperation<GattDescriptorsResult*>** operation) {
return E_NOTIMPL;
auto async_op = Make<base::win::AsyncOperation<GattDescriptorsResult*>>();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(async_op->callback(),
Make<FakeGattDescriptorsResultWinrt>(fake_descriptors_)));
*operation = async_op.Detach();
return S_OK;
}
HRESULT FakeGattCharacteristicWinrt::GetDescriptorsWithCacheModeAsync(
......@@ -258,4 +267,10 @@ void FakeGattCharacteristicWinrt::SimulateGattCharacteristicWriteError(
}
}
void FakeGattCharacteristicWinrt::SimulateGattDescriptor(
base::StringPiece uuid) {
fake_descriptors_.push_back(
Make<FakeGattDescriptorWinrt>(uuid, ++last_descriptor_attribute_handle_));
}
} // namespace device
......@@ -22,6 +22,7 @@
namespace device {
class BluetoothTestWinrt;
class FakeGattDescriptorWinrt;
class FakeGattCharacteristicWinrt
: public Microsoft::WRL::RuntimeClass<
......@@ -152,6 +153,7 @@ class FakeGattCharacteristicWinrt
void SimulateGattCharacteristicWrite();
void SimulateGattCharacteristicWriteError(
BluetoothGattService::GattErrorCode error_code);
void SimulateGattDescriptor(base::StringPiece uuid);
private:
BluetoothTestWinrt* bluetooth_test_winrt_;
......@@ -169,6 +171,10 @@ class FakeGattCharacteristicWinrt
GenericAttributeProfile::IGattWriteResult>)>
write_value_callback_;
std::vector<Microsoft::WRL::ComPtr<FakeGattDescriptorWinrt>>
fake_descriptors_;
uint16_t last_descriptor_attribute_handle_;
DISALLOW_COPY_AND_ASSIGN(FakeGattCharacteristicWinrt);
};
......
......@@ -4,6 +4,9 @@
#include "device/bluetooth/test/fake_gatt_descriptor_winrt.h"
#include "base/strings/string_piece.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace device {
namespace {
......@@ -21,7 +24,10 @@ using ABI::Windows::Storage::Streams::IBuffer;
} // namespace
FakeGattDescriptorWinrt::FakeGattDescriptorWinrt() = default;
FakeGattDescriptorWinrt::FakeGattDescriptorWinrt(base::StringPiece uuid,
uint16_t attribute_handle)
: uuid_(BluetoothUUID::GetCanonicalValueAsGUID(uuid)),
attribute_handle_(attribute_handle) {}
FakeGattDescriptorWinrt::~FakeGattDescriptorWinrt() = default;
......@@ -36,11 +42,13 @@ HRESULT FakeGattDescriptorWinrt::put_ProtectionLevel(
}
HRESULT FakeGattDescriptorWinrt::get_Uuid(GUID* value) {
return E_NOTIMPL;
*value = uuid_;
return S_OK;
}
HRESULT FakeGattDescriptorWinrt::get_AttributeHandle(uint16_t* value) {
return E_NOTIMPL;
*value = attribute_handle_;
return S_OK;
}
HRESULT FakeGattDescriptorWinrt::ReadValueAsync(
......
......@@ -11,6 +11,7 @@
#include <stdint.h>
#include "base/macros.h"
#include "base/strings/string_piece_forward.h"
namespace device {
......@@ -23,7 +24,7 @@ class FakeGattDescriptorWinrt
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDescriptor2> {
public:
FakeGattDescriptorWinrt();
FakeGattDescriptorWinrt(base::StringPiece uuid, uint16_t attribute_handle);
~FakeGattDescriptorWinrt() override;
// IGattDescriptor:
......@@ -58,6 +59,9 @@ class FakeGattDescriptorWinrt
GattWriteResult*>** operation) override;
private:
GUID uuid_;
uint16_t attribute_handle_;
DISALLOW_COPY_AND_ASSIGN(FakeGattDescriptorWinrt);
};
......
......@@ -4,25 +4,68 @@
#include "device/bluetooth/test/fake_gatt_descriptors_result_winrt.h"
namespace device {
#include "base/win/vector.h"
#include "device/bluetooth/test/fake_gatt_descriptor_winrt.h"
namespace {
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDescriptor;
using ABI::Windows::Foundation::Collections::IVectorView;
using ABI::Windows::Foundation::IReference;
using Microsoft::WRL::ComPtr;
using Microsoft::WRL::Make;
} // namespace
FakeGattDescriptorsResultWinrt::FakeGattDescriptorsResultWinrt() = default;
// Note: As UWP does not provide GattDescriptor specializations for
// IObservableVector, VectorChangedEventHandler and IVector we need to supply
// our own. UUIDs were generated using `uuidgen`.
namespace ABI {
namespace Windows {
namespace Foundation {
namespace Collections {
template <>
struct __declspec(uuid("b259bb8d-2a87-44f6-9f9c-321cb98b7750"))
IObservableVector<GattDescriptor*>
: IObservableVector_impl<
Internal::AggregateType<GattDescriptor*, IGattDescriptor*>> {};
template <>
struct __declspec(uuid("39bc2e35-9a9a-4f93-ba00-7caaf965457e"))
VectorChangedEventHandler<GattDescriptor*>
: VectorChangedEventHandler_impl<
Internal::AggregateType<GattDescriptor*, IGattDescriptor*>> {};
template <>
struct __declspec(
uuid("1865abfa-a793-4b20-910c-f43e3fd12c3c")) IVector<GattDescriptor*>
: IVector_impl<Internal::AggregateType<GattDescriptor*, IGattDescriptor*>> {
};
} // namespace Collections
} // namespace Foundation
} // namespace Windows
} // namespace ABI
namespace device {
FakeGattDescriptorsResultWinrt::FakeGattDescriptorsResultWinrt(
const std::vector<ComPtr<FakeGattDescriptorWinrt>>& fake_descriptors)
: descriptors_(fake_descriptors.begin(), fake_descriptors.end()) {}
FakeGattDescriptorsResultWinrt::~FakeGattDescriptorsResultWinrt() = default;
HRESULT FakeGattDescriptorsResultWinrt::get_Status(
GattCommunicationStatus* value) {
return E_NOTIMPL;
*value = GattCommunicationStatus_Success;
return S_OK;
}
HRESULT FakeGattDescriptorsResultWinrt::get_ProtocolError(
......@@ -32,7 +75,7 @@ HRESULT FakeGattDescriptorsResultWinrt::get_ProtocolError(
HRESULT FakeGattDescriptorsResultWinrt::get_Descriptors(
IVectorView<GattDescriptor*>** value) {
return E_NOTIMPL;
return Make<base::win::Vector<GattDescriptor*>>(descriptors_)->GetView(value);
}
} // namespace device
......@@ -8,14 +8,19 @@
#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <windows.foundation.collections.h>
#include <windows.foundation.h>
#include <wrl/client.h>
#include <wrl/implements.h>
#include <stdint.h>
#include <vector>
#include "base/macros.h"
namespace device {
class FakeGattDescriptorWinrt;
class FakeGattDescriptorsResultWinrt
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<
......@@ -23,7 +28,9 @@ class FakeGattDescriptorsResultWinrt
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDescriptorsResult> {
public:
FakeGattDescriptorsResultWinrt();
explicit FakeGattDescriptorsResultWinrt(
const std::vector<Microsoft::WRL::ComPtr<FakeGattDescriptorWinrt>>&
fake_descriptors);
~FakeGattDescriptorsResultWinrt() override;
// IGattDescriptorsResult:
......@@ -38,6 +45,11 @@ class FakeGattDescriptorsResultWinrt
GattDescriptor*>** value) override;
private:
std::vector<
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::
GenericAttributeProfile::IGattDescriptor>>
descriptors_;
DISALLOW_COPY_AND_ASSIGN(FakeGattDescriptorsResultWinrt);
};
......
......@@ -48,7 +48,8 @@ FakeGattDeviceServiceWinrt::FakeGattDeviceServiceWinrt(
uint16_t attribute_handle)
: bluetooth_test_winrt_(bluetooth_test_winrt),
uuid_(BluetoothUUID::GetCanonicalValueAsGUID(uuid)),
attribute_handle_(attribute_handle) {}
attribute_handle_(attribute_handle),
characteristic_attribute_handle_(attribute_handle_) {}
FakeGattDeviceServiceWinrt::~FakeGattDeviceServiceWinrt() = default;
......@@ -160,9 +161,13 @@ FakeGattDeviceServiceWinrt::GetIncludedServicesForUuidWithCacheModeAsync(
void FakeGattDeviceServiceWinrt::SimulateGattCharacteristic(
base::StringPiece uuid,
int properties) {
fake_characteristics_.push_back(
Make<FakeGattCharacteristicWinrt>(bluetooth_test_winrt_, properties, uuid,
characteristic_attribute_handle_++));
// In order to ensure attribute handles are unique across the Gatt Server
// we reserve sufficient address space for descriptors for each
// characteristic. We allocate space for 32 descriptors, which should be
// enough for tests.
fake_characteristics_.push_back(Make<FakeGattCharacteristicWinrt>(
bluetooth_test_winrt_, properties, uuid,
characteristic_attribute_handle_ += 0x20));
}
} // namespace device
......@@ -120,7 +120,7 @@ class FakeGattDeviceServiceWinrt
std::vector<Microsoft::WRL::ComPtr<FakeGattCharacteristicWinrt>>
fake_characteristics_;
uint16_t characteristic_attribute_handle_ = 0;
uint16_t characteristic_attribute_handle_;
DISALLOW_COPY_AND_ASSIGN(FakeGattDeviceServiceWinrt);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment