File indexing completed on 2024-04-21 04:56:52
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "notificationsplugin.h" 0008 0009 #include "plugin_notifications_debug.h" 0010 #include "sendreplydialog.h" 0011 #include <dbushelper.h> 0012 0013 #include <KPluginFactory> 0014 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) 0015 #include <KStartupInfo> 0016 #include <private/qtx11extras_p.h> 0017 #endif 0018 0019 K_PLUGIN_CLASS_WITH_JSON(NotificationsPlugin, "kdeconnect_notifications.json") 0020 0021 void NotificationsPlugin::connected() 0022 { 0023 NetworkPacket np(PACKET_TYPE_NOTIFICATION_REQUEST, {{QStringLiteral("request"), true}}); 0024 sendPacket(np); 0025 } 0026 0027 void NotificationsPlugin::receivePacket(const NetworkPacket &np) 0028 { 0029 if (np.get<bool>(QStringLiteral("request"))) { 0030 qCWarning(KDECONNECT_PLUGIN_NOTIFICATIONS) << "Unexpected notification request. Maybe the paired client is very old?"; 0031 } 0032 0033 if (np.get<bool>(QStringLiteral("isCancel"))) { 0034 QString id = np.get<QString>(QStringLiteral("id")); 0035 // cut off kdeconnect-android's prefix if there: 0036 if (id.startsWith(QLatin1String("org.kde.kdeconnect_tp::"))) 0037 id = id.mid(id.indexOf(QLatin1String("::")) + 2); 0038 removeNotification(id); 0039 return; 0040 } 0041 0042 QString id = np.get<QString>(QStringLiteral("id")); 0043 0044 Notification *noti = nullptr; 0045 0046 if (!m_internalIdToPublicId.contains(id)) { 0047 noti = new Notification(np, device(), this); 0048 0049 if (noti->isReady()) { 0050 addNotification(noti); 0051 } else { 0052 connect(noti, &Notification::ready, this, &NotificationsPlugin::notificationReady); 0053 } 0054 } else { 0055 QString pubId = m_internalIdToPublicId.value(id); 0056 noti = m_notifications.value(pubId); 0057 noti->update(np); 0058 } 0059 } 0060 0061 void NotificationsPlugin::clearNotifications() 0062 { 0063 qDeleteAll(m_notifications); 0064 m_notifications.clear(); 0065 Q_EMIT allNotificationsRemoved(); 0066 } 0067 0068 QStringList NotificationsPlugin::activeNotifications() 0069 { 0070 return m_notifications.keys(); 0071 } 0072 0073 void NotificationsPlugin::notificationReady() 0074 { 0075 Notification *noti = static_cast<Notification *>(sender()); 0076 disconnect(noti, &Notification::ready, this, &NotificationsPlugin::notificationReady); 0077 addNotification(noti); 0078 } 0079 0080 void NotificationsPlugin::addNotification(Notification *noti) 0081 { 0082 const QString &internalId = noti->internalId(); 0083 0084 if (m_internalIdToPublicId.contains(internalId)) { 0085 removeNotification(internalId); 0086 } 0087 0088 // qCDebug(KDECONNECT_PLUGIN_NOTIFICATIONS) << "addNotification" << internalId; 0089 0090 connect(noti, &Notification::dismissRequested, this, &NotificationsPlugin::dismissRequested); 0091 0092 connect(noti, &Notification::replyRequested, this, [this, noti] { 0093 replyRequested(noti); 0094 }); 0095 0096 connect(noti, &Notification::actionTriggered, this, &NotificationsPlugin::sendAction); 0097 connect(noti, &Notification::replied, this, [this, noti](const QString &message) { 0098 sendReply(noti->replyId(), message); 0099 }); 0100 0101 const QString &publicId = newId(); 0102 m_notifications[publicId] = noti; 0103 m_internalIdToPublicId[internalId] = publicId; 0104 0105 QDBusConnection::sessionBus().registerObject(device()->dbusPath() + QStringLiteral("/notifications/") + publicId, 0106 noti, 0107 QDBusConnection::ExportScriptableContents); 0108 Q_EMIT notificationPosted(publicId); 0109 } 0110 0111 void NotificationsPlugin::removeNotification(const QString &internalId) 0112 { 0113 // qCDebug(KDECONNECT_PLUGIN_NOTIFICATIONS) << "removeNotification" << internalId; 0114 0115 if (!m_internalIdToPublicId.contains(internalId)) { 0116 qCDebug(KDECONNECT_PLUGIN_NOTIFICATIONS) << "Not found noti by internal Id: " << internalId; 0117 return; 0118 } 0119 0120 QString publicId = m_internalIdToPublicId.take(internalId); 0121 0122 Notification *noti = m_notifications.take(publicId); 0123 if (!noti) { 0124 qCDebug(KDECONNECT_PLUGIN_NOTIFICATIONS) << "Not found noti by public Id: " << publicId; 0125 return; 0126 } 0127 0128 // Deleting the notification will unregister it automatically 0129 noti->deleteLater(); 0130 0131 Q_EMIT notificationRemoved(publicId); 0132 } 0133 0134 void NotificationsPlugin::dismissRequested(const QString &internalId) 0135 { 0136 NetworkPacket np(PACKET_TYPE_NOTIFICATION_REQUEST); 0137 np.set<QString>(QStringLiteral("cancel"), internalId); 0138 sendPacket(np); 0139 0140 // Workaround: we erase notifications without waiting a response from the 0141 // phone because we won't receive a response if we are out of sync and this 0142 // notification no longer exists. Ideally, each time we reach the phone 0143 // after some time disconnected we should re-sync all the notifications. 0144 removeNotification(internalId); 0145 } 0146 0147 void NotificationsPlugin::replyRequested(Notification *noti) 0148 { 0149 QString replyId = noti->replyId(); 0150 QString appName = noti->appName(); 0151 QString originalMessage = noti->ticker(); 0152 SendReplyDialog *dialog = new SendReplyDialog(originalMessage, replyId, appName); 0153 connect(dialog, &SendReplyDialog::sendReply, this, &NotificationsPlugin::sendReply); 0154 dialog->show(); 0155 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) 0156 auto window = qobject_cast<QWindow *>(dialog->windowHandle()); 0157 if (window && QX11Info::isPlatformX11()) { 0158 KStartupInfo::setNewStartupId(window, QX11Info::nextStartupId()); 0159 } 0160 #endif 0161 dialog->raise(); 0162 } 0163 0164 void NotificationsPlugin::sendReply(const QString &replyId, const QString &message) 0165 { 0166 NetworkPacket np(PACKET_TYPE_NOTIFICATION_REPLY); 0167 np.set<QString>(QStringLiteral("requestReplyId"), replyId); 0168 np.set<QString>(QStringLiteral("message"), message); 0169 sendPacket(np); 0170 } 0171 0172 void NotificationsPlugin::sendAction(const QString &key, const QString &action) 0173 { 0174 NetworkPacket np(PACKET_TYPE_NOTIFICATION_ACTION); 0175 np.set<QString>(QStringLiteral("key"), key); 0176 np.set<QString>(QStringLiteral("action"), action); 0177 sendPacket(np); 0178 } 0179 0180 QString NotificationsPlugin::newId() 0181 { 0182 return QString::number(++m_lastId); 0183 } 0184 0185 QString NotificationsPlugin::dbusPath() const 0186 { 0187 return QLatin1String("/modules/kdeconnect/devices/%1/notifications").arg(device()->id()); 0188 } 0189 0190 #include "moc_notificationsplugin.cpp" 0191 #include "notificationsplugin.moc"