Implement scanner for fast pair subsequent pairing

PiperOrigin-RevId: 548841808
This commit is contained in:
Qin Wang
2023-07-17 17:20:01 -07:00
committed by Copybara-Service
parent 7899d18907
commit 99053e4df3
12 changed files with 738 additions and 7 deletions
+9
View File
@@ -97,6 +97,14 @@ class FastPairDevice {
return ble_address_;
}
void SetShowUiNotification(bool should_show_ui_notification) {
should_show_ui_notification_ = should_show_ui_notification;
}
std::optional<bool> ShouldShowUiNotification() const {
return should_show_ui_notification_;
}
private:
std::string model_id_;
@@ -126,6 +134,7 @@ class FastPairDevice {
AccountKey account_key_;
std::optional<DeviceMetadata> metadata_;
std::optional<bool> should_show_ui_notification_;
};
std::ostream& operator<<(std::ostream& stream, const FastPairDevice& device);
@@ -94,6 +94,10 @@ Mediator::Mediator(
void Mediator::OnDeviceFound(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": " << device;
if (device.ShouldShowUiNotification().value_or(false)) {
NEARBY_LOGS(INFO) << __func__ << ": Ignoring because show UI flag is false";
return;
}
if (IsDeviceCurrentlyShowingNotification(device)) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Extending notification for re-discovered device="
@@ -15,11 +15,13 @@
#include "fastpair/repository/fake_fast_pair_repository.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/constant.h"
#include "fastpair/proto/fastpair_rpcs.proto.h"
@@ -36,16 +38,32 @@ void FakeFastPairRepository::ClearFakeMetadata(absl::string_view hex_model_id) {
data_.erase(hex_model_id);
}
void FakeFastPairRepository::SetResultOfCheckIfAssociatedWithCurrentAccount(
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id) {
account_key_ = std::move(account_key);
model_id_ = std::move(model_id);
}
void FakeFastPairRepository::GetDeviceMetadata(
absl::string_view hex_model_id, DeviceMetadataCallback callback) {
executor_.Execute([callback = std::move(callback), this,
executor_.Execute([this, callback = std::move(callback),
hex_model_id = std::string(hex_model_id)]() mutable {
if (data_.contains(hex_model_id)) {
callback(*data_[hex_model_id]);
std::move(callback)(*data_[hex_model_id]);
} else {
std::move(callback)(std::nullopt);
}
});
}
void FakeFastPairRepository::CheckIfAssociatedWithCurrentAccount(
AccountKeyFilter& account_key_filter, CheckAccountKeysCallback callback) {
executor_.Execute([this, callback = std::move(callback)]() mutable {
std::move(callback)(account_key_, model_id_);
});
}
std::unique_ptr<FakeFastPairRepository> FakeFastPairRepository::Create(
absl::string_view model_id, absl::string_view public_anti_spoof_key) {
proto::Device metadata;
@@ -64,6 +82,5 @@ std::unique_ptr<FakeFastPairRepository> FakeFastPairRepository::Create(
repository->SetFakeMetadata(model_id, metadata);
return repository;
}
} // namespace fastpair
} // namespace nearby
@@ -17,9 +17,11 @@
#include <memory>
#include <string>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/platform/single_thread_executor.h"
@@ -39,6 +41,10 @@ class FakeFastPairRepository : public FastPairRepository {
void SetFakeMetadata(absl::string_view hex_model_id, proto::Device metadata);
void ClearFakeMetadata(absl::string_view hex_model_id);
void SetResultOfCheckIfAssociatedWithCurrentAccount(
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id);
// FastPairRepository::
void AddObserver(Observer* observer) override{};
void RemoveObserver(Observer* observer) override{};
@@ -58,10 +64,14 @@ class FakeFastPairRepository : public FastPairRepository {
void CheckIfAssociatedWithCurrentAccount(
AccountKeyFilter& account_key_filter,
CheckAccountKeysCallback callback) override{};
CheckAccountKeysCallback callback) override;
private:
absl::flat_hash_map<std::string, std::unique_ptr<DeviceMetadata>> data_;
// Results of CheckIfAssociatedWithCurrentAccount
std::optional<AccountKey> account_key_;
std::optional<absl::string_view> model_id_;
SingleThreadExecutor executor_;
};
} // namespace fastpair
+1
View File
@@ -69,6 +69,7 @@ cc_test(
"//fastpair/internal/mediums",
"//fastpair/proto:fastpair_cc_proto",
"//fastpair/repository:test_support",
"//fastpair/testing",
"//internal/platform:base",
"//internal/platform:test_util",
"//internal/platform:types",
+21
View File
@@ -18,11 +18,13 @@ cc_library(
name = "scanning",
srcs = [
"fast_pair_discoverable_scanner_impl.cc",
"fast_pair_non_discoverable_scanner.cc",
"fast_pair_scanner_impl.cc",
],
hdrs = [
"fast_pair_discoverable_scanner.h",
"fast_pair_discoverable_scanner_impl.h",
"fast_pair_non_discoverable_scanner.h",
"fast_pair_scanner.h",
"fast_pair_scanner_impl.h",
],
@@ -112,3 +114,22 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_non_discoverable_scanner_test",
size = "small",
srcs = [
"fast_pair_non_discoverable_scanner_test.cc",
],
shard_count = 16,
deps = [
":scanning",
":test_support",
"//fastpair/common",
"//fastpair/repository:test_support",
"//fastpair/testing",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,194 @@
// 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/scanning/fastpair/fast_pair_non_discoverable_scanner.h"
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include "fastpair/common/constant.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "fastpair/dataparser/fast_pair_data_parser.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
// static
FastPairNonDiscoverableScanner::Factory*
FastPairNonDiscoverableScanner::Factory::g_test_factory_ = nullptr;
// static
std::unique_ptr<FastPairNonDiscoverableScanner>
FastPairNonDiscoverableScanner::Factory::Create(
FastPairScanner& scanner, NonDiscoverableScannerCallback found_callback,
NonDiscoverableScannerCallback lost_callback,
SingleThreadExecutor* executor,
FastPairDeviceRepository* device_repository) {
if (g_test_factory_) {
return g_test_factory_->CreateInstance(scanner, std::move(found_callback),
std::move(lost_callback), executor,
device_repository);
}
return std::make_unique<FastPairNonDiscoverableScanner>(
scanner, std::move(found_callback), std::move(lost_callback), executor,
device_repository);
}
// static
void FastPairNonDiscoverableScanner::Factory::SetFactoryForTesting(
Factory* g_test_factory) {
g_test_factory_ = g_test_factory;
}
FastPairNonDiscoverableScanner::FastPairNonDiscoverableScanner(
FastPairScanner& scanner, NonDiscoverableScannerCallback found_callback,
NonDiscoverableScannerCallback lost_callback,
SingleThreadExecutor* executor, FastPairDeviceRepository* device_repository)
: scanner_(scanner),
found_callback_(std::move(found_callback)),
lost_callback_(std::move(lost_callback)),
executor_(executor),
device_repository_(device_repository) {
scanner_.AddObserver(this);
}
FastPairNonDiscoverableScanner::~FastPairNonDiscoverableScanner() {
scanner_.RemoveObserver(this);
}
void FastPairNonDiscoverableScanner::OnDeviceFound(
const BlePeripheral& peripheral) {
std::string fast_pair_service_data =
peripheral.GetAdvertisementBytes(kServiceId).string_data();
if (fast_pair_service_data.empty()) {
NEARBY_LOGS(WARNING) << __func__
<< ": Device doesn't have any Fast Pair Service Data.";
return;
}
executor_->Execute(
"device-found",
[this, fast_pair_service_data = std::move(fast_pair_service_data),
address =
peripheral.GetName()]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
NEARBY_LOGS(INFO) << __func__ << ": Attempting to parse advertisement.";
FastPairDataParser::ParseNotDiscoverableAdvertisement(
fast_pair_service_data, address,
[&](std::optional<NonDiscoverableAdvertisement> advertisement) {
OnAdvertisementParsed(address, advertisement);
});
});
}
void FastPairNonDiscoverableScanner::OnAdvertisementParsed(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement) {
if (!advertisement.has_value()) {
NEARBY_LOGS(INFO)
<< __func__ << ": Returning early because no advertisement was parsed.";
return;
}
NEARBY_LOGS(INFO)
<< __func__
<< ": Attempting to check if device is associated with current account.";
AccountKeyFilter account_filter(advertisement.value());
FastPairRepository::Get()->CheckIfAssociatedWithCurrentAccount(
account_filter, [&, address = std::string(address),
advertisement = std::move(advertisement)](
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id) {
OnAccountKeyFilterCheckResult(address, advertisement, account_key,
model_id);
});
}
void FastPairNonDiscoverableScanner::OnAccountKeyFilterCheckResult(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement,
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id) {
if (!account_key.has_value() || !model_id.has_value()) {
return;
}
NEARBY_LOGS(INFO) << __func__ << ": Attempting to get device metadata.";
FastPairRepository::Get()->GetDeviceMetadata(
model_id.value(),
[&, address = std::string(address),
advertisement = std::move(advertisement), model_id = model_id.value(),
account_key =
account_key.value()](std::optional<DeviceMetadata> device_metadata) {
OnDeviceMetadataRetrieved(address, advertisement, model_id, account_key,
device_metadata);
});
}
void FastPairNonDiscoverableScanner::OnDeviceMetadataRetrieved(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement,
absl::string_view model_id, AccountKey account_key,
std::optional<DeviceMetadata> device_metadata) {
if (!device_metadata.has_value()) {
NEARBY_LOGS(WARNING) << __func__ << ": Failed to get device metadata";
return;
}
auto fast_pair_device = std::make_unique<FastPairDevice>(
model_id, address, Protocol::kFastPairSubsequentPairing);
fast_pair_device->SetAccountKey(account_key);
fast_pair_device->SetMetadata(device_metadata.value());
fast_pair_device->SetShowUiNotification(
advertisement->type == NonDiscoverableAdvertisement::Type::kShowUi);
executor_->Execute(
"add-device",
[this, fast_pair_device = std::move(fast_pair_device)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable {
FastPairDevice* device =
device_repository_->AddDevice(std::move(fast_pair_device));
NotifyDeviceFound(*device);
});
}
void FastPairNonDiscoverableScanner::NotifyDeviceFound(FastPairDevice& device) {
NEARBY_LOGS(VERBOSE) << "Notify Device found:"
<< "BluetoothAddress = " << device.GetBleAddress()
<< ", Model id = " << device.GetModelId();
found_callback_(device);
}
void FastPairNonDiscoverableScanner::OnDeviceLost(
const BlePeripheral& peripheral) {
NEARBY_LOGS(INFO) << __func__ << ": Running lost callback";
executor_->Execute("device-lost",
[this, address = peripheral.GetName()]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
auto opt_device =
device_repository_->FindDevice(address);
// Don't invoke callback if we didn't notify this
// device.
if (!opt_device.has_value()) return;
FastPairDevice* device = opt_device.value();
lost_callback_(*device);
device_repository_->RemoveDevice(device);
});
}
} // namespace fastpair
} // namespace nearby
@@ -0,0 +1,104 @@
// 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_SCANNING_FASTPAIR_FAST_PAIR_NON_DISCOVERABLE_SCANNER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAST_PAIR_NON_DISCOVERABLE_SCANNER_H_
#include <memory>
#include <optional>
#include "absl/functional/any_invocable.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/scanning/fastpair/fast_pair_scanner.h"
#include "internal/base/observer_list.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
using NonDiscoverableScannerCallback =
absl::AnyInvocable<void(FastPairDevice& device)>;
// This class detects Fast Pair 'not discoverable' advertisements (see
// https://developers.google.com/nearby/fast-pair/spec#AdvertisingWhenNotDiscoverable)
// and invokes the |found_callback| when it finds a device within the
// appropriate range. |lost_callback| will be invoked when that device is lost.
class FastPairNonDiscoverableScanner : public FastPairScanner::Observer {
public:
class Factory {
public:
static std::unique_ptr<FastPairNonDiscoverableScanner> Create(
FastPairScanner& scanner, NonDiscoverableScannerCallback found_callback,
NonDiscoverableScannerCallback lost_callback,
SingleThreadExecutor* executor,
FastPairDeviceRepository* device_repository);
static void SetFactoryForTesting(Factory* g_test_factory);
protected:
virtual ~Factory() = default;
virtual std::unique_ptr<FastPairNonDiscoverableScanner> CreateInstance(
FastPairScanner& scanner, NonDiscoverableScannerCallback found_callback,
NonDiscoverableScannerCallback lost_callback,
SingleThreadExecutor* executor,
FastPairDeviceRepository* device_repository) = 0;
private:
static Factory* g_test_factory_;
};
FastPairNonDiscoverableScanner(FastPairScanner& scanner,
NonDiscoverableScannerCallback found_callback,
NonDiscoverableScannerCallback lost_callback,
SingleThreadExecutor* executor,
FastPairDeviceRepository* device_repository);
FastPairNonDiscoverableScanner(const FastPairNonDiscoverableScanner&) =
delete;
FastPairNonDiscoverableScanner& operator=(
const FastPairNonDiscoverableScanner&) = delete;
~FastPairNonDiscoverableScanner();
// FastPairScanner::Observer
void OnDeviceFound(const BlePeripheral& peripheral) override;
void OnDeviceLost(const BlePeripheral& peripheral) override;
private:
void OnAdvertisementParsed(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement);
void OnAccountKeyFilterCheckResult(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement,
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id);
void OnDeviceMetadataRetrieved(
absl::string_view address,
std::optional<NonDiscoverableAdvertisement> advertisement,
absl::string_view model_id, AccountKey account_key,
std::optional<DeviceMetadata> device_metadata);
void NotifyDeviceFound(FastPairDevice& device)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
FastPairScanner& scanner_;
NonDiscoverableScannerCallback found_callback_ ABSL_GUARDED_BY(*executor_);
NonDiscoverableScannerCallback lost_callback_ ABSL_GUARDED_BY(*executor_);
SingleThreadExecutor* executor_;
FastPairDeviceRepository* device_repository_ ABSL_GUARDED_BY(*executor_);
ObserverList<FastPairScanner::Observer> observer_list_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAST_PAIR_NON_DISCOVERABLE_SCANNER_H_
@@ -0,0 +1,298 @@
// 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/scanning/fastpair/fast_pair_non_discoverable_scanner.h"
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "fastpair/common/account_key.h"
#include "fastpair/repository/fake_fast_pair_repository.h"
#include "fastpair/scanning/fastpair/fake_fast_pair_scanner.h"
#include "fastpair/testing/fast_pair_service_data_creator.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr int kNotDiscoverableAdvHeader = 0b00000110;
constexpr int kAccountKeyFilterHeader = 0b01100000;
constexpr int kAccountKeyFilterNoNotificationHeader = 0b01100010;
constexpr int kSaltHeader = 0b00010001;
constexpr absl::string_view kModelId("aabbcc");
constexpr absl::string_view kBleAddress("11:12:13:14:15:16");
constexpr absl::string_view kAccountKeyFilter("112233445566");
constexpr absl::string_view kSalt("01");
// Short timeout for operation that we expect to timeout.
constexpr absl::Duration kFailureTimeout = absl::Milliseconds(100);
class FakeBlePeripheral : public api::BlePeripheral {
public:
explicit FakeBlePeripheral(absl::string_view name,
std::vector<uint8_t> service_data) {
name_ = std::string(name);
ByteArray advertisement_bytes(
std::string(service_data.begin(), service_data.end()));
advertisement_data_ = advertisement_bytes;
}
FakeBlePeripheral(const FakeBlePeripheral&) = default;
~FakeBlePeripheral() override = default;
std::string GetName() const override { return name_; }
ByteArray GetAdvertisementBytes(
const std::string& service_id) const override {
return advertisement_data_;
}
void SetName(const std::string& name) { name_ = name; }
void SetAdvertisementBytes(ByteArray advertisement_bytes) {
advertisement_data_ = advertisement_bytes;
}
private:
std::string name_;
ByteArray advertisement_data_;
};
class FastPairNonDiscoverableScannerTest : public ::testing::Test {
protected:
void TearDown() override {
executor_.Shutdown();
}
std::vector<uint8_t> GetAdvServicedata() {
return FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
}
std::vector<uint8_t> GetAdvNoUiServicedata() {
return FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterNoNotificationHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
}
std::vector<uint8_t> GetAdvWrongServicedata() {
return FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader /*InvalidType*/ (0b01100001)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
}
SingleThreadExecutor executor_;
FastPairDeviceRepository devices_{&executor_};
std::unique_ptr<FakeFastPairScanner> scanner_;
std::unique_ptr<FastPairNonDiscoverableScanner> non_discoverable_scanner_;
};
TEST_F(FastPairNonDiscoverableScannerTest, FoundAssociatedDevice) {
const std::vector<uint8_t> account_key_vec{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
AccountKey account_key(account_key_vec);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(account_key,
kModelId);
auto ble_peripheral =
std::make_unique<FakeBlePeripheral>(kBleAddress, GetAdvServicedata());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_,
[&](FastPairDevice& device) {
EXPECT_EQ(device.GetModelId(), kModelId);
EXPECT_EQ(device.GetBleAddress(), kBleAddress);
EXPECT_EQ(device.GetProtocol(), Protocol::kFastPairSubsequentPairing);
EXPECT_EQ(device.GetAccountKey(), account_key);
EXPECT_TRUE(device.ShouldShowUiNotification());
found_notification.Notify();
},
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
found_notification.WaitForNotification();
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
lost_notification.WaitForNotification();
}
TEST_F(FastPairNonDiscoverableScannerTest, FoundNonAssociatedDevice) {
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(std::nullopt,
std::nullopt);
auto ble_peripheral =
std::make_unique<FakeBlePeripheral>(kBleAddress, GetAdvServicedata());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_, [&](FastPairDevice& device) { found_notification.Notify(); },
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
found_notification.WaitForNotificationWithTimeout(kFailureTimeout));
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
lost_notification.WaitForNotificationWithTimeout(kFailureTimeout));
}
TEST_F(FastPairNonDiscoverableScannerTest, FoundNoUIDevice) {
const std::vector<uint8_t> account_key_vec{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
AccountKey account_key(account_key_vec);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(account_key,
kModelId);
auto ble_peripheral =
std::make_unique<FakeBlePeripheral>(kBleAddress, GetAdvNoUiServicedata());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_,
[&](FastPairDevice& device) {
EXPECT_EQ(device.GetModelId(), kModelId);
EXPECT_EQ(device.GetBleAddress(), kBleAddress);
EXPECT_EQ(device.GetProtocol(), Protocol::kFastPairSubsequentPairing);
EXPECT_EQ(device.GetAccountKey(), account_key);
EXPECT_FALSE(device.ShouldShowUiNotification().value());
found_notification.Notify();
},
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
found_notification.WaitForNotification();
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
lost_notification.WaitForNotification();
}
TEST_F(FastPairNonDiscoverableScannerTest, FailedToGetDeviceMetadata) {
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(AccountKey(),
kModelId);
auto ble_peripheral =
std::make_unique<FakeBlePeripheral>(kBleAddress, GetAdvServicedata());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_, [&](FastPairDevice& device) { found_notification.Notify(); },
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
found_notification.WaitForNotificationWithTimeout(kFailureTimeout));
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
lost_notification.WaitForNotificationWithTimeout(kFailureTimeout));
}
TEST_F(FastPairNonDiscoverableScannerTest, NoServiceData) {
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(AccountKey(),
kModelId);
auto ble_peripheral =
std::make_unique<FakeBlePeripheral>(kBleAddress, std::vector<uint8_t>());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_, [&](FastPairDevice& device) { found_notification.Notify(); },
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
found_notification.WaitForNotificationWithTimeout(kFailureTimeout));
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
lost_notification.WaitForNotificationWithTimeout(kFailureTimeout));
}
TEST_F(FastPairNonDiscoverableScannerTest, FailedToParseNonDiscoverableAdv) {
scanner_ = std::make_unique<FakeFastPairScanner>();
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(AccountKey(),
kModelId);
auto ble_peripheral = std::make_unique<FakeBlePeripheral>(
kBleAddress, GetAdvWrongServicedata());
absl::Notification found_notification;
absl::Notification lost_notification;
non_discoverable_scanner_ = FastPairNonDiscoverableScanner::Factory::Create(
*scanner_, [&](FastPairDevice& device) { found_notification.Notify(); },
[&](FastPairDevice& device) { lost_notification.Notify(); }, &executor_,
&devices_);
scanner_->NotifyDeviceFound(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
found_notification.WaitForNotificationWithTimeout(kFailureTimeout));
scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get()));
EXPECT_FALSE(
lost_notification.WaitForNotificationWithTimeout(kFailureTimeout));
}
} // namespace
} // namespace fastpair
} // namespace nearby
+10
View File
@@ -20,6 +20,7 @@
#include "absl/functional/bind_front.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h"
#include "fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h"
#include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h"
#include "internal/platform/logging.h"
@@ -59,6 +60,7 @@ void ScannerBrokerImpl::RemoveObserver(Observer* observer) {
std::unique_ptr<ScannerBroker::ScanningSession>
ScannerBrokerImpl::StartScanning(Protocol protocol) {
DCHECK(!fast_pair_discoverable_scanner_);
DCHECK(!fast_pair_non_discoverable_scanner_);
NEARBY_LOGS(VERBOSE) << "Starting Fast Pair Scanning.";
scanner_ = std::make_unique<FastPairScannerImpl>(mediums_, executor_);
fast_pair_discoverable_scanner_ =
@@ -67,6 +69,13 @@ ScannerBrokerImpl::StartScanning(Protocol protocol) {
absl::bind_front(&ScannerBrokerImpl::NotifyDeviceFound, this),
absl::bind_front(&ScannerBrokerImpl::NotifyDeviceLost, this),
executor_, device_repository_);
fast_pair_non_discoverable_scanner_ =
FastPairNonDiscoverableScanner::Factory::Create(
*scanner_,
absl::bind_front(&ScannerBrokerImpl::NotifyDeviceFound, this),
absl::bind_front(&ScannerBrokerImpl::NotifyDeviceLost, this),
executor_, device_repository_);
scanning_session_ = scanner_->StartScanning();
return std::make_unique<ScanningSessionImpl>(this, protocol);
}
@@ -77,6 +86,7 @@ void ScannerBrokerImpl::StopScanning(Protocol protocol) {
observers_.Clear();
DestroyOnExecutor(std::move(fast_pair_discoverable_scanner_), executor_);
DestroyOnExecutor(std::move(fast_pair_non_discoverable_scanner_), executor_);
DestroyOnExecutor(std::move(scanner_), executor_);
}
+3
View File
@@ -21,6 +21,7 @@
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h"
#include "fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h"
#include "fastpair/scanning/fastpair/fast_pair_scanner.h"
#include "fastpair/scanning/scanner_broker.h"
#include "internal/base/observer_list.h"
@@ -49,6 +50,8 @@ class ScannerBrokerImpl : public ScannerBroker {
SingleThreadExecutor* executor_;
std::unique_ptr<FastPairScanner> scanner_;
std::unique_ptr<FastPairDiscoverableScanner> fast_pair_discoverable_scanner_;
std::unique_ptr<FastPairNonDiscoverableScanner>
fast_pair_non_discoverable_scanner_;
ObserverList<Observer> observers_;
FastPairDeviceRepository* device_repository_;
std::unique_ptr<FastPairScanner::ScanningSession> scanning_session_;
+63 -3
View File
@@ -16,6 +16,7 @@
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
@@ -24,8 +25,9 @@
#include "fastpair/common/protocol.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/proto/fastpair_rpcs.proto.h"
#include "fastpair/scanning/scanner_broker.h"
#include "fastpair/repository/fake_fast_pair_repository.h"
#include "fastpair/scanning/scanner_broker.h"
#include "fastpair/testing/fast_pair_service_data_creator.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
@@ -33,8 +35,12 @@
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(1000);
constexpr int kNotDiscoverableAdvHeader = 0b00000110;
constexpr int kAccountKeyFilterHeader = 0b01100000;
constexpr int kSaltHeader = 0b00010001;
constexpr absl::string_view kAccountKeyFilter("112233445566");
constexpr absl::string_view kSalt("01");
constexpr absl::string_view kServiceID{"Fast Pair"};
constexpr absl::string_view kModelId{"718c17"};
constexpr absl::string_view kFastPairServiceUuid{
@@ -69,7 +75,7 @@ class ScannerBrokerImplTest : public testing::Test {
MediumEnvironment& env_{MediumEnvironment::Instance()};
};
TEST_F(ScannerBrokerImplTest, CanStartScanning) {
TEST_F(ScannerBrokerImplTest, FoundDiscoverableAdvertisement) {
env_.Start();
// Setup FakeFastPairRepository
std::string decoded_key;
@@ -113,6 +119,60 @@ TEST_F(ScannerBrokerImplTest, CanStartScanning) {
scanning_session.reset();
env_.Stop();
}
TEST_F(ScannerBrokerImplTest, FoundNonDiscoverableAdvertisement) {
env_.Start();
SingleThreadExecutor executor;
FastPairDeviceRepository devices(&executor);
auto repository = std::make_unique<FakeFastPairRepository>();
proto::Device metadata;
repository->SetFakeMetadata(kModelId, metadata);
repository->SetResultOfCheckIfAssociatedWithCurrentAccount(AccountKey(),
kModelId);
// Create Fast Pair Scanner and add its observer
Mediums mediums_1;
auto scanner_broker =
std::make_unique<ScannerBrokerImpl>(mediums_1, &executor, &devices);
CountDownLatch accept_latch(1);
CountDownLatch lost_latch(1);
ScannerBrokerObserver observer(scanner_broker.get(), &accept_latch,
&lost_latch);
// Create Advertiser and startAdvertising
Mediums mediums_2;
std::string service_id(kServiceID);
std::vector<uint8_t> service_data =
FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
ByteArray advertisement_bytes(
std::string(service_data.begin(), service_data.end()));
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
// Fast Pair scanner startScanning
auto scanning_session =
scanner_broker->StartScanning(Protocol::kFastPairInitialPairing);
// Notify device found
EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result());
// Advertiser stopAdvertising
mediums_2.GetBle().GetMedium().StopAdvertising(service_id);
// Notify device lost
EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result());
scanning_session.reset();
env_.Stop();
}
} // namespace
} // namespace fastpair
} // namespace nearby