summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--endianhelpers.h2
-rw-r--r--main.cc23
-rw-r--r--notificationconn.cc61
-rw-r--r--notificationconn.h8
-rw-r--r--rpm/sapd.yaml27
-rw-r--r--sailfish/notificationmonitor.cpp79
-rw-r--r--sailfish/notificationmonitor.h28
-rw-r--r--sailfish/org.freedesktop.Notifications.xml17
-rw-r--r--sapbtlistener.cc22
-rw-r--r--sapbtlistener.h9
-rw-r--r--sapbtpeer.h4
-rw-r--r--sapd.pro31
-rw-r--r--saprotocol.h4
13 files changed, 284 insertions, 31 deletions
diff --git a/endianhelpers.h b/endianhelpers.h
index f11c669..3060382 100644
--- a/endianhelpers.h
+++ b/endianhelpers.h
@@ -10,7 +10,7 @@ template<typename T>
inline T read(const QByteArray &data, int &offset)
{
T unswapped;
- qMemCopy(&unswapped, &data.constData()[offset], sizeof(T)); // Unaligned access warning!
+ memcpy(&unswapped, &data.constData()[offset], sizeof(T)); // Unaligned access warning!
offset += sizeof(T);
return qFromBigEndian<T>(unswapped);
}
diff --git a/main.cc b/main.cc
index b30e9b5..feb0acb 100644
--- a/main.cc
+++ b/main.cc
@@ -1,5 +1,6 @@
#include <iostream>
#include <QtCore/QCoreApplication>
+#include <QtCore/QSettings>
#include <QtCore/QStringList>
#include "sapmanager.h"
#include "sapbtlistener.h"
@@ -18,8 +19,24 @@ int main(int argc, char *argv[])
app.setOrganizationDomain("com.javispedro");
app.setApplicationName("sapd");
- if (app.arguments().size() != 2) {
- cerr << "Usage:: sapd <bt address>" << endl;
+ QBluetoothAddress address;
+ QSettings settings;
+ QString address_from_settings = settings.value("device/address").toString();
+ if (!address_from_settings.isEmpty()) {
+ address = QBluetoothAddress(address_from_settings);
+ }
+
+ if (app.arguments().size() >= 2) {
+ // Get the address from the command line.
+ address = QBluetoothAddress(app.arguments().at(1));
+ }
+
+ if (address.isNull()) {
+ cerr << "Usage: sapd <bt address>" << endl;
+ cerr << "If you don't want to specify the BT address every time, put it in "
+ << qPrintable(settings.fileName())
+ << endl;
+ settings.setValue("device/address", QString());
return EXIT_FAILURE;
}
@@ -31,8 +48,6 @@ int main(int argc, char *argv[])
QScopedPointer<SAPBTListener> sap_listener(new SAPBTListener);
- QBluetoothAddress address = QBluetoothAddress(app.arguments().at(1));
-
sap_listener->start();
sap_listener->nudge(address);
diff --git a/notificationconn.cc b/notificationconn.cc
index fde3303..231427e 100644
--- a/notificationconn.cc
+++ b/notificationconn.cc
@@ -6,6 +6,10 @@
#include "endianhelpers.h"
#include "notificationconn.h"
+#if SAILFISH
+#include "sailfish/notificationmonitor.h"
+#endif
+
NotificationConn::Notification::Notification()
: type(NotificationPopup), sequenceNumber(0), urgent(false),
applicationId(0), category(0),
@@ -44,7 +48,7 @@ QByteArray NotificationConn::packNotification(const Notification &n)
if (!n.body.isEmpty()) attributeCount++;
if (!n.thumbnail.isEmpty()) attributeCount++;
if (!n.applicationName.isEmpty()) attributeCount++;
- //TODO if (n.openInHost) attributeCount++;
+ // TODO if (n.openInHost) attributeCount++;
//if (n.openInWatch) attributeCount++;
if (n.notificationId != -1) attributeCount++;
@@ -94,12 +98,27 @@ QByteArray NotificationConn::packNotification(const Notification &n)
return data;
}
+void NotificationConn::sendNotification(const Notification &n)
+{
+ QByteArray packet = packNotification(n);
+ packet.prepend('\0');
+
+ qDebug() << packet.toHex();
+
+ _socket->send(packet);
+}
+
void NotificationConn::handleConnected()
{
- qDebug() << "Manager socket now connected!";
+ qDebug() << "NotificationManager socket now connected!";
+#if SAILFISH
+ NotificationMonitor *monitor = NotificationMonitor::instance();
+ connect(monitor, SIGNAL(incomingNotification(QString,QIcon,QString,int,QString,QDateTime)),
+ this, SLOT(handleIncomingNotification(QString,QIcon,QString,int,QString,QDateTime)));
+#else
QTimer::singleShot(2000, this, SLOT(performTest()));
-
+#endif
}
void NotificationConn::handleMessageReceived()
@@ -112,12 +131,37 @@ void NotificationConn::handleMessageReceived()
// TODO Seems that we receive the notification ID that we should act upon.
}
+void NotificationConn::handleIncomingNotification(const QString &sender, const QIcon &icon, const QString &summary, int count, const QString &body, const QDateTime &dateTime)
+{
+ short applicationId = _knownSenders.value(sender, 0);
+ if (!applicationId) {
+ applicationId = _knownSenders.size() + 1;
+ _knownSenders.insert(sender, applicationId);
+ }
+
+ Notification n;
+ n.sequenceNumber = ++_lastSeqNumber;
+ n.type = NotificationPopup;
+ n.time = dateTime;
+ n.title = summary;
+ n.packageName = sender;
+ n.applicationName = sender;
+ n.body = body;
+ n.sender = 0;
+ n.count = 0; // TODO figure this out
+ n.category = 0;
+ n.applicationId = applicationId;
+ n.notificationId = ++_lastNotifId;
+
+ sendNotification(n);
+}
+
void NotificationConn::performTest()
{
qDebug() << "Performing notif test";
Notification n;
- n.sequenceNumber = 1;
+ n.sequenceNumber = ++_lastSeqNumber;
n.type = NotificationPopup;
n.time = QDateTime::currentDateTime();
n.title = "A title";
@@ -128,12 +172,7 @@ void NotificationConn::performTest()
n.count = 13;
n.category = 0;
n.applicationId = 0xc2d7;
- n.notificationId = 1;
+ n.notificationId = ++_lastNotifId;
- QByteArray packet = packNotification(n);
- packet.prepend('\0');
-
- qDebug() << packet.toHex();
-
- _socket->send(packet);
+ sendNotification(n);
}
diff --git a/notificationconn.h b/notificationconn.h
index 9be3e20..da3e3c3 100644
--- a/notificationconn.h
+++ b/notificationconn.h
@@ -54,18 +54,20 @@ protected:
};
QByteArray packNotification(const Notification &n);
-
-private:
-
+ void sendNotification(const Notification &n);
private slots:
void handleConnected();
void handleMessageReceived();
+ void handleIncomingNotification(const QString &sender, const QIcon &icon, const QString &summary, int count, const QString &body, const QDateTime &dateTime);
void performTest();
private:
SAPConnection *_conn;
SAPSocket *_socket;
+ QHash<QString, short> _knownSenders;
+ int _lastSeqNumber;
+ int _lastNotifId;
};
#endif // NOTIFICATIONCONN_H
diff --git a/rpm/sapd.yaml b/rpm/sapd.yaml
new file mode 100644
index 0000000..212f735
--- /dev/null
+++ b/rpm/sapd.yaml
@@ -0,0 +1,27 @@
+Name: sapd
+Summary: Accesory protocol daemon
+Version: 0.1.0
+Release: 1
+Group: Communications/Bluetooth
+URL: https://gitorious.org/javispedro-jolla-misc/sapd/
+License: GPLv3
+Sources:
+- '%{name}-%{version}.tar.bz2'
+Description: |
+ A daemon that speaks accessory protocol.
+Configure: none
+Builder: qtc5
+
+PkgConfigBR:
+ - sailfishapp >= 1.0.2
+ - Qt5Core
+ - Qt5DBus
+ - Qt5Bluetooth
+ - openssl
+
+PkgBR:
+# Workaround current sailfish qt5connectivity packaging bug
+ - qt5-qtconnectivity-qtbluetooth-devel
+
+Files:
+ - '%{_bindir}'
diff --git a/sailfish/notificationmonitor.cpp b/sailfish/notificationmonitor.cpp
new file mode 100644
index 0000000..f22ce02
--- /dev/null
+++ b/sailfish/notificationmonitor.cpp
@@ -0,0 +1,79 @@
+#include <QtCore/QDebug>
+#include <QtGui/QIcon>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusConnectionInterface>
+
+#include "notificationmonitor.h"
+#include "notifications_adaptor.h"
+
+static NotificationMonitor *global_monitor = 0;
+
+NotificationMonitor::NotificationMonitor(QObject *parent) :
+ QObject(parent)
+{
+ QDBusConnection bus = QDBusConnection::sessionBus();
+ QDBusConnectionInterface *dbus = bus.interface();
+ dbus->call("AddMatch",
+ "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
+ new NotificationsAdaptor(this);
+ bus.registerObject("/org/freedesktop/Notifications", this);
+}
+
+NotificationMonitor::~NotificationMonitor()
+{
+ QDBusConnection bus = QDBusConnection::sessionBus();
+ QDBusConnectionInterface *dbus = bus.interface();
+ dbus->call("RemoveMatch",
+ "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
+}
+
+NotificationMonitor *NotificationMonitor::instance()
+{
+ if (!global_monitor) {
+ global_monitor = new NotificationMonitor;
+ }
+ return global_monitor;
+}
+
+uint NotificationMonitor::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantHash &hints, int expire_timeout)
+{
+ QIcon icon;
+
+ qDebug() << "Got notification" << app_name << app_icon << summary << body;
+
+ // Avoid sending a reply for this method call, since we've received it
+ // because we're eavesdropping.
+ // The actual target of the method call will send the proper reply, not us.
+ Q_ASSERT(calledFromDBus());
+ setDelayedReply(true);
+
+ // If the notification mentions a specific icon, then use it.
+ // But otherwise let's prefer our builtin icons.
+ if (app_icon.startsWith("/")) {
+ icon = QIcon(app_icon);
+ } else if (app_icon.startsWith("file:")) {
+ QUrl url(app_icon);
+ icon = QIcon(url.toLocalFile());
+ } else {
+ QString category = hints.value("category").toString();
+ // Let's hardcode a few categories for now..
+ if (!category.isEmpty()) {
+ qDebug() << "TODO: Category icons";
+ }
+ }
+
+ int count = hints.value("x-nemo-item-count").toInt();
+ QDateTime dateTime = hints.value("x-nemo-timestamp").toDateTime();
+ if (!dateTime.isValid()) {
+ dateTime = QDateTime::currentDateTime();
+ }
+
+ if (summary.isEmpty() && body.isEmpty()) {
+ // Avoid sending empty notifications to watch.
+ return 0;
+ }
+
+ emit incomingNotification(app_name, icon, summary, count, body, dateTime);
+
+ return 0;
+}
diff --git a/sailfish/notificationmonitor.h b/sailfish/notificationmonitor.h
new file mode 100644
index 0000000..c0f7691
--- /dev/null
+++ b/sailfish/notificationmonitor.h
@@ -0,0 +1,28 @@
+#ifndef NOTIFICATIONMONITOR_H
+#define NOTIFICATIONMONITOR_H
+
+#include <QtCore/QObject>
+#include <QtCore/QDateTime>
+#include <QtDBus/QDBusContext>
+
+class NotificationMonitor : public QObject, protected QDBusContext
+{
+ Q_OBJECT
+
+public:
+ ~NotificationMonitor();
+
+ static NotificationMonitor *instance();
+
+signals:
+ void incomingNotification(const QString &sender, const QIcon &icon, const QString &summary, int count, const QString &body, const QDateTime &dateTime);
+
+private:
+ explicit NotificationMonitor(QObject *parent = 0);
+
+private slots:
+ friend class NotificationsAdaptor;
+ uint Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantHash &hints, int expire_timeout);
+};
+
+#endif // NOTIFICATIONMONITOR_H
diff --git a/sailfish/org.freedesktop.Notifications.xml b/sailfish/org.freedesktop.Notifications.xml
new file mode 100644
index 0000000..d3f8bef
--- /dev/null
+++ b/sailfish/org.freedesktop.Notifications.xml
@@ -0,0 +1,17 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.Notifications">
+ <!-- (Partial) Desktop Notification Specification interface -->
+ <method name="Notify">
+ <arg name="app_name" type="s" direction="in"/>
+ <arg name="replaces_id" type="u" direction="in"/>
+ <arg name="app_icon" type="s" direction="in"/>
+ <arg name="summary" type="s" direction="in"/>
+ <arg name="body" type="s" direction="in"/>
+ <arg name="actions" type="as" direction="in"/>
+ <arg name="hints" type="a{sv}" direction="in"/>
+ <arg name="expire_timeout" type="i" direction="in"/>
+ <arg name="id" type="u" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantHash"/>
+ </method>
+</node>
diff --git a/sapbtlistener.cc b/sapbtlistener.cc
index 1b4550a..76ecb94 100644
--- a/sapbtlistener.cc
+++ b/sapbtlistener.cc
@@ -1,6 +1,9 @@
#include <QtCore/QDebug>
+
+#ifdef MANUAL_SDP
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
+#endif
#include "saprotocol.h"
#include "sapbtlistener.h"
@@ -12,6 +15,10 @@
namespace
{
+
+#ifdef MANUAL_SDP
+// Basically, QBluetoothServiceInfo is not yet compatible with Bluez5,
+// so we hack around it by doing our own SDP connection.
void add_sdp_record(sdp_session_t *session, const QBluetoothUuid &btuuid, quint16 port)
{
sdp_list_t *svclass_id, *apseq, *root;
@@ -63,6 +70,7 @@ void add_sdp_records(quint16 port)
add_sdp_record(sess, SAProtocol::dataServiceUuid, port);
}
+#endif
}
@@ -82,7 +90,11 @@ void SAPBTListener::start()
return;
}
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+ _server = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
+#else
_server = new QRfcommServer(this);
+#endif
connect(_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!_server->listen(QBluetoothAddress(), 0)) {
qWarning() << "Failed to start Bluetooth listener socket";
@@ -92,7 +104,7 @@ void SAPBTListener::start()
quint8 serverPort = _server->serverPort();
-#if 1
+#if MANUAL_SDP
// Basically, QBluetoothServiceInfo is not yet compatible with Bluez5,
// so we hack around it by doing our own SDP connection.
add_sdp_records(serverPort);
@@ -123,7 +135,7 @@ void SAPBTListener::start()
_service.setServiceProvider("gearbtteest");
QBluetoothServiceInfo::Sequence classIds;
- classIds.append(QVariant::fromValue(SAPProtocol::dataServiceUuid));
+ classIds.append(QVariant::fromValue(SAProtocol::dataServiceUuid));
_service.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds);
QBluetoothServiceInfo::Sequence browseGroupList;
@@ -167,7 +179,11 @@ void SAPBTListener::stop()
void SAPBTListener::nudge(const QBluetoothAddress &address)
{
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+ QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
+#else
QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket, this);
+#endif
connect(socket, SIGNAL(connected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)),
@@ -177,7 +193,7 @@ void SAPBTListener::nudge(const QBluetoothAddress &address)
socket->connectToService(address, 2); //SAPProtocol::nudgeServiceUuid);
-#if 1
+#if DESKTOP
// At the same time set up and HFP connection to the watch.
new HfpAg(address, this);
#endif
diff --git a/sapbtlistener.h b/sapbtlistener.h
index a59a5e1..3fe821d 100644
--- a/sapbtlistener.h
+++ b/sapbtlistener.h
@@ -3,7 +3,10 @@
#include <QtCore/QObject>
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+#include <QtBluetooth/QBluetoothServer>
+#include <QtBluetooth/QBluetoothServiceInfo>
+#elif QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtBluetooth/QRfcommServer>
#include <QtBluetooth/QBluetoothServiceInfo>
QT_USE_NAMESPACE_BLUETOOTH
@@ -36,7 +39,11 @@ private slots:
private:
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+ QBluetoothServer *_server;
+#else
QRfcommServer *_server;
+#endif
QBluetoothServiceInfo _service;
};
diff --git a/sapbtpeer.h b/sapbtpeer.h
index cc060f8..da77f22 100644
--- a/sapbtpeer.h
+++ b/sapbtpeer.h
@@ -3,7 +3,9 @@
#include <QtCore/QObject>
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+#include <QtBluetooth/QBluetoothSocket>
+#elif QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtBluetooth/QBluetoothSocket>
QT_USE_NAMESPACE_BLUETOOTH
#else
diff --git a/sapd.pro b/sapd.pro
index ee30305..f2157d4 100644
--- a/sapd.pro
+++ b/sapd.pro
@@ -1,21 +1,36 @@
TARGET = sapd
TEMPLATE = app
-QT += core dbus
-QT -= gui
+QT += core gui dbus
CONFIG += console
-greaterThan(QT_MAJOR_VERSION, 4) {
+CONFIG += link_pkgconfig
+PKGCONFIG += openssl
+
+exists(/usr/lib/libsailfishapp.so) {
+ # Building for Jolla Sailfish, Qt5, Bluez5
+ QT += bluetooth
+ DEFINES += SAILFISH
+ DBUS_ADAPTORS += sailfish/org.freedesktop.Notifications.xml
+ SOURCES += sailfish/notificationmonitor.cpp
+ HEADERS += sailfish/notificationmonitor.h
+} else:greaterThan(QT_MAJOR_VERSION, 4) {
+ # Building for desktop, Qt5, Bluez5
QT += bluetooth
+ DEFINES += DESKTOP
+ SOURCES += hfpag.cc
+ HEADERS += hfpag.h
} else {
+ # Building for desktop, Qt4, Bluez5
CONFIG += mobility
MOBILITY += connectivity
- DEFINES += DESKTOP
+ DEFINES += DESKTOP MANUAL_SDP
SOURCES += hfpag.cc
HEADERS += hfpag.h
+ PKGCONFIG += bluez
}
-CONFIG += link_pkgconfig
-PKGCONFIG += bluez openssl
+target.path = /usr/bin
+INSTALLS += target
SOURCES += main.cc \
sapbtlistener.cc \
@@ -76,3 +91,7 @@ HEADERS += \
notificationagent.h \
notificationconn.h \
endianhelpers.h
+
+OTHER_FILES += \
+ rpm/sapd.yaml \
+ sailfish/org.freedesktop.Notifications.xml
diff --git a/saprotocol.h b/saprotocol.h
index 469a293..3f38e05 100644
--- a/saprotocol.h
+++ b/saprotocol.h
@@ -3,7 +3,9 @@
#include <QtCore/QObject>
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
+#if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
+#include <QtBluetooth/QBluetoothUuid>
+#elif QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtBluetooth/QBluetoothUuid>
QT_USE_NAMESPACE_BLUETOOTH
#else