Commit ce8d3b30 authored by Jan Wilken Doerrie's avatar Jan Wilken Doerrie Committed by Commit Bot

[bluetooth] Implement GATT Connections for WinRT

This change implements initiating GATT connections for WinRT. While
currently no GATT discovery is attempted, this will be provided in a
future CL. GATT connections are created by obtaining an instance of
BluetoothLEDevice.

Bug: 821766
Change-Id: I7f20127a84b781859300af18b31da0e9ee24a32b
Reviewed-on: https://chromium-review.googlesource.com/1090217
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571156}
parent 3c41dd4c
......@@ -390,7 +390,7 @@ void BluetoothAdapterWinrt::AddDiscoverySession(
ble_advertisement_watcher_.Get(),
&IBluetoothLEAdvertisementWatcher::add_Received,
base::BindRepeating(&BluetoothAdapterWinrt::OnAdvertisementReceived,
base::Unretained(this)));
weak_ptr_factory_.GetWeakPtr()));
if (!advertisement_received_token) {
ui_task_runner_->PostTask(
FROM_HERE,
......@@ -528,6 +528,13 @@ BluetoothAdapterWinrt::ActivateBluetoothAdvertisementLEWatcherInstance(
return watcher.CopyTo(instance);
}
std::unique_ptr<BluetoothDeviceWinrt> BluetoothAdapterWinrt::CreateDevice(
uint64_t raw_address,
base::Optional<std::string> local_name) {
return std::make_unique<BluetoothDeviceWinrt>(this, raw_address,
std::move(local_name));
}
void BluetoothAdapterWinrt::OnGetDefaultAdapter(
base::ScopedClosureRunner on_init,
ComPtr<IBluetoothAdapter> adapter) {
......@@ -703,8 +710,7 @@ void BluetoothAdapterWinrt::OnAdvertisementReceived(
bool was_inserted = false;
std::tie(it, was_inserted) = devices_.emplace(
std::move(bluetooth_address),
std::make_unique<BluetoothDeviceWinrt>(this, raw_bluetooth_address,
GetDeviceName(received)));
CreateDevice(raw_bluetooth_address, GetDeviceName(received)));
DCHECK(was_inserted);
}
......
......@@ -25,6 +25,8 @@ class ScopedClosureRunner;
namespace device {
class BluetoothDeviceWinrt;
class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
public:
// BluetoothAdapter:
......@@ -61,7 +63,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
protected:
friend class BluetoothAdapterWin;
friend class BluetoothTestWin;
friend class BluetoothTestWinrt;
BluetoothAdapterWinrt();
~BluetoothAdapterWinrt() override;
......@@ -100,6 +102,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
virtual HRESULT ActivateBluetoothAdvertisementLEWatcherInstance(
ABI::Windows::Devices::Bluetooth::Advertisement::
IBluetoothLEAdvertisementWatcher** instance) const;
virtual std::unique_ptr<BluetoothDeviceWinrt> CreateDevice(
uint64_t raw_address,
base::Optional<std::string> local_name);
private:
void OnGetDefaultAdapter(
......
......@@ -593,6 +593,17 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDevice {
FRIEND_TEST_ALL_PREFIXES(BluetoothTest, RemoveOutdatedDevices);
FRIEND_TEST_ALL_PREFIXES(BluetoothTest, RemoveOutdatedDeviceGattConnect);
FRIEND_TEST_ALL_PREFIXES(
BluetoothTestWinrtOnly,
BluetoothGattConnection_DisconnectGatt_SimulateConnect);
FRIEND_TEST_ALL_PREFIXES(
BluetoothTestWinrtOnly,
BluetoothGattConnection_DisconnectGatt_SimulateDisconnect);
FRIEND_TEST_ALL_PREFIXES(BluetoothTestWinrtOnly,
BluetoothGattConnection_ErrorAfterConnection);
FRIEND_TEST_ALL_PREFIXES(BluetoothTestWinrtOnly,
BluetoothGattConnection_DisconnectGatt_Cleanup);
// Helper class to easily update the sets of UUIDs and keep them in sync with
// the set of all the device's UUIDs.
class DeviceUUIDs {
......
......@@ -905,7 +905,11 @@ TEST_F(BluetoothTest, MAYBE_GetName_NullName) {
#define MAYBE_CreateGattConnection DISABLED_CreateGattConnection
#endif
// Basic CreateGattConnection test.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, CreateGattConnection) {
#else
TEST_F(BluetoothTest, MAYBE_CreateGattConnection) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -932,7 +936,11 @@ TEST_F(BluetoothTest, MAYBE_CreateGattConnection) {
#define MAYBE_DisconnectionNotifiesDeviceChanged \
DISABLED_DisconnectionNotifiesDeviceChanged
#endif
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, DisconnectionNotifiesDeviceChanged) {
#else
TEST_F(BluetoothTest, MAYBE_DisconnectionNotifiesDeviceChanged) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -964,7 +972,11 @@ TEST_F(BluetoothTest, MAYBE_DisconnectionNotifiesDeviceChanged) {
#endif
// Creates BluetoothGattConnection instances and tests that the interface
// functions even when some Disconnect and the BluetoothDevice is destroyed.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, BluetoothGattConnection) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -978,6 +990,7 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection) {
ResetEventCounts();
device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
GetConnectErrorCallback(Call::NOT_EXPECTED));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, gatt_connection_attempts_);
SimulateGattConnection(device);
......@@ -1085,7 +1098,11 @@ TEST_F(BluetoothTest,
DISABLED_BluetoothGattConnection_AlreadyConnected
#endif
// Calls CreateGattConnection after already connected.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, BluetoothGattConnection_AlreadyConnected) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_AlreadyConnected) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1117,8 +1134,13 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_AlreadyConnected) {
DISABLED_BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected
#endif
// Creates BluetoothGattConnection after one exists that has disconnected.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly,
BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected) {
#else
TEST_F(BluetoothTest,
MAYBE_BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1158,8 +1180,13 @@ TEST_F(BluetoothTest,
DISABLED_BluetoothGattConnection_DisconnectWhenObjectsDestroyed
#endif
// Deletes BluetoothGattConnection causing disconnection.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly,
BluetoothGattConnection_DisconnectWhenObjectsDestroyed) {
#else
TEST_F(BluetoothTest,
MAYBE_BluetoothGattConnection_DisconnectWhenObjectsDestroyed) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1190,7 +1217,11 @@ TEST_F(BluetoothTest,
DISABLED_BluetoothGattConnection_DisconnectInProgress
#endif
// Starts process of disconnecting and then calls BluetoothGattConnection.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, BluetoothGattConnection_DisconnectInProgress) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_DisconnectInProgress) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1239,7 +1270,11 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_DisconnectInProgress) {
#endif
// Calls CreateGattConnection but receives notice that the device disconnected
// before it ever connects.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, BluetoothGattConnection_SimulateDisconnect) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_SimulateDisconnect) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1251,6 +1286,7 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_SimulateDisconnect) {
ResetEventCounts();
device->CreateGattConnection(GetGattConnectionCallback(Call::NOT_EXPECTED),
GetConnectErrorCallback(Call::EXPECTED));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, gatt_connection_attempts_);
SimulateGattDisconnection(device);
base::RunLoop().RunUntilIdle();
......@@ -1267,8 +1303,13 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_SimulateDisconnect) {
DISABLED_BluetoothGattConnection_DisconnectGatt_SimulateConnect
#endif
// Calls CreateGattConnection & DisconnectGatt, then simulates connection.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly,
BluetoothGattConnection_DisconnectGatt_SimulateConnect) {
#else
TEST_F(BluetoothTest,
MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateConnect) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1280,9 +1321,14 @@ TEST_F(BluetoothTest,
ResetEventCounts();
device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
GetConnectErrorCallback(Call::NOT_EXPECTED));
device->DisconnectGatt();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, gatt_connection_attempts_);
#if !defined(OS_WIN)
// On Windows there is currently no way to cancel a pending GATT connection
// from the callers site.
device->DisconnectGatt();
EXPECT_EQ(1, gatt_disconnection_attempts_);
#endif
SimulateGattConnection(device);
base::RunLoop().RunUntilIdle();
......@@ -1398,7 +1444,11 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_DisconnectGatt_Cleanup) {
#endif
// Calls CreateGattConnection, but simulate errors connecting. Also, verifies
// multiple errors should only invoke callbacks once.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrtOnly, BluetoothGattConnection_ErrorAfterConnection) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_ErrorAfterConnection) {
#endif
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
......@@ -1410,15 +1460,17 @@ TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_ErrorAfterConnection) {
ResetEventCounts();
device->CreateGattConnection(GetGattConnectionCallback(Call::NOT_EXPECTED),
GetConnectErrorCallback(Call::EXPECTED));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, gatt_connection_attempts_);
SimulateGattConnectionError(device, BluetoothDevice::ERROR_AUTH_FAILED);
SimulateGattConnectionError(device, BluetoothDevice::ERROR_FAILED);
base::RunLoop().RunUntilIdle();
#if defined(OS_ANDROID)
#if defined(OS_ANDROID) || defined(OS_WIN)
// TODO: Change to ERROR_AUTH_FAILED. We should be getting a callback
// only with the first error, but our android framework doesn't yet
// support sending different errors.
// http://crbug.com/578191
// On Windows, any GattConnectioError will result in ERROR_FAILED.
EXPECT_EQ(BluetoothDevice::ERROR_FAILED, last_connect_error_code_);
#else
EXPECT_EQ(BluetoothDevice::ERROR_AUTH_FAILED, last_connect_error_code_);
......
......@@ -4,22 +4,89 @@
#include "device/bluetooth/bluetooth_device_winrt.h"
#include <windows.foundation.h>
#include <wrl/event.h>
#include <utility>
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/core_winrt_util.h"
#include "base/win/scoped_hstring.h"
#include "device/bluetooth/bluetooth_adapter_winrt.h"
#include "device/bluetooth/event_utils_winrt.h"
namespace device {
BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
uint64_t raw_address,
base::Optional<std::string> name)
namespace {
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Connected;
using ABI::Windows::Devices::Bluetooth::BluetoothLEDevice;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IClosable;
using Microsoft::WRL::ComPtr;
void CloseDevice(ComPtr<IBluetoothLEDevice> ble_device) {
if (!ble_device)
return;
ComPtr<IClosable> closable;
HRESULT hr = ble_device.As(&closable);
if (FAILED(hr)) {
VLOG(2) << "As IClosable failed: " << logging::SystemErrorCodeToString(hr);
return;
}
hr = closable->Close();
if (FAILED(hr)) {
VLOG(2) << "IClosable::close() failed: "
<< logging::SystemErrorCodeToString(hr);
}
}
void RemoveConnectionStatusHandler(IBluetoothLEDevice* ble_device,
EventRegistrationToken token) {
HRESULT hr = ble_device->remove_ConnectionStatusChanged(token);
if (FAILED(hr)) {
VLOG(2) << "Removing ConnectionStatus Handler failed: "
<< logging::SystemErrorCodeToString(hr);
}
}
} // namespace
BluetoothDeviceWinrt::BluetoothDeviceWinrt(
BluetoothAdapterWinrt* adapter,
uint64_t raw_address,
base::Optional<std::string> local_name)
: BluetoothDevice(adapter),
raw_address_(raw_address),
address_(CanonicalizeAddress(raw_address)),
name_(std::move(name)) {}
local_name_(std::move(local_name)),
weak_ptr_factory_(this) {}
BluetoothDeviceWinrt::~BluetoothDeviceWinrt() = default;
BluetoothDeviceWinrt::~BluetoothDeviceWinrt() {
CloseDevice(ble_device_);
if (!connection_changed_token_)
return;
RemoveConnectionStatusHandler(ble_device_.Get(), *connection_changed_token_);
}
uint32_t BluetoothDeviceWinrt::GetBluetoothClass() const {
NOTIMPLEMENTED();
......@@ -57,7 +124,17 @@ uint16_t BluetoothDeviceWinrt::GetAppearance() const {
}
base::Optional<std::string> BluetoothDeviceWinrt::GetName() const {
return name_;
if (!ble_device_)
return local_name_;
HSTRING name;
HRESULT hr = ble_device_->get_Name(&name);
if (FAILED(hr)) {
VLOG(2) << "Getting Name failed: " << logging::SystemErrorCodeToString(hr);
return local_name_;
}
return base::win::ScopedHString(name).GetAsUTF8();
}
bool BluetoothDeviceWinrt::IsPaired() const {
......@@ -66,13 +143,22 @@ bool BluetoothDeviceWinrt::IsPaired() const {
}
bool BluetoothDeviceWinrt::IsConnected() const {
NOTIMPLEMENTED();
return false;
return IsGattConnected();
}
bool BluetoothDeviceWinrt::IsGattConnected() const {
NOTIMPLEMENTED();
return false;
if (!ble_device_)
return false;
BluetoothConnectionStatus status;
HRESULT hr = ble_device_->get_ConnectionStatus(&status);
if (FAILED(hr)) {
VLOG(2) << "Getting ConnectionStatus failed: "
<< logging::SystemErrorCodeToString(hr);
return false;
}
return status == BluetoothConnectionStatus_Connected;
}
bool BluetoothDeviceWinrt::IsConnectable() const {
......@@ -171,11 +257,139 @@ std::string BluetoothDeviceWinrt::CanonicalizeAddress(uint64_t address) {
}
void BluetoothDeviceWinrt::CreateGattConnectionImpl() {
NOTIMPLEMENTED();
ComPtr<IBluetoothLEDeviceStatics> device_statics;
HRESULT hr = GetBluetoothLEDeviceStaticsActivationFactory(&device_statics);
if (FAILED(hr)) {
VLOG(2) << "GetBluetoothLEDeviceStaticsActivationFactory failed: "
<< logging::SystemErrorCodeToString(hr);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
weak_ptr_factory_.GetWeakPtr(),
ConnectErrorCode::ERROR_FAILED));
return;
}
// Note: Even though we might have obtained a BluetoothLEDevice instance in
// the past, we need to request a new instance as the old device might have
// been closed. See also
// https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client#connecting-to-the-device
ComPtr<IAsyncOperation<BluetoothLEDevice*>> from_bluetooth_address_op;
hr = device_statics->FromBluetoothAddressAsync(raw_address_,
&from_bluetooth_address_op);
if (FAILED(hr)) {
VLOG(2) << "BluetoothLEDevice::FromBluetoothAddressAsync failed: "
<< logging::SystemErrorCodeToString(hr);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
weak_ptr_factory_.GetWeakPtr(),
ConnectErrorCode::ERROR_FAILED));
return;
}
hr = PostAsyncResults(
std::move(from_bluetooth_address_op),
base::BindOnce(&BluetoothDeviceWinrt::OnFromBluetoothAddress,
weak_ptr_factory_.GetWeakPtr()));
if (FAILED(hr)) {
VLOG(2) << "PostAsyncResults failed: "
<< logging::SystemErrorCodeToString(hr);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
weak_ptr_factory_.GetWeakPtr(),
ConnectErrorCode::ERROR_FAILED));
}
}
void BluetoothDeviceWinrt::DisconnectGatt() {
NOTIMPLEMENTED();
CloseDevice(ble_device_);
}
HRESULT BluetoothDeviceWinrt::GetBluetoothLEDeviceStaticsActivationFactory(
IBluetoothLEDeviceStatics** statics) const {
return base::win::GetActivationFactory<
IBluetoothLEDeviceStatics,
RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice>(statics);
}
void BluetoothDeviceWinrt::OnFromBluetoothAddress(
ComPtr<IBluetoothLEDevice> ble_device) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!ble_device) {
VLOG(2) << "Getting Device From Bluetooth Address failed.";
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
return;
}
if (connection_changed_token_) {
// As we are about to replace |ble_device_| with |ble_device| we will also
// unregister the existing event handler and add a new one to the new
// device.
RemoveConnectionStatusHandler(ble_device_.Get(),
*connection_changed_token_);
}
ble_device_ = std::move(ble_device);
connection_changed_token_ = AddTypedEventHandler(
ble_device_.Get(), &IBluetoothLEDevice::add_ConnectionStatusChanged,
base::BindRepeating(&BluetoothDeviceWinrt::OnConnectionStatusChanged,
weak_ptr_factory_.GetWeakPtr()));
ComPtr<IBluetoothLEDevice3> ble_device_3;
HRESULT hr = ble_device_.As(&ble_device_3);
if (FAILED(hr)) {
VLOG(2) << "Obtaining IBluetoothLEDevice3 failed: "
<< logging::SystemErrorCodeToString(hr);
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
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);
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
return;
}
hr = PostAsyncResults(std::move(get_gatt_services_op),
base::BindOnce(&BluetoothDeviceWinrt::OnGetGattServices,
weak_ptr_factory_.GetWeakPtr()));
if (FAILED(hr)) {
VLOG(2) << "PostAsyncResults failed: "
<< logging::SystemErrorCodeToString(hr);
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
}
}
void BluetoothDeviceWinrt::OnConnectionStatusChanged(
IBluetoothLEDevice* ble_device,
IInspectable* object) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
IsGattConnected() ? DidConnectGatt() : DidDisconnectGatt();
}
void BluetoothDeviceWinrt::OnGetGattServices(
ComPtr<IGattDeviceServicesResult> result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!result)
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
GattCommunicationStatus status;
HRESULT hr = result->get_Status(&status);
if (FAILED(hr)) {
VLOG(2) << "GattDeviceServicesResult::get_Status() failed: "
<< logging::SystemErrorCodeToString(hr);
return;
}
if (status != GattCommunicationStatus_Success)
DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
// In case of success a gatt connection is established and an invocation
// of OnConnectionStatusChanged() is expected.
}
} // namespace device
......@@ -5,13 +5,18 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_
#include <windows.devices.bluetooth.h>
#include <wrl/client.h>
#include <stdint.h>
#include <string>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_export.h"
......@@ -23,7 +28,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
public:
BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
uint64_t raw_address,
base::Optional<std::string> name);
base::Optional<std::string> local_name);
~BluetoothDeviceWinrt() override;
// BluetoothDevice:
......@@ -77,9 +82,39 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
void CreateGattConnectionImpl() override;
void DisconnectGatt() override;
// This is declared virtual so that they can be overridden by tests.
virtual HRESULT GetBluetoothLEDeviceStaticsActivationFactory(
ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics** statics)
const;
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice>
ble_device_;
private:
void OnFromBluetoothAddress(
Microsoft::WRL::ComPtr<
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> ble_device);
void OnConnectionStatusChanged(
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice* ble_device,
IInspectable* object);
void OnGetGattServices(
Microsoft::WRL::ComPtr<
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult> result);
uint64_t raw_address_;
std::string address_;
base::Optional<std::string> name_;
base::Optional<std::string> local_name_;
base::Optional<EventRegistrationToken> connection_changed_token_;
THREAD_CHECKER(thread_checker_);
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<BluetoothDeviceWinrt> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceWinrt);
};
......
This diff is collapsed.
......@@ -117,8 +117,21 @@ class BluetoothTestWinrt : public BluetoothTestWin,
BluetoothTestWinrt();
~BluetoothTestWinrt() override;
// BluetoothTestBase:
bool PlatformSupportsLowEnergy() override;
void InitWithDefaultAdapter() override;
void InitWithoutDefaultAdapter() override;
void InitWithFakeAdapter() override;
BluetoothDevice* SimulateLowEnergyDevice(int device_ordinal) override;
void SimulateGattConnection(BluetoothDevice* device) override;
void SimulateGattConnectionError(
BluetoothDevice* device,
BluetoothDevice::ConnectErrorCode error_code) override;
void SimulateGattDisconnection(BluetoothDevice* device) override;
void DeleteDevice(BluetoothDevice* device) override;
void OnFakeBluetoothDeviceConnectGattCalled();
void OnFakeBluetoothGattDisconnect();
private:
base::test::ScopedFeatureList scoped_feature_list_;
......
......@@ -4,28 +4,55 @@
#include "device/bluetooth/test/fake_bluetooth_le_device_winrt.h"
#include <wrl/client.h>
#include <utility>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/async_operation.h"
#include "device/bluetooth/test/bluetooth_test_win.h"
#include "device/bluetooth/test/fake_gatt_device_services_result_winrt.h"
namespace device {
namespace {
using ABI::Windows::Devices::Bluetooth::BluetoothCacheMode;
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Connected;
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Disconnected;
using ABI::Windows::Devices::Bluetooth::BluetoothLEDevice;
using ABI::Windows::Devices::Enumeration::DeviceAccessStatus;
using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_AccessDenied;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_ProtocolError;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus_Unreachable;
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::Enumeration::DeviceAccessStatus;
using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation;
using ABI::Windows::Foundation::Collections::IVectorView;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::ITypedEventHandler;
using Microsoft::WRL::Make;
} // namespace
FakeBluetoothLEDeviceWinrt::FakeBluetoothLEDeviceWinrt() = default;
FakeBluetoothLEDeviceWinrt::FakeBluetoothLEDeviceWinrt(
BluetoothTestWinrt* bluetooth_test_winrt)
: bluetooth_test_winrt_(bluetooth_test_winrt) {}
FakeBluetoothLEDeviceWinrt::~FakeBluetoothLEDeviceWinrt() = default;
......@@ -44,7 +71,8 @@ HRESULT FakeBluetoothLEDeviceWinrt::get_GattServices(
HRESULT FakeBluetoothLEDeviceWinrt::get_ConnectionStatus(
BluetoothConnectionStatus* value) {
return E_NOTIMPL;
*value = status_;
return S_OK;
}
HRESULT FakeBluetoothLEDeviceWinrt::get_BluetoothAddress(uint64_t* value) {
......@@ -82,12 +110,14 @@ HRESULT FakeBluetoothLEDeviceWinrt::remove_GattServicesChanged(
HRESULT FakeBluetoothLEDeviceWinrt::add_ConnectionStatusChanged(
ITypedEventHandler<BluetoothLEDevice*, IInspectable*>* handler,
EventRegistrationToken* token) {
return E_NOTIMPL;
handler_ = handler;
return S_OK;
}
HRESULT FakeBluetoothLEDeviceWinrt::remove_ConnectionStatusChanged(
EventRegistrationToken token) {
return E_NOTIMPL;
handler_ = nullptr;
return S_OK;
}
HRESULT FakeBluetoothLEDeviceWinrt::get_DeviceAccessInformation(
......@@ -102,7 +132,11 @@ HRESULT FakeBluetoothLEDeviceWinrt::RequestAccessAsync(
HRESULT FakeBluetoothLEDeviceWinrt::GetGattServicesAsync(
IAsyncOperation<GattDeviceServicesResult*>** operation) {
return E_NOTIMPL;
auto async_op = Make<base::win::AsyncOperation<GattDeviceServicesResult*>>();
gatt_services_callback_ = async_op->callback();
*operation = async_op.Detach();
bluetooth_test_winrt_->OnFakeBluetoothDeviceConnectGattCalled();
return S_OK;
}
HRESULT FakeBluetoothLEDeviceWinrt::GetGattServicesWithCacheModeAsync(
......@@ -124,8 +158,47 @@ HRESULT FakeBluetoothLEDeviceWinrt::GetGattServicesForUuidWithCacheModeAsync(
return E_NOTIMPL;
}
FakeBluetoothLEDeviceStaticsWinrt::FakeBluetoothLEDeviceStaticsWinrt() =
default;
HRESULT FakeBluetoothLEDeviceWinrt::Close() {
bluetooth_test_winrt_->OnFakeBluetoothGattDisconnect();
return S_OK;
}
void FakeBluetoothLEDeviceWinrt::SimulateGattConnection() {
if (gatt_services_callback_) {
std::move(gatt_services_callback_)
.Run(Make<FakeGattDeviceServicesResultWinrt>(
GattCommunicationStatus_Success));
}
status_ = BluetoothConnectionStatus_Connected;
handler_->Invoke(this, nullptr);
}
void FakeBluetoothLEDeviceWinrt ::SimulateGattConnectionError(
BluetoothDevice::ConnectErrorCode error_code) {
if (!gatt_services_callback_)
return;
std::move(gatt_services_callback_)
.Run(Make<FakeGattDeviceServicesResultWinrt>(
GattCommunicationStatus_ProtocolError));
}
void FakeBluetoothLEDeviceWinrt::SimulateGattDisconnection() {
if (gatt_services_callback_) {
std::move(gatt_services_callback_)
.Run(Make<FakeGattDeviceServicesResultWinrt>(
GattCommunicationStatus_Unreachable));
return;
}
status_ = BluetoothConnectionStatus_Disconnected;
handler_->Invoke(this, nullptr);
}
FakeBluetoothLEDeviceStaticsWinrt::FakeBluetoothLEDeviceStaticsWinrt(
BluetoothTestWinrt* bluetooth_test_winrt)
: bluetooth_test_winrt_(bluetooth_test_winrt) {}
FakeBluetoothLEDeviceStaticsWinrt::~FakeBluetoothLEDeviceStaticsWinrt() =
default;
......@@ -139,7 +212,13 @@ HRESULT FakeBluetoothLEDeviceStaticsWinrt::FromIdAsync(
HRESULT FakeBluetoothLEDeviceStaticsWinrt::FromBluetoothAddressAsync(
uint64_t bluetooth_address,
IAsyncOperation<BluetoothLEDevice*>** operation) {
return E_NOTIMPL;
auto async_op = Make<base::win::AsyncOperation<BluetoothLEDevice*>>();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(async_op->callback(),
Make<FakeBluetoothLEDeviceWinrt>(bluetooth_test_winrt_)));
*operation = async_op.Detach();
return S_OK;
}
HRESULT FakeBluetoothLEDeviceStaticsWinrt::GetDeviceSelector(
......
......@@ -11,18 +11,23 @@
#include <stdint.h>
#include "base/callback.h"
#include "base/macros.h"
#include "device/bluetooth/bluetooth_device.h"
namespace device {
class BluetoothTestWinrt;
class FakeBluetoothLEDeviceWinrt
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice,
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3> {
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3,
ABI::Windows::Foundation::IClosable> {
public:
FakeBluetoothLEDeviceWinrt();
explicit FakeBluetoothLEDeviceWinrt(BluetoothTestWinrt* bluetooth_test_winrt);
~FakeBluetoothLEDeviceWinrt() override;
// IBluetoothLEDevice:
......@@ -90,7 +95,31 @@ class FakeBluetoothLEDeviceWinrt
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceServicesResult*>** operation) override;
// IClosable:
IFACEMETHODIMP Close() override;
void SimulateGattConnection();
void SimulateGattConnectionError(
BluetoothDevice::ConnectErrorCode error_code);
void SimulateGattDisconnection();
private:
BluetoothTestWinrt* bluetooth_test_winrt_ = nullptr;
ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus status_ =
ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Connected;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::ITypedEventHandler<
ABI::Windows::Devices::Bluetooth::BluetoothLEDevice*,
IInspectable*>>
handler_;
base::OnceCallback<void(
Microsoft::WRL::ComPtr<
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult>)>
gatt_services_callback_;
DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEDeviceWinrt);
};
......@@ -100,7 +129,8 @@ class FakeBluetoothLEDeviceStaticsWinrt
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics> {
public:
FakeBluetoothLEDeviceStaticsWinrt();
explicit FakeBluetoothLEDeviceStaticsWinrt(
BluetoothTestWinrt* bluetooth_test_winrt);
~FakeBluetoothLEDeviceStaticsWinrt() override;
// IBluetoothLEDeviceStatics:
......@@ -117,6 +147,8 @@ class FakeBluetoothLEDeviceStaticsWinrt
IFACEMETHODIMP GetDeviceSelector(HSTRING* device_selector) override;
private:
BluetoothTestWinrt* bluetooth_test_winrt_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEDeviceStaticsWinrt);
};
......
......@@ -17,15 +17,18 @@ using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
} // namespace
FakeGattDeviceServicesResultWinrt::FakeGattDeviceServicesResultWinrt() =
default;
FakeGattDeviceServicesResultWinrt::FakeGattDeviceServicesResultWinrt(
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus status)
: status_(status) {}
FakeGattDeviceServicesResultWinrt::~FakeGattDeviceServicesResultWinrt() =
default;
HRESULT FakeGattDeviceServicesResultWinrt::get_Status(
GattCommunicationStatus* value) {
return E_NOTIMPL;
*value = status_;
return S_OK;
}
HRESULT FakeGattDeviceServicesResultWinrt::get_ProtocolError(
......
......@@ -23,7 +23,9 @@ class FakeGattDeviceServicesResultWinrt
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
IGattDeviceServicesResult> {
public:
FakeGattDeviceServicesResultWinrt();
explicit FakeGattDeviceServicesResultWinrt(
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus status);
~FakeGattDeviceServicesResultWinrt() override;
// IGattDeviceServicesResult:
......@@ -38,6 +40,9 @@ class FakeGattDeviceServicesResultWinrt
GattDeviceService*>** value) override;
private:
ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCommunicationStatus status_;
DISALLOW_COPY_AND_ASSIGN(FakeGattDeviceServicesResultWinrt);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment