blob: c8fba1cd1d1dae8c51b1f95d4deaf4c539caeaea [file] [log] [blame]
// Copyright 2017 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_remote_gatt_characteristic.h"
#include <utility>
#include <vector>
#include "base/optional.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
#include "device/bluetooth/test/fake_read_response.h"
namespace bluetooth {
FakeRemoteGattCharacteristic::FakeRemoteGattCharacteristic(
const std::string& characteristic_id,
const device::BluetoothUUID& characteristic_uuid,
mojom::CharacteristicPropertiesPtr properties,
device::BluetoothRemoteGattService* service)
: characteristic_id_(characteristic_id),
characteristic_uuid_(characteristic_uuid),
service_(service),
weak_ptr_factory_(this) {
properties_ = PROPERTY_NONE;
if (properties->broadcast)
properties_ |= PROPERTY_BROADCAST;
if (properties->read)
properties_ |= PROPERTY_READ;
if (properties->write_without_response)
properties_ |= PROPERTY_WRITE_WITHOUT_RESPONSE;
if (properties->write)
properties_ |= PROPERTY_WRITE;
if (properties->notify)
properties_ |= PROPERTY_NOTIFY;
if (properties->indicate)
properties_ |= PROPERTY_INDICATE;
if (properties->authenticated_signed_writes)
properties_ |= PROPERTY_AUTHENTICATED_SIGNED_WRITES;
if (properties->extended_properties)
properties_ |= PROPERTY_EXTENDED_PROPERTIES;
}
FakeRemoteGattCharacteristic::~FakeRemoteGattCharacteristic() = default;
std::string FakeRemoteGattCharacteristic::AddFakeDescriptor(
const device::BluetoothUUID& descriptor_uuid) {
FakeDescriptorMap::iterator it;
bool inserted;
// Attribute instance Ids need to be unique.
std::string new_descriptor_id = base::StringPrintf(
"%s_%zu", GetIdentifier().c_str(), ++last_descriptor_id_);
std::tie(it, inserted) = fake_descriptors_.emplace(
new_descriptor_id, std::make_unique<FakeRemoteGattDescriptor>(
new_descriptor_id, descriptor_uuid, this));
DCHECK(inserted);
return it->second->GetIdentifier();
}
void FakeRemoteGattCharacteristic::SetNextReadResponse(
uint16_t gatt_code,
const base::Optional<std::vector<uint8_t>>& value) {
DCHECK(!next_read_response_);
next_read_response_.emplace(gatt_code, value);
}
void FakeRemoteGattCharacteristic::SetNextWriteResponse(uint16_t gatt_code) {
DCHECK(!next_write_response_);
next_write_response_.emplace(gatt_code);
}
void FakeRemoteGattCharacteristic::SetNextSubscribeToNotificationsResponse(
uint16_t gatt_code) {
DCHECK(!next_subscribe_to_notifications_response_);
next_subscribe_to_notifications_response_.emplace(gatt_code);
}
bool FakeRemoteGattCharacteristic::AllResponsesConsumed() {
// TODO(crbug.com/569709): Update this when
// SetNextUnsubscribeFromNotificationsResponse is implemented.
return !next_read_response_ && !next_write_response_ &&
!next_subscribe_to_notifications_response_ &&
std::all_of(
fake_descriptors_.begin(), fake_descriptors_.end(),
[](const auto& e) { return e.second->AllResponsesConsumed(); });
}
std::string FakeRemoteGattCharacteristic::GetIdentifier() const {
return characteristic_id_;
}
device::BluetoothUUID FakeRemoteGattCharacteristic::GetUUID() const {
return characteristic_uuid_;
}
FakeRemoteGattCharacteristic::Properties
FakeRemoteGattCharacteristic::GetProperties() const {
return properties_;
}
FakeRemoteGattCharacteristic::Permissions
FakeRemoteGattCharacteristic::GetPermissions() const {
NOTREACHED();
return PERMISSION_NONE;
}
const std::vector<uint8_t>& FakeRemoteGattCharacteristic::GetValue() const {
NOTREACHED();
return value_;
}
device::BluetoothRemoteGattService* FakeRemoteGattCharacteristic::GetService()
const {
return service_;
}
std::vector<device::BluetoothRemoteGattDescriptor*>
FakeRemoteGattCharacteristic::GetDescriptors() const {
std::vector<device::BluetoothRemoteGattDescriptor*> descriptors;
for (const auto& it : fake_descriptors_)
descriptors.push_back(it.second.get());
return descriptors;
}
device::BluetoothRemoteGattDescriptor*
FakeRemoteGattCharacteristic::GetDescriptor(
const std::string& identifier) const {
const auto& it = fake_descriptors_.find(identifier);
if (it == fake_descriptors_.end())
return nullptr;
return it->second.get();
}
void FakeRemoteGattCharacteristic::ReadRemoteCharacteristic(
const ValueCallback& callback,
const ErrorCallback& error_callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FakeRemoteGattCharacteristic::DispatchReadResponse,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
}
void FakeRemoteGattCharacteristic::WriteRemoteCharacteristic(
const std::vector<uint8_t>& value,
const base::Closure& callback,
const ErrorCallback& error_callback) {
// It doesn't make sense to dispatch a custom write response if the
// characteristic only supports write without response but we still need to
// run the callback because that's the guarantee the API makes.
if (properties_ & PROPERTY_WRITE_WITHOUT_RESPONSE) {
last_written_value_ = value;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
return;
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FakeRemoteGattCharacteristic::DispatchWriteResponse,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback,
value));
}
void FakeRemoteGattCharacteristic::SubscribeToNotifications(
device::BluetoothRemoteGattDescriptor* ccc_descriptor,
const base::Closure& callback,
const ErrorCallback& error_callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FakeRemoteGattCharacteristic::
DispatchSubscribeToNotificationsResponse,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
}
void FakeRemoteGattCharacteristic::UnsubscribeFromNotifications(
device::BluetoothRemoteGattDescriptor* ccc_descriptor,
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakeRemoteGattCharacteristic::DispatchReadResponse(
const ValueCallback& callback,
const ErrorCallback& error_callback) {
DCHECK(next_read_response_);
uint16_t gatt_code = next_read_response_->gatt_code();
base::Optional<std::vector<uint8_t>> value = next_read_response_->value();
next_read_response_.reset();
switch (gatt_code) {
case mojom::kGATTSuccess:
DCHECK(value);
value_ = std::move(value.value());
callback.Run(value_);
break;
case mojom::kGATTInvalidHandle:
DCHECK(!value);
error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
break;
default:
NOTREACHED();
}
}
void FakeRemoteGattCharacteristic::DispatchWriteResponse(
const base::Closure& callback,
const ErrorCallback& error_callback,
const std::vector<uint8_t>& value) {
DCHECK(next_write_response_);
uint16_t gatt_code = next_write_response_.value();
next_write_response_.reset();
switch (gatt_code) {
case mojom::kGATTSuccess:
last_written_value_ = value;
callback.Run();
break;
case mojom::kGATTInvalidHandle:
error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
break;
default:
NOTREACHED();
}
}
void FakeRemoteGattCharacteristic::DispatchSubscribeToNotificationsResponse(
const base::Closure& callback,
const ErrorCallback& error_callback) {
DCHECK(next_subscribe_to_notifications_response_);
uint16_t gatt_code = next_subscribe_to_notifications_response_.value();
next_subscribe_to_notifications_response_.reset();
switch (gatt_code) {
case mojom::kGATTSuccess:
callback.Run();
break;
case mojom::kGATTInvalidHandle:
error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
break;
default:
NOTREACHED();
}
}
} // namespace bluetooth