diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index 2f9e8eb6..cdd33e18 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -104,6 +104,7 @@ cc_library( "@boringssl//:crypto", "@com_google_absl//absl/strings", ], + alwayslink = 1, ) cc_library( diff --git a/internal/platform/implementation/g3/ble_v2.cc b/internal/platform/implementation/g3/ble_v2.cc index a91edfa6..c3a6f7ab 100644 --- a/internal/platform/implementation/g3/ble_v2.cc +++ b/internal/platform/implementation/g3/ble_v2.cc @@ -262,10 +262,17 @@ std::unique_ptr BleV2Medium::StartAdvertising( return nullptr; } + if (callback.start_advertising_result) { + callback.start_advertising_result(BleOperationStatus::kSucceeded); + } absl::MutexLock lock(&mutex_); MediumEnvironment::Instance().UpdateBleV2MediumForAdvertising( /*enabled=*/true, *this, adapter_->GetPeripheralV2(), advertising_data); - return std::make_unique(AdvertisingSession{}); + return std::make_unique( + AdvertisingSession{.stop_advertising = [this] { + return StopAdvertising() ? BleOperationStatus::kSucceeded + : BleOperationStatus::kFailed; + }}); } bool BleV2Medium::StartScanning(const Uuid& service_uuid, diff --git a/presence/implementation/mediums/ble.h b/presence/implementation/mediums/ble.h index c26d9603..ee778303 100644 --- a/presence/implementation/mediums/ble.h +++ b/presence/implementation/mediums/ble.h @@ -16,9 +16,10 @@ #define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_BLE_H_ #include +#include +#include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/implementation/ble_v2.h" #include "internal/platform/uuid.h" #include "presence/power_mode.h" #include "presence/scan_request.h" @@ -30,42 +31,65 @@ namespace presence { ABSL_CONST_INIT const location::nearby::Uuid kPresenceServiceUuid( 0x0000fcf100001000, 0x800000805f9b34fb); -using ScanningSession = - ::location::nearby::api::ble_v2::BleMedium::ScanningSession; -using ScanningCallback = - ::location::nearby::api::ble_v2::BleMedium::ScanningCallback; -using ::location::nearby::api::ble_v2::TxPowerLevel; - /* * This Ble class utilizes platform/ble_v2 BleV2Medium, provides ble functions * for presence logic layer to invoke. * This class would have states like if ble is available or not, if it's doing * broadcast/scan. */ -template -// since we are using template for test, then we need to keep functions defs in -// the header, more details: go/cstyle#Self_contained_Headers. class Ble { public: + using TxPowerLevel = ::location::nearby::api::ble_v2::TxPowerLevel; + using ScanningSession = + ::location::nearby::api::ble_v2::BleMedium::ScanningSession; + using ScanningCallback = + ::location::nearby::api::ble_v2::BleMedium::ScanningCallback; + using AdvertiseParameters = + ::location::nearby::api::ble_v2::AdvertiseParameters; + using AdvertisingSession = + ::location::nearby::api::ble_v2::BleMedium::AdvertisingSession; + using AdvertisingCallback = + ::location::nearby::api::ble_v2::BleMedium::AdvertisingCallback; + using BleAdvertisementData = + ::location::nearby::api::ble_v2::BleAdvertisementData; + using BleMedium = ::location::nearby::api::ble_v2::BleMedium; + explicit Ble(location::nearby::BluetoothAdapter& bluetooth_adapter) - : adapter_(bluetooth_adapter), - medium_(std::make_unique(bluetooth_adapter)) {} - ~Ble() = default; + : medium_(bluetooth_adapter) {} - bool IsAvailable() const { return medium_->IsValid(); } + bool IsAvailable() const { return medium_.IsValid(); } + // Starts broadcasting NP advertisement in `payload`. The caller should use + // the returned `AdvertisingSession` to stop the broadcast. + std::unique_ptr StartAdvertising( + absl::string_view payload, bool is_extended_advertisement, + PowerMode power_mode, AdvertisingCallback callback) { + BleAdvertisementData advertising_data = {.is_extended_advertisement = + is_extended_advertisement}; + advertising_data.service_data.insert( + {kPresenceServiceUuid, + location::nearby::ByteArray(std::string(payload))}); + AdvertiseParameters advertise_set_parameters = { + .tx_power_level = ConvertPowerModeToPowerLevel(power_mode), + .is_connectable = true, + }; + return medium_.StartAdvertising(advertising_data, advertise_set_parameters, + callback); + } + + // Starts scanning for NP advertisements. The caller should use the returned + // `ScanningSession` to stop scanning. std::unique_ptr StartScanning(ScanRequest scan_request, ScanningCallback callback) { - return medium_->StartScanning( + return medium_.StartScanning( kPresenceServiceUuid, ConvertPowerModeToPowerLevel(scan_request.power_mode), callback); } - private: - friend class BleTest; - location::nearby::BluetoothAdapter& adapter_; - std::unique_ptr medium_; + // Provides access to platform implementation. It's used in tests. + BleMedium* GetImpl() const { return medium_.GetImpl(); } + private: TxPowerLevel ConvertPowerModeToPowerLevel(PowerMode power_mode) { switch (power_mode) { case PowerMode::kNoPower: @@ -79,6 +103,8 @@ class Ble { } return TxPowerLevel::kUnknown; } + + location::nearby::BleV2Medium medium_; }; } // namespace presence diff --git a/presence/implementation/mediums/ble_test.cc b/presence/implementation/mediums/ble_test.cc index ea2f354d..8613c139 100644 --- a/presence/implementation/mediums/ble_test.cc +++ b/presence/implementation/mediums/ble_test.cc @@ -32,6 +32,7 @@ namespace nearby { namespace presence { +namespace { using FeatureFlags = location::nearby::FeatureFlags::Flags; using BleOperationStatus = location::nearby::api::ble_v2::BleOperationStatus; @@ -43,6 +44,12 @@ using TxPowerLevel = location::nearby::api::ble_v2::TxPowerLevel; using ScanningCallback = location::nearby::api::ble_v2::BleMedium::ScanningCallback; using Uuid = location::nearby::Uuid; +using location::nearby::api::ble_v2::BleAdvertisementData; +using location::nearby::api::ble_v2::BlePeripheral; +using AdvertisingCallback = + location::nearby::api::ble_v2::BleMedium::AdvertisingCallback; +using AdvertisingSession = + location::nearby::api::ble_v2::BleMedium::AdvertisingSession; constexpr FeatureFlags kTestCases[] = { FeatureFlags{}, @@ -50,14 +57,6 @@ constexpr FeatureFlags kTestCases[] = { class BleTest : public testing::TestWithParam { public: - class MockBleMedium { - public: - explicit MockBleMedium(location::nearby::BluetoothAdapter& adapter){} - - MOCK_METHOD((std::unique_ptr), StartScanning, - (const Uuid& service_uuid, TxPowerLevel tx_power_level, - ScanningCallback callback)); - }; constexpr static absl::Duration kWaitDuration = absl::Milliseconds(1000); std::string account_name_ = "Test-Name"; @@ -88,12 +87,8 @@ class BleTest : public testing::TestWithParam { protected: BleTest() { env_.Stop(); } - absl::optional GetBleStatus( - const Ble& ble) { - return env_.GetBleV2MediumStatus(*ble.medium_->GetImpl()); - } - MockBleMedium* GetMedium(const Ble& ble) { - return ble.medium_.get(); + absl::optional GetBleStatus(const Ble& ble) { + return env_.GetBleV2MediumStatus(*ble.GetImpl()); } location::nearby::MediumEnvironment& env_{ location::nearby::MediumEnvironment::Instance()}; @@ -107,7 +102,7 @@ INSTANTIATE_TEST_SUITE_P(ParametrisedBleTest, BleTest, TEST_P(BleTest, CanStartThenStopScanning) { env_.Start(); ::location::nearby::BluetoothAdapter adapter; - Ble ble(adapter); + Ble ble(adapter); ScanRequest scan_request{ .power_mode = PowerMode::kBalanced, @@ -136,20 +131,51 @@ TEST_P(BleTest, CanStartThenStopScanning) { env_.Stop(); } -// Using MockBleMedium to verify StartScanning is using the expected parameters -// with underneath BleMedium. -TEST_P(BleTest, VerifyStartScanning) { +TEST_P(BleTest, AdvertiseAndScan) { + // Create two Ble devices, one advertises, the other one scans, and verify + // that the NP advertisement was sent from one to the other. env_.Start(); - ::location::nearby::BluetoothAdapter adapter; - Ble ble(adapter); - EXPECT_CALL(*GetMedium(ble), StartScanning(kPresenceServiceUuid, - TxPowerLevel::kMedium, testing::_)) - .Times(1); + location::nearby::BluetoothAdapter client_adapter; + Ble client(client_adapter); + location::nearby::BluetoothAdapter server_adapter; + Ble server(server_adapter); + std::string advert_data = "my advertisement"; + ScanRequest scan_request{ + .power_mode = PowerMode::kBalanced, + }; + location::nearby::CountDownLatch advertise_latch(1); + location::nearby::CountDownLatch scan_latch(1); + std::vector advertisements; + std::unique_ptr scanning_session = client.StartScanning( + scan_request, + ScanningCallback{.advertisement_found_cb = + [&](BlePeripheral& peripheral, + BleAdvertisementData advertisement_data) { + advertisements.push_back(advertisement_data); + scan_latch.CountDown(); + }}); + std::unique_ptr + advertising_session = server.StartAdvertising( + advert_data, /*is_extended_advertisement=*/false, + PowerMode::kBalanced, + AdvertisingCallback{ + .start_advertising_result = [&](BleOperationStatus status) { + advertise_latch.CountDown(); + }}); - std::unique_ptr scanning_session = - ble.StartScanning(scan_request_, ScanningCallback{}); + EXPECT_TRUE(advertise_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(scan_latch.Await(kWaitDuration).result()); + EXPECT_EQ(scanning_session->stop_scanning(), BleOperationStatus::kSucceeded); + EXPECT_EQ(advertising_session->stop_advertising(), + BleOperationStatus::kSucceeded); + ASSERT_FALSE(advertisements.empty()); + EXPECT_EQ(advertisements[0] + .service_data.find(kPresenceServiceUuid) + ->second.AsStringView(), + advert_data); env_.Stop(); } +} // namespace } // namespace presence } // namespace nearby diff --git a/presence/implementation/mediums/mediums.h b/presence/implementation/mediums/mediums.h index b8e741d9..a8aa78e4 100644 --- a/presence/implementation/mediums/mediums.h +++ b/presence/implementation/mediums/mediums.h @@ -15,7 +15,6 @@ #ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_MEDIUMS_H_ #define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_MEDIUMS_H_ -#include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" #include "presence/implementation/mediums/ble.h" @@ -28,15 +27,12 @@ namespace presence { */ class Mediums { public: - Mediums() = default; - ~Mediums() = default; - // Returns a handle to the Ble medium. - Ble& GetBle(); + Ble& GetBle(); private: location::nearby::BluetoothAdapter adapter_; - Ble ble_{adapter_}; + Ble ble_{adapter_}; }; } // namespace presence