mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Add StartAdvertising to BLE medium.
StartAdvertising allows us to broadcast Nearby Presence advertisements. We can now test scanning and advertising with the MediumEnvironment rather than mocking platform code. PiperOrigin-RevId: 484662211
This commit is contained in:
committed by
Copybara-Service
parent
5d742558a4
commit
81f6b547bb
@@ -104,6 +104,7 @@ cc_library(
|
||||
"@boringssl//:crypto",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
|
||||
@@ -262,10 +262,17 @@ std::unique_ptr<BleV2Medium::AdvertisingSession> 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>(AdvertisingSession{});
|
||||
return std::make_unique<AdvertisingSession>(
|
||||
AdvertisingSession{.stop_advertising = [this] {
|
||||
return StopAdvertising() ? BleOperationStatus::kSucceeded
|
||||
: BleOperationStatus::kFailed;
|
||||
}});
|
||||
}
|
||||
|
||||
bool BleV2Medium::StartScanning(const Uuid& service_uuid,
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_BLE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#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 <typename Medium>
|
||||
// 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<Medium>(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<AdvertisingSession> 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<ScanningSession> 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> 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
|
||||
|
||||
@@ -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<FeatureFlags> {
|
||||
public:
|
||||
class MockBleMedium {
|
||||
public:
|
||||
explicit MockBleMedium(location::nearby::BluetoothAdapter& adapter){}
|
||||
|
||||
MOCK_METHOD((std::unique_ptr<ScanningSession>), 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<FeatureFlags> {
|
||||
|
||||
protected:
|
||||
BleTest() { env_.Stop(); }
|
||||
absl::optional<BleV2MediumStatus> GetBleStatus(
|
||||
const Ble<location::nearby::BleV2Medium>& ble) {
|
||||
return env_.GetBleV2MediumStatus(*ble.medium_->GetImpl());
|
||||
}
|
||||
MockBleMedium* GetMedium(const Ble<MockBleMedium>& ble) {
|
||||
return ble.medium_.get();
|
||||
absl::optional<BleV2MediumStatus> 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<location::nearby::BleV2Medium> 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<MockBleMedium> 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<BleAdvertisementData> advertisements;
|
||||
std::unique_ptr<ScanningSession> 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<location::nearby::api::ble_v2::BleMedium::AdvertisingSession>
|
||||
advertising_session = server.StartAdvertising(
|
||||
advert_data, /*is_extended_advertisement=*/false,
|
||||
PowerMode::kBalanced,
|
||||
AdvertisingCallback{
|
||||
.start_advertising_result = [&](BleOperationStatus status) {
|
||||
advertise_latch.CountDown();
|
||||
}});
|
||||
|
||||
std::unique_ptr<ScanningSession> 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
|
||||
|
||||
@@ -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<location::nearby::BleV2Medium>& GetBle();
|
||||
Ble& GetBle();
|
||||
|
||||
private:
|
||||
location::nearby::BluetoothAdapter adapter_;
|
||||
Ble<location::nearby::BleV2Medium> ble_{adapter_};
|
||||
Ble ble_{adapter_};
|
||||
};
|
||||
|
||||
} // namespace presence
|
||||
|
||||
Reference in New Issue
Block a user