#include "content/browser/bluetooth/bluetooth_adapter_factory_wrapper.h"
#include <stddef.h>
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/no_destructor.h"
#include "base/task/single_thread_task_runner.h"
#include "content/browser/bluetooth/web_bluetooth_service_impl.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
namespace content {
namespace {
using ::device::BluetoothAdapter;
using ::device::BluetoothAdapterFactory;
}
BluetoothAdapterFactoryWrapper::BluetoothAdapterFactoryWrapper() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
BluetoothAdapterFactoryWrapper::~BluetoothAdapterFactoryWrapper() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(adapter_observers_.empty());
set_adapter(nullptr);
}
BluetoothAdapterFactoryWrapper& BluetoothAdapterFactoryWrapper::Get() {
static base::NoDestructor<BluetoothAdapterFactoryWrapper> singleton;
return *singleton;
}
bool BluetoothAdapterFactoryWrapper::IsLowEnergySupported() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (adapter_ || test_adapter_)
return true;
return BluetoothAdapterFactory::Get()->IsLowEnergySupported();
}
void BluetoothAdapterFactoryWrapper::AcquireAdapter(
WebBluetoothServiceImpl* service,
AcquireAdapterCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!GetAdapter(service));
MaybeAddAdapterObserver(service);
if (adapter_) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), adapter_));
return;
}
if (test_adapter_) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&BluetoothAdapterFactoryWrapper::OnGetAdapter,
weak_ptr_factory_.GetWeakPtr(),
std::move(callback), test_adapter_));
return;
}
DCHECK(BluetoothAdapterFactory::Get()->IsLowEnergySupported());
BluetoothAdapterFactory::Get()->GetAdapter(
base::BindOnce(&BluetoothAdapterFactoryWrapper::OnGetAdapter,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void BluetoothAdapterFactoryWrapper::ReleaseAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!HasAdapter(service)) {
return;
}
RemoveAdapterObserver(service);
if (adapter_observers_.empty())
set_adapter(nullptr);
}
BluetoothAdapter* BluetoothAdapterFactoryWrapper::GetAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (HasAdapter(service)) {
return adapter_.get();
}
return nullptr;
}
void BluetoothAdapterFactoryWrapper::SetBluetoothAdapterForTesting(
scoped_refptr<BluetoothAdapter> test_adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (adapter_) {
set_adapter(std::move(test_adapter));
return;
}
test_adapter_ = std::move(test_adapter);
}
void BluetoothAdapterFactoryWrapper::OnGetAdapter(
AcquireAdapterCallback continuation,
scoped_refptr<BluetoothAdapter> adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
test_adapter_.reset();
set_adapter(adapter);
std::move(continuation).Run(adapter_);
}
bool BluetoothAdapterFactoryWrapper::HasAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return base::Contains(adapter_observers_, service);
}
void BluetoothAdapterFactoryWrapper::MaybeAddAdapterObserver(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto [it, inserted] = adapter_observers_.insert(service);
if (inserted && adapter_) {
adapter_->AddObserver(service);
}
}
void BluetoothAdapterFactoryWrapper::RemoveAdapterObserver(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
size_t removed = adapter_observers_.erase(service);
DCHECK(removed);
if (adapter_) {
adapter_->RemoveObserver(service);
}
}
void BluetoothAdapterFactoryWrapper::set_adapter(
scoped_refptr<BluetoothAdapter> adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (adapter.get() == adapter_.get())
return;
if (adapter_.get()) {
for (WebBluetoothServiceImpl* service : adapter_observers_) {
adapter_->RemoveObserver(service);
}
}
adapter_ = std::move(adapter);
if (adapter_.get()) {
for (WebBluetoothServiceImpl* service : adapter_observers_) {
adapter_->AddObserver(service);
}
}
}
}