// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/quick_pair/scanning/scanner_broker_impl.h"
#include <memory>
#include "ash/quick_pair/common/device.h"
#include "ash/quick_pair/common/protocol.h"
#include "ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.h"
#include "ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl.h"
#include "ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h"
#include "ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process_manager.h"
#include "components/cross_device/logging/logging.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
namespace {
bool ShouldNotDiscoverableScanningBeEnabled(ash::LoginStatus status) {
switch (status) {
case ash::LoginStatus::NOT_LOGGED_IN:
case ash::LoginStatus::LOCKED:
case ash::LoginStatus::KIOSK_APP:
case ash::LoginStatus::GUEST:
case ash::LoginStatus::PUBLIC:
return false;
case ash::LoginStatus::USER:
case ash::LoginStatus::CHILD:
default:
return true;
}
}
} // namespace
namespace ash {
namespace quick_pair {
ScannerBrokerImpl::ScannerBrokerImpl(QuickPairProcessManager* process_manager)
: process_manager_(process_manager) {
DCHECK(process_manager_);
device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
&ScannerBrokerImpl::OnGetAdapter, weak_pointer_factory_.GetWeakPtr()));
}
ScannerBrokerImpl::~ScannerBrokerImpl() = default;
void ScannerBrokerImpl::OnGetAdapter(
scoped_refptr<device::BluetoothAdapter> adapter) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
adapter_ = adapter;
if (start_scanning_on_adapter_callbacks_.empty())
return;
CD_LOG(VERBOSE, Feature::FP) << __func__ << ": Running saved callbacks.";
for (auto& callback : start_scanning_on_adapter_callbacks_)
std::move(callback).Run();
start_scanning_on_adapter_callbacks_.clear();
}
void ScannerBrokerImpl::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void ScannerBrokerImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void ScannerBrokerImpl::StartScanning(Protocol protocol) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CD_LOG(VERBOSE, Feature::FP) << __func__ << ": protocol=" << protocol;
if (!adapter_) {
CD_LOG(VERBOSE, Feature::FP)
<< __func__ << ": No adapter yet, saving callback for later.";
start_scanning_on_adapter_callbacks_.push_back(
base::BindOnce(&ScannerBrokerImpl::StartScanning,
weak_pointer_factory_.GetWeakPtr(), protocol));
return;
}
switch (protocol) {
case Protocol::kFastPairInitial:
case Protocol::kFastPairRetroactive:
case Protocol::kFastPairSubsequent:
StartFastPairScanning();
break;
}
}
void ScannerBrokerImpl::StopScanning(Protocol protocol) {
CD_LOG(VERBOSE, Feature::FP) << __func__ << ": protocol=" << protocol;
switch (protocol) {
case Protocol::kFastPairInitial:
case Protocol::kFastPairRetroactive:
case Protocol::kFastPairSubsequent:
StopFastPairScanning();
break;
}
}
void ScannerBrokerImpl::StartFastPairScanning() {
DCHECK(!fast_pair_discoverable_scanner_);
DCHECK(!fast_pair_not_discoverable_scanner_);
DCHECK(adapter_);
CD_LOG(VERBOSE, Feature::FP) << "Starting Fast Pair Scanning.";
fast_pair_scanner_ = base::MakeRefCounted<FastPairScannerImpl>();
fast_pair_discoverable_scanner_ =
FastPairDiscoverableScannerImpl::Factory::Create(
fast_pair_scanner_, adapter_,
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceFound,
weak_pointer_factory_.GetWeakPtr()),
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceLost,
weak_pointer_factory_.GetWeakPtr()));
// If there is no signed in user, don't instantiate the not discoverable
// scanner, but observe login events in case that we get logged in later on.
if (!ShouldNotDiscoverableScanningBeEnabled(
Shell::Get()->session_controller()->login_status())) {
CD_LOG(VERBOSE, Feature::FP)
<< __func__ << ": No logged in user to enable not discoverable scanner";
// Observe log in events in the case the login was delayed if we aren't
// observing already.
if (!shell_observation_.IsObserving())
shell_observation_.Observe(Shell::Get()->session_controller());
return;
}
fast_pair_not_discoverable_scanner_ =
FastPairNotDiscoverableScannerImpl::Factory::Create(
fast_pair_scanner_, adapter_,
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceFound,
weak_pointer_factory_.GetWeakPtr()),
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceLost,
weak_pointer_factory_.GetWeakPtr()));
}
void ScannerBrokerImpl::OnLoginStatusChanged(LoginStatus login_status) {
if (!ShouldNotDiscoverableScanningBeEnabled(login_status) ||
!fast_pair_scanner_ || !adapter_ ||
fast_pair_not_discoverable_scanner_.get()) {
return;
}
CD_LOG(VERBOSE, Feature::FP)
<< __func__ << ": Logged in user, instantiate not discoverable scanner";
fast_pair_not_discoverable_scanner_ =
FastPairNotDiscoverableScannerImpl::Factory::Create(
fast_pair_scanner_, adapter_,
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceFound,
weak_pointer_factory_.GetWeakPtr()),
base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceLost,
weak_pointer_factory_.GetWeakPtr()));
}
void ScannerBrokerImpl::StopFastPairScanning() {
fast_pair_discoverable_scanner_.reset();
fast_pair_not_discoverable_scanner_.reset();
fast_pair_scanner_.reset();
shell_observation_.Reset();
CD_LOG(VERBOSE, Feature::FP) << "Stopping Fast Pair Scanning.";
}
void ScannerBrokerImpl::NotifyDeviceFound(scoped_refptr<Device> device) {
CD_LOG(INFO, Feature::FP)
<< __func__ << ": device.metadata_id=" << device->metadata_id();
for (auto& observer : observers_) {
observer.OnDeviceFound(device);
}
}
void ScannerBrokerImpl::NotifyDeviceLost(scoped_refptr<Device> device) {
CD_LOG(INFO, Feature::FP)
<< __func__ << ": device.metadata_id=" << device->metadata_id();
for (auto& observer : observers_) {
observer.OnDeviceLost(device);
}
}
void ScannerBrokerImpl::OnDevicePaired(scoped_refptr<Device> device) {
if (fast_pair_scanner_)
fast_pair_scanner_->OnDevicePaired(device);
}
} // namespace quick_pair
} // namespace ash