// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/nearby/common/connections_manager/fake_nearby_connections_manager.h"
#include "base/containers/contains.h"
#include "base/containers/map_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/types/optional_util.h"
FakeNearbyConnectionsManager::FakeNearbyConnectionsManager() = default;
FakeNearbyConnectionsManager::~FakeNearbyConnectionsManager() = default;
void FakeNearbyConnectionsManager::Shutdown() {
DCHECK(!IsAdvertising());
DCHECK(!IsDiscovering());
is_shutdown_ = true;
}
void FakeNearbyConnectionsManager::StartAdvertising(
std::vector<uint8_t> endpoint_info,
IncomingConnectionListener* listener,
PowerLevel power_level,
DataUsage data_usage,
ConnectionsCallback callback) {
DCHECK(!IsAdvertising());
is_shutdown_ = false;
advertising_listener_ = listener;
advertising_data_usage_ = data_usage;
advertising_power_level_ = power_level;
advertising_endpoint_info_ = std::move(endpoint_info);
if (capture_next_start_advertising_callback_) {
pending_start_advertising_callback_ = std::move(callback);
capture_next_start_advertising_callback_ = false;
} else {
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess);
}
}
void FakeNearbyConnectionsManager::StopAdvertising(
ConnectionsCallback callback) {
DCHECK(IsAdvertising());
DCHECK(!is_shutdown());
advertising_listener_ = nullptr;
advertising_data_usage_ = DataUsage::kUnknown;
advertising_power_level_ = PowerLevel::kUnknown;
advertising_endpoint_info_.reset();
if (capture_next_stop_advertising_callback_) {
pending_stop_advertising_callback_ = std::move(callback);
capture_next_stop_advertising_callback_ = false;
} else {
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess);
}
}
void FakeNearbyConnectionsManager::InjectBluetoothEndpoint(
const std::string& service_id,
const std::string& endpoint_id,
const std::vector<uint8_t> endpoint_info,
const std::vector<uint8_t> remote_bluetooth_mac_address,
ConnectionsCallback callback) {
// Assume that this FakeNearbyConnectionsManager object starts/stops
// the discovery session to inject into. This assumption doesn't hold for
// NearbyConnectionsManagerImpl: if one starts discovery, another can inject
// an endpoint into the former's discovery session if the same `service_id` is
// used for discovery start and injection.
if (!IsDiscovering()) {
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kError);
}
discovery_listener_->OnEndpointDiscovered(endpoint_id, endpoint_info);
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess);
}
void FakeNearbyConnectionsManager::StartDiscovery(
DiscoveryListener* listener,
DataUsage data_usage,
ConnectionsCallback callback) {
is_shutdown_ = false;
discovery_listener_ = listener;
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess);
}
void FakeNearbyConnectionsManager::StopDiscovery() {
DCHECK(IsDiscovering());
DCHECK(!is_shutdown());
discovery_listener_ = nullptr;
// TODO(alexchau): Implement.
}
void FakeNearbyConnectionsManager::Connect(
std::vector<uint8_t> endpoint_info,
const std::string& endpoint_id,
std::optional<std::vector<uint8_t>> bluetooth_mac_address,
DataUsage data_usage,
NearbyConnectionCallback callback) {
DCHECK(!is_shutdown());
connected_data_usage_ = data_usage;
connection_endpoint_infos_.emplace(endpoint_id, std::move(endpoint_info));
std::move(callback).Run(connection_.get());
}
void FakeNearbyConnectionsManager::Disconnect(const std::string& endpoint_id) {
DCHECK(!is_shutdown());
connection_endpoint_infos_.erase(endpoint_id);
}
void FakeNearbyConnectionsManager::Send(
const std::string& endpoint_id,
PayloadPtr payload,
base::WeakPtr<PayloadStatusListener> listener) {
DCHECK(!is_shutdown());
if (send_payload_callback_) {
send_payload_callback_.Run(std::move(payload), listener);
}
}
void FakeNearbyConnectionsManager::RegisterPayloadStatusListener(
int64_t payload_id,
base::WeakPtr<PayloadStatusListener> listener) {
DCHECK(!is_shutdown());
payload_status_listeners_[payload_id] = listener;
}
void FakeNearbyConnectionsManager::RegisterPayloadPath(
int64_t payload_id,
const base::FilePath& file_path,
ConnectionsCallback callback) {
DCHECK(!is_shutdown());
registered_payload_paths_[payload_id] = file_path;
{
base::ScopedAllowBlockingForTesting allow_blocking;
base::File file(file_path, base::File::Flags::FLAG_CREATE_ALWAYS |
base::File::Flags::FLAG_READ |
base::File::Flags::FLAG_WRITE);
}
auto* status = base::FindOrNull(payload_path_status_, payload_id);
std::move(callback).Run(
status ? *status : nearby::connections::mojom::Status::kPayloadUnknown);
}
FakeNearbyConnectionsManager::Payload*
FakeNearbyConnectionsManager::GetIncomingPayload(int64_t payload_id) {
DCHECK(!is_shutdown());
auto it = incoming_payloads_.find(payload_id);
if (it == incoming_payloads_.end()) {
return nullptr;
}
return it->second.get();
}
void FakeNearbyConnectionsManager::Cancel(int64_t payload_id) {
DCHECK(!is_shutdown());
base::WeakPtr<PayloadStatusListener> listener =
GetRegisteredPayloadStatusListener(payload_id);
if (listener) {
listener->OnStatusUpdate(
nearby::connections::mojom::PayloadTransferUpdate::New(
payload_id, nearby::connections::mojom::PayloadStatus::kCanceled,
/*total_bytes=*/0,
/*bytes_transferred=*/0),
/*upgraded_medium=*/std::nullopt);
payload_status_listeners_.erase(payload_id);
}
canceled_payload_ids_.insert(payload_id);
}
void FakeNearbyConnectionsManager::ClearIncomingPayloads() {
base::ScopedAllowBlockingForTesting allow_blocking;
incoming_payloads_.clear();
payload_status_listeners_.clear();
}
void FakeNearbyConnectionsManager::ClearIncomingPayloadWithId(
int64_t payload_id) {
base::ScopedAllowBlockingForTesting allow_blocking;
incoming_payloads_.erase(payload_id);
payload_status_listeners_.erase(payload_id);
}
std::optional<std::string> FakeNearbyConnectionsManager::GetAuthenticationToken(
const std::string& endpoint_id) {
DCHECK(!is_shutdown());
return base::OptionalFromPtr(
base::FindOrNull(endpoint_auth_tokens_, endpoint_id));
}
std::optional<std::vector<uint8_t>>
FakeNearbyConnectionsManager::GetRawAuthenticationToken(
const std::string& endpoint_id) {
DCHECK(!is_shutdown());
return base::OptionalFromPtr(
base::FindOrNull(endpoint_raw_auth_tokens_, endpoint_id));
}
void FakeNearbyConnectionsManager::SetAuthenticationToken(
const std::string& endpoint_id,
const std::string& token) {
endpoint_auth_tokens_[endpoint_id] = token;
}
void FakeNearbyConnectionsManager::SetRawAuthenticationToken(
const std::string& endpoint_id,
std::vector<uint8_t> token) {
endpoint_raw_auth_tokens_[endpoint_id] = std::move(token);
}
void FakeNearbyConnectionsManager::RegisterBandwidthUpgradeListener(
base::WeakPtr<BandwidthUpgradeListener> listener) {
bandwidth_upgrade_listener_ = listener;
}
void FakeNearbyConnectionsManager::UpgradeBandwidth(
const std::string& endpoint_id) {
upgrade_bandwidth_endpoint_ids_.insert(endpoint_id);
}
void FakeNearbyConnectionsManager::ConnectV3(
PresenceDevice remote_presence_device,
DataUsage data_usage,
NearbyConnectionCallback callback) {
CHECK(!is_shutdown());
connected_data_usage_ = data_usage;
std::move(callback).Run(connection_.get());
}
void FakeNearbyConnectionsManager::DisconnectV3(
PresenceDevice remote_presence_device) {
CHECK(!is_shutdown());
}
base::WeakPtr<NearbyConnectionsManager>
FakeNearbyConnectionsManager::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void FakeNearbyConnectionsManager::OnEndpointFound(
const std::string& endpoint_id,
nearby::connections::mojom::DiscoveredEndpointInfoPtr info) {
if (!discovery_listener_) {
return;
}
discovery_listener_->OnEndpointDiscovered(endpoint_id, info->endpoint_info);
}
void FakeNearbyConnectionsManager::OnEndpointLost(
const std::string& endpoint_id) {
if (!discovery_listener_) {
return;
}
discovery_listener_->OnEndpointLost(endpoint_id);
}
bool FakeNearbyConnectionsManager::IsAdvertising() const {
return advertising_listener_ != nullptr;
}
bool FakeNearbyConnectionsManager::IsDiscovering() const {
return discovery_listener_ != nullptr;
}
bool FakeNearbyConnectionsManager::DidUpgradeBandwidth(
const std::string& endpoint_id) const {
return upgrade_bandwidth_endpoint_ids_.find(endpoint_id) !=
upgrade_bandwidth_endpoint_ids_.end();
}
void FakeNearbyConnectionsManager::SetPayloadPathStatus(
int64_t payload_id,
ConnectionsStatus status) {
payload_path_status_[payload_id] = status;
}
base::WeakPtr<FakeNearbyConnectionsManager::PayloadStatusListener>
FakeNearbyConnectionsManager::GetRegisteredPayloadStatusListener(
int64_t payload_id) {
if (auto* ptr = base::FindOrNull(payload_status_listeners_, payload_id)) {
return *ptr;
}
return nullptr;
}
void FakeNearbyConnectionsManager::SetIncomingPayload(int64_t payload_id,
PayloadPtr payload) {
incoming_payloads_[payload_id] = std::move(payload);
}
bool FakeNearbyConnectionsManager::WasPayloadCanceled(
const int64_t& payload_id) const {
return base::Contains(canceled_payload_ids_, payload_id);
}
std::optional<base::FilePath>
FakeNearbyConnectionsManager::GetRegisteredPayloadPath(int64_t payload_id) {
return base::OptionalFromPtr(
base::FindOrNull(registered_payload_paths_, payload_id));
}
void FakeNearbyConnectionsManager::CleanupForProcessStopped() {
advertising_listener_ = nullptr;
advertising_data_usage_ = DataUsage::kUnknown;
advertising_power_level_ = PowerLevel::kUnknown;
advertising_endpoint_info_.reset();
discovery_listener_ = nullptr;
is_shutdown_ = true;
}
FakeNearbyConnectionsManager::ConnectionsCallback
FakeNearbyConnectionsManager::GetStartAdvertisingCallback() {
capture_next_start_advertising_callback_ = true;
return base::BindOnce(
&FakeNearbyConnectionsManager::HandleStartAdvertisingCallback,
base::Unretained(this));
}
FakeNearbyConnectionsManager::ConnectionsCallback
FakeNearbyConnectionsManager::GetStopAdvertisingCallback() {
capture_next_stop_advertising_callback_ = true;
return base::BindOnce(
&FakeNearbyConnectionsManager::HandleStopAdvertisingCallback,
base::Unretained(this));
}
void FakeNearbyConnectionsManager::HandleStartAdvertisingCallback(
ConnectionsStatus status) {
if (pending_start_advertising_callback_) {
std::move(pending_start_advertising_callback_).Run(status);
}
capture_next_start_advertising_callback_ = false;
}
void FakeNearbyConnectionsManager::HandleStopAdvertisingCallback(
ConnectionsStatus status) {
if (pending_stop_advertising_callback_) {
std::move(pending_stop_advertising_callback_).Run(status);
}
capture_next_stop_advertising_callback_ = false;
}