blob: aacaf680a627fb9cf2e2a0b5f6e5bb1b16a17691 [file] [log] [blame]
// 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/bluetooth_gatt_discoverer_winrt.h"
#include <windows.foundation.collections.h>
#include <utility>
#include "base/logging.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
#include "device/bluetooth/event_utils_winrt.h"
namespace device {
namespace {
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceService;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceService;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::Collections::IVectorView;
using Microsoft::WRL::ComPtr;
} // namespace
BluetoothGattDiscovererWinrt::BluetoothGattDiscovererWinrt(
ComPtr<IBluetoothLEDevice> ble_device)
: ble_device_(std::move(ble_device)), weak_ptr_factory_(this) {}
BluetoothGattDiscovererWinrt::~BluetoothGattDiscovererWinrt() = default;
void BluetoothGattDiscovererWinrt::StartGattDiscovery(
GattDiscoveryCallback callback) {
callback_ = std::move(callback);
ComPtr<IBluetoothLEDevice3> ble_device_3;
HRESULT hr = ble_device_.As(&ble_device_3);
if (FAILED(hr)) {
VLOG(2) << "Obtaining IBluetoothLEDevice3 failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
ComPtr<IAsyncOperation<GattDeviceServicesResult*>> get_gatt_services_op;
hr = ble_device_3->GetGattServicesAsync(&get_gatt_services_op);
if (FAILED(hr)) {
VLOG(2) << "BluetoothLEDevice::GetGattServicesAsync failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
hr = PostAsyncResults(
std::move(get_gatt_services_op),
base::BindOnce(&BluetoothGattDiscovererWinrt::OnGetGattServices,
weak_ptr_factory_.GetWeakPtr()));
if (FAILED(hr)) {
VLOG(2) << "PostAsyncResults failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
}
}
const BluetoothGattDiscovererWinrt::GattServiceList&
BluetoothGattDiscovererWinrt::GetGattServices() const {
return gatt_services_;
}
void BluetoothGattDiscovererWinrt::OnGetGattServices(
ComPtr<IGattDeviceServicesResult> services_result) {
if (!services_result) {
VLOG(2) << "Getting GATT Services failed.";
std::move(callback_).Run(false);
return;
}
GattCommunicationStatus status;
HRESULT hr = services_result->get_Status(&status);
if (FAILED(hr)) {
VLOG(2) << "Getting GATT Communication Status failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
if (status != GattCommunicationStatus_Success) {
VLOG(2) << "Unexpected GattCommunicationStatus: " << status;
// TODO(https://crbug.com/821766): Obtain and log the protocol error if
// appropriate. Mention BT spec Version 5.0 Vol 3, Part F, 3.4.1.1 "Error
// Response".
std::move(callback_).Run(false);
return;
}
ComPtr<IVectorView<GattDeviceService*>> services;
hr = services_result->get_Services(&services);
if (FAILED(hr)) {
VLOG(2) << "Getting GATT Services failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
unsigned size;
hr = services->get_Size(&size);
if (FAILED(hr)) {
VLOG(2) << "Getting Size of GATT Services failed: "
<< logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
for (unsigned i = 0; i < size; ++i) {
ComPtr<IGattDeviceService> service;
hr = services->GetAt(i, &service);
if (FAILED(hr)) {
VLOG(2) << "GetAt(" << i
<< ") failed: " << logging::SystemErrorCodeToString(hr);
std::move(callback_).Run(false);
return;
}
gatt_services_.push_back(std::move(service));
}
std::move(callback_).Run(true);
}
} // namespace device