From 54ab6c2a6475967523e2250c926cee61bc37f1b1 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 11 Apr 2018 15:54:09 -0700 Subject: libqtappfw: bluetooth: add initial agl-service-bluetooth support Add initial support for libqtappfw of the agl-service-bluetooth binding to allow removal of QML logic from the Settings application Bug-AGL: SPEC-1385 Change-Id: Iea909af113590667d619afcf09c50523c1c34035 Signed-off-by: Matt Ranostay --- CMakeLists.txt | 6 +- bluetooth.cpp | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ bluetooth.h | 92 +++++++++++++++++++++++ bluetoothmessage.cpp | 30 ++++++++ bluetoothmessage.h | 44 +++++++++++ message.h | 1 + messageengine.cpp | 6 +- 7 files changed, 381 insertions(+), 3 deletions(-) create mode 100644 bluetooth.cpp create mode 100644 bluetooth.h create mode 100644 bluetoothmessage.cpp create mode 100644 bluetoothmessage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 122c193..a3f5dcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,12 +14,14 @@ CONFIGURE_FILE("qtappfw.pc.in" "qtappfw.pc" @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qtappfw.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) -add_library(qtappfw SHARED message.cpp messageengine.cpp telephony.cpp telephonymessage.cpp) +add_library(qtappfw SHARED message.cpp messageengine.cpp + bluetooth.cpp bluetoothmessage.cpp + telephony.cpp telephonymessage.cpp) target_link_libraries(qtappfw Qt5::WebSockets) set_target_properties(qtappfw PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 - PUBLIC_HEADER "message.h;messageengine.h;telephony.h;telephonymessage.h") + PUBLIC_HEADER "message.h;messageengine.h;bluetooth.h;bluetoothmessage.h;telephony.h;telephonymessage.h") target_include_directories(qtappfw PRIVATE .) install(TARGETS qtappfw LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/bluetooth.cpp b/bluetooth.cpp new file mode 100644 index 0000000..377139c --- /dev/null +++ b/bluetooth.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 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 "message.h" +#include "messageengine.h" +#include "bluetooth.h" +#include "bluetoothmessage.h" + +Bluetooth::Bluetooth (QUrl &url, QObject * parent) : + QObject(parent), + m_mloop(nullptr) +{ + m_mloop = new MessageEngine(url); + QObject::connect(m_mloop, &MessageEngine::connected, this, &Bluetooth::onConnected); + QObject::connect(m_mloop, &MessageEngine::disconnected, this, &Bluetooth::onDisconnected); + QObject::connect(m_mloop, &MessageEngine::messageReceived, this, &Bluetooth::onMessageReceived); +} + +Bluetooth::~Bluetooth() +{ + delete m_mloop; +} + +void Bluetooth::generic_command(QString verb, QString value) +{ + BluetoothMessage *tmsg = new BluetoothMessage(); + QJsonObject parameter; + + if (!value.isEmpty()) + parameter.insert("value", value); + + tmsg->createRequest(verb, parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); +} + +void Bluetooth::setPower(bool state) +{ + generic_command("power", state ? "true": "false"); + + m_power = state; + + emit powerChanged(); +} + +void Bluetooth::setDiscoverable(bool state) +{ + const QStringList properties { "Pairable", "Discoverable" }; + QStringListIterator propertyIterator(properties); + + while (propertyIterator.hasNext()) { + BluetoothMessage *tmsg = new BluetoothMessage(); + QJsonObject parameter; + + parameter.insert("Property", propertyIterator.next()); + parameter.insert("value", state ? "true" : "false"); + + tmsg->createRequest("set_property", parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); + } + + m_discoverable = state; + + emit discoverableChanged(); +} + +void Bluetooth::start_discovery() +{ + generic_command("start_discovery", ""); + generic_command("discovery_result", ""); +} + +void Bluetooth::stop_discovery() +{ + generic_command("stop_discovery", ""); +} + +void Bluetooth::remove_device(QString address) +{ + generic_command("remove_device", address); +} + +void Bluetooth::pair(QString address) +{ + generic_command("pair", address); +} + +void Bluetooth::cancel_pair(QString address) +{ + generic_command("cancel_pair", address); +} + +void Bluetooth::connect(QString address, QString uuid) +{ + BluetoothMessage *tmsg = new BluetoothMessage(); + QJsonObject parameter; + + parameter.insert("value", address); + parameter.insert("uuid", uuid); + tmsg->createRequest("connect", parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); +} + +void Bluetooth::connect(QString address) +{ + generic_command("connect", address); +} + +void Bluetooth::disconnect(QString address, QString uuid) +{ + BluetoothMessage *tmsg = new BluetoothMessage(); + QJsonObject parameter; + + parameter.insert("value", address); + parameter.insert("uuid", uuid); + tmsg->createRequest("disconnect", parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); +} + +void Bluetooth::disconnect(QString address) +{ + generic_command("disconnect", address); +} + +void Bluetooth::send_confirmation() +{ + generic_command("send_confirmation", "yes"); +} + +void Bluetooth::onConnected() +{ + QStringListIterator eventIterator(events); + BluetoothMessage *tmsg; + + while (eventIterator.hasNext()) { + tmsg = new BluetoothMessage(); + QJsonObject parameter; + parameter.insert("value", eventIterator.next()); + tmsg->createRequest("subscribe", parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); + } + + // get initial power state + generic_command("power", QString()); +} + +void Bluetooth::onDisconnected() +{ + QStringListIterator eventIterator(events); + BluetoothMessage *tmsg; + + while (eventIterator.hasNext()) { + tmsg = new BluetoothMessage(); + QJsonObject parameter; + parameter.insert("value", eventIterator.next()); + tmsg->createRequest("unsubscribe", parameter); + m_mloop->sendMessage(tmsg); + tmsg->deleteLater(); + } +} + +void Bluetooth::onMessageReceived(MessageType type, Message *msg) +{ + if (msg->isEvent() && type == BluetoothEventMessage) { + BluetoothMessage *tmsg = qobject_cast(msg); + + if (tmsg->isConnectionEvent()) { + emit connectionEvent(tmsg->eventData()); + } else if (tmsg->isRequestConfirmationEvent()) { + emit requestConfirmationEvent(tmsg->eventData()); + } else if (tmsg->isDeviceAddedEvent()) { + emit deviceAddedEvent(tmsg->eventData()); + } else if (tmsg->isDeviceRemovedEvent()) { + emit deviceRemovedEvent(tmsg->eventData()); + } else if (tmsg->isDeviceUpdatedEvent()) { + emit deviceUpdatedEvent(tmsg->eventData()); + } + } else if (msg->isReply() && type == GenericMessage) { + if (this->isDiscoveryListResponse(msg)) { + emit deviceListEvent(msg->replyData()); + } else if (this->isPowerResponse(msg)) { + m_power = msg->replyData().value("power").toString() == "on"; + emit powerChanged(); + } + } + + msg->deleteLater(); +} diff --git a/bluetooth.h b/bluetooth.h new file mode 100644 index 0000000..0bce40f --- /dev/null +++ b/bluetooth.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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_H +#define BLUETOOTH_H + +#include +#include + +#include "messageengine.h" + +class Bluetooth : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool power READ power WRITE setPower NOTIFY powerChanged) + Q_PROPERTY(bool discoverable READ discoverable WRITE setDiscoverable NOTIFY discoverableChanged) + + public: + explicit Bluetooth(QUrl &url, QObject * parent = Q_NULLPTR); + virtual ~Bluetooth(); + + void setPower(bool); + void setDiscoverable(bool); + + Q_INVOKABLE void start_discovery(void); + Q_INVOKABLE void stop_discovery(void); + + Q_INVOKABLE void remove_device(QString address); + Q_INVOKABLE void pair(QString address); + Q_INVOKABLE void cancel_pair(QString address); + + Q_INVOKABLE void connect(QString address, QString uuid); + Q_INVOKABLE void connect(QString address); + + Q_INVOKABLE void disconnect(QString address, QString uuid); + Q_INVOKABLE void disconnect(QString address); + + Q_INVOKABLE void send_confirmation(void); + + bool power() const { return m_power; }; + bool discoverable() const { return m_discoverable; }; + + signals: + void powerChanged(); + void discoverableChanged(); + + void connectionEvent(QJsonObject data); + void requestConfirmationEvent(QJsonObject data); + void deviceAddedEvent(QJsonObject data); + void deviceRemovedEvent(QJsonObject data); + void deviceUpdatedEvent(QJsonObject data); + void deviceListEvent(QJsonObject data); + + private: + MessageEngine *m_mloop; + void generic_command(QString, QString); + + // slots + void onConnected(); + void onDisconnected(); + void onMessageReceived(MessageType, Message*); + + bool isDiscoveryListResponse(Message *tmsg) { return (tmsg->replyInfo() == "BT - Scan Result is Displayed"); }; + bool isPowerResponse(Message *tmsg) { return (tmsg->replyInfo() == "Radio - Power set"); }; + + // values + bool m_power; + bool m_discoverable; + + const QStringList events { + "connection", + "request_confirmation", + "device_added", + "device_removed", + "device_updated", + }; +}; + +#endif // BLUETOOTH_H diff --git a/bluetoothmessage.cpp b/bluetoothmessage.cpp new file mode 100644 index 0000000..52ecbed --- /dev/null +++ b/bluetoothmessage.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include + +#include "bluetoothmessage.h" + +bool BluetoothMessage::createRequest(QString verb, QJsonObject parameter) +{ + if (!verbs.contains(verb)) + return false; + + return Message::createRequest("Bluetooth-Manager", verb, parameter); +} diff --git a/bluetoothmessage.h b/bluetoothmessage.h new file mode 100644 index 0000000..6ce2f3e --- /dev/null +++ b/bluetoothmessage.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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_MESSAGE_H +#define BLUETOOTH_MESSAGE_H + +#include "message.h" + +class BluetoothMessage : public Message +{ + Q_OBJECT + public: + bool isConnectionEvent() { return (this->eventName() == "connection"); }; + bool isRequestConfirmationEvent() { return (this->eventName() == "request_confirmation"); }; + bool isDeviceAddedEvent() { return (this->eventName() == "device_added"); }; + bool isDeviceRemovedEvent() { return (this->eventName() == "device_removed"); }; + bool isDeviceUpdatedEvent() { return (this->eventName() == "device_updated"); }; + bool createRequest(QString verb, QJsonObject parameter); + + private: + QStringList verbs { + "start_discovery" , "stop_discovery", "power", + "remove_device", "pair", "cancel_pair", + "connect", "disconnect", "device_priorites", + "set_device_property", "set_property", "discovery_result", + "set_avrcp_controls", "send_confirmation", + "subscribe", "unsubscribe", + }; +}; + +#endif // BLUETOOTH_MESSAGE_H diff --git a/message.h b/message.h index 7aab2e9..bcb1b33 100644 --- a/message.h +++ b/message.h @@ -32,6 +32,7 @@ enum MessageId { enum MessageType { GenericMessage, TelephonyEventMessage, + BluetoothEventMessage, }; class Message : public QObject diff --git a/messageengine.cpp b/messageengine.cpp index 7d53694..c68093d 100644 --- a/messageengine.cpp +++ b/messageengine.cpp @@ -16,6 +16,7 @@ #include "message.h" #include "messageengine.h" +#include "bluetoothmessage.h" #include "telephonymessage.h" #include @@ -71,7 +72,10 @@ void MessageEngine::onTextMessageReceived(QString jsonStr) MessageType type; // FIXME: This should be rewritten using a factory class with a // parser parameter to remove API specific handling here - if (api == "telephony") { + if (api == "Bluetooth-Manager") { + message = new BluetoothMessage; + type = BluetoothEventMessage; + } else if (api == "telephony") { message = new TelephonyMessage; type = TelephonyEventMessage; } else { -- cgit 1.2.3-korg