// Default implementation does nothing
}
+void Adapter::Observer::OnDeviceConnectionStateChanged(
+ Adapter* adapter, const std::string& device_address, bool connected) {
+ // Default implementation does nothing
+}
+
Adapter::Adapter()
: state_(ADAPTER_STATE_OFF),
address_(kDefaultAddress),
return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
}
+bool Adapter::IsDeviceConnected(const std::string& device_address) {
+ std::lock_guard<std::mutex> lock(connected_devices_lock_);
+ return connected_devices_.find(device_address) != connected_devices_.end();
+}
+
LowEnergyClientFactory* Adapter::GetLowEnergyClientFactory() const {
return ble_client_factory_.get();
}
}
}
+void Adapter::AclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state) {
+ std::string device_address = BtAddrString(&remote_bdaddr);
+ bool connected = (state == BT_ACL_STATE_CONNECTED);
+ LOG(INFO) << "ACL state changed: " << device_address << " - connected: "
+ << (connected ? "true" : "false");
+
+ // If this is reported with an error status, I suppose the best thing we can
+ // do is to log it and ignore the event.
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "AclStateChangedCallback called with status: "
+ << BtStatusText(status);
+ return;
+ }
+
+ // Introduce a scope to manage |connected_devices_lock_| with RAII.
+ {
+ std::lock_guard<std::mutex> lock(connected_devices_lock_);
+ if (connected)
+ connected_devices_.insert(device_address);
+ else
+ connected_devices_.erase(device_address);
+ }
+
+ std::lock_guard<std::mutex> lock(observers_lock_);
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ OnDeviceConnectionStateChanged(this, device_address, connected));
+}
+
bool Adapter::SetAdapterProperty(bt_property_type_t type,
void* value, int length) {
CHECK(length > 0);
#include <atomic>
#include <mutex>
#include <string>
+#include <unordered_set>
#include <base/macros.h>
#include <base/observer_list.h>
// Observer interface allows other classes to receive notifications from us.
// All of the methods in this interface are declared as optional to allow
// different layers to process only those events that they are interested in.
+ //
+ // All methods take in an |adapter| argument which points to the Adapter
+ // object that the Observer instance was added to.
class Observer {
public:
virtual ~Observer() = default;
+ // Called when there is a change in the state of the local Bluetooth
+ // |adapter| from |prev_state| to |new_state|.
virtual void OnAdapterStateChanged(Adapter* adapter,
AdapterState prev_state,
AdapterState new_state);
+
+ // Called when there is a change in the connection state between the local
+ // |adapter| and a remote device with address |device_address|. If the ACL
+ // state changes from disconnected to connected, then |connected| will be
+ // true and vice versa.
+ virtual void OnDeviceConnectionStateChanged(
+ Adapter* adapter, const std::string& device_address, bool connected);
};
Adapter();
// multi-advertisement feature.
bool IsMultiAdvertisementSupported() const;
+ // Returns true if the remote device with address |device_address| is
+ // currently connected. This is not a const method as it modifies the state of
+ // the associated internal mutex.
+ bool IsDeviceConnected(const std::string& device_address);
+
// Returns a pointer to the LowEnergyClientFactory. This can be used to
// register per-application LowEnergyClient instances to perform BLE GAP
// operations.
void AdapterPropertiesCallback(bt_status_t status,
int num_properties,
bt_property_t* properties) override;
+ void AclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state) override;
// Sends a request to set the given HAL adapter property type and value.
bool SetAdapterProperty(bt_property_type_t type, void* value, int length);
std::mutex observers_lock_;
base::ObserverList<Observer> observers_;
+ // List of devices addresses that are currently connected.
+ std::mutex connected_devices_lock_;
+ std::unordered_set<std::string> connected_devices_;
+
// Factory used to create per-app LowEnergyClient instances.
std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
*GetServerObservers(), func)
#define VERIFY_INTERFACE_OR_RETURN() \
- if (!g_interface) { \
- LOG(WARNING) << "Callback received after |g_interface| is NULL"; \
- return; \
- }
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
lock_guard<mutex> lock(g_instance_lock);
#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_bluetooth_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
void AdapterStateChangedCallback(bt_state_t state) {
lock_guard<mutex> lock(g_instance_lock);
- if (!g_bluetooth_interface) {
- LOG(WARNING) << "Callback received after global instance was destroyed";
- return;
- }
-
+ VERIFY_INTERFACE_OR_RETURN();
VLOG(1) << "Adapter state changed: " << BtStateText(state);
FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
}
int num_properties,
bt_property_t* properties) {
lock_guard<mutex> lock(g_instance_lock);
- if (!g_bluetooth_interface) {
- LOG(WARNING) << "Callback received after global instance was destroyed";
- return;
- }
-
+ VERIFY_INTERFACE_OR_RETURN();
VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
<< ", num_properties: " << num_properties;
FOR_EACH_BLUETOOTH_OBSERVER(
void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
lock_guard<mutex> lock(g_instance_lock);
- if (!g_bluetooth_interface) {
- LOG(WARNING) << "Callback received after global instance was destroyed";
- return;
- }
-
+ VERIFY_INTERFACE_OR_RETURN();
VLOG(1) << "Discovery state changed - state: " << BtDiscoveryStateText(state);
FOR_EACH_BLUETOOTH_OBSERVER(DiscoveryStateChangedCallback(state));
}
+void AclStateChangedCallback(bt_status_t status,
+ bt_bdaddr_t *remote_bd_addr,
+ bt_acl_state_t state) {
+ lock_guard<mutex> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(remote_bd_addr);
+ VLOG(1) << "Remote device ACL state changed - status: "
+ << BtStatusText(status)
+ << " - BD_ADDR: " << BtAddrString(remote_bd_addr)
+ << " - state: "
+ << ((state == BT_ACL_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED");
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ AclStateChangedCallback(status, *remote_bd_addr, state));
+}
+
void ThreadEventCallback(bt_cb_thread_evt evt) {
VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
nullptr, /* pin_request_cb */
nullptr, /* ssp_request_cb */
nullptr, /* bond_state_changed_cb */
- nullptr, /* acl_state_changed_cb */
+ AclStateChangedCallback,
ThreadEventCallback,
nullptr, /* dut_mode_recv_cb */
nullptr, /* le_test_mode_cb */
// Do nothing.
}
+void BluetoothInterface::Observer::AclStateChangedCallback(
+ bt_status_t /* status */,
+ const bt_bdaddr_t& /* remote_bdaddr */,
+ bt_acl_state_t /* state */) {
+ // Do nothing.
+}
+
// static
bool BluetoothInterface::Initialize() {
lock_guard<mutex> lock(g_instance_lock);
int num_properties,
bt_property_t* properties);
virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
+ virtual void AclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state);
// TODO(armansito): Complete the list of callbacks.
};
NotifyAdapterPropertiesChanged(1, &property);
}
+void FakeBluetoothInterface::NotifyAclStateChangedCallback(
+ bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ AclStateChangedCallback(status, remote_bdaddr, state));
+}
+
void FakeBluetoothInterface::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void NotifyAdapterAddressPropertyChanged(const bt_bdaddr_t* address);
void NotifyAdapterLocalLeFeaturesPropertyChanged(
const bt_local_le_features_t* features);
+ void NotifyAclStateChangedCallback(
+ bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state);
// hal::BluetoothInterface overrides:
void AddObserver(Observer* observer) override;
#include <gtest/gtest.h>
#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
#include "service/hal/fake_bluetooth_gatt_interface.h"
#include "service/hal/fake_bluetooth_interface.h"
TestObserver(bluetooth::Adapter* adapter)
: adapter_(adapter),
prev_state_(bluetooth::ADAPTER_STATE_INVALID),
- cur_state_(bluetooth::ADAPTER_STATE_INVALID) {
+ cur_state_(bluetooth::ADAPTER_STATE_INVALID),
+ last_device_connected_state_(false) {
CHECK(adapter_);
adapter_->AddObserver(this);
}
bluetooth::AdapterState prev_state() const { return prev_state_; }
bluetooth::AdapterState cur_state() const { return cur_state_; }
+ std::string last_connection_state_address() const {
+ return last_connection_state_address_;
+ }
+
+ bool last_device_connected_state() const {
+ return last_device_connected_state_;
+ }
+
// bluetooth::Adapter::Observer override:
void OnAdapterStateChanged(bluetooth::Adapter* adapter,
bluetooth::AdapterState prev_state,
- bluetooth::AdapterState new_state) {
+ bluetooth::AdapterState new_state) override {
ASSERT_EQ(adapter_, adapter);
prev_state_ = prev_state;
cur_state_ = new_state;
}
+ void OnDeviceConnectionStateChanged(
+ Adapter* adapter,
+ const std::string& device_address,
+ bool connected) override {
+ ASSERT_EQ(adapter_, adapter);
+ last_connection_state_address_ = device_address;
+ last_device_connected_state_ = connected;
+ }
+
private:
bluetooth::Adapter* adapter_;
bluetooth::AdapterState prev_state_, cur_state_;
+ std::string last_connection_state_address_;
+ bool last_device_connected_state_;
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
}
+TEST_F(AdapterTest, IsDeviceConnected) {
+ const char kDeviceAddr[] = "12:34:56:78:9A:BC";
+ TestObserver observer(adapter_.get());
+
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+
+ bt_bdaddr_t hal_addr;
+ ASSERT_TRUE(util::BdAddrFromString(kDeviceAddr, &hal_addr));
+
+ // status != BT_STATUS_SUCCESS should be ignored
+ fake_hal_iface_->NotifyAclStateChangedCallback(
+ BT_STATUS_FAIL, hal_addr, BT_ACL_STATE_CONNECTED);
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_TRUE(observer.last_connection_state_address().empty());
+ EXPECT_FALSE(observer.last_device_connected_state());
+
+ // Connected
+ fake_hal_iface_->NotifyAclStateChangedCallback(
+ BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_CONNECTED);
+ EXPECT_TRUE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+ EXPECT_TRUE(observer.last_device_connected_state());
+
+ // Disconnected
+ fake_hal_iface_->NotifyAclStateChangedCallback(
+ BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_DISCONNECTED);
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+ EXPECT_FALSE(observer.last_device_connected_state());
+}
+
} // namespace
} // namespace bluetooth