diff --git a/fastpair/BUILD b/fastpair/BUILD index 664d985d..43c3a171 100644 --- a/fastpair/BUILD +++ b/fastpair/BUILD @@ -52,3 +52,70 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "fast_pair_seeker", + hdrs = ["fast_pair_seeker.h"], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//:__subpackages__"], + deps = [ + "//fastpair/common", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", + ], +) + +cc_library( + name = "fast_pair_plugin", + hdrs = ["fast_pair_plugin.h"], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//:__subpackages__"], + deps = [ + ":fast_pair_events", + ":fast_pair_seeker", + ], +) + +cc_library( + name = "fast_pair_events", + hdrs = ["fast_pair_events.h"], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//:__subpackages__"], + deps = [ + ], +) + +cc_library( + name = "fast_pair_service", + srcs = ["fast_pair_service.cc"], + hdrs = ["fast_pair_service.h"], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//:__subpackages__"], + deps = [ + ":fast_pair_plugin", + ":fast_pair_seeker", + "//fastpair/internal", + "//internal/platform:types", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + ], +) + +cc_test( + name = "fast_pair_service_test", + size = "small", + srcs = [ + "fast_pair_service_test.cc", + ], + deps = [ + ":fast_pair_plugin", + ":fast_pair_service", + "//fastpair/internal", + "//internal/platform:logging", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/fast_pair_events.h b/fastpair/fast_pair_events.h new file mode 100644 index 00000000..65249fab --- /dev/null +++ b/fastpair/fast_pair_events.h @@ -0,0 +1,38 @@ +// Copyright 2023 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_FAST_PAIR_EVENTS_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_EVENTS_H_ + +namespace nearby { +namespace fastpair { + +// Fast Pair plugins receive notifications from the FP service about various +// system events. The structures below provide details about the events. + +struct InitialDiscoveryEvent {}; + +struct SubsequentDiscoveryEvent {}; + +struct PairEvent {}; + +struct ScreenEvent {}; + +struct BatteryEvent {}; + +struct RingEvent {}; + +} // namespace fastpair +} // namespace nearby +#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_EVENTS_H_ diff --git a/fastpair/fast_pair_plugin.h b/fastpair/fast_pair_plugin.h new file mode 100644 index 00000000..0d6628c1 --- /dev/null +++ b/fastpair/fast_pair_plugin.h @@ -0,0 +1,58 @@ +// Copyright 2023 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_FAST_PAIR_PLUGIN_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_PLUGIN_H_ + +#include + +#include "fastpair/fast_pair_events.h" +#include "fastpair/fast_pair_seeker.h" + +namespace nearby { +namespace fastpair { + +class FastPairPlugin { + public: + virtual ~FastPairPlugin() = default; + + // All functions below are synchronous. + virtual void OnInitialDiscoveryEvent(const InitialDiscoveryEvent& event) {} + virtual void OnSubsequentDiscoveryEvent( + const SubsequentDiscoveryEvent& event) {} + // Handles pair, unpair events. + virtual void OnPairEvent(const PairEvent& event) {} + virtual void OnScreenEvent(const ScreenEvent& event) {} + virtual void OnBatteryEvent(const BatteryEvent& event) {} + virtual void OnRingEvent(const RingEvent& event) {} +}; + +class FastPairPluginProvider { + public: + virtual ~FastPairPluginProvider() = default; + + // Returns an instance of `FastPairPlugin`. + // + // The plugin can use the `seeker` to communicate with the Fast Pair Seeker + // Service. `seeker` is always non-null and has a lifetime at least as long as + // the plugin returned by this call. + // `device` is a non-null. + virtual std::unique_ptr GetPlugin( + FastPairSeeker* seeker, const FastPairDevice* device) = 0; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_PLUGIN_H_ diff --git a/fastpair/fast_pair_seeker.h b/fastpair/fast_pair_seeker.h new file mode 100644 index 00000000..d945c923 --- /dev/null +++ b/fastpair/fast_pair_seeker.h @@ -0,0 +1,79 @@ +// Copyright 2023 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_FAST_PAIR_SEEKER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SEEKER_H_ + +#include "absl/functional/any_invocable.h" +#include "absl/status/status.h" +#include "fastpair/common/fast_pair_device.h" + +namespace nearby { +namespace fastpair { + +// Pairing result callback. +struct PairingCallback { + absl::AnyInvocable + on_pairing_result = + [](const FastPairDevice& device, absl::Status status) {}; +}; + +// Initial Pairing parameters. +struct InitialPairingParam {}; + +// Subsequent Pairing parameters. +struct SubsequentPairingParam {}; + +// Retroactive Pairing parameters. +struct RetroactivePairingParam {}; + +// Fast Pair Seeker API available to plugins. +class FastPairSeeker { + public: + virtual ~FastPairSeeker() = default; + + // Starts asynchronous initial pairing flow. This pairing flow is used with + // devices that we see for the first time. + // + // Returns an error if pairing flow could not be started. Otherwise, the + // pairing result will be returned via the `callback`. + virtual absl::Status StartInitialPairing(FastPairDevice& device, + const InitialPairingParam& params, + PairingCallback callback) = 0; + + // Starts asynchronous subsequent pairing flow. This pairing flow is used when + // device is an already known peripheral. The user paired with that device in + // the past, perhaps using a different seeker and `device` already has an + // Account Key. + // + // Returns an error if pairing flow could not be started. Otherwise, the + // pairing result will be returned via the `callback`. + virtual absl::Status StartSubsequentPairing( + FastPairDevice& device, const SubsequentPairingParam& params, + PairingCallback callback) = 0; + + // Starts asynchronous retroactive pairing flow. This pairing flow is used + // when the user has paired manually with a new device and we want to + // retroactively exchange an Account Key. See: + // https://developers.google.com/nearby/fast-pair/specifications/extensions/retroactiveacctkey + // + // Returns an error if pairing flow could not be started. Otherwise, the + // pairing result will be returned via the `callback`. + virtual absl::Status StartRetroactivePairing( + FastPairDevice& device, const RetroactivePairingParam& param, + PairingCallback callback) = 0; +}; +} // namespace fastpair +} // namespace nearby +#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SEEKER_H_ diff --git a/fastpair/fast_pair_service.cc b/fastpair/fast_pair_service.cc new file mode 100644 index 00000000..93823b51 --- /dev/null +++ b/fastpair/fast_pair_service.cc @@ -0,0 +1,146 @@ +// Copyright 2023 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/fast_pair_service.h" + +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "fastpair/fast_pair_plugin.h" +#include "fastpair/internal/fast_pair_seeker_impl.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { + +namespace { +constexpr absl::Duration kTimeout = absl::Seconds(3); +} + +FastPairService::FastPairService() { + seeker_ = + std::make_unique(FastPairSeekerImpl::ServiceCallbacks{ + .on_device_added = + [this](std::unique_ptr device) { + AddDevice(std::move(device)); + }, + .on_device_lost = + [this](const FastPairDevice& device) { RemoveDevice(&device); }, + .on_initial_discovery = + [this](const FastPairDevice& device, + InitialDiscoveryEvent event) { + OnInitialDiscoveryEvent(device, std::move(event)); + }, + .on_subsequent_discovery = + [this](const FastPairDevice& device, + SubsequentDiscoveryEvent event) { + OnSubsequentDiscoveryEvent(device, std::move(event)); + }, + .on_pair_event = + [this](const FastPairDevice& device, PairEvent event) { + OnPairEvent(device, std::move(event)); + }, + .on_screen_event = + [this](const FastPairDevice& device, ScreenEvent event) { + OnScreenEvent(device, std::move(event)); + }, + .on_battery_event = + [this](const FastPairDevice& device, BatteryEvent event) { + OnBatteryEvent(device, std::move(event)); + }, + .on_ring_event = + [this](const FastPairDevice& device, RingEvent event) { + OnRingEvent(device, std::move(event)); + }}); +} + +absl::Status FastPairService::RegisterPluginProvider( + absl::string_view name, std::unique_ptr provider) { + Future result; + executor_.Execute("register-plugin", [&]() { + bool success = + providers_.insert({std::string(name), std::move(provider)}).second; + absl::Status status = success + ? absl::OkStatus() + : absl::AlreadyExistsError(absl::StrFormat( + "Plugin '%s' already registered", name)); + result.Set(status); + }); + ExceptionOr status = result.Get(kTimeout); + return status.ok() ? status.GetResult() + : absl::DeadlineExceededError("Register plugin timeout"); +} + +absl::Status FastPairService::UnregisterPluginProvider(absl::string_view name) { + Future result; + executor_.Execute("unregister-plugin", [&]() { + bool success = success = providers_.erase(name); + absl::Status status = success + ? absl::OkStatus() + : absl::NotFoundError(absl::StrFormat( + "Plugin '%s' already registered", name)); + result.Set(status); + }); + ExceptionOr status = result.Get(kTimeout); + return status.ok() ? status.GetResult() + : absl::DeadlineExceededError("Unregister plugin timeout"); +} + +void FastPairService::AddDevice(std::unique_ptr device) { + NEARBY_LOGS(INFO) << "Add device " << *device; + executor_.Execute("add-device", [this, device = std::move(device)]() mutable { + devices_.push_back(std::move(device)); + }); +} + +void FastPairService::RemoveDevice(const FastPairDevice* device) { + NEARBY_LOGS(INFO) << "Remove device " << *device; + executor_.Execute("remove-device", [this, device]() { + devices_.erase( + std::remove_if(devices_.begin(), devices_.end(), + [&](const std::unique_ptr& item) { + return item.get() == device; + }), + devices_.end()); + }); +} + +void FastPairService::OnInitialDiscoveryEvent(const FastPairDevice& device, + InitialDiscoveryEvent event) { + executor_.Execute("on-initial-discovery", [this, device = &device, + event = std::move(event)]() { + NEARBY_LOGS(INFO) << "OnInitialDiscoveryEvent " << *device; + for (auto& entry : providers_) { + auto plugin = entry.second->GetPlugin(seeker_.get(), device); + plugin->OnInitialDiscoveryEvent(event); + } + }); +} +void FastPairService::OnSubsequentDiscoveryEvent( + const FastPairDevice& device, SubsequentDiscoveryEvent event) {} +void FastPairService::OnPairEvent(const FastPairDevice& device, + PairEvent event) {} +void FastPairService::OnScreenEvent(const FastPairDevice& device, + ScreenEvent event) {} +void FastPairService::OnBatteryEvent(const FastPairDevice& device, + BatteryEvent event) {} +void FastPairService::OnRingEvent(const FastPairDevice& device, + RingEvent event) {} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/fast_pair_service.h b/fastpair/fast_pair_service.h new file mode 100644 index 00000000..9e9286d8 --- /dev/null +++ b/fastpair/fast_pair_service.h @@ -0,0 +1,74 @@ +// Copyright 2023 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_FAST_PAIR_SERVICE_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SERVICE_H_ + +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "fastpair/fast_pair_plugin.h" +#include "fastpair/fast_pair_seeker.h" +#include "internal/platform/single_thread_executor.h" + +namespace nearby { +namespace fastpair { + +// Fast Pair Seeker Service. There should be only one instance of the service +// running on the system. +class FastPairService { + public: + FastPairService(); + + // Registers a plugin provider. `name` must be a unique. + // Returns an error if a provider with the same `name` is already registered. + absl::Status RegisterPluginProvider( + absl::string_view name, std::unique_ptr provider); + + // Unregisters a plugin provider and removes all plugins created by that + // provider. Returns an error if there is no plugin provider registered with + // `name`. + absl::Status UnregisterPluginProvider(absl::string_view name); + + // Returns a `FastPairSeeker` implementation. The returned object has the + // same lifetime as this `FastPairService` instance. + FastPairSeeker* GetSeeker() const { return seeker_.get(); } + + private: + void AddDevice(std::unique_ptr device); + void RemoveDevice(const FastPairDevice* device); + void OnInitialDiscoveryEvent(const FastPairDevice& device, + InitialDiscoveryEvent event); + void OnSubsequentDiscoveryEvent(const FastPairDevice& device, + SubsequentDiscoveryEvent event); + void OnPairEvent(const FastPairDevice& device, PairEvent event); + void OnScreenEvent(const FastPairDevice& device, ScreenEvent event); + void OnBatteryEvent(const FastPairDevice& device, BatteryEvent event); + void OnRingEvent(const FastPairDevice& device, RingEvent event); + SingleThreadExecutor executor_; + std::unique_ptr seeker_; + absl::flat_hash_map> + providers_; + std::vector> devices_; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SERVICE_H_ diff --git a/fastpair/fast_pair_service_test.cc b/fastpair/fast_pair_service_test.cc new file mode 100644 index 00000000..2f23c187 --- /dev/null +++ b/fastpair/fast_pair_service_test.cc @@ -0,0 +1,87 @@ +// Copyright 2023 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/fast_pair_service.h" + +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "fastpair/fast_pair_plugin.h" +#include "fastpair/internal/fast_pair_seeker_impl.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { + +namespace { +using ::testing::status::StatusIs; + +class FakeFastPairPluginProvider : public FastPairPluginProvider { + public: + std::unique_ptr GetPlugin( + FastPairSeeker* seeker, const FastPairDevice* device) override { + return std::make_unique(); + } +}; + +TEST(FastPairService, RegisterUnregister) { + constexpr absl::string_view kPluginName = "my plugin"; + FastPairService service; + + EXPECT_OK(service.RegisterPluginProvider( + kPluginName, std::make_unique())); + EXPECT_OK(service.UnregisterPluginProvider(kPluginName)); +} + +TEST(FastPairService, RegisterTwiceFails) { + constexpr absl::string_view kPluginName = "my plugin"; + FastPairService service; + EXPECT_OK(service.RegisterPluginProvider( + kPluginName, std::make_unique())); + + EXPECT_THAT(service.RegisterPluginProvider( + kPluginName, std::make_unique()), + StatusIs(absl::StatusCode::kAlreadyExists)); +} + +TEST(FastPairService, UnregisterTwiceFails) { + constexpr absl::string_view kPluginName = "my plugin"; + FastPairService service; + EXPECT_OK(service.RegisterPluginProvider( + kPluginName, std::make_unique())); + EXPECT_OK(service.UnregisterPluginProvider(kPluginName)); + + EXPECT_THAT(service.UnregisterPluginProvider(kPluginName), + StatusIs(absl::StatusCode::kNotFound)); +} + +TEST(FastPairService, FakeInitialPairing) { + constexpr absl::string_view kPluginName = "my plugin"; + FastPairService service; + EXPECT_OK(service.RegisterPluginProvider( + kPluginName, std::make_unique())); + FastPairSeekerExt* seeker = + static_cast(service.GetSeeker()); + + EXPECT_OK(seeker->StartFastPairScan()); + EXPECT_OK(seeker->StopFastPairScan()); + + EXPECT_OK(service.UnregisterPluginProvider(kPluginName)); +} + +} // namespace +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/BUILD b/fastpair/internal/BUILD new file mode 100644 index 00000000..553c53b4 --- /dev/null +++ b/fastpair/internal/BUILD @@ -0,0 +1,18 @@ +licenses(["notice"]) + +cc_library( + name = "internal", + srcs = ["fast_pair_seeker_impl.cc"], + hdrs = [ + "fast_pair_seeker_impl.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + visibility = [ + "//fastpair:__subpackages__", + ], + deps = [ + "//fastpair:fast_pair_events", + "//fastpair:fast_pair_seeker", + "@com_google_absl//absl/status", + ], +) diff --git a/fastpair/internal/fast_pair_seeker_impl.cc b/fastpair/internal/fast_pair_seeker_impl.cc new file mode 100644 index 00000000..2588996b --- /dev/null +++ b/fastpair/internal/fast_pair_seeker_impl.cc @@ -0,0 +1,60 @@ +// Copyright 2023 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/internal/fast_pair_seeker_impl.h" + +#include +#include + +#include "absl/status/status.h" + +namespace nearby { +namespace fastpair { + +absl::Status FastPairSeekerImpl::StartInitialPairing( + FastPairDevice& device, const InitialPairingParam& params, + PairingCallback callback) { + return absl::UnimplementedError("StartInitialPairing"); +} + +absl::Status FastPairSeekerImpl::StartSubsequentPairing( + FastPairDevice& device, const SubsequentPairingParam& params, + PairingCallback callback) { + return absl::UnimplementedError("StartSubsequentPairing"); +} + +absl::Status FastPairSeekerImpl::StartRetroactivePairing( + FastPairDevice& device, const RetroactivePairingParam& param, + PairingCallback callback) { + return absl::UnimplementedError("StartRetroactivePairing"); +} + +absl::Status FastPairSeekerImpl::StartFastPairScan() { + // TODO(jsobczak): Replace with actual implementation + auto device = std::make_unique( + "model_id", "11:22:33:44:55:66", Protocol::kFastPairInitialPairing); + test_device_ = device.get(); + callbacks_.on_device_added(std::move(device)); + callbacks_.on_initial_discovery(*test_device_, {}); + return absl::OkStatus(); +} + +absl::Status FastPairSeekerImpl::StopFastPairScan() { + // TODO(jsobczak): Replace with actual implementation + callbacks_.on_device_lost(*test_device_); + return absl::OkStatus(); +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/fast_pair_seeker_impl.h b/fastpair/internal/fast_pair_seeker_impl.h new file mode 100644 index 00000000..6aa6d3c9 --- /dev/null +++ b/fastpair/internal/fast_pair_seeker_impl.h @@ -0,0 +1,83 @@ +// Copyright 2023 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_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_ + +#include +#include + +#include "fastpair/fast_pair_events.h" +#include "fastpair/fast_pair_seeker.h" + +namespace nearby { +namespace fastpair { + +// Fast Pair Seeker Extended interface. +// The methods in this interface are available only to FP internal plugins. +class FastPairSeekerExt : public FastPairSeeker { + public: + virtual absl::Status StartFastPairScan() = 0; + virtual absl::Status StopFastPairScan() = 0; +}; + +class FastPairSeekerImpl : public FastPairSeekerExt { + public: + struct ServiceCallbacks { + absl::AnyInvocable)> on_device_added; + absl::AnyInvocable on_device_lost; + + absl::AnyInvocable + on_initial_discovery; + absl::AnyInvocable + on_subsequent_discovery; + absl::AnyInvocable on_pair_event; + absl::AnyInvocable + on_screen_event; + absl::AnyInvocable + on_battery_event; + absl::AnyInvocable on_ring_event; + }; + + explicit FastPairSeekerImpl(ServiceCallbacks callbacks) + : callbacks_(std::move(callbacks)) {} + + // From FastPairSeeker. + absl::Status StartInitialPairing(FastPairDevice& device, + const InitialPairingParam& params, + PairingCallback callback) override; + + absl::Status StartSubsequentPairing(FastPairDevice& device, + const SubsequentPairingParam& params, + PairingCallback callback) override; + + absl::Status StartRetroactivePairing(FastPairDevice& device, + const RetroactivePairingParam& param, + PairingCallback callback) override; + + // From FastPairSeekerExt + absl::Status StartFastPairScan() override; + absl::Status StopFastPairScan() override; + + // Internal methods, not exported to plugins. + + private: + ServiceCallbacks callbacks_; + FastPairDevice* test_device_ = nullptr; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_