| // Copyright 2018 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/test/fake_bluetooth_le_advertisement_winrt.h" |
| |
| #include <windows.foundation.collections.h> |
| |
| #include <algorithm> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_split.h" |
| #include "base/win/reference.h" |
| #include "base/win/scoped_hstring.h" |
| #include "base/win/vector.h" |
| #include "device/bluetooth/bluetooth_device_winrt.h" |
| #include "device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h" |
| #include "device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h" |
| |
| namespace { |
| |
| using ABI::Windows::Devices::Bluetooth::Advertisement:: |
| BluetoothLEAdvertisementDataSection; |
| using ABI::Windows::Devices::Bluetooth::Advertisement:: |
| BluetoothLEAdvertisementFlags; |
| using ABI::Windows::Devices::Bluetooth::Advertisement:: |
| BluetoothLEManufacturerData; |
| using ABI::Windows::Devices::Bluetooth::Advertisement:: |
| IBluetoothLEAdvertisementDataSection; |
| using ABI::Windows::Devices::Bluetooth::Advertisement:: |
| IBluetoothLEManufacturerData; |
| using ABI::Windows::Foundation::IReference; |
| using ABI::Windows::Foundation::Collections::IVector; |
| using ABI::Windows::Foundation::Collections::IVectorView; |
| using Microsoft::WRL::ComPtr; |
| using Microsoft::WRL::Make; |
| |
| } // namespace |
| |
| // Note: As UWP does not provide GUID and specializations for all required |
| // templates we need to supply our own. UUIDs were generated using `uuidgen`. |
| namespace ABI { |
| namespace Windows { |
| namespace Foundation { |
| namespace Collections { |
| |
| template <> |
| struct __declspec(uuid("241709e6-4b79-44b4-827c-9bcb6025ebe6")) |
| IObservableVector<GUID> : IObservableVector_impl<GUID> {}; |
| |
| template <> |
| struct __declspec(uuid("868ba4c1-7019-470b-b667-df34fa20efc6")) |
| VectorChangedEventHandler<GUID> : VectorChangedEventHandler_impl<GUID> {}; |
| |
| template <> |
| struct __declspec(uuid("5a7b58a6-fbd4-4ef9-98fd-d700649cd32e")) |
| IObservableVector<BluetoothLEManufacturerData*> |
| : IObservableVector_impl< |
| Internal::AggregateType<BluetoothLEManufacturerData*, |
| IBluetoothLEManufacturerData*>> {}; |
| |
| template <> |
| struct __declspec(uuid("0a57dc65-0e06-46ff-9ff7-cf2390847d2a")) |
| VectorChangedEventHandler<BluetoothLEManufacturerData*> |
| : VectorChangedEventHandler_impl< |
| Internal::AggregateType<BluetoothLEManufacturerData*, |
| IBluetoothLEManufacturerData*>> {}; |
| |
| template <> |
| struct __declspec(uuid("eeec55af-8cd4-4935-aa43-31aa2c5567b9")) |
| IObservableVector<BluetoothLEAdvertisementDataSection*> |
| : IObservableVector_impl< |
| Internal::AggregateType<BluetoothLEAdvertisementDataSection*, |
| IBluetoothLEAdvertisementDataSection*>> {}; |
| |
| template <> |
| struct __declspec(uuid("978f98e6-b03c-41c8-a529-7781fd06f1e4")) |
| VectorChangedEventHandler<BluetoothLEAdvertisementDataSection*> |
| : VectorChangedEventHandler_impl< |
| Internal::AggregateType<BluetoothLEAdvertisementDataSection*, |
| IBluetoothLEAdvertisementDataSection*>> {}; |
| |
| } // namespace Collections |
| } // namespace Foundation |
| } // namespace Windows |
| } // namespace ABI |
| |
| namespace device { |
| |
| namespace { |
| |
| constexpr size_t kNumBytesCanonicalUuid = 16; |
| |
| std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> ToDataSections( |
| const BluetoothDevice::ServiceDataMap& service_data) { |
| std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> data_sections; |
| data_sections.reserve(service_data.size()); |
| for (const auto& pair : service_data) { |
| std::vector<uint8_t> data; |
| data.reserve(kNumBytesCanonicalUuid + pair.second.size()); |
| |
| // HexDecode the UUID while ignoring dashes. |
| for (const auto& token : |
| base::SplitStringPiece(pair.first.canonical_value(), "-", |
| base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { |
| std::vector<uint8_t> tmp; |
| base::HexStringToBytes(token, &tmp); |
| data.insert(data.end(), tmp.begin(), tmp.end()); |
| } |
| |
| // Reverse the data as UUIDs are specified in little endian order in the |
| // advertisement payload. |
| std::reverse(data.begin(), data.end()); |
| |
| // Append the actual service data and append a new data section. |
| data.insert(data.end(), pair.second.begin(), pair.second.end()); |
| data_sections.push_back( |
| Make<FakeBluetoothLEAdvertisementDataSectionWinrt>(std::move(data))); |
| } |
| |
| return data_sections; |
| } |
| |
| } // namespace |
| |
| FakeBluetoothLEAdvertisementWinrt::FakeBluetoothLEAdvertisementWinrt() = |
| default; |
| |
| FakeBluetoothLEAdvertisementWinrt::FakeBluetoothLEAdvertisementWinrt( |
| base::Optional<std::string> local_name, |
| base::Optional<uint8_t> flags, |
| BluetoothDevice::UUIDList advertised_uuids, |
| base::Optional<int8_t> tx_power, |
| BluetoothDevice::ServiceDataMap service_data, |
| BluetoothDevice::ManufacturerDataMap manufacturer_data) |
| : local_name_(std::move(local_name)), |
| flags_(std::move(flags)), |
| advertised_uuids_(std::move(advertised_uuids)), |
| tx_power_(std::move(tx_power)), |
| service_data_(std::move(service_data)), |
| manufacturer_data_(std::move(manufacturer_data)) {} |
| |
| FakeBluetoothLEAdvertisementWinrt::~FakeBluetoothLEAdvertisementWinrt() = |
| default; |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::get_Flags( |
| IReference<BluetoothLEAdvertisementFlags>** value) { |
| // While non-intuitive, this matches production behavior. When a reference is |
| // supposed to be empty, the pointer is set to null and S_OK is returned. |
| if (!flags_) { |
| *value = nullptr; |
| return S_OK; |
| } |
| |
| return Make<base::win::Reference<BluetoothLEAdvertisementFlags>>( |
| static_cast<BluetoothLEAdvertisementFlags>(*flags_)) |
| .CopyTo(value); |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::put_Flags( |
| IReference<BluetoothLEAdvertisementFlags>* value) { |
| return E_NOTIMPL; |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::get_LocalName(HSTRING* value) { |
| if (!local_name_) |
| return E_FAIL; |
| |
| *value = base::win::ScopedHString::Create(*local_name_).release(); |
| return S_OK; |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::put_LocalName(HSTRING value) { |
| return E_NOTIMPL; |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::get_ServiceUuids( |
| IVector<GUID>** value) { |
| std::vector<GUID> guids; |
| guids.reserve(advertised_uuids_.size()); |
| for (const auto& uuid : advertised_uuids_) { |
| guids.emplace_back( |
| BluetoothUUID::GetCanonicalValueAsGUID(uuid.canonical_value())); |
| } |
| |
| return Make<base::win::Vector<GUID>>(std::move(guids)).CopyTo(value); |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::get_ManufacturerData( |
| IVector<BluetoothLEManufacturerData*>** value) { |
| std::vector<ComPtr<IBluetoothLEManufacturerData>> manufacturer_data; |
| manufacturer_data.reserve(manufacturer_data_.size()); |
| for (const auto& pair : manufacturer_data_) { |
| manufacturer_data.push_back( |
| Make<FakeBluetoothLEManufacturerData>(pair.first, pair.second)); |
| } |
| |
| return Make<base::win::Vector<BluetoothLEManufacturerData*>>( |
| std::move(manufacturer_data)) |
| .CopyTo(value); |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::get_DataSections( |
| IVector<BluetoothLEAdvertisementDataSection*>** value) { |
| return E_NOTIMPL; |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::GetManufacturerDataByCompanyId( |
| uint16_t company_id, |
| IVectorView<BluetoothLEManufacturerData*>** data_list) { |
| return E_NOTIMPL; |
| } |
| |
| HRESULT FakeBluetoothLEAdvertisementWinrt::GetSectionsByType( |
| uint8_t type, |
| IVectorView<BluetoothLEAdvertisementDataSection*>** section_list) { |
| std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> data_sections; |
| if (type == BluetoothDeviceWinrt::kTxPowerLevelDataSection && tx_power_) { |
| data_sections.push_back(Make<FakeBluetoothLEAdvertisementDataSectionWinrt>( |
| std::vector<uint8_t>({*tx_power_}))); |
| } |
| |
| // For simplicity we only implement querying 128 Bit UUID Service Data. |
| if (type == BluetoothDeviceWinrt::k128BitServiceDataSection) |
| data_sections = ToDataSections(service_data_); |
| |
| return Make<base::win::Vector<BluetoothLEAdvertisementDataSection*>>( |
| std::move(data_sections)) |
| ->GetView(section_list); |
| } |
| |
| } // namespace device |