summaryrefslogtreecommitdiffstats
path: root/bluetooth
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2021-12-16 15:07:44 -0500
committerScott Murray <scott.murray@konsulko.com>2021-12-16 16:03:51 -0500
commitfad93b42c285ffb463e9494070f40d3b339d732f (patch)
tree6ae60914c578bd34b8ebbde9b271859e8b87ab65 /bluetooth
parentfe20f1b029f67dee1f790ade7a9114086f2abd38 (diff)
Initial rework to replace app framework usage
Changes: - Remove "core" code related to WebSocket messaging for the app framework. - Stub out hvac, navigation, network, and weather interfaces. This allows building several of the demo applications without modification for now. The network interface will definitely be reused to plumb in a new connman-glib library derived from the previous network binding. The others may potentially be reused to plumb in other new backend implementations. - Update the Network interface object constructor arguments to add a agent registration flag. This prepares for the connman-glib switch and means users will not need to be updated twice. - Update the Bluetooth interface to use a new bluez-glib library that is derived from the previous Bluetooth binding. This has been successfully tested with a the Settings application. - Remove signal-composer and voice API interface code as there are no direct replacements planned. The signal-composer interface was effectively exposing the binding events, so has little reuse potential with a new backend. For the voice interface, if some form of Alexa support becomes desirable, it can potentially be brought back for adaptation if required. - Disable compilation of the remaining interfaces for now. Some like map, pbap, and mediaplayer are very likely to be used as the basis for updating their associated applications, so keeping the code for the planned iterative development seems easier. - Updated copyright lines in all touched files. Bug-AGL: SPEC-4182 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: Ib717ac8ac68ec457eaee74755dcf9d4f36b79d12
Diffstat (limited to 'bluetooth')
-rw-r--r--bluetooth/CMakeLists.txt6
-rw-r--r--bluetooth/bluetooth.cpp369
-rw-r--r--bluetooth/bluetooth.h42
-rw-r--r--bluetooth/bluetootheventhandler.cpp121
-rw-r--r--bluetooth/bluetootheventhandler.h71
-rw-r--r--bluetooth/bluetoothmodel.cpp207
-rw-r--r--bluetooth/bluetoothmodel.h20
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;