chromium/device/bluetooth/test/fake_gatt_characteristic_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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "device/bluetooth/test/fake_gatt_characteristic_winrt.h"

#include <string_view>
#include <utility>

#include "base/check.h"
#include "base/functional/bind.h"
#include "base/task/single_thread_task_runner.h"
#include "base/win/async_operation.h"
#include "base/win/winrt_storage_util.h"
#include "device/bluetooth/public/cpp/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_value_changed_event_args_winrt.h"
#include "device/bluetooth/test/fake_gatt_write_result_winrt.h"

namespace device {

namespace {

using ABI::Windows::Devices::Bluetooth::BluetoothCacheMode;
using ABI::Windows::Devices::Bluetooth::BluetoothCacheMode_Uncached;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattCharacteristic;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattCharacteristicProperties;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattClientCharacteristicConfigurationDescriptorValue;
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::
    GattPresentationFormat;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattProtectionLevel;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattReadClientCharacteristicConfigurationDescriptorResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattReadResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattValueChangedEventArgs;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteOption;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteOption_WriteWithResponse;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattReadResult;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::ITypedEventHandler;
using ABI::Windows::Foundation::Collections::IVectorView;
using ABI::Windows::Storage::Streams::IBuffer;
using Microsoft::WRL::Make;

}  // namespace

FakeGattCharacteristicWinrt::FakeGattCharacteristicWinrt(
    BluetoothTestWinrt* bluetooth_test_winrt,
    int properties,
    std::string_view uuid,
    uint16_t attribute_handle)
    : bluetooth_test_winrt_(bluetooth_test_winrt),
      properties_(static_cast<GattCharacteristicProperties>(properties)),
      uuid_(BluetoothUUID::GetCanonicalValueAsGUID(uuid)),
      attribute_handle_(attribute_handle),
      last_descriptor_attribute_handle_(attribute_handle) {}

FakeGattCharacteristicWinrt::~FakeGattCharacteristicWinrt() = default;

HRESULT FakeGattCharacteristicWinrt::GetDescriptors(
    GUID descriptor_uuid,
    IVectorView<GattDescriptor*>** value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::get_CharacteristicProperties(
    GattCharacteristicProperties* value) {
  *value = properties_;
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::get_ProtectionLevel(
    GattProtectionLevel* value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::put_ProtectionLevel(
    GattProtectionLevel value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::get_UserDescription(HSTRING* value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::get_Uuid(GUID* value) {
  *value = uuid_;
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::get_AttributeHandle(uint16_t* value) {
  *value = attribute_handle_;
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::get_PresentationFormats(
    IVectorView<GattPresentationFormat*>** value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::ReadValueAsync(
    IAsyncOperation<GattReadResult*>** value) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::ReadValueWithCacheModeAsync(
    BluetoothCacheMode cache_mode,
    IAsyncOperation<GattReadResult*>** value) {
  if (cache_mode != BluetoothCacheMode_Uncached)
    return E_NOTIMPL;

  auto async_op = Make<base::win::AsyncOperation<GattReadResult*>>();
  DCHECK(!read_value_callback_);
  read_value_callback_ = async_op->callback();
  *value = async_op.Detach();
  bluetooth_test_winrt_->OnFakeBluetoothCharacteristicReadValue();
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::WriteValueAsync(
    IBuffer* value,
    IAsyncOperation<GattCommunicationStatus>** async_op) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::WriteValueWithOptionAsync(
    IBuffer* value,
    GattWriteOption write_option,
    IAsyncOperation<GattCommunicationStatus>** async_op) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::
    ReadClientCharacteristicConfigurationDescriptorAsync(
        IAsyncOperation<
            GattReadClientCharacteristicConfigurationDescriptorResult*>**
            async_op) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::
    WriteClientCharacteristicConfigurationDescriptorAsync(
        GattClientCharacteristicConfigurationDescriptorValue
            client_characteristic_configuration_descriptor_value,
        IAsyncOperation<GattCommunicationStatus>** async_op) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::add_ValueChanged(
    ITypedEventHandler<GattCharacteristic*, GattValueChangedEventArgs*>*
        value_changed_handler,
    EventRegistrationToken* value_changed_event_cookie) {
  value_changed_handler_ = value_changed_handler;
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::remove_ValueChanged(
    EventRegistrationToken value_changed_event_cookie) {
  value_changed_handler_.Reset();
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::GetDescriptorsAsync(
    IAsyncOperation<GattDescriptorsResult*>** operation) {
  auto async_op = Make<base::win::AsyncOperation<GattDescriptorsResult*>>();
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(async_op->callback(),
                     Make<FakeGattDescriptorsResultWinrt>(fake_descriptors_)));
  *operation = async_op.Detach();
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::GetDescriptorsWithCacheModeAsync(
    BluetoothCacheMode cache_mode,
    IAsyncOperation<GattDescriptorsResult*>** operation) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::GetDescriptorsForUuidAsync(
    GUID descriptor_uuid,
    IAsyncOperation<GattDescriptorsResult*>** operation) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::GetDescriptorsForUuidWithCacheModeAsync(
    GUID descriptor_uuid,
    BluetoothCacheMode cache_mode,
    IAsyncOperation<GattDescriptorsResult*>** operation) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::WriteValueWithResultAsync(
    IBuffer* value,
    IAsyncOperation<GattWriteResult*>** operation) {
  return E_NOTIMPL;
}

HRESULT FakeGattCharacteristicWinrt::WriteValueWithResultAndOptionAsync(
    IBuffer* value,
    GattWriteOption write_option,
    IAsyncOperation<GattWriteResult*>** operation) {
  uint8_t* data;
  uint32_t size;
  base::win::GetPointerToBufferData(value, &data, &size);
  bluetooth_test_winrt_->OnFakeBluetoothCharacteristicWriteValue(
      std::vector<uint8_t>(data, data + size));
  auto async_op = Make<base::win::AsyncOperation<GattWriteResult*>>();
  DCHECK(!write_value_callback_);
  if (write_option == GattWriteOption_WriteWithResponse) {
    write_value_callback_ = async_op->callback();
  } else {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(async_op->callback(), Make<FakeGattWriteResultWinrt>()));
  }
  *operation = async_op.Detach();
  return S_OK;
}

HRESULT FakeGattCharacteristicWinrt::
    WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
        GattClientCharacteristicConfigurationDescriptorValue
            client_characteristic_configuration_descriptor_value,
        IAsyncOperation<GattWriteResult*>** operation) {
  bluetooth_test_winrt_->OnFakeBluetoothGattSetCharacteristicNotification(
      static_cast<BluetoothTestBase::NotifyValueState>(
          client_characteristic_configuration_descriptor_value));
  auto async_op = Make<base::win::AsyncOperation<GattWriteResult*>>();
  notify_session_callback_ = async_op->callback();
  *operation = async_op.Detach();
  return S_OK;
}

void FakeGattCharacteristicWinrt::SimulateGattCharacteristicRead(
    const std::vector<uint8_t>& data) {
  if (read_value_callback_)
    std::move(read_value_callback_).Run(Make<FakeGattReadResultWinrt>(data));
}

void FakeGattCharacteristicWinrt::SimulateGattCharacteristicReadError(
    BluetoothGattService::GattErrorCode error_code) {
  if (read_value_callback_) {
    std::move(read_value_callback_)
        .Run(Make<FakeGattReadResultWinrt>(error_code));
  }
}

void FakeGattCharacteristicWinrt::SimulateGattCharacteristicWrite() {
  if (write_value_callback_)
    std::move(write_value_callback_).Run(Make<FakeGattWriteResultWinrt>());
}

void FakeGattCharacteristicWinrt::SimulateGattCharacteristicWriteError(
    BluetoothGattService::GattErrorCode error_code) {
  if (write_value_callback_) {
    std::move(write_value_callback_)
        .Run(Make<FakeGattWriteResultWinrt>(error_code));
  }
}

void FakeGattCharacteristicWinrt::SimulateGattDescriptor(
    std::string_view uuid) {
  fake_descriptors_.push_back(Make<FakeGattDescriptorWinrt>(
      bluetooth_test_winrt_, uuid, ++last_descriptor_attribute_handle_));
}

void FakeGattCharacteristicWinrt::SimulateGattNotifySessionStarted() {
  std::move(notify_session_callback_).Run(Make<FakeGattWriteResultWinrt>());
}

void FakeGattCharacteristicWinrt::SimulateGattNotifySessionStartError(
    BluetoothGattService::GattErrorCode error_code) {
  std::move(notify_session_callback_)
      .Run(Make<FakeGattWriteResultWinrt>(error_code));
}

void FakeGattCharacteristicWinrt::SimulateGattNotifySessionStopped() {
  std::move(notify_session_callback_).Run(Make<FakeGattWriteResultWinrt>());
}

void FakeGattCharacteristicWinrt::SimulateGattNotifySessionStopError(
    BluetoothGattService::GattErrorCode error_code) {
  std::move(notify_session_callback_)
      .Run(Make<FakeGattWriteResultWinrt>(error_code));
}

void FakeGattCharacteristicWinrt::SimulateGattCharacteristicChanged(
    const std::vector<uint8_t>& value) {
  DCHECK(value_changed_handler_);
  value_changed_handler_->Invoke(
      this, Make<FakeGattValueChangedEventArgsWinrt>(value).Get());
}

}  // namespace device