diff options
Diffstat (limited to 'bluetooth')
-rw-r--r-- | bluetooth/CMakeLists.txt | 6 | ||||
-rw-r--r-- | bluetooth/bluetooth.cpp | 369 | ||||
-rw-r--r-- | bluetooth/bluetooth.h | 42 | ||||
-rw-r--r-- | bluetooth/bluetootheventhandler.cpp | 121 | ||||
-rw-r--r-- | bluetooth/bluetootheventhandler.h | 71 | ||||
-rw-r--r-- | bluetooth/bluetoothmodel.cpp | 207 | ||||
-rw-r--r-- | bluetooth/bluetoothmodel.h | 20 |
7 files changed, 520 insertions, 316 deletions
diff --git a/bluetooth/CMakeLists.txt b/bluetooth/CMakeLists.txt index e514aab..3137e3c 100644 --- a/bluetooth/CMakeLists.txt +++ b/bluetooth/CMakeLists.txt @@ -3,16 +3,16 @@ CONFIGURE_FILE("qtappfw-bt.pc.in" "qtappfw-bt.pc" @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qtappfw-bt.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) -add_library(qtappfw-bt SHARED bluetooth.cpp bluetoothmodel.cpp) +add_library(qtappfw-bt SHARED bluetooth.cpp bluetoothmodel.cpp bluetootheventhandler.cpp) target_include_directories(qtappfw-bt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_include_directories(qtappfw-bt PRIVATE "${CMAKE_INSTALL_INCLUDEDIR}") -target_link_libraries(qtappfw-bt qtappfw-core) +target_link_libraries(qtappfw-bt Qt5::Qml PkgConfig::glib PkgConfig::bluez_glib) set_target_properties(qtappfw-bt PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 - PUBLIC_HEADER "bluetooth.h;bluetoothmodel.h") + PUBLIC_HEADER "bluetooth.h") install(TARGETS qtappfw-bt LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/bluetooth/bluetooth.cpp b/bluetooth/bluetooth.cpp index 82ef2f1..c58b64b 100644 --- a/bluetooth/bluetooth.cpp +++ b/bluetooth/bluetooth.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2020 Konsulko Group + * Copyright (C) 2018-2021 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,301 +16,248 @@ #include <QDebug> -#include "callmessage.h" -#include "eventmessage.h" -#include "responsemessage.h" -#include "messagefactory.h" -#include "messageengine.h" -#include "messageenginefactory.h" +#include <bluez-glib.h> + #include "bluetooth.h" #include "bluetoothmodel.h" +#include "bluetootheventhandler.h" -Bluetooth::Bluetooth (QUrl &url, QQmlContext *context, QObject * parent) : - QObject(parent), - m_context(context) +Bluetooth::Bluetooth (bool register_agent, QQmlContext *context, QObject * parent) : + QObject(parent), + m_context(context), + m_agent(register_agent) { - m_mloop = MessageEngineFactory::getInstance().getMessageEngine(url); - m_bluetooth = new BluetoothModel(); - QObject::connect(m_mloop.get(), &MessageEngine::connected, this, &Bluetooth::onConnected); - QObject::connect(m_mloop.get(), &MessageEngine::disconnected, this, &Bluetooth::onDisconnected); - QObject::connect(m_mloop.get(), &MessageEngine::messageReceived, this, &Bluetooth::onMessageReceived); - - BluetoothModelFilter *m_model = new BluetoothModelFilter(); - m_model->setSourceModel(m_bluetooth); - m_model->setFilterFixedString("true"); - context->setContextProperty("BluetoothPairedModel", m_model); - - m_model = new BluetoothModelFilter(); - m_model->setSourceModel(m_bluetooth); - m_model->setFilterFixedString("false"); - context->setContextProperty("BluetoothDiscoveryModel", m_model); - - uuids.insert("a2dp", "0000110a-0000-1000-8000-00805f9b34fb"); - uuids.insert("avrcp", "0000110e-0000-1000-8000-00805f9b34fb"); - uuids.insert("hfp", "0000111f-0000-1000-8000-00805f9b34fb"); + m_bluetooth = new BluetoothModel(); + BluetoothModelFilter *m_model = new BluetoothModelFilter(); + m_model->setSourceModel(m_bluetooth); + m_model->setFilterFixedString("true"); + context->setContextProperty("BluetoothPairedModel", m_model); + + m_model = new BluetoothModelFilter(); + m_model->setSourceModel(m_bluetooth); + m_model->setFilterFixedString("false"); + context->setContextProperty("BluetoothDiscoveryModel", m_model); + + m_event_handler = new BluetoothEventHandler(this, register_agent); + + uuids.insert("a2dp", "0000110a-0000-1000-8000-00805f9b34fb"); + uuids.insert("avrcp", "0000110e-0000-1000-8000-00805f9b34fb"); + uuids.insert("hfp", "0000111f-0000-1000-8000-00805f9b34fb"); } Bluetooth::~Bluetooth() { } -void Bluetooth::send_command(QString verb, QJsonObject parameter) -{ - std::unique_ptr<Message> msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* btmsg = static_cast<CallMessage*>(msg.get()); - btmsg->createRequest("Bluetooth-Manager", verb, parameter); - m_mloop->sendMessage(std::move(msg)); -} - void Bluetooth::setPower(bool state) { - QJsonObject parameter; - parameter.insert("powered", state ? "true" : "false"); - send_command("adapter_state", parameter); + bluez_adapter_set_powered(NULL, state ? TRUE : FALSE); } void Bluetooth::setDiscoverable(bool state) { - QJsonObject parameter; - parameter.insert("discoverable", state ? "true" : "false"); - send_command("adapter_state", parameter); + bluez_adapter_set_discoverable(NULL, state); - m_discoverable = state; + m_discoverable = state; - emit discoverableChanged(); + emit discoverableChanged(); } -void Bluetooth::discovery_command(bool state) +void Bluetooth::start() { - QJsonObject parameter; - parameter.insert("discovery", state ? "true" : "false"); + bluez_init(m_agent, m_agent, m_event_handler->init_cb, m_event_handler); +} - set_discovery_filter(); +void Bluetooth::discovery_command(bool state) +{ + set_discovery_filter(); - send_command("adapter_state", parameter); + bluez_adapter_set_discovery(NULL, state ? TRUE : FALSE); } void Bluetooth::start_discovery() { - discovery_command(true); - - // temp workaround to list already discovered devices - send_command("managed_objects", QJsonObject()); + discovery_command(true); } void Bluetooth::stop_discovery() { - discovery_command(false); + discovery_command(false); } void Bluetooth::remove_device(QString device) { - QJsonObject parameter; - parameter.insert("device", device); + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); - send_command("remove_device", parameter); + bluez_device_remove(device_cstr); } void Bluetooth::pair(QString device) { - QJsonObject parameter; - parameter.insert("device", device); + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); - send_command("pair", parameter); + bluez_device_pair(device_cstr, m_event_handler->device_pair_cb, m_event_handler); } -void Bluetooth::cancel_pair(QString device) +void Bluetooth::cancel_pair(void) { - send_command("cancel_pairing", QJsonObject()); + bluez_cancel_pairing(); } void Bluetooth::connect(QString device, QString uuid) { - QJsonObject parameter; - uuid = process_uuid(uuid); - parameter.insert("device", device); - parameter.insert("uuid", uuid); - send_command("connect", parameter); + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); + + uuid = process_uuid(uuid); + QByteArray uuid_ba = uuid.toLocal8Bit(); + const char *uuid_cstr = uuid_ba.data(); + + bluez_device_connect(device_cstr, + uuid_cstr, + m_event_handler->device_connect_cb, + m_event_handler); } void Bluetooth::connect(QString device) { - QJsonObject parameter; - parameter.insert("device", device); - send_command("connect", parameter); + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); + + bluez_device_connect(device_cstr, + NULL, + m_event_handler->device_connect_cb, + m_event_handler); } void Bluetooth::disconnect(QString device, QString uuid) { - QJsonObject parameter; - uuid = process_uuid(uuid); - parameter.insert("device", device); - parameter.insert("uuid", uuid); - send_command("disconnect", parameter); -} + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); -void Bluetooth::disconnect(QString device) -{ - QJsonObject parameter; - parameter.insert("device", device); - send_command("disconnect", parameter); -} + uuid = process_uuid(uuid); + QByteArray uuid_ba = uuid.toLocal8Bit(); + const char *uuid_cstr = uuid_ba.data(); -void Bluetooth::send_confirmation(int pincode) -{ - QJsonObject parameter; - parameter.insert("pincode", pincode); - send_command("confirm_pairing", parameter); + bluez_device_disconnect(device_cstr, uuid_cstr); } - -void Bluetooth::set_discovery_filter() +void Bluetooth::disconnect(QString device) { - QStringListIterator eventIterator(uuids.values()); - QJsonObject parameter; - QJsonArray array; - - while (eventIterator.hasNext()) - array.push_back(eventIterator.next()); + QByteArray device_ba = device.toLocal8Bit(); + const char *device_cstr = device_ba.data(); - // send inital adapter state + discovery filter - parameter.insert("filter", array); - parameter.insert("transport", "bredr"); - send_command("adapter_state", parameter); + bluez_device_disconnect(device_cstr, NULL); } -void Bluetooth::onConnected() +void Bluetooth::send_confirmation(int pincode) { - QStringListIterator eventIterator(events); - - while (eventIterator.hasNext()) { - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - send_command("subscribe", parameter); - } + QString pincode_str; + pincode_str.setNum(pincode); + QByteArray pincode_ba = pincode_str.toLocal8Bit(); + const char *pincode_cstr = pincode_ba.data(); - // send initial list - send_command("managed_objects", QJsonObject()); - - // get initial power state - send_command("adapter_state", QJsonObject()); + bluez_confirm_pairing(pincode_cstr); } -void Bluetooth::onDisconnected() +void Bluetooth::init_adapter_state(QString adapter) { - QStringListIterator eventIterator(events); + // Get initial power state + GVariant *reply = NULL; + gboolean rc = bluez_adapter_get_state(NULL, &reply); + if (rc && reply) { + GVariantDict *props_dict = g_variant_dict_new(reply); + gboolean powered = FALSE; + if (g_variant_dict_lookup(props_dict, "Powered", "b", &powered)) { + if (m_power != powered) { + m_power = powered; + emit powerChanged(m_power); + } + } + g_variant_dict_unref(props_dict); + g_variant_unref(reply); + } - while (eventIterator.hasNext()) { - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - send_command("unsubscribe", parameter); - } + // Get initial device list + refresh_device_list(); } -void Bluetooth::populateDeviceList(QJsonObject data) +void Bluetooth::refresh_device_list(void) { - QJsonArray devices = data.value("devices").toArray(); - - m_bluetooth->removeAllDevices(); - - for (auto value : devices) { - BluetoothDevice *device = m_bluetooth->updateDeviceProperties(nullptr, value.toObject()); - m_bluetooth->addDevice(device); - } + gboolean rc; + GVariant *reply = NULL; + + rc = bluez_adapter_get_devices(NULL, &reply); + if(!rc) + return; + + m_bluetooth->removeAllDevices(); + + GVariantIter *array = NULL; + g_variant_get(reply, "a{sv}", &array); + const gchar *key = NULL; + GVariant *var = NULL; + while (g_variant_iter_next(array, "{&sv}", &key, &var)) { + BluetoothDevice *device = m_bluetooth->updateDeviceProperties(nullptr, key, var); + if (device) + m_bluetooth->addDevice(device); + + g_variant_unref(var); + } + g_variant_iter_free(array); + g_variant_unref(reply); } -void Bluetooth::processDeviceChangesEvent(QJsonObject data) +void Bluetooth::set_discovery_filter(void) { - QString action = data.value("action").toString(); - QString id = data.value("device").toString(); - - if (id.isEmpty()) - return; - - BluetoothDevice *device = m_bluetooth->getDevice(id); - if (action == "removed") { - if (device != nullptr) - m_bluetooth->removeDevice(device); - return; - } - - BluetoothDevice *ndevice = m_bluetooth->updateDeviceProperties(device, data); - if (ndevice == nullptr) { - qDebug() << "bt - failed to create device object with id: " << id; - return; - } - if (device == nullptr) //device not previously in model - m_bluetooth->addDevice(ndevice); + QList<QString> values = uuids.values(); + QStringListIterator eventIterator(values); + + gchar **uuids_array = (gchar**) g_malloc0((values.count() + 1) * sizeof(gchar*)); + int i = 0; + while (eventIterator.hasNext()) { + QByteArray uuid_ba = eventIterator.next().toLocal8Bit(); + gchar *uuid_cstr = g_strdup(uuid_ba.data()); + uuids_array[i++] = uuid_cstr; + } + + gchar *transport = g_strdup("bredr"); + bluez_adapter_set_discovery_filter(NULL, uuids_array, transport); + + for (i = 0; i < values.count(); i++) + g_free(uuids_array[i]); + g_free(uuids_array); + g_free(transport); } -void Bluetooth::processAdapterChangesEvent(QJsonObject data) +void Bluetooth::update_adapter_power(bool powered) { - QString action = data.value("action").toString(); - if (action != "changed") - return; + if (!powered) + m_bluetooth->removeAllDevices(); - QJsonObject properties = data.value("properties").toObject(); - if (!properties.contains("powered")) - return; + if (m_power != powered) { + m_power = powered; + emit powerChanged(powered); - bool powered = properties.find("powered").value().toBool(); - if (!powered) - m_bluetooth->removeAllDevices(); + if (powered) + refresh_device_list(); + } - if (m_power != powered) { - m_power = powered; - emit powerChanged(powered); - } - if (!m_power) - m_discoverable = false; + if (!m_power) { + bool discoverable = m_discoverable; + m_discoverable = false; + if (discoverable != m_discoverable) + emit discoverableChanged(); + } } -void Bluetooth::onMessageReceived(std::shared_ptr<Message> msg) +void Bluetooth::request_confirmation(int pincode) { - if (!msg) - return; - - if (msg->isEvent()) { - std::shared_ptr<EventMessage> emsg = std::static_pointer_cast<EventMessage>(msg); - QString ename = emsg->eventName(); - QString eapi = emsg->eventApi(); - QJsonObject data = emsg->eventData(); - if (eapi != "Bluetooth-Manager") - return; - if (ename == "device_changes") { - processDeviceChangesEvent(data); - } else if (ename == "adapter_changes") { - processAdapterChangesEvent(data); - } else if (ename == "agent") { - emit requestConfirmationEvent(data); - } - } else if (msg->isReply()) { - std::shared_ptr<ResponseMessage> rmsg = std::static_pointer_cast<ResponseMessage>(msg); - QString verb = rmsg->requestVerb(); - QJsonObject data = rmsg->replyData(); - if (rmsg->requestApi() != "Bluetooth-Manager") - return; - - if (rmsg->replyStatus() == "failed") { - qDebug() << "failed bt verb:" << verb; - if (rmsg->replyInfo().contains("No adapter")) { - m_power = false; - emit powerChanged(m_power); - } - } - else if (verb == "managed_objects") { - populateDeviceList(data); - } else if (verb == "adapter_state") { - bool powered = data.value("powered").toBool(); - if (m_power != powered) { - m_power = powered; - emit powerChanged(m_power); - } - } - } + QString pincode_str; + pincode_str.setNum(pincode); + emit requestConfirmationEvent(pincode_str); } diff --git a/bluetooth/bluetooth.h b/bluetooth/bluetooth.h index b79e8f9..c7ef55c 100644 --- a/bluetooth/bluetooth.h +++ b/bluetooth/bluetooth.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2020 Konsulko Group + * Copyright (C) 2018-2021 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,10 @@ #include <memory> #include <QObject> -#include <QJsonObject> -#include <QJsonArray> #include <QtQml/QQmlContext> class BluetoothModel; -class MessageEngine; -class Message; +class BluetoothEventHandler; class Bluetooth : public QObject { @@ -34,18 +31,20 @@ class Bluetooth : public QObject Q_PROPERTY(bool discoverable READ discoverable WRITE setDiscoverable NOTIFY discoverableChanged) public: - explicit Bluetooth(QUrl &url, QQmlContext *context, QObject * parent = Q_NULLPTR); + explicit Bluetooth(bool register_agent, QQmlContext *context, QObject * parent = Q_NULLPTR); virtual ~Bluetooth(); void setPower(bool); void setDiscoverable(bool); + Q_INVOKABLE void start(void); + Q_INVOKABLE void start_discovery(void); Q_INVOKABLE void stop_discovery(void); Q_INVOKABLE void remove_device(QString device); Q_INVOKABLE void pair(QString device); - Q_INVOKABLE void cancel_pair(QString device); + Q_INVOKABLE void cancel_pair(void); Q_INVOKABLE void connect(QString device, QString uuid); Q_INVOKABLE void connect(QString device); @@ -62,24 +61,21 @@ class Bluetooth : public QObject void powerChanged(bool state); void discoverableChanged(); - void connectionEvent(QJsonObject data); - void requestConfirmationEvent(QJsonObject data); + //void connectionEvent(QJsonObject data); + void requestConfirmationEvent(QString pincode); private: - std::shared_ptr<MessageEngine> m_mloop; QQmlContext *m_context; BluetoothModel *m_bluetooth; - void send_command(QString, QJsonObject); - void set_discovery_filter(); - void discovery_command(bool); - void populateDeviceList(QJsonObject data); - void processDeviceChangesEvent(QJsonObject data); - void processAdapterChangesEvent(QJsonObject data); + BluetoothEventHandler *m_event_handler; + bool m_agent; - // slots - void onConnected(); - void onDisconnected(); - void onMessageReceived(std::shared_ptr<Message>); + void init_adapter_state(QString); + void refresh_device_list(void); + void set_discovery_filter(void); + void discovery_command(bool); + void update_adapter_power(bool); + void request_confirmation(int); QString process_uuid(QString uuid) { if (uuid.length() == 36) return uuid; return uuids.value(uuid); }; @@ -89,11 +85,7 @@ class Bluetooth : public QObject QMap<QString, QString> uuids; - const QStringList events { - "adapter_changes", - "device_changes", - "agent", - }; + friend class BluetoothEventHandler; }; #endif // BLUETOOTH_H diff --git a/bluetooth/bluetootheventhandler.cpp b/bluetooth/bluetootheventhandler.cpp new file mode 100644 index 0000000..0acd5f5 --- /dev/null +++ b/bluetooth/bluetootheventhandler.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <QDebug> +#include <bluez-glib.h> + +#include "bluetootheventhandler.h" +#include "bluetooth.h" +#include "bluetoothmodel.h" + + +BluetoothEventHandler::BluetoothEventHandler (Bluetooth *parent, bool register_agent) : + m_parent(parent), + m_agent(register_agent) +{ + bluez_add_adapter_event_callback(adapter_event_cb, this); + bluez_add_device_event_callback(device_event_cb, this); + if (register_agent) + bluez_add_agent_event_callback(agent_event_cb, this); +} + +BluetoothEventHandler::~BluetoothEventHandler() +{ +} + +void BluetoothEventHandler::handle_init_event(gchar *adapter, gboolean status) +{ + if (status) + m_parent->init_adapter_state(QString(adapter)); + else + qCritical() << "BlueZ initialization failed"; +} + +void BluetoothEventHandler::handle_adapter_event(gchar *adapter, + bluez_event_t event, + GVariant *properties) +{ + if (!adapter || event != BLUEZ_EVENT_CHANGE) + return; + + GVariantDict *props_dict = g_variant_dict_new(properties); + if (!props_dict) + return; + + gboolean powered = FALSE; + if (!g_variant_dict_lookup(props_dict, "Powered", "b", &powered)) { + g_variant_dict_unref(props_dict); + return; + } + + g_variant_dict_unref(props_dict); + + m_parent->update_adapter_power(powered); +} + +void BluetoothEventHandler::handle_device_event(gchar *adapter, + gchar *device, + bluez_event_t event, + GVariant *properties) +{ + if (!device) + return; + + BluetoothDevice *model_device = m_parent->m_bluetooth->getDevice(QString(device)); + if (event == BLUEZ_EVENT_REMOVE) { + if(model_device != nullptr) + m_parent->m_bluetooth->removeDevice(model_device); + + return; + } + + BluetoothDevice *new_device = m_parent->m_bluetooth->updateDeviceProperties(model_device, device, properties); + if (new_device == nullptr) { + qCritical() << "Failed to create device object with id: " << QString(device); + return; + } + if (model_device == nullptr && event == BLUEZ_EVENT_ADD) { + // device not previously in model + m_parent->m_bluetooth->addDevice(new_device); + } +} + +void BluetoothEventHandler::handle_agent_event(gchar *device, + bluez_agent_event_t event, + GVariant *properties) +{ + const gchar *path = NULL; + int pincode; + + if (event == BLUEZ_AGENT_EVENT_REQUEST_CONFIRMATION) { + g_variant_get(properties, "(ou)", &path, &pincode); + if (path) + m_parent->request_confirmation(pincode); + } +} + +void BluetoothEventHandler::handle_connect_event(gchar *device, gboolean status) +{ + if (!status) + qDebug() << "connect failed"; +} + +void BluetoothEventHandler::handle_pair_event(gchar *device, gboolean status) +{ + if (!status) + qDebug() << "pairing failed"; +} + diff --git a/bluetooth/bluetootheventhandler.h b/bluetooth/bluetootheventhandler.h new file mode 100644 index 0000000..ff970f5 --- /dev/null +++ b/bluetooth/bluetootheventhandler.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLUETOOTH_EVENT_HANDLER_H +#define BLUETOOTH_EVENT_HANDLER_H + +class Bluetooth; + +class BluetoothEventHandler +{ + public: + explicit BluetoothEventHandler(Bluetooth *parent, bool register_agent); + virtual ~BluetoothEventHandler(); + + static void init_cb(gchar *adapter, gboolean status, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_init_event(adapter, status); + } + + static void device_connect_cb(gchar *device, gboolean status, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_connect_event(device, status); + } + + static void device_pair_cb(gchar *device, gboolean status, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_pair_event(device, status); + } + + private: + Bluetooth *m_parent; + bool m_agent; + + // Callback functions for bluez-glib hooks + static void adapter_event_cb(gchar *adapter, bluez_event_t event, GVariant *properties, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_adapter_event(adapter, event, properties); + } + + static void device_event_cb(gchar *adapter, gchar *device, bluez_event_t event, GVariant *properties, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_device_event(adapter, device, event, properties); + } + + static void agent_event_cb(gchar *device, bluez_agent_event_t event, GVariant *properties, gpointer user_data) { + if (user_data) + ((BluetoothEventHandler*) user_data)->handle_agent_event(device, event, properties); + } + + void handle_init_event(gchar *adapter, gboolean status); + void handle_adapter_event(gchar *adapter, bluez_event_t event, GVariant *properties); + void handle_device_event(gchar *adapter, gchar *device, bluez_event_t event, GVariant *properties); + void handle_agent_event(gchar *device, bluez_agent_event_t event, GVariant *properties); + void handle_connect_event(gchar *device, gboolean status); + void handle_pair_event(gchar *device, gboolean status); +}; + +#endif // BLUETOOTH_EVENT_HANDLER_H diff --git a/bluetooth/bluetoothmodel.cpp b/bluetooth/bluetoothmodel.cpp index 294b50b..605f950 100644 --- a/bluetooth/bluetoothmodel.cpp +++ b/bluetooth/bluetoothmodel.cpp @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2019-2021 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "bluetoothmodel.h" #include <QDebug> @@ -13,52 +29,52 @@ BluetoothDevice::BluetoothDevice(const QString &id, QString BluetoothDevice::id() const { - return m_id; + return m_id; } QString BluetoothDevice::address() const { - return m_address; + return m_address; } QString BluetoothDevice::name() const { - return m_name; + return m_name; } bool BluetoothDevice::paired() const { - return m_paired; + return m_paired; } bool BluetoothDevice::connected() const { - return m_connected; + return m_connected; } void BluetoothDevice::setId(const QString id) { - m_id = id; + m_id = id; } void BluetoothDevice::setAddress(const QString address) { - m_address = address; + m_address = address; } void BluetoothDevice::setName(const QString name) { - m_name = name; + m_name = name; } void BluetoothDevice::setPaired(const bool paired) { - m_paired = paired; + m_paired = paired; } void BluetoothDevice::setConnected(const bool connected) { - m_connected = connected; + m_connected = connected; } BluetoothModel::BluetoothModel(QObject *parent) @@ -68,117 +84,158 @@ BluetoothModel::BluetoothModel(QObject *parent) void BluetoothModel::addDevice(BluetoothDevice *device) { - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_devices << device; - endInsertRows(); + if (!device) + return; + + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_devices << device; + endInsertRows(); } void BluetoothModel::removeDevice(BluetoothDevice *device) { - int row = m_devices.indexOf(device); - beginRemoveRows(QModelIndex(), row, row); - m_devices.removeAt(row); - endRemoveRows(); - delete device; + if (!device) + return; + + int row = m_devices.indexOf(device); + if (row < 0) + return; + beginRemoveRows(QModelIndex(), row, row); + m_devices.removeAt(row); + endRemoveRows(); + delete device; } void BluetoothModel::removeAllDevices() { - beginRemoveRows(QModelIndex(), 0, m_devices.count() - 1); - qDeleteAll(m_devices.begin(), m_devices.end()); - m_devices.clear(); - endRemoveRows(); + if (!m_devices.count()) + return; + + beginRemoveRows(QModelIndex(), 0, m_devices.count() - 1); + qDeleteAll(m_devices.begin(), m_devices.end()); + m_devices.clear(); + endRemoveRows(); } int BluetoothModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); - return m_devices.count(); + Q_UNUSED(parent); + return m_devices.count(); } QVariant BluetoothModel::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= m_devices.count()) - return QVariant(); + if (index.row() < 0 || index.row() >= m_devices.count()) + return QVariant(); - const BluetoothDevice *device = m_devices[index.row()]; + const BluetoothDevice *device = m_devices[index.row()]; - switch (role) { + switch (role) { case IdRole: - return device->id(); + return device->id(); case AddressRole: - return device->address(); + return device->address(); case NameRole: - return device->name(); + return device->name(); case PairedRole: - return device->paired(); + return device->paired(); case ConnectedRole: - return device->connected(); - } + return device->connected(); + } - return QVariant(); + return QVariant(); } QHash<int, QByteArray> BluetoothModel::roleNames() const { - QHash<int, QByteArray> roles; - roles[IdRole] = "id"; - roles[AddressRole] = "address"; - roles[NameRole] = "name"; - roles[PairedRole] = "paired"; - roles[ConnectedRole] = "connected"; + QHash<int, QByteArray> roles; + roles[IdRole] = "id"; + roles[AddressRole] = "address"; + roles[NameRole] = "name"; + roles[PairedRole] = "paired"; + roles[ConnectedRole] = "connected"; - return roles; + return roles; } QModelIndex BluetoothModel::indexOf(BluetoothDevice *device) { - int row = m_devices.indexOf(device); + int row = m_devices.indexOf(device); - return index(row); + return index(row); } BluetoothDevice *BluetoothModel::getDevice(QString id) { - for (auto device : m_devices) { - if (device->id() == id) - return device; - } + for (auto device : m_devices) { + if (device->id() == id) + return device; + } - return nullptr; + return nullptr; } -BluetoothDevice *BluetoothModel::updateDeviceProperties(BluetoothDevice *device, QJsonObject data) +BluetoothDevice *BluetoothModel::updateDeviceProperties(BluetoothDevice *device, const gchar *dev_str, GVariant *properties) { - QJsonObject properties = data.value("properties").toObject(); - QString id = data.value("device").toString(); - QString address = properties.value("address").toString(); - QString name = properties.value("name").toString(); - bool paired = properties.value("paired").toBool(); - bool connected = properties.value("connected").toBool(); + GVariantDict *props_dict = g_variant_dict_new(properties); + if (!props_dict) + return nullptr; + + QString id(dev_str); + if (id.isEmpty()) { + g_variant_dict_unref(props_dict); + return nullptr; + } + + gchar *p = NULL; + QString address; + if (g_variant_dict_lookup(props_dict, "Address", "s", &p)) { + address = QString(p); + g_free(p); + } + + p = NULL; + QString name; + if (g_variant_dict_lookup(props_dict, "Name", "s", &p)) { + name = QString(p); + g_free(p); + } + + gboolean paired = FALSE; + bool have_paired = false; + if (g_variant_dict_lookup(props_dict, "Paired", "b", &paired)) { + have_paired = true; + } + + gboolean connected = FALSE; + bool have_connected = false; + if (g_variant_dict_lookup(props_dict, "Connected", "b", &connected)) { + have_connected = true; + } - if (id.isEmpty()) - return nullptr; + g_variant_dict_unref(props_dict); - if (device == nullptr) - return new BluetoothDevice(id, address, name, paired, connected); + if (device == nullptr) { + // Create new device object + return new BluetoothDevice(id, address, name, paired, connected); + } - device->setId(id); + device->setId(id); - if (!address.isEmpty()) - device->setAddress(address); + if (!address.isEmpty()) + device->setAddress(address); - if (!name.isEmpty()) - device->setName(name); + if (!name.isEmpty()) + device->setName(name); - if (properties.contains("paired")) - device->setPaired(paired); + if (have_paired) + device->setPaired(paired); - if (properties.contains("connected")) - device->setConnected(connected); + if (have_connected) + device->setConnected(connected); - emit dataChanged(indexOf(device), indexOf(device)); + emit dataChanged(indexOf(device), indexOf(device)); - return device; + return device; } BluetoothModelFilter::BluetoothModelFilter(QObject *parent) : QSortFilterProxyModel(parent) @@ -187,9 +244,9 @@ BluetoothModelFilter::BluetoothModelFilter(QObject *parent) : QSortFilterProxyMo bool BluetoothModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { - BluetoothModel *model = qobject_cast<BluetoothModel *>(sourceModel()); - QModelIndex index = model->index(sourceRow); - bool paired = model->data(index, BluetoothModel::BluetoothRoles::PairedRole).toBool(); + BluetoothModel *model = qobject_cast<BluetoothModel *>(sourceModel()); + QModelIndex index = model->index(sourceRow); + bool paired = model->data(index, BluetoothModel::BluetoothRoles::PairedRole).toBool(); - return ((paired ? "true" : "false") == filterRegExp().pattern()); + return ((paired ? "true" : "false") == filterRegExp().pattern()); } diff --git a/bluetooth/bluetoothmodel.h b/bluetooth/bluetoothmodel.h index 0fc07aa..a060ad8 100644 --- a/bluetooth/bluetoothmodel.h +++ b/bluetooth/bluetoothmodel.h @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2019,2021 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef BLUETOOTH_MODEL_H #define BLUETOOTH_MODEL_H @@ -5,7 +21,7 @@ #include <QSortFilterProxyModel> #include <QStringList> #include <QtQml/QQmlContext> -#include <QJsonObject> +#include <glib.h> class BluetoothDevice { @@ -53,7 +69,7 @@ class BluetoothModel : public QAbstractListModel void removeDevice(BluetoothDevice *device); void removeAllDevices(); BluetoothDevice *getDevice(QString address); - BluetoothDevice *updateDeviceProperties(BluetoothDevice *device, QJsonObject data); + BluetoothDevice *updateDeviceProperties(BluetoothDevice *device, const gchar *dev_str, GVariant *properties); int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; |