// 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.
#ifndef ASH_QUICK_PAIR_KEYED_SERVICE_QUICK_PAIR_MEDIATOR_H_
#define ASH_QUICK_PAIR_KEYED_SERVICE_QUICK_PAIR_MEDIATOR_H_
#include <memory>
#include "ash/quick_pair/companion_app/companion_app_broker.h"
#include "ash/quick_pair/feature_status_tracker/quick_pair_feature_status_tracker.h"
#include "ash/quick_pair/keyed_service/fast_pair_bluetooth_config_delegate.h"
#include "ash/quick_pair/pairing/pairer_broker.h"
#include "ash/quick_pair/pairing/retroactive_pairing_detector.h"
#include "ash/quick_pair/scanning/scanner_broker.h"
#include "ash/quick_pair/ui/ui_broker.h"
#include "base/memory/scoped_refptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chromeos/ash/services/bluetooth_config/adapter_state_controller.h"
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
class PrefRegistrySimple;
namespace chromeos {
namespace bluetooth_config {
class FastPairDelegate;
} // namespace bluetooth_config
} // namespace chromeos
namespace ash {
namespace quick_pair {
class FastPairRepository;
class Device;
class QuickPairProcessManager;
class QuickPairMetricsLogger;
class MessageStreamLookup;
class BatteryUpdateMessageHandler;
// Implements the Mediator design pattern for the components in the Quick Pair
// system, e.g. the UI Broker, Scanning Broker and Pairing Broker.
class Mediator final
: public FeatureStatusTracker::Observer,
public ScannerBroker::Observer,
public PairerBroker::Observer,
public UIBroker::Observer,
public CompanionAppBroker::Observer,
public RetroactivePairingDetector::Observer,
public FastPairBluetoothConfigDelegate::Delegate,
public bluetooth_config::AdapterStateController::Observer,
public bluetooth_config::mojom::DiscoverySessionStatusObserver {
public:
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr<Mediator> BuildInstance() = 0;
};
class FactoryImpl : public Factory {
private:
// Mediator::Factory:
std::unique_ptr<Mediator> BuildInstance() override;
};
Mediator(
std::unique_ptr<FeatureStatusTracker> feature_status_tracker,
std::unique_ptr<ScannerBroker> scanner_broker,
std::unique_ptr<RetroactivePairingDetector> retroactive_pairing_detector,
std::unique_ptr<MessageStreamLookup> message_stream_lookup,
std::unique_ptr<PairerBroker> pairer_broker,
std::unique_ptr<UIBroker> ui_broker,
std::unique_ptr<CompanionAppBroker> companion_app_broker,
std::unique_ptr<FastPairRepository> fast_pair_repository,
std::unique_ptr<QuickPairProcessManager> process_manager);
Mediator(const Mediator&) = delete;
Mediator& operator=(const Mediator&) = delete;
~Mediator() override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
bluetooth_config::FastPairDelegate* GetFastPairDelegate();
// FeatureStatusTracker::Observer
void OnFastPairEnabledChanged(bool is_enabled) override;
// ScannerBroker::Observer
void OnDeviceFound(scoped_refptr<Device> device) override;
void OnDeviceLost(scoped_refptr<Device> device) override;
// PairerBroker::Observer
void OnDevicePaired(scoped_refptr<Device> device) override;
void OnPairFailure(scoped_refptr<Device> device,
PairFailure failure) override;
void OnAccountKeyWrite(scoped_refptr<Device> device,
std::optional<AccountKeyFailure> error) override;
// UIBroker::Observer
void OnDiscoveryAction(scoped_refptr<Device> device,
DiscoveryAction action) override;
void OnPairingFailureAction(scoped_refptr<Device> device,
PairingFailedAction action) override;
void OnCompanionAppAction(scoped_refptr<Device> device,
CompanionAppAction action) override;
void OnAssociateAccountAction(scoped_refptr<Device> device,
AssociateAccountAction action) override;
// CompanionAppBroker::Observer
void ShowInstallCompanionApp(scoped_refptr<Device> device) override;
void ShowLaunchCompanionApp(scoped_refptr<Device> device) override;
void OnCompanionAppInstalled(scoped_refptr<Device> device) override;
// RetroactivePairingDetector::Observer
void OnRetroactivePairFound(scoped_refptr<Device> device) override;
// FastPairBluetoothConfigDelegate::Delegate
void OnAdapterStateControllerChanged(bluetooth_config::AdapterStateController*
adapter_state_controller) override;
// bluetooth_config::AdapterStateController::Observer
void OnAdapterStateChanged() override;
// bluetooth_config::mojom::DiscoverySessionStatusObserver
void OnHasAtLeastOneDiscoverySessionChanged(
bool has_at_least_one_discovery_session) override;
private:
// Represents a device's most recent state when its found for a discovery
// notification (initial and subsequent pairing scenarios). This is used
// to determine if a device can have a notification shown again in the
// `discovery_notification_block-list_` block-list.
enum class DiscoveryNotificationDismissalState {
// If the notification is dismissed, do not show again for 2 seconds.
kDismissed,
// If notification is dismissed again, do not show again for 5 minutes.
kShortBan,
// If notification is dismissed again, do not show until the block-list is
// reset, which happens when the user session ends or when the Bluetooth
// or Fast Pair toggle is toggled off.
kLongBan,
};
void SetFastPairState(bool is_enabled);
void BindToCrosBluetoothConfig();
void CancelPairing();
bool IsDeviceCurrentlyShowingNotification(scoped_refptr<Device> device);
bool IsDeviceBlockedForDiscoveryNotifications(scoped_refptr<Device> device);
void UpdateDiscoveryBlockList(scoped_refptr<Device> device);
void RemoveFromDiscoveryBlockList(scoped_refptr<Device> device);
bool has_at_least_one_discovery_session_ = false;
// |device_currently_showing_notification_| can be null if there is no
// notification currently displayed to user.
scoped_refptr<Device> device_currently_showing_notification_;
// The discovery notification block-list, where
// std::pair<std::string, Protocol> represents the block-list key of the
// device’s model ID and the pairing protocol corresponding (either initial
// or subsequent), and the value is
// std::pair<DiscoveryNotificationDismissalState, std::optional<base::Time>
// representing the current state of the device and the timestamp of when it
// is set to expire. It is optional because `kLongBan` does not have an expire
// timeout. This block-list bans a device model (by model ID), which means
// that if a user has two of the same device, or two devices are pairing in
// the same range, both will be blocked for discovery notifications. This is a
// rare edge case that we consider in order to align with Android by banning
// by model id. We don’t expect many users to have two of the same device, or
// two of the same device pairing in the same range at the same time, and
// users can pair via Bluetooth settings if needed. We cannot use the BLE
// address as a unique identifier for a device because it rotates, and when
// Fast Pair shows the discovery notifications, it does not yet have the
// classic mac address to unique identify a device (this is given as part of
// the FastPairHandshake).
base::flat_map<
std::pair<std::string, Protocol>,
std::pair<DiscoveryNotificationDismissalState, std::optional<base::Time>>>
discovery_notification_block_list_;
std::unique_ptr<FeatureStatusTracker> feature_status_tracker_;
std::unique_ptr<ScannerBroker> scanner_broker_;
std::unique_ptr<MessageStreamLookup> message_stream_lookup_;
std::unique_ptr<PairerBroker> pairer_broker_;
std::unique_ptr<RetroactivePairingDetector> retroactive_pairing_detector_;
std::unique_ptr<UIBroker> ui_broker_;
std::unique_ptr<CompanionAppBroker> companion_app_broker_;
std::unique_ptr<FastPairRepository> fast_pair_repository_;
std::unique_ptr<QuickPairProcessManager> process_manager_;
std::unique_ptr<QuickPairMetricsLogger> metrics_logger_;
std::unique_ptr<FastPairBluetoothConfigDelegate>
fast_pair_bluetooth_config_delegate_;
std::unique_ptr<BatteryUpdateMessageHandler> battery_update_message_handler_;
base::ScopedObservation<FeatureStatusTracker, FeatureStatusTracker::Observer>
feature_status_tracker_observation_{this};
base::ScopedObservation<ScannerBroker, ScannerBroker::Observer>
scanner_broker_observation_{this};
base::ScopedObservation<PairerBroker, PairerBroker::Observer>
pairer_broker_observation_{this};
base::ScopedObservation<RetroactivePairingDetector,
RetroactivePairingDetector::Observer>
retroactive_pairing_detector_observation_{this};
base::ScopedObservation<UIBroker, UIBroker::Observer> ui_broker_observation_{
this};
base::ScopedObservation<CompanionAppBroker, CompanionAppBroker::Observer>
companion_app_broker_observation_{this};
base::ScopedObservation<bluetooth_config::AdapterStateController,
bluetooth_config::AdapterStateController::Observer>
adapter_state_controller_observation_{this};
mojo::Remote<bluetooth_config::mojom::CrosBluetoothConfig>
remote_cros_bluetooth_config_;
mojo::Receiver<bluetooth_config::mojom::DiscoverySessionStatusObserver>
cros_discovery_session_observer_receiver_{this};
base::WeakPtrFactory<Mediator> weak_ptr_factory_{this};
};
} // namespace quick_pair
} // namespace ash
#endif // ASH_QUICK_PAIR_KEYED_SERVICE_QUICK_PAIR_MEDIATOR_H_