Add UI Discovery check and show into Mediator.

PiperOrigin-RevId: 538000396
This commit is contained in:
hai007
2023-06-05 15:43:24 -07:00
committed by Copybara-Service
parent 19bc10ff26
commit aefef91114
4 changed files with 369 additions and 36 deletions
+11 -4
View File
@@ -28,11 +28,13 @@ cc_library(
],
deps = [
"//fastpair/common",
"//fastpair/internal/mediums",
"//fastpair/repository:device_repository",
"//fastpair/scanning:scanner",
"//fastpair/server_access",
"//fastpair/ui:fast_pair_ui",
"//internal/platform:logging",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
"//internal/platform:types",
],
)
@@ -45,10 +47,15 @@ cc_test(
shard_count = 16,
deps = [
":keyed_service",
"//fastpair/scanning:mocks",
"//fastpair/server_access:mocks",
"//fastpair/server_access:test_support",
"//fastpair/testing",
"//fastpair/ui:fast_pair_ui",
"//fastpair/ui:mock_fast_pair_ui",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
+90 -5
View File
@@ -18,26 +18,92 @@
#include <utility>
#include "fastpair/common/protocol.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/scanning/scanner_broker_impl.h"
#include "fastpair/server_access/fast_pair_repository_impl.h"
#include "fastpair/ui/actions.h"
#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h"
#include "fastpair/ui/ui_broker_impl.h"
#include "internal/platform/logging.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
Mediator::Mediator(std::unique_ptr<ScannerBroker> scanner_broker,
std::unique_ptr<FastPairRepository> fast_pair_repository)
: scanner_broker_(std::move(scanner_broker)),
fast_pair_repository_(std::move(fast_pair_repository)) {
Mediator::Mediator(
std::unique_ptr<Mediums> mediums, std::unique_ptr<UIBroker> ui_broker,
std::unique_ptr<FastPairNotificationController> notification_controller,
std::unique_ptr<FastPairRepository> fast_pair_repository,
std::unique_ptr<SingleThreadExecutor> executor)
: mediums_(std::move(mediums)),
ui_broker_(std::move(ui_broker)),
notification_controller_(std::move(notification_controller)),
fast_pair_repository_(std::move(fast_pair_repository)),
executor_(std::move(executor)) {
devices_ = std::make_unique<FastPairDeviceRepository>(executor_.get());
scanner_broker_ = std::make_unique<ScannerBrokerImpl>(
*mediums_, executor_.get(), devices_.get());
scanner_broker_->AddObserver(this);
ui_broker_->AddObserver(this);
}
void Mediator::OnDeviceFound(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": " << device;
if (IsDeviceCurrentlyShowingNotification(device)) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Extending notification for re-discovered device="
<< *device_currently_showing_notification_;
// TODO(b/278768167): Add ui_broker_->ExtendNotification();
return;
} else if (device_currently_showing_notification_) {
NEARBY_LOGS(VERBOSE)
<< __func__
<< ": Already showing a notification for a different device= "
<< *device_currently_showing_notification_;
return;
}
// Show discovery notification
device_currently_showing_notification_ = &device;
ui_broker_->ShowDiscovery(device, *notification_controller_);
}
void Mediator::OnDeviceLost(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": " << device;
}
void Mediator::OnDiscoveryAction(const FastPairDevice& device,
DiscoveryAction action) {
switch (action) {
case DiscoveryAction::kPairToDevice:
NEARBY_LOGS(INFO) << __func__ << ": Action = kPairToDevice";
// TODO(285451051): Adding show pairing for higher than v1 version in ui
// broker
// TODO(282022590): Adding pairer broker to pair device
break;
case DiscoveryAction::kDismissedByOs:
NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByOs";
break;
case DiscoveryAction::kDismissedByUser:
// When the user explicitly dismisses the discovery notification, update
// the device's block-list value accordingly.
NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByUser";
// TODO(285453663): update discovery block list
[[fallthrough]];
case DiscoveryAction::kDismissedByTimeout:
NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByTimeout";
device_currently_showing_notification_ = nullptr;
break;
case DiscoveryAction::kLearnMore:
NEARBY_LOGS(INFO) << __func__ << ": Action = kLearnMore";
break;
default:
NEARBY_LOGS(INFO) << __func__ << ": Action = kUnknow";
break;
}
}
void Mediator::StartScanning() {
if (IsFastPairEnabled()) {
scanning_session_ =
@@ -48,10 +114,29 @@ void Mediator::StartScanning() {
}
bool Mediator::IsFastPairEnabled() {
// TODO(b/275452353): Add feature_status_tracker IsFastPairEnabled()
// TODO(b/275452353): Add feature_status_tracker IsFastPairEnabled()
// Currently default to true.
NEARBY_LOGS(VERBOSE) << __func__ << ": " << true;
return true;
}
bool Mediator::IsDeviceCurrentlyShowingNotification(
const FastPairDevice& device) {
// BLE addresses could have rotated, causing this check to return false for
// the same device. Fast Pair considers a device different if they have
// different BLE addresses. Similarly, the this check will fail if it is the
// same physical device under different scenarios: for example, if a device
// is found via the initial scenario and via the subsequent scenario, Fast
// Pair does not consider them the same device.
return device_currently_showing_notification_ &&
device_currently_showing_notification_->GetModelId() ==
device.GetModelId() &&
device_currently_showing_notification_->GetBleAddress() ==
device.GetBleAddress() &&
device_currently_showing_notification_->GetProtocol() !=
device.GetProtocol();
}
} // namespace fastpair
} // namespace nearby
+43 -4
View File
@@ -17,20 +17,44 @@
#include <memory>
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/scanning/scanner_broker.h"
#include "fastpair/server_access/fast_pair_repository.h"
#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h"
#include "fastpair/ui/ui_broker.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
// Implements the Mediator design pattern for the components in the Fast Pair
class Mediator final : public ScannerBroker::Observer {
class Mediator final : public ScannerBroker::Observer,
public UIBroker::Observer {
public:
Mediator(std::unique_ptr<ScannerBroker> scanner_broker,
std::unique_ptr<FastPairRepository> fast_pair_repository);
Mediator(
std::unique_ptr<Mediums> mediums, std::unique_ptr<UIBroker> ui_broker,
std::unique_ptr<FastPairNotificationController> notification_controller,
std::unique_ptr<FastPairRepository> fast_pair_repository,
std::unique_ptr<SingleThreadExecutor> executor);
Mediator(const Mediator&) = delete;
Mediator& operator=(const Mediator&) = delete;
~Mediator() override = default;
~Mediator() override {
if (scanning_session_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << "scanner is not running";
}
scanning_session_.reset();
scanner_broker_->RemoveObserver(this);
DestroyOnExecutor(std::move(scanner_broker_), executor_.get());
scanner_broker_.reset();
ui_broker_->RemoveObserver(this);
ui_broker_.reset();
};
FastPairNotificationController* GetNotificationController() {
return notification_controller_.get();
}
// ScannerBroker::Observer
void OnDeviceFound(FastPairDevice& device) override;
@@ -38,12 +62,27 @@ class Mediator final : public ScannerBroker::Observer {
void StartScanning();
// UIBroker::Observer
void OnDiscoveryAction(const FastPairDevice& device,
DiscoveryAction action) override;
private:
bool IsFastPairEnabled();
bool IsDeviceCurrentlyShowingNotification(const FastPairDevice& device);
// |device_currently_showing_notification_| can be null if there is no
// notification currently displayed to the user.
FastPairDevice* device_currently_showing_notification_ = nullptr;
std::unique_ptr<Mediums> mediums_;
std::unique_ptr<ScannerBroker> scanner_broker_;
std::unique_ptr<ScannerBroker::ScanningSession> scanning_session_;
std::unique_ptr<UIBroker> ui_broker_;
std::unique_ptr<FastPairNotificationController> notification_controller_;
std::unique_ptr<FastPairRepository> fast_pair_repository_;
std::unique_ptr<SingleThreadExecutor> executor_;
std::unique_ptr<FastPairDeviceRepository> devices_;
};
} // namespace fastpair
+225 -23
View File
@@ -14,56 +14,258 @@
#include "fastpair/keyed_service/fast_pair_mediator.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "fastpair/scanning/mock_scanner_broker.h"
#include "fastpair/server_access/mock_fast_pair_repository.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "fastpair/server_access/fake_fast_pair_repository.h"
#include "fastpair/testing/fast_pair_service_data_creator.h"
#include "fastpair/ui/actions.h"
#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h"
#include "fastpair/ui/fast_pair/mock_fast_pair_notification_controller.h"
#include "fastpair/ui/mock_ui_broker.h"
#include "fastpair/ui/ui_broker.h"
#include "fastpair/ui/ui_broker_impl.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::string_view kModelId = "718c17";
constexpr absl::string_view kServiceID = "Fast Pair";
constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(1000);
constexpr absl::string_view kFastPairServiceUuid =
"0000FE2C-0000-1000-8000-00805F9B34FB";
constexpr absl::string_view kPublicAntiSpoof =
"Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+"
"0wVcljfT3XPoiy1fntlneziyLD5knDVAJSE+RM/zlPRP/Jg==";
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 kModelId2 = "9adb11";
constexpr absl::string_view kPublicAntiSpoof2 =
"z+grhW8lWVA34JUQhXOxMrk1WqVy+VpEDd2K+01ZJvS6KdV0OUg7FRMzq+"
"ITuOqKO/2TIRKEAEfMKdyk2Ob1Vw==";
constexpr absl::string_view kAddress = "74:74:46:01:6C:21";
class MediatorTest : public testing::Test {
public:
void SetUp() override {
scanner_broker_ = std::make_unique<MockScannerBroker>();
mock_scanner_broker_ =
static_cast<MockScannerBroker*>(scanner_broker_.get());
env_.Start();
mediums_ = std::make_unique<Mediums>();
fast_pair_repository_ = std::make_unique<MockFastPairRepository>();
mock_fast_pair_repository_ =
static_cast<MockFastPairRepository*>(fast_pair_repository_.get());
// Setup FakeFastPairRepository for two devices
repository_ = FakeFastPairRepository::Create(kModelId, kPublicAntiSpoof);
std::string decoded_key;
absl::Base64Unescape(kPublicAntiSpoof2, &decoded_key);
proto::Device metadata;
metadata.mutable_anti_spoofing_key_pair()->set_public_key(decoded_key);
repository_->SetFakeMetadata(kModelId2, metadata);
ui_broker_ = std::make_unique<MockUIBroker>();
mock_ui_broker_ = static_cast<MockUIBroker*>(ui_broker_.get());
notification_controller_ =
std::make_unique<FastPairNotificationController>();
executor_ = std::make_unique<SingleThreadExecutor>();
}
void TearDown() override {
scanner_broker_.reset();
fast_pair_repository_.reset();
executor_.reset();
mediums_.reset();
repository_.reset();
ui_broker_.reset();
mock_ui_broker_ = nullptr;
notification_controller_.reset();
mediator_.reset();
mock_scanner_broker_ = nullptr;
mock_fast_pair_repository_ = nullptr;
env_.Stop();
}
protected:
std::unique_ptr<ScannerBroker> scanner_broker_;
std::unique_ptr<FastPairRepository> fast_pair_repository_;
MockScannerBroker* mock_scanner_broker_;
MockFastPairRepository* mock_fast_pair_repository_;
MediumEnvironment& env_{MediumEnvironment::Instance()};
std::unique_ptr<Mediums> mediums_;
std::unique_ptr<FakeFastPairRepository> repository_;
std::unique_ptr<UIBroker> ui_broker_;
std::unique_ptr<FastPairNotificationController> notification_controller_;
std::unique_ptr<SingleThreadExecutor> executor_;
MockUIBroker* mock_ui_broker_;
std::unique_ptr<Mediator> mediator_;
};
TEST_F(MediatorTest, SannerBrokerCallStartScanning) {
EXPECT_CALL(*mock_scanner_broker_, StartScanning);
mediator_ = std::make_unique<Mediator>(
std::move(scanner_broker_),
std::move(fast_pair_repository_));
mediator_->StartScanning();
TEST_F(MediatorTest, StartScanningFoundDevice) {
absl::Notification done;
EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).WillOnce([&done] {
done.Notify();
});
// Create Fast Pair Mediator
mediator_ =
std::make_unique<Mediator>(std::move(mediums_), std::move(ui_broker_),
std::move(notification_controller_),
std::move(repository_), std::move(executor_));
// Create Advertiser and startAdvertising
Mediums mediums_advertiser;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_advertiser.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
mediator_->StartScanning();
done.WaitForNotification();
}
TEST_F(MediatorTest, StartScanningFoundDifferentDeviceWhenDisplaying) {
absl::Notification done;
EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] {
done.Notify();
});
// Create Fast Pair Mediator
mediator_ =
std::make_unique<Mediator>(std::move(mediums_), std::move(ui_broker_),
std::move(notification_controller_),
std::move(repository_), std::move(executor_));
// Create Advertiser and startAdvertising
Mediums mediums_advertiser;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_advertiser.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
// Create a different Advertiser and startAdvertising to cause confliction
Mediums mediums_advertiser2;
ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId2)};
mediums_advertiser2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes2, fast_pair_service_uuid);
mediator_->StartScanning();
done.WaitForNotification();
}
TEST_F(MediatorTest, StartScanningFoundSameDeviceWhenDisplaying) {
absl::Notification done;
EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] {
done.Notify();
});
// Create Fast Pair Mediator
mediator_ =
std::make_unique<Mediator>(std::move(mediums_), std::move(ui_broker_),
std::move(notification_controller_),
std::move(repository_), std::move(executor_));
// Create Advertiser and startAdvertising
Mediums mediums_advertiser;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_advertiser.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
// Create another same Advertiser and startAdvertising to cause confliction
Mediums mediums_advertiser2;
ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId)};
mediums_advertiser2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes2, fast_pair_service_uuid);
mediator_->StartScanning();
done.WaitForNotification();
}
TEST_F(MediatorTest,
StartScanningForSubsequentPairingFoundSameDeviceWhenDisplaying) {
absl::Notification done;
EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] {
done.Notify();
});
// Create Fast Pair Mediator
mediator_ =
std::make_unique<Mediator>(std::move(mediums_), std::move(ui_broker_),
std::move(notification_controller_),
std::move(repository_), std::move(executor_));
// Create Advertiser and advertising discoverable advertisement
Mediums mediums_advertiser;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_advertiser.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
// Create another same Advertiser and advertising non-discoverable
// advertisement to cause confliction
Mediums mediums_advertiser2;
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
ByteArray advertisement_bytes2{std::string(bytes.begin(), bytes.end())};
mediums_advertiser2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes2, fast_pair_service_uuid);
mediator_->StartScanning();
done.WaitForNotification();
}
TEST_F(MediatorTest, OnDiscoveryActionClicked) {
absl::Notification done;
EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(2).WillOnce([&done] {
done.Notify();
});
// Create Fast Pair Mediator
mediator_ =
std::make_unique<Mediator>(std::move(mediums_), std::move(ui_broker_),
std::move(notification_controller_),
std::move(repository_), std::move(executor_));
// Create Advertiser and startAdvertising
Mediums mediums_advertiser;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_advertiser.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
mediator_->StartScanning();
done.WaitForNotificationWithTimeout(kTaskWaitTimeout);
FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing);
mock_ui_broker_->NotifyDiscoveryAction(device,
DiscoveryAction::kDismissedByTimeout);
// Create another same Advertiser and startAdvertising to cause confliction
Mediums mediums_advertiser2;
ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId)};
mediums_advertiser2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes2, fast_pair_service_uuid);
done.WaitForNotification();
}
} // namespace
} // namespace fastpair
} // namespace nearby