text: // 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_gatt_device_service_winrt.h"
  
  #include <wrl/client.h>
  
  #include <utility>
  
  #include "base/bind.h"
  #include "base/strings/string16.h"
  #include "base/strings/string_piece.h"
  #include "base/strings/utf_string_conversions.h"
  #include "base/threading/thread_task_runner_handle.h"
  #include "base/win/async_operation.h"
  #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
  #include "device/bluetooth/test/fake_bluetooth_le_device_winrt.h"
  #include "device/bluetooth/test/fake_gatt_characteristic_winrt.h"
  #include "device/bluetooth/test/fake_gatt_characteristics_result_winrt.h"
  
  namespace device {
  
  namespace {
  
  using ABI::Windows::Devices::Bluetooth::BluetoothCacheMode;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattCharacteristic;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattCharacteristicsResult;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattDeviceService;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattDeviceServicesResult;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattOpenStatus;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattOpenStatus_AccessDenied;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattOpenStatus_AlreadyOpened;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattOpenStatus_Success;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattSharingMode;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
      GattSharingMode_SharedReadAndWrite;
  using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession;
  using ABI::Windows::Devices::Enumeration::DeviceAccessStatus;
  using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation;
  using ABI::Windows::Foundation::IAsyncOperation;
  using ABI::Windows::Foundation::Collections::IVectorView;
  using Microsoft::WRL::ComPtr;
  using Microsoft::WRL::Make;
  
  }  // namespace
  
  FakeGattDeviceServiceWinrt::FakeGattDeviceServiceWinrt(
      BluetoothTestWinrt* bluetooth_test_winrt,
      ComPtr<FakeBluetoothLEDeviceWinrt> fake_device,
      base::StringPiece uuid,
      uint16_t attribute_handle,
      bool allowed)
      : bluetooth_test_winrt_(bluetooth_test_winrt),
        fake_device_(std::move(fake_device)),
        uuid_(BluetoothUUID::GetCanonicalValueAsGUID(uuid)),
        attribute_handle_(attribute_handle),
        allowed_(allowed),
        characteristic_attribute_handle_(attribute_handle_) {
    fake_device_->AddReference();
  }
  
  FakeGattDeviceServiceWinrt::~FakeGattDeviceServiceWinrt() {
    fake_device_->RemoveReference();
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetCharacteristics(
      GUID characteristic_uuid,
      IVectorView<GattCharacteristic*>** value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetIncludedServices(
      GUID service_uuid,
      IVectorView<GattDeviceService*>** value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_DeviceId(HSTRING* value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_Uuid(GUID* value) {
    *value = uuid_;
    return S_OK;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_AttributeHandle(uint16_t* value) {
    *value = attribute_handle_;
    return S_OK;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_DeviceAccessInformation(
      IDeviceAccessInformation** value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_Session(IGattSession** value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::get_SharingMode(GattSharingMode* value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::RequestAccessAsync(
      IAsyncOperation<DeviceAccessStatus>** value) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::OpenAsync(
      GattSharingMode sharing_mode,
      IAsyncOperation<GattOpenStatus>** operation) {
    if (sharing_mode != GattSharingMode_SharedReadAndWrite)
      return E_NOTIMPL;
  
    GattOpenStatus status;
    if (allowed_) {
      status = opened_ ? GattOpenStatus_AlreadyOpened : GattOpenStatus_Success;
      opened_ = true;
    } else {
      status = GattOpenStatus_AccessDenied;
    }
  
    auto async_op = Make<base::win::AsyncOperation<GattOpenStatus>>();
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::BindOnce(async_op->callback(), status));
    *operation = async_op.Detach();
    return S_OK;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetCharacteristicsAsync(
      IAsyncOperation<GattCharacteristicsResult*>** operation) {
    // It has been observed that this method will implicitly call
    // OpenAsync(Exclusive) if the service has not been opened already. Catch
    // calls to an unopened service as we do not want to take an exclusive lock
    // on a service.
    if (!opened_)
      return E_NOTIMPL;
  
    auto async_op = Make<base::win::AsyncOperation<GattCharacteristicsResult*>>();
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::BindOnce(async_op->callback(),
                                  Make<FakeGattCharacteristicsResultWinrt>(
                                      fake_characteristics_)));
    *operation = async_op.Detach();
    return S_OK;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetCharacteristicsWithCacheModeAsync(
      BluetoothCacheMode cache_mode,
      IAsyncOperation<GattCharacteristicsResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetCharacteristicsForUuidAsync(
      GUID characteristic_uuid,
      IAsyncOperation<GattCharacteristicsResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetCharacteristicsForUuidWithCacheModeAsync(
      GUID characteristic_uuid,
      BluetoothCacheMode cache_mode,
      IAsyncOperation<GattCharacteristicsResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetIncludedServicesAsync(
      IAsyncOperation<GattDeviceServicesResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetIncludedServicesWithCacheModeAsync(
      BluetoothCacheMode cache_mode,
      IAsyncOperation<GattDeviceServicesResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT FakeGattDeviceServiceWinrt::GetIncludedServicesForUuidAsync(
      GUID service_uuid,
      IAsyncOperation<GattDeviceServicesResult*>** operation) {
    return E_NOTIMPL;
  }
  
  HRESULT
  FakeGattDeviceServiceWinrt::GetIncludedServicesForUuidWithCacheModeAsync(
      GUID service_uuid,
      BluetoothCacheMode cache_mode,
      IAsyncOperation<GattDeviceServicesResult*>** operation) {
    return E_NOTIMPL;
  }
  
  void FakeGattDeviceServiceWinrt::SimulateGattCharacteristic(
      base::StringPiece uuid,
      int properties) {
    // 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
  