Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9f0f180 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Gerrit Code Review
Browse files

Merge "service: Add OnScanResult Delegate event."

parents 2fc026ce 99a30e5a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -246,6 +246,12 @@ void FakeBluetoothGattInterface::NotifyRegisterClientCallback(
                    RegisterClientCallback(this, status, client_if, app_uuid));
}

void FakeBluetoothGattInterface::NotifyScanResultCallback(
    const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) {
  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
                    ScanResultCallback(this, bda, rssi, adv_data));
}

void FakeBluetoothGattInterface::NotifyMultiAdvEnableCallback(
    int client_if, int status) {
  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+2 −0
Original line number Diff line number Diff line
@@ -90,6 +90,8 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface {
  // Client callbacks:
  void NotifyRegisterClientCallback(int status, int client_if,
                                    const bt_uuid_t& app_uuid);
  void NotifyScanResultCallback(const bt_bdaddr_t& bda, int rssi,
                                uint8_t* adv_data);
  void NotifyMultiAdvEnableCallback(int client_if, int status);
  void NotifyMultiAdvDataCallback(int client_if, int status);
  void NotifyMultiAdvDisableCallback(int client_if, int status);
+57 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <base/logging.h>

#include "service/adapter.h"
#include "service/logging_helpers.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcidefs.h"

@@ -29,6 +30,12 @@ namespace bluetooth {

namespace {

// 31 + 31 for advertising data and scan response. This is the maximum length
// TODO(armansito): Fix the HAL to return a concatenated blob that contains the
// true length of each field and also provide a length parameter so that we
// can support advertising length extensions in the future.
const size_t kScanRecordLength = 62;

BLEStatus GetBLEStatus(int status) {
  if (status == BT_STATUS_FAIL)
    return BLE_STATUS_FAILURE;
@@ -36,6 +43,30 @@ BLEStatus GetBLEStatus(int status) {
  return static_cast<BLEStatus>(status);
}

// Returns the length of the given scan record array. We have to calculate this
// based on the maximum possible data length and the TLV data. See TODO above
// |kScanRecordLength|.
size_t GetScanRecordLength(uint8_t* bytes) {
  for (size_t i = 0, field_len = 0; i < kScanRecordLength;
       i += (field_len + 1)) {
    field_len = bytes[i];

    // Assert here that the data returned from the stack is correctly formatted
    // in TLV form and that the length of the current field won't exceed the
    // total data length.
    CHECK(i + field_len < kScanRecordLength);

    // If the field length is zero and we haven't reached the maximum length,
    // then we have found the length, as the stack will pad the data with zeros
    // accordingly.
    if (field_len == 0)
      return i;
  }

  // We have reached the end.
  return kScanRecordLength;
}

// TODO(armansito): BTIF currently expects each advertising field in a
// specific format passed directly in arguments. We should fix BTIF to accept
// the advertising data directly instead.
@@ -303,6 +334,11 @@ LowEnergyClient::~LowEnergyClient() {
    StopScan();
}

void LowEnergyClient::SetDelegate(Delegate* delegate) {
  lock_guard<mutex> lock(delegate_mutex_);
  delegate_ = delegate;
}

bool LowEnergyClient::StartScan(const ScanSettings& settings,
                                const std::vector<ScanFilter>& filters) {
  VLOG(2) << __func__;
@@ -456,6 +492,27 @@ int LowEnergyClient::GetInstanceId() const {
  return client_id_;
}

void LowEnergyClient::ScanResultCallback(
    hal::BluetoothGattInterface* gatt_iface,
    const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) {
  // Ignore scan results if this client didn't start a scan.
  if (!scan_started_.load())
    return;

  lock_guard<mutex> lock(delegate_mutex_);
  if (!delegate_)
    return;

  // TODO(armansito): Apply software filters here.

  size_t record_len = GetScanRecordLength(adv_data);
  std::vector<uint8_t> scan_record(adv_data, adv_data + record_len);

  ScanResult result(BtAddrString(&bda), scan_record, rssi);

  delegate_->OnScanResult(this, result);
}

void LowEnergyClient::MultiAdvEnableCallback(
    hal::BluetoothGattInterface* gatt_iface,
    int client_id, int status) {
+29 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "service/common/bluetooth/advertise_settings.h"
#include "service/common/bluetooth/low_energy_constants.h"
#include "service/common/bluetooth/scan_filter.h"
#include "service/common/bluetooth/scan_result.h"
#include "service/common/bluetooth/scan_settings.h"
#include "service/common/bluetooth/uuid.h"
#include "service/hal/bluetooth_gatt_interface.h"
@@ -42,10 +43,30 @@ class Adapter;
class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
                        public BluetoothInstance {
 public:
  // The Delegate interface is used to notify asynchronous events related to BLE
  // GAP operations.
  class Delegate {
   public:
    Delegate() = default;
    virtual ~Delegate() = default;

    // Called asynchronously to notify the delegate of nearby BLE advertisers
    // found during a device scan.
    virtual void OnScanResult(LowEnergyClient* client,
                              const ScanResult& scan_result) = 0;

   private:
    DISALLOW_COPY_AND_ASSIGN(Delegate);
  };

  // The destructor automatically unregisters this client instance from the
  // stack.
  ~LowEnergyClient() override;

  // Assigns a delegate to this instance. |delegate| must out-live this
  // LowEnergyClient instance.
  void SetDelegate(Delegate* delegate);

  // Callback type used to return the result of asynchronous operations below.
  using StatusCallback = std::function<void(BLEStatus)>;

@@ -99,6 +120,9 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id);

  // BluetoothGattInterface::ClientObserver overrides:
  void ScanResultCallback(
      hal::BluetoothGattInterface* gatt_iface,
      const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override;
  void MultiAdvEnableCallback(
      hal::BluetoothGattInterface* gatt_iface,
      int client_id, int status) override;
@@ -161,6 +185,11 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  // If true, then this client have a BLE device scan in progress.
  std::atomic_bool scan_started_;

  // Raw handle to the Delegate, which must outlive this LowEnergyClient
  // instance.
  std::mutex delegate_mutex_;
  Delegate* delegate_;

  DISALLOW_COPY_AND_ASSIGN(LowEnergyClient);
};

+86 −0
Original line number Diff line number Diff line
@@ -70,6 +70,29 @@ class MockGattHandler
  DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
};

class TestDelegate : public LowEnergyClient::Delegate {
 public:
  TestDelegate() : scan_result_count_(0) {
  }

  ~TestDelegate() override = default;

  int scan_result_count() const { return scan_result_count_; }
  const ScanResult& last_scan_result() const { return last_scan_result_; }

  void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) {
    ASSERT_TRUE(client);
    scan_result_count_++;
    last_scan_result_ = scan_result;
  }

 private:
  int scan_result_count_;
  ScanResult last_scan_result_;

  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};

// Created this class for testing Advertising Data Setting
// It provides a work around in order to verify the arguments
// in the arrays passed to MultiAdvSetInstData due to mocks
@@ -836,5 +859,68 @@ TEST_F(LowEnergyClientPostRegisterTest, ScanSettings) {
  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
}

TEST_F(LowEnergyClientPostRegisterTest, ScanRecord) {
  TestDelegate delegate;
  le_client_->SetDelegate(&delegate);

  EXPECT_EQ(0, delegate.scan_result_count());

  const uint8_t kTestRecord0[] = { 0x02, 0x01, 0x00, 0x00 };
  const uint8_t kTestRecord1[] = { 0x00 };
  const uint8_t kTestRecord2[] = {
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00
  };
  const bt_bdaddr_t kTestAddress = {
    { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
  };
  const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
  const int kTestRssi = 64;

  // Scan wasn't started. Result should be ignored.
  fake_hal_gatt_iface_->NotifyScanResultCallback(
      kTestAddress, kTestRssi, (uint8_t*) kTestRecord0);
  EXPECT_EQ(0, delegate.scan_result_count());

  // Start a scan session for |le_client_|.
  EXPECT_CALL(mock_adapter_, IsEnabled())
      .Times(1)
      .WillOnce(Return(true));
  EXPECT_CALL(*mock_handler_, Scan(_))
      .Times(2)
      .WillOnce(Return(BT_STATUS_SUCCESS))
      .WillOnce(Return(BT_STATUS_SUCCESS));
  ScanSettings settings;
  std::vector<ScanFilter> filters;
  ASSERT_TRUE(le_client_->StartScan(settings, filters));

  fake_hal_gatt_iface_->NotifyScanResultCallback(
      kTestAddress, kTestRssi, (uint8_t*) kTestRecord0);
  EXPECT_EQ(1, delegate.scan_result_count());
  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
  EXPECT_EQ(3U, delegate.last_scan_result().scan_record().size());

  fake_hal_gatt_iface_->NotifyScanResultCallback(
      kTestAddress, kTestRssi, (uint8_t*) kTestRecord1);
  EXPECT_EQ(2, delegate.scan_result_count());
  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
  EXPECT_TRUE(delegate.last_scan_result().scan_record().empty());

  fake_hal_gatt_iface_->NotifyScanResultCallback(
      kTestAddress, kTestRssi, (uint8_t*) kTestRecord2);
  EXPECT_EQ(3, delegate.scan_result_count());
  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
  EXPECT_EQ(62U, delegate.last_scan_result().scan_record().size());

  le_client_->SetDelegate(nullptr);
}

}  // namespace
}  // namespace bluetooth