chromium/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.cc

// Copyright 2018 The Chromium Authors
// 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/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 {

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 = pair.first.GetBytes();

    // 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(
    std::optional<std::string> local_name,
    std::optional<uint8_t> flags,
    BluetoothDevice::UUIDList advertised_uuids,
    std::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>({static_cast<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