blob: aa75c6709eaabd3f6ccf7909f0cb4dc1056478dc [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_peripheral.h"
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/test/fake_remote_gatt_service.h"
namespace bluetooth {
FakePeripheral::FakePeripheral(FakeCentral* fake_central,
const std::string& address)
: device::BluetoothDevice(fake_central),
address_(address),
system_connected_(false),
gatt_connected_(false),
last_service_id_(0),
pending_gatt_discovery_(false),
weak_ptr_factory_(this) {}
FakePeripheral::~FakePeripheral() = default;
void FakePeripheral::SetName(base::Optional<std::string> name) {
name_ = std::move(name);
}
void FakePeripheral::SetSystemConnected(bool connected) {
system_connected_ = connected;
}
void FakePeripheral::SetServiceUUIDs(UUIDSet service_uuids) {
service_uuids_ = std::move(service_uuids);
}
void FakePeripheral::SetNextGATTConnectionResponse(uint16_t code) {
DCHECK(!next_connection_response_);
DCHECK(create_gatt_connection_error_callbacks_.empty());
next_connection_response_ = code;
}
void FakePeripheral::SetNextGATTDiscoveryResponse(uint16_t code) {
DCHECK(!next_discovery_response_);
next_discovery_response_ = code;
}
bool FakePeripheral::AllResponsesConsumed() {
return !next_connection_response_ && !next_discovery_response_ &&
std::all_of(gatt_services_.begin(), gatt_services_.end(),
[](const auto& e) {
FakeRemoteGattService* fake_remote_gatt_service =
static_cast<FakeRemoteGattService*>(e.second.get());
return fake_remote_gatt_service->AllResponsesConsumed();
});
}
void FakePeripheral::SimulateGATTDisconnection() {
gatt_services_.clear();
// TODO(crbug.com/728870): Only set get_connected_ to false once system
// connected peripherals are supported and Web Bluetooth uses them. See issue
// for more details.
system_connected_ = false;
gatt_connected_ = false;
SetGattServicesDiscoveryComplete(false);
DidDisconnectGatt();
}
std::string FakePeripheral::AddFakeService(
const device::BluetoothUUID& service_uuid) {
// Attribute instance Ids need to be unique.
std::string new_service_id =
base::StringPrintf("%s_%zu", GetAddress().c_str(), ++last_service_id_);
GattServiceMap::iterator it;
bool inserted;
std::tie(it, inserted) = gatt_services_.emplace(
new_service_id,
std::make_unique<FakeRemoteGattService>(new_service_id, service_uuid,
true /* is_primary */, this));
DCHECK(inserted);
return it->second->GetIdentifier();
}
bool FakePeripheral::RemoveFakeService(const std::string& identifier) {
auto it = gatt_services_.find(identifier);
if (it == gatt_services_.end()) {
return false;
}
gatt_services_.erase(it);
return true;
}
uint32_t FakePeripheral::GetBluetoothClass() const {
NOTREACHED();
return 0;
}
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
device::BluetoothTransport FakePeripheral::GetType() const {
NOTREACHED();
return device::BLUETOOTH_TRANSPORT_INVALID;
}
#endif
std::string FakePeripheral::GetIdentifier() const {
NOTREACHED();
return std::string();
}
std::string FakePeripheral::GetAddress() const {
return address_;
}
device::BluetoothDevice::VendorIDSource FakePeripheral::GetVendorIDSource()
const {
NOTREACHED();
return VENDOR_ID_UNKNOWN;
}
uint16_t FakePeripheral::GetVendorID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetProductID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetDeviceID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetAppearance() const {
NOTREACHED();
return 0;
}
base::Optional<std::string> FakePeripheral::GetName() const {
return name_;
}
base::string16 FakePeripheral::GetNameForDisplay() const {
return base::string16();
}
bool FakePeripheral::IsPaired() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsConnected() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsGattConnected() const {
// TODO(crbug.com/728870): Return gatt_connected_ only once system connected
// peripherals are supported and Web Bluetooth uses them. See issue for more
// details.
return system_connected_ || gatt_connected_;
}
bool FakePeripheral::IsConnectable() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsConnecting() const {
NOTREACHED();
return false;
}
device::BluetoothDevice::UUIDSet FakePeripheral::GetUUIDs() const {
return service_uuids_;
}
bool FakePeripheral::ExpectingPinCode() const {
NOTREACHED();
return false;
}
bool FakePeripheral::ExpectingPasskey() const {
NOTREACHED();
return false;
}
bool FakePeripheral::ExpectingConfirmation() const {
NOTREACHED();
return false;
}
void FakePeripheral::GetConnectionInfo(const ConnectionInfoCallback& callback) {
NOTREACHED();
}
void FakePeripheral::SetConnectionLatency(ConnectionLatency connection_latency,
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::Connect(PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::SetPinCode(const std::string& pincode) {
NOTREACHED();
}
void FakePeripheral::SetPasskey(uint32_t passkey) {
NOTREACHED();
}
void FakePeripheral::ConfirmPairing() {
NOTREACHED();
}
void FakePeripheral::RejectPairing() {
NOTREACHED();
}
void FakePeripheral::CancelPairing() {
NOTREACHED();
}
void FakePeripheral::Disconnect(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::Forget(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::ConnectToService(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::ConnectToServiceInsecurely(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::CreateGattConnection(
const GattConnectionCallback& callback,
const ConnectErrorCallback& error_callback) {
create_gatt_connection_success_callbacks_.push_back(callback);
create_gatt_connection_error_callbacks_.push_back(error_callback);
// TODO(crbug.com/728870): Stop overriding CreateGattConnection once
// IsGattConnected() is fixed. See issue for more details.
if (gatt_connected_)
return DidConnectGatt();
CreateGattConnectionImpl();
}
bool FakePeripheral::IsGattServicesDiscoveryComplete() const {
const bool discovery_complete =
BluetoothDevice::IsGattServicesDiscoveryComplete();
DCHECK(!(pending_gatt_discovery_ && discovery_complete));
// There is currently no method to intiate a Service Discovery procedure.
// Web Bluetooth keeps a queue of pending getPrimaryServices() requests until
// BluetoothAdapter::Observer::GattServicesDiscovered is called.
// We use a call to IsGattServicesDiscoveryComplete as a signal that Web
// Bluetooth needs to initiate a Service Discovery procedure and post
// a task to call GattServicesDiscovered to simulate that the procedure has
// completed.
// TODO(crbug.com/729456): Remove this override and run
// DiscoverGattServices() callback with next_discovery_response_ once
// DiscoverGattServices() is implemented.
if (!pending_gatt_discovery_ && !discovery_complete) {
pending_gatt_discovery_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FakePeripheral::DispatchDiscoveryResponse,
weak_ptr_factory_.GetWeakPtr()));
}
return discovery_complete;
}
void FakePeripheral::CreateGattConnectionImpl() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FakePeripheral::DispatchConnectionResponse,
weak_ptr_factory_.GetWeakPtr()));
}
void FakePeripheral::DispatchConnectionResponse() {
DCHECK(next_connection_response_);
uint16_t code = next_connection_response_.value();
next_connection_response_.reset();
if (code == mojom::kHCISuccess) {
gatt_connected_ = true;
DidConnectGatt();
} else if (code == mojom::kHCIConnectionTimeout) {
DidFailToConnectGatt(ERROR_FAILED);
} else {
DidFailToConnectGatt(ERROR_UNKNOWN);
}
}
void FakePeripheral::DispatchDiscoveryResponse() {
DCHECK(next_discovery_response_);
uint16_t code = next_discovery_response_.value();
next_discovery_response_.reset();
pending_gatt_discovery_ = false;
if (code == mojom::kHCISuccess) {
SetGattServicesDiscoveryComplete(true);
GetAdapter()->NotifyGattServicesDiscovered(this);
} else {
SetGattServicesDiscoveryComplete(false);
}
}
void FakePeripheral::DisconnectGatt() {
}
#if defined(OS_CHROMEOS)
void FakePeripheral::ExecuteWrite(
const base::Closure& callback,
const ExecuteWriteErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void FakePeripheral::AbortWrite(const base::Closure& callback,
const AbortWriteErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
#endif
} // namespace bluetooth