diff --git a/fastpair/scanning/BUILD b/fastpair/scanning/BUILD new file mode 100644 index 00000000..757f100e --- /dev/null +++ b/fastpair/scanning/BUILD @@ -0,0 +1,62 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_library( + name = "scanner", + srcs = [ + "scanner_broker_impl.cc", + ], + hdrs = [ + "scanner_broker.h", + "scanner_broker_impl.h", + ], + visibility = [ + "//:__subpackages__", + "//fastpair:__subpackages__", + ], + deps = [ + "//fastpair/common", + "//fastpair/internal/ble", + "//fastpair/scanning/fastpair:scanning", + "//internal/base", + "//internal/platform:base", + "//internal/platform:comm", + "//internal/platform:logging", + "//internal/platform:types", + "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "scanner_broker_impl_test", + size = "small", + srcs = [ + "scanner_broker_impl_test.cc", + ], + shard_count = 16, + deps = [ + ":scanner", + "//fastpair/common", + "//fastpair/scanning/fastpair:scanning", + "//fastpair/scanning/fastpair:test_support", + "//internal/platform:test_util", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/scanning/fastpair/BUILD b/fastpair/scanning/fastpair/BUILD index 8b8d7243..337391a1 100644 --- a/fastpair/scanning/fastpair/BUILD +++ b/fastpair/scanning/fastpair/BUILD @@ -48,6 +48,26 @@ cc_library( ], ) +cc_library( + name = "test_support", + srcs = [ + "fake_fast_pair_scanner.cc", + ], + hdrs = [ + "fake_fast_pair_discoverable_scanner.h", + "fake_fast_pair_scanner.h", + ], + visibility = [ + "//fastpair/scanning:__subpackages__", + ], + deps = [ + ":scanning", + "//fastpair/common", + "//internal/base", + "@com_google_absl//absl/functional:any_invocable", + ], +) + cc_test( name = "fast_pair_scanner_impl_test", size = "small", diff --git a/fastpair/scanning/fastpair/fake_fast_pair_discoverable_scanner.h b/fastpair/scanning/fastpair/fake_fast_pair_discoverable_scanner.h new file mode 100644 index 00000000..7dcbb8b9 --- /dev/null +++ b/fastpair/scanning/fastpair/fake_fast_pair_discoverable_scanner.h @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_DISCOVERABLE_SCANNER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_DISCOVERABLE_SCANNER_H_ + +#include + +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" + +namespace nearby { +namespace fastpair { + +class FakeFastPairDiscoverableScanner : public FastPairDiscoverableScanner { + public: + FakeFastPairDiscoverableScanner(DeviceCallback found_callback, + DeviceCallback lost_callback) + : found_callback_(std::move(found_callback)), + lost_callback_(std::move(lost_callback)) {} + + ~FakeFastPairDiscoverableScanner() override = default; + + void TriggerDeviceFoundCallback(FastPairDevice& device) { + found_callback_(device); + } + + void TriggerDeviceLostCallback(FastPairDevice& device) { + lost_callback_(device); + } + + private: + DeviceCallback found_callback_; + DeviceCallback lost_callback_; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_DISCOVERABLE_SCANNER_H_ diff --git a/fastpair/scanning/fastpair/fake_fast_pair_scanner.cc b/fastpair/scanning/fastpair/fake_fast_pair_scanner.cc new file mode 100644 index 00000000..2f003064 --- /dev/null +++ b/fastpair/scanning/fastpair/fake_fast_pair_scanner.cc @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastpair/scanning/fastpair/fake_fast_pair_scanner.h" + +namespace nearby { +namespace fastpair { + +void FakeFastPairScanner::AddObserver(Observer* observer) { + observer_.AddObserver(observer); +} + +void FakeFastPairScanner::RemoveObserver(Observer* observer) { + observer_.RemoveObserver(observer); +} + +void FakeFastPairScanner::NotifyDeviceFound(const BlePeripheral& peripheral) { + for (auto& obs : observer_) obs->OnDeviceFound(peripheral); +} + +void FakeFastPairScanner::NotifyDeviceLost(const BlePeripheral& peripheral) { + for (auto& obs : observer_) obs->OnDeviceLost(peripheral); +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/scanning/fastpair/fake_fast_pair_scanner.h b/fastpair/scanning/fastpair/fake_fast_pair_scanner.h new file mode 100644 index 00000000..90cd7c95 --- /dev/null +++ b/fastpair/scanning/fastpair/fake_fast_pair_scanner.h @@ -0,0 +1,44 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_SCANNER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_SCANNER_H_ + +#include "fastpair/scanning/fastpair/fast_pair_scanner.h" +#include "internal/base/observer_list.h" + +namespace nearby { +namespace fastpair { + +class FakeFastPairScanner final : public FastPairScanner { + public: + FakeFastPairScanner() = default; + FakeFastPairScanner(const FakeFastPairScanner&) = delete; + FakeFastPairScanner& operator=(const FakeFastPairScanner&) = delete; + + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + void NotifyDeviceFound(const BlePeripheral& peripheral); + void NotifyDeviceLost(const BlePeripheral& peripheral); + + private: + ~FakeFastPairScanner() override = default; + + ObserverList observer_; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAKE_FAST_PAIR_SCANNER_H_ diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc index 154821d5..1f59ba12 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc @@ -30,6 +30,27 @@ constexpr absl::Duration kFastPairLowPowerActiveSeconds = absl::Seconds(2); constexpr absl::Duration kFastPairLowPowerInactiveSeconds = absl::Seconds(3); } // namespace +// static +FastPairScannerImpl::Factory* FastPairScannerImpl::Factory::g_test_factory_ = + nullptr; + +// static +std::shared_ptr FastPairScannerImpl::Factory::Create() { + if (g_test_factory_) { + return g_test_factory_->CreateInstance(); + } + + return std::make_shared(); +} + +// static +void FastPairScannerImpl::Factory::SetFactoryForTesting( + Factory* g_test_factory) { + g_test_factory_ = g_test_factory; +} + +FastPairScannerImpl::Factory::~Factory() = default; + // FastPairScannerImpl FastPairScannerImpl::FastPairScannerImpl() { task_runner_ = std::make_shared(1); diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl.h b/fastpair/scanning/fastpair/fast_pair_scanner_impl.h index ab454a13..8534be02 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl.h +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl.h @@ -33,6 +33,20 @@ namespace fastpair { class FastPairScannerImpl : public FastPairScanner { public: + class Factory { + public: + static std::shared_ptr Create(); + + static void SetFactoryForTesting(Factory* g_test_factory); + + protected: + virtual ~Factory(); + virtual std::shared_ptr CreateInstance() = 0; + + private: + static Factory* g_test_factory_; + }; + FastPairScannerImpl(); FastPairScannerImpl(const FastPairScannerImpl&) = delete; FastPairScannerImpl& operator=(const FastPairScannerImpl&) = delete; diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc index f61def65..6f2b9c99 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc @@ -122,6 +122,15 @@ class FastPairScannerImplTest : public testing::Test { std::unique_ptr scanner_observer_; }; +TEST_F(FastPairScannerImplTest, FactoryCreatSuccessfully) { + env_.Start(); + std::shared_ptr scanner = + FastPairScannerImpl::Factory::Create(); + EXPECT_TRUE(scanner); + scanner.reset(); + env_.Stop(); +} + TEST_F(FastPairScannerImplTest, StartScanningSuccessfully) { env_.Start(); scanner_->StartScanning(); diff --git a/fastpair/scanning/scanner_broker.h b/fastpair/scanning/scanner_broker.h new file mode 100644 index 00000000..0e191e28 --- /dev/null +++ b/fastpair/scanning/scanner_broker.h @@ -0,0 +1,51 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_H_ + +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/protocol.h" + +namespace nearby { +namespace fastpair { + +// The ScannerBroker is the entry point for the Scanning component in the Fast +// Pair. It is responsible for brokering the start/stop scanning calls +// to the correct concrete Scanner implementation, and exposing an observer +// pattern for other components to become aware of device found/lost events. +class ScannerBroker { + public: + // Observes the activity of the scan broker. + class Observer { + public: + virtual ~Observer() = default; + + virtual void OnDeviceFound(const FastPairDevice& device) = 0; + virtual void OnDeviceLost(const FastPairDevice& device) = 0; + }; + + virtual ~ScannerBroker() = default; + + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + virtual void StartScanning(Protocol protocol) = 0; + virtual void StopScanning(Protocol protocol) = 0; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_H_ diff --git a/fastpair/scanning/scanner_broker_impl.cc b/fastpair/scanning/scanner_broker_impl.cc new file mode 100644 index 00000000..e08279b7 --- /dev/null +++ b/fastpair/scanning/scanner_broker_impl.cc @@ -0,0 +1,91 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastpair/scanning/scanner_broker_impl.h" + +#include +#include + +#include "absl/functional/bind_front.h" +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h" +#include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" +#include "internal/platform/bluetooth_adapter.h" +#include "internal/platform/logging.h" +#include "internal/platform/task_runner_impl.h" + +namespace nearby { +namespace fastpair { +ScannerBrokerImpl::ScannerBrokerImpl() { + adapter_ = std::make_shared(); + task_runner_ = std::make_shared(1); +} + +void ScannerBrokerImpl::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void ScannerBrokerImpl::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void ScannerBrokerImpl::StartScanning(Protocol protocol) { + NEARBY_LOGS(VERBOSE) << __func__ << ": protocol=" << protocol; + task_runner_->PostTask([this]() { StartFastPairScanning(); }); +} + +void ScannerBrokerImpl::StopScanning(Protocol protocol) { + NEARBY_LOGS(VERBOSE) << __func__ << ": protocol=" << protocol; + task_runner_->PostTask([this]() { StopFastPairScanning(); }); +} +void ScannerBrokerImpl::StartFastPairScanning() { + DCHECK(!fast_pair_discoverable_scanner_); + DCHECK(adapter_); + NEARBY_LOGS(VERBOSE) << "Starting Fast Pair Scanning."; + scanner_impl_ = std::make_shared(); + scanner_impl_->StartScanning(); + scanner_ = std::move(scanner_impl_); + + fast_pair_discoverable_scanner_ = + FastPairDiscoverableScannerImpl::Factory::Create( + scanner_, adapter_, + absl::bind_front(&ScannerBrokerImpl::NotifyDeviceFound, this), + absl::bind_front(&ScannerBrokerImpl::NotifyDeviceLost, this)); +} + +void ScannerBrokerImpl::StopFastPairScanning() { + fast_pair_discoverable_scanner_.reset(); + observers_.Clear(); + NEARBY_LOGS(VERBOSE) << __func__ << "Stopping Fast Pair Scanning."; +} + +void ScannerBrokerImpl::NotifyDeviceFound(const FastPairDevice& device) { + NEARBY_LOGS(INFO) << __func__ << ": Notifying device found, model id = " + << device.model_id; + for (auto& observer : observers_) { + observer->OnDeviceFound(device); + } +} + +void ScannerBrokerImpl::NotifyDeviceLost(const FastPairDevice& device) { + NEARBY_LOGS(INFO) << __func__ << ": Notifying device lost, model id = " + << device.model_id; + for (auto& observer : observers_) { + observer->OnDeviceLost(device); + } +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/scanning/scanner_broker_impl.h b/fastpair/scanning/scanner_broker_impl.h new file mode 100644 index 00000000..c496f883 --- /dev/null +++ b/fastpair/scanning/scanner_broker_impl.h @@ -0,0 +1,62 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_IMPL_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_IMPL_H_ + +#include +#include +#include + +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" +#include "fastpair/scanning/scanner_broker.h" +#include "internal/base/observer_list.h" +#include "internal/platform/bluetooth_adapter.h" +#include "internal/platform/task_runner.h" + +namespace nearby { +namespace fastpair { + +class ScannerBrokerImpl : public ScannerBroker { + public: + explicit ScannerBrokerImpl(); + ~ScannerBrokerImpl() override = default; + + // ScannerBroker: + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + void StartScanning(Protocol protocol) override; + void StopScanning(Protocol protocol) override; + + private: + void StartFastPairScanning(); + void StopFastPairScanning(); + void NotifyDeviceFound(const FastPairDevice& device); + void NotifyDeviceLost(const FastPairDevice& device); + + std::shared_ptr task_runner_; + std::shared_ptr scanner_; + std::shared_ptr scanner_impl_; + std::shared_ptr adapter_; + std::unique_ptr fast_pair_discoverable_scanner_; + ObserverList observers_; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_IMPL_H_ diff --git a/fastpair/scanning/scanner_broker_impl_test.cc b/fastpair/scanning/scanner_broker_impl_test.cc new file mode 100644 index 00000000..2a77588d --- /dev/null +++ b/fastpair/scanning/scanner_broker_impl_test.cc @@ -0,0 +1,216 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastpair/scanning/scanner_broker_impl.h" + +#include +#include +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/protocol.h" +#include "fastpair/scanning/fastpair/fake_fast_pair_discoverable_scanner.h" +#include "fastpair/scanning/fastpair/fake_fast_pair_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h" +#include "fastpair/scanning/fastpair/fast_pair_scanner.h" +#include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" +#include "internal/platform/medium_environment.h" + +namespace nearby { +namespace fastpair { +namespace { + +constexpr absl::string_view kTestDeviceAddress("11:12:13:14:15:16"); +constexpr absl::string_view kValidModelId("718c17"); + +class FakeFastPairScannerFactory : public FastPairScannerImpl::Factory { + public: + // FastPairScannerImpl::Factory: + std::shared_ptr CreateInstance() override { + auto fake_fast_pair_scanner = std::shared_ptr(); + fake_fast_pair_scanner_ = fake_fast_pair_scanner.get(); + return fake_fast_pair_scanner; + } + + ~FakeFastPairScannerFactory() override = default; + + FakeFastPairScanner* fake_fast_pair_scanner() { + return fake_fast_pair_scanner_; + } + + private: + FakeFastPairScanner* fake_fast_pair_scanner_ = nullptr; +}; + +class FakeFastPairDiscoverableScannerFactory + : public FastPairDiscoverableScannerImpl::Factory { + public: + // FastPairDiscoverableScannerImpl::Factory: + std::unique_ptr CreateInstance( + std::shared_ptr scanner, + std::shared_ptr adapter, DeviceCallback found_callback, + DeviceCallback lost_callback) override { + create_instance_ = true; + auto fake_fast_pair_discoverable_scanner = + std::make_unique( + std::move(found_callback), std::move(lost_callback)); + fake_fast_pair_discoverable_scanner_ = + fake_fast_pair_discoverable_scanner.get(); + return fake_fast_pair_discoverable_scanner; + } + + ~FakeFastPairDiscoverableScannerFactory() override = default; + + FakeFastPairDiscoverableScanner* fake_fast_pair_discoverable_scanner() { + return fake_fast_pair_discoverable_scanner_; + } + + bool create_instance() { return create_instance_; } + + protected: + bool create_instance_ = false; + FakeFastPairDiscoverableScanner* fake_fast_pair_discoverable_scanner_ = + nullptr; +}; + +class ScannerBrokerImplTest : public testing::Test, + public ScannerBroker::Observer { + public: + ScannerBrokerImplTest() { + adapter_ = std::shared_ptr(); + scanner_factory_ = std::make_unique(); + FastPairScannerImpl::Factory::SetFactoryForTesting(scanner_factory_.get()); + + discoverable_scanner_factory_ = + std::make_unique(); + FastPairDiscoverableScannerImpl::Factory::SetFactoryForTesting( + discoverable_scanner_factory_.get()); + } + + ~ScannerBrokerImplTest() override { + scanner_broker_->RemoveObserver(this); + scanner_broker_.reset(); + adapter_.reset(); + } + + void CreateScannerBroker() { + scanner_broker_ = std::make_unique(); + scanner_broker_->AddObserver(this); + } + + void TriggerDiscoverableDeviceFound() { + FastPairDevice device(std::string(kValidModelId), + std::string(kTestDeviceAddress), + Protocol::kFastPairInitialPairing); + discoverable_scanner_factory_->fake_fast_pair_discoverable_scanner() + ->TriggerDeviceFoundCallback(device); + } + + void TriggerDiscoverableDeviceLost() { + FastPairDevice device(std::string(kValidModelId), + std::string(kTestDeviceAddress), + Protocol::kFastPairInitialPairing); + discoverable_scanner_factory_->fake_fast_pair_discoverable_scanner() + ->TriggerDeviceLostCallback(device); + } + + void OnDeviceFound(const FastPairDevice& device) override { + device_found_ = true; + } + + void OnDeviceLost(const FastPairDevice& device) override { + device_lost_ = true; + } + + protected: + bool device_found_ = false; + bool device_lost_ = false; + MediumEnvironment& env_{MediumEnvironment::Instance()}; + std::shared_ptr adapter_; + std::unique_ptr scanner_factory_; + std::unique_ptr + discoverable_scanner_factory_; + std::unique_ptr scanner_broker_; +}; + +TEST_F(ScannerBrokerImplTest, DiscoverableFound) { + env_.Start(); + EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); + + CreateScannerBroker(); + scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + EXPECT_FALSE(device_found_); + EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); + + TriggerDiscoverableDeviceFound(); + EXPECT_TRUE(device_found_); + env_.Stop(); +} + +TEST_F(ScannerBrokerImplTest, DiscoverableLost) { + env_.Start(); + EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); + + CreateScannerBroker(); + scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + EXPECT_FALSE(device_found_); + EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); + + TriggerDiscoverableDeviceLost(); + EXPECT_TRUE(device_lost_); + env_.Stop(); +} + +TEST_F(ScannerBrokerImplTest, RemoveObserver) { + env_.Start(); + EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); + + CreateScannerBroker(); + scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + EXPECT_FALSE(device_found_); + EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); + + scanner_broker_->RemoveObserver(this); + TriggerDiscoverableDeviceLost(); + EXPECT_FALSE(device_lost_); + env_.Stop(); +} + +TEST_F(ScannerBrokerImplTest, StopScanning) { + env_.Start(); + CreateScannerBroker(); + EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); + + scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); + + scanner_broker_->StopScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); + SystemClock::Sleep(absl::Milliseconds(200)); + EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); + env_.Stop(); +} + +} // namespace +} // namespace fastpair +} // namespace nearby