From 2a74eb68f883bd17731aec98cdaaa87ab6d849a6 Mon Sep 17 00:00:00 2001 From: Holger Kaelberer Date: Thu, 10 Sep 2015 16:36:03 +0200 Subject: [PATCH] notifications: add initial support for desktop-to-xxx notifications Eavesdrop on the Notify call of the org.freedesktop.Notifications dbus-interface, proxy all caught notifications to our peer device and track them in the internal notifications-list. Also fix "cancel" requests from peer devices, by cutting of kdeconnect-android's id-prefix. --- plugins/notifications/CMakeLists.txt | 1 + .../notificationsdbusinterface.cpp | 19 +++- .../notificationsdbusinterface.h | 2 +- .../notifications/notificationslistener.cpp | 101 ++++++++++++++++++ plugins/notifications/notificationslistener.h | 46 ++++++++ plugins/notifications/notificationsplugin.cpp | 3 + plugins/notifications/notificationsplugin.h | 2 + 7 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 plugins/notifications/notificationslistener.cpp create mode 100644 plugins/notifications/notificationslistener.h diff --git a/plugins/notifications/CMakeLists.txt b/plugins/notifications/CMakeLists.txt index 41c5b78f8..fbb459eec 100644 --- a/plugins/notifications/CMakeLists.txt +++ b/plugins/notifications/CMakeLists.txt @@ -4,6 +4,7 @@ set(kdeconnect_notifications_SRCS notification.cpp notificationsplugin.cpp notificationsdbusinterface.cpp + notificationslistener.cpp ) kdeconnect_add_plugin(kdeconnect_notifications JSON kdeconnect_notifications.json SOURCES ${kdeconnect_notifications_SRCS}) diff --git a/plugins/notifications/notificationsdbusinterface.cpp b/plugins/notifications/notificationsdbusinterface.cpp index 3c504c646..4e2c7e0ea 100644 --- a/plugins/notifications/notificationsdbusinterface.cpp +++ b/plugins/notifications/notificationsdbusinterface.cpp @@ -45,6 +45,7 @@ NotificationsDbusInterface::NotificationsDbusInterface(KdeConnectPlugin* plugin) NotificationsDbusInterface::~NotificationsDbusInterface() { + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsDbusInterface"; } void NotificationsDbusInterface::clearNotifications() @@ -60,7 +61,21 @@ QStringList NotificationsDbusInterface::activeNotifications() void NotificationsDbusInterface::processPackage(const NetworkPackage& np) { if (np.get("isCancel")) { - removeNotification(np.get("id")); + QString id = np.get("id"); + // cut off kdeconnect-android's prefix if there: + if (id.startsWith("org.kde.kdeconnect_tp::")) + id = id.mid(id.indexOf("::") + 2); + removeNotification(id); + } else if (np.get("isRequest")) { + for (const auto& n: mNotifications) { + NetworkPackage np(PACKAGE_TYPE_NOTIFICATION); + np.set("id", n->internalId()); + np.set("appName", n->appName()); + np.set("ticker", n->ticker()); + np.set("isClearable", n->dismissable()); + np.set("requestAnswer", true); + mPlugin->sendPackage(np); + } } else { //TODO: Uncoment when we are able to display app icon on plasmoid @@ -114,7 +129,7 @@ void NotificationsDbusInterface::removeNotification(const QString& internalId) qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "removeNotification" << internalId; if (!mInternalIdToPublicId.contains(internalId)) { - qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found"; + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found: " << internalId; return; } diff --git a/plugins/notifications/notificationsdbusinterface.h b/plugins/notifications/notificationsdbusinterface.h index 21d5a6afe..fd36a1088 100644 --- a/plugins/notifications/notificationsdbusinterface.h +++ b/plugins/notifications/notificationsdbusinterface.h @@ -45,6 +45,7 @@ public: void processPackage(const NetworkPackage& np); void clearNotifications(); void dismissRequested(const QString& notification); + void addNotification(Notification* noti); public Q_SLOTS: Q_SCRIPTABLE QStringList activeNotifications(); @@ -54,7 +55,6 @@ Q_SIGNALS: Q_SCRIPTABLE void notificationRemoved(const QString& publicId); private /*methods*/: - void addNotification(Notification* noti); void removeNotification(const QString& internalId); QString newId(); //Generates successive identifitiers to use as public ids diff --git a/plugins/notifications/notificationslistener.cpp b/plugins/notifications/notificationslistener.cpp new file mode 100644 index 000000000..88ad98bc1 --- /dev/null +++ b/plugins/notifications/notificationslistener.cpp @@ -0,0 +1,101 @@ +/** + * Copyright 2015 Holger Kaelberer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include + +#include "notificationslistener.h" +#include "notificationsplugin.h" +#include "notification_debug.h" +#include "notificationsdbusinterface.h" + +NotificationsListener::NotificationsListener(KdeConnectPlugin* aPlugin, + NotificationsDbusInterface* aDbusInterface) + : QDBusAbstractAdaptor(aPlugin), + mPlugin(aPlugin), + dbusInterface(aDbusInterface) +{ + bool ret = QDBusConnection::sessionBus() + .registerObject("/org/freedesktop/Notifications", + this, + QDBusConnection::ExportScriptableContents); + if (!ret) + qCWarning(KDECONNECT_PLUGIN_NOTIFICATION) + << "Error registering notifications listener for device" + << mPlugin->device()->name() << ":" + << QDBusConnection::sessionBus().lastError(); + else + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) + << "Registered notifications listener for device" + << mPlugin->device()->name(); + + QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus"); + iface.call("AddMatch", + "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'"); +} + +NotificationsListener::~NotificationsListener() +{ + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsListener"; + QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus"); + QDBusMessage res = iface.call("RemoveMatch", + "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'"); + QDBusConnection::sessionBus().unregisterObject("/org/freedesktop/Notifications"); +} + +uint NotificationsListener::Notify(const QString &appName, uint replacesId, + const QString &appIcon, + const QString &summary, const QString &body, + const QStringList &actions, + const QVariantMap &hints, int timeout) +{ + static int id = 0; + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Got notification appName=" << appName << "replacesId=" << replacesId << "appIcon=" << appIcon << "summary=" << summary << "body=" << body << "actions=" << actions << "hints=" << hints << "timeout=" << timeout; + Q_UNUSED(hints); + Q_UNUSED(actions); + Q_UNUSED(appIcon); + Q_UNUSED(body); + + // skip our own notifications + if (appName == QLatin1String("KDE Connect")) + return 0; + + NetworkPackage np(PACKAGE_TYPE_NOTIFICATION); + np.set("id", QString::number(replacesId > 0 ? replacesId : ++id)); + np.set("appName", appName); + np.set("ticker", summary); + np.set("isClearable", timeout == 0); // KNotifications are persistent if + // timeout == 0, for other notifications + // clearability is pointless + + Notification *notification = new Notification(np, QString(), this); + dbusInterface->addNotification(notification); + + mPlugin->sendPackage(np); + + return (replacesId > 0 ? replacesId : id); +} diff --git a/plugins/notifications/notificationslistener.h b/plugins/notifications/notificationslistener.h new file mode 100644 index 000000000..7887b5981 --- /dev/null +++ b/plugins/notifications/notificationslistener.h @@ -0,0 +1,46 @@ +/** + * Copyright 2015 Holger Kaelberer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +class KdeConnectPlugin; +class NotificationsDbusInterface; +class Notification; + +class NotificationsListener : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Notifications") + +public: + explicit NotificationsListener(KdeConnectPlugin* aPlugin, + NotificationsDbusInterface* aDbusInterface); + virtual ~NotificationsListener(); + +private: + KdeConnectPlugin* mPlugin; + NotificationsDbusInterface* dbusInterface; + +public Q_SLOTS: + Q_SCRIPTABLE uint Notify(const QString&, uint, const QString&, + const QString&, const QString&, + const QStringList&, const QVariantMap&, int); +}; diff --git a/plugins/notifications/notificationsplugin.cpp b/plugins/notifications/notificationsplugin.cpp index badb5d340..f47f5d8dc 100644 --- a/plugins/notifications/notificationsplugin.cpp +++ b/plugins/notifications/notificationsplugin.cpp @@ -21,6 +21,7 @@ #include "notificationsplugin.h" #include "notificationsdbusinterface.h" +#include "notificationslistener.h" #include "notification_debug.h" #include @@ -33,6 +34,7 @@ NotificationsPlugin::NotificationsPlugin(QObject* parent, const QVariantList& ar : KdeConnectPlugin(parent, args) { notificationsDbusInterface = new NotificationsDbusInterface(this); + notificationsListener = new NotificationsListener(this, notificationsDbusInterface); } void NotificationsPlugin::connected() @@ -44,6 +46,7 @@ void NotificationsPlugin::connected() NotificationsPlugin::~NotificationsPlugin() { + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsPlugin"; //FIXME: Qt dbus does not allow to remove an adaptor! (it causes a crash in // the next dbus access to its parent). The implication of not deleting this // is that disabling the plugin leaks the interface. As a mitigation we are diff --git a/plugins/notifications/notificationsplugin.h b/plugins/notifications/notificationsplugin.h index 7cc67c5f4..599c89c71 100644 --- a/plugins/notifications/notificationsplugin.h +++ b/plugins/notifications/notificationsplugin.h @@ -32,6 +32,7 @@ * KdeConnectPlugin at the same time (both are QObject) */ class NotificationsDbusInterface; +class NotificationsListener; class NotificationsPlugin : public KdeConnectPlugin @@ -48,6 +49,7 @@ public Q_SLOTS: private: NotificationsDbusInterface* notificationsDbusInterface; + NotificationsListener* notificationsListener; };