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

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

Merge "Add Connect and Disconnect methods to LowEnergyClient"

parents 7fd16c5e 4b871ea6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -168,6 +168,12 @@ bool BluetoothLowEnergyBinderServer::StopMultiAdvertising(int client_id) {
  return true;
}

void BluetoothLowEnergyBinderServer::OnConnectionState(
      bluetooth::LowEnergyClient* client, int status,
      const char* address, bool connected) {
  VLOG(2) << __func__ << " address: " << address << " connected: " << connected;
}

void BluetoothLowEnergyBinderServer::OnScanResult(
    bluetooth::LowEnergyClient* client,
    const bluetooth::ScanResult& result) {
+2 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ class BluetoothLowEnergyBinderServer
  bool StopMultiAdvertising(int client_id) override;

  // bluetooth::LowEnergyClient::Delegate overrides:
  void OnConnectionState(bluetooth::LowEnergyClient* client, int status,
                         const char* address, bool connected) override;
  void OnScanResult(bluetooth::LowEnergyClient* client,
                    const bluetooth::ScanResult& result) override;

+86 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <base/logging.h>

#include "service/adapter.h"
#include "service/common/bluetooth/util/address_helper.h"
#include "service/logging_helpers.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcidefs.h"
@@ -334,6 +335,49 @@ LowEnergyClient::~LowEnergyClient() {
    StopScan();
}

bool LowEnergyClient::Connect(std::string address, bool is_direct) {
  VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;

  bt_bdaddr_t bda;
  util::BdAddrFromString(address, &bda);

  bt_status_t status = hal::BluetoothGattInterface::Get()->
      GetClientHALInterface()->connect(client_id_, &bda, is_direct,
                                       BT_TRANSPORT_LE);
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "HAL call to connect failed";
    return false;
  }

  return true;
}

bool LowEnergyClient::Disconnect(std::string address) {
  VLOG(2) << __func__ << "Address: " << address;

  bt_bdaddr_t bda;
  util::BdAddrFromString(address, &bda);

  std::map<const bt_bdaddr_t, int>::iterator conn_id;
  {
    lock_guard<mutex> lock(connection_fields_lock_);
    conn_id = connection_ids_.find(bda);
    if (conn_id == connection_ids_.end()) {
      LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
      return false;
    }
  }

  bt_status_t status = hal::BluetoothGattInterface::Get()->
      GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second);
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "HAL call to disconnect failed";
    return false;
  }

  return true;
}

void LowEnergyClient::SetDelegate(Delegate* delegate) {
  lock_guard<mutex> lock(delegate_mutex_);
  delegate_ = delegate;
@@ -513,6 +557,46 @@ void LowEnergyClient::ScanResultCallback(
  delegate_->OnScanResult(this, result);
}

void LowEnergyClient::ConnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) {
  if (client_id != client_id_)
    return;

  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;

  {
    lock_guard<mutex> lock(connection_fields_lock_);
    auto success = connection_ids_.emplace(bda, conn_id);
    if (!success.second) {
      LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
    }
  }

  if (delegate_)
    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
                                 true);
}

void LowEnergyClient::DisconnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) {
  if (client_id != client_id_)
    return;

  VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
  {
    lock_guard<mutex> lock(connection_fields_lock_);
    if (!connection_ids_.erase(bda)) {
      LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
    }
  }

  if (delegate_)
    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
                                 false);
}

void LowEnergyClient::MultiAdvEnableCallback(
    hal::BluetoothGattInterface* gatt_iface,
    int client_id, int status) {
+33 −1
Original line number Diff line number Diff line
@@ -35,6 +35,12 @@

namespace bluetooth {

struct ConnComparator {
    bool operator()(const bt_bdaddr_t& a, const bt_bdaddr_t& b) const {
        return memcmp(&a, &b, sizeof(bt_bdaddr_t)) < 0;
    }
};

class Adapter;

// A LowEnergyClient represents an application's handle to perform various
@@ -55,6 +61,10 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
    virtual void OnScanResult(LowEnergyClient* client,
                              const ScanResult& scan_result) = 0;

    // Called asynchronously to notify the delegate of connection state change
    virtual void OnConnectionState(LowEnergyClient* client, int status,
                                   const char* address, bool connected) = 0;

   private:
    DISALLOW_COPY_AND_ASSIGN(Delegate);
  };
@@ -70,6 +80,15 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  // Callback type used to return the result of asynchronous operations below.
  using StatusCallback = std::function<void(BLEStatus)>;

  // Initiates a BLE connection do device with address |address|. If
  // |is_direct| is set, use direct connect procedure. Return true on success
  //, false otherwise.
  bool Connect(std::string address, bool is_direct);

  // Disconnect from previously connected BLE device with address |address|.
  // Return true on success, false otherwise.
  bool Disconnect(std::string address);

  // Initiates a BLE device scan for this client using the given |settings| and
  // |filters|. See the documentation for ScanSettings and ScanFilter for how
  // these parameters can be configured. Return true on success, false
@@ -123,6 +142,13 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  void ScanResultCallback(
      hal::BluetoothGattInterface* gatt_iface,
      const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override;

  void ConnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) override;
  void DisconnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) override;
  void MultiAdvEnableCallback(
      hal::BluetoothGattInterface* gatt_iface,
      int client_id, int status) override;
@@ -190,6 +216,12 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  std::mutex delegate_mutex_;
  Delegate* delegate_;

  // Protects device connection related members below.
  std::mutex connection_fields_lock_;

  // Maps bluetooth address to connection id
  std::map<const bt_bdaddr_t, int, ConnComparator> connection_ids_;

  DISALLOW_COPY_AND_ASSIGN(LowEnergyClient);
};

+72 −4
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@

using ::testing::_;
using ::testing::Return;
using ::testing::Pointee;
using ::testing::DoAll;
using ::testing::Invoke;

namespace bluetooth {
namespace {
@@ -74,7 +77,7 @@ class MockGattHandler

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

  ~TestDelegate() override = default;
@@ -82,6 +85,14 @@ class TestDelegate : public LowEnergyClient::Delegate {
  int scan_result_count() const { return scan_result_count_; }
  const ScanResult& last_scan_result() const { return last_scan_result_; }

  int connection_state_count() const { return connection_state_count_; }

  void OnConnectionState(LowEnergyClient* client, int status,
                         const char* address, bool connected)  {
    ASSERT_TRUE(client);
    connection_state_count_++;
  }

  void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) {
    ASSERT_TRUE(client);
    scan_result_count_++;
@@ -92,6 +103,8 @@ class TestDelegate : public LowEnergyClient::Delegate {
  int scan_result_count_;
  ScanResult last_scan_result_;

  int connection_state_count_;

  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};

@@ -937,5 +950,60 @@ TEST_F(LowEnergyClientPostRegisterTest, ScanRecord) {
  le_client_->SetDelegate(nullptr);
}

MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
                        " bitwise equal to " + ::testing::PrintToString(x)) {
  static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
  return std::memcmp(&arg, &x, sizeof(x)) == 0;
}

TEST_F(LowEnergyClientPostRegisterTest, Connect) {
  const bt_bdaddr_t kTestAddress = {
    { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
  };
  const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
  const bool kTestDirect = false;
  const int connId = 12;

  TestDelegate delegate;
  le_client_->SetDelegate(&delegate);

  // TODO(jpawlowski): NotifyConnectCallback should be called after returning
  // success, fix it when it becomes important.
  // These should succeed and result in a HAL call
  EXPECT_CALL(*mock_handler_, Connect(le_client_->GetInstanceId(),
          Pointee(BitEq(kTestAddress)), kTestDirect, BT_TRANSPORT_LE))
      .Times(1)
      .WillOnce(DoAll(
        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, bool is_direct,
                   int transport){
          fake_hal_gatt_iface_->NotifyConnectCallback(connId, BT_STATUS_SUCCESS,
                                                      client_id, *bd_addr);
        }),
        Return(BT_STATUS_SUCCESS)));

  EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
  EXPECT_EQ(1, delegate.connection_state_count());

  // TODO(jpawlowski): same as above
  // These should succeed and result in a HAL call
  EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
        Pointee(BitEq(kTestAddress)), connId))
      .Times(1)
      .WillOnce(DoAll(
        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, int connId){
          fake_hal_gatt_iface_->NotifyDisconnectCallback(connId,
                                                         BT_STATUS_SUCCESS,
                                                         client_id, *bd_addr);
        }),
        Return(BT_STATUS_SUCCESS)));

  EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
  EXPECT_EQ(2, delegate.connection_state_count());

  le_client_->SetDelegate(nullptr);
  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
}


}  // namespace
}  // namespace bluetooth