diff --git a/declarativeplugin/kdeconnectdeclarativeplugin.cpp b/declarativeplugin/kdeconnectdeclarativeplugin.cpp index 6ba072cd3..2711cf101 100644 --- a/declarativeplugin/kdeconnectdeclarativeplugin.cpp +++ b/declarativeplugin/kdeconnectdeclarativeplugin.cpp @@ -72,6 +72,7 @@ void KdeConnectDeclarativePlugin::registerTypes(const char* uri) registerFactory(uri, "DeviceDbusInterfaceFactory"); registerFactory(uri, "DeviceBatteryDbusInterfaceFactory"); + registerFactory(uri, "DeviceConnectivityReportDbusInterfaceFactory"); registerFactory(uri, "FindMyPhoneDbusInterfaceFactory"); registerFactory(uri, "SftpDbusInterfaceFactory"); registerFactory(uri, "RemoteKeyboardDbusInterfaceFactory"); diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt index f48ff35ef..f1410b1bf 100644 --- a/interfaces/CMakeLists.txt +++ b/interfaces/CMakeLists.txt @@ -41,6 +41,7 @@ set(libkdeconnect_SRC geninterface(${PROJECT_SOURCE_DIR}/core/daemon.h daemoninterface) geninterface(${PROJECT_SOURCE_DIR}/core/device.h deviceinterface) geninterface(${PROJECT_SOURCE_DIR}/plugins/battery/batteryplugin.h batteryinterface) +geninterface(${PROJECT_SOURCE_DIR}/plugins/connectivity-report/connectivity_reportplugin.h connectivityinterface) geninterface(${PROJECT_SOURCE_DIR}/plugins/sftp/sftpplugin.h devicesftpinterface) geninterface(${PROJECT_SOURCE_DIR}/plugins/notifications/notificationsplugin.h devicenotificationsinterface) geninterface(${PROJECT_SOURCE_DIR}/plugins/findmyphone/findmyphoneplugin.h devicefindmyphoneinterface) diff --git a/interfaces/dbusinterfaces.cpp b/interfaces/dbusinterfaces.cpp index 59c62acf1..761615466 100644 --- a/interfaces/dbusinterfaces.cpp +++ b/interfaces/dbusinterfaces.cpp @@ -66,6 +66,14 @@ BatteryDbusInterface::BatteryDbusInterface(const QString& id, QObject* parent) BatteryDbusInterface::~BatteryDbusInterface() = default; +ConnectivityReportDbusInterface::ConnectivityReportDbusInterface(const QString& id, QObject* parent) + : OrgKdeKdeconnectDeviceConnectivity_reportInterface(DaemonDbusInterface::activatedService(), QStringLiteral("/modules/kdeconnect/devices/") + id + QStringLiteral("/connectivity_report"), DBusHelper::sessionBus(), parent) +{ + connect(this, &OrgKdeKdeconnectDeviceConnectivity_reportInterface::refreshed, this, &ConnectivityReportDbusInterface::refreshedProxy); +} + +ConnectivityReportDbusInterface::~ConnectivityReportDbusInterface() = default; + DeviceNotificationsDbusInterface::DeviceNotificationsDbusInterface(const QString& id, QObject* parent) : OrgKdeKdeconnectDeviceNotificationsInterface(DaemonDbusInterface::activatedService(), QStringLiteral("/modules/kdeconnect/devices/") + id + QStringLiteral("/notifications"), DBusHelper::sessionBus(), parent) { diff --git a/interfaces/dbusinterfaces.h b/interfaces/dbusinterfaces.h index c1b4dce7c..f04103d67 100644 --- a/interfaces/dbusinterfaces.h +++ b/interfaces/dbusinterfaces.h @@ -12,6 +12,7 @@ #include "daemoninterface.h" #include "deviceinterface.h" #include "batteryinterface.h" +#include "connectivityinterface.h" #include "devicesftpinterface.h" #include "devicefindmyphoneinterface.h" #include "devicenotificationsinterface.h" @@ -91,6 +92,20 @@ Q_SIGNALS: void refreshedProxy(bool isCharging, int charge); }; +class KDECONNECTINTERFACES_EXPORT ConnectivityReportDbusInterface + : public OrgKdeKdeconnectDeviceConnectivity_reportInterface +{ + Q_OBJECT + Q_PROPERTY(QString cellularNetworkType READ cellularNetworkType NOTIFY refreshedProxy) + Q_PROPERTY(int cellularNetworkStrength READ cellularNetworkStrength NOTIFY refreshedProxy) +public: + explicit ConnectivityReportDbusInterface(const QString& deviceId, QObject* parent = nullptr); + ~ConnectivityReportDbusInterface() override; + +Q_SIGNALS: + void refreshedProxy(QString cellularNetworkType, int cellularNetworkStrength); +}; + class KDECONNECTINTERFACES_EXPORT DeviceNotificationsDbusInterface : public OrgKdeKdeconnectDeviceNotificationsInterface { diff --git a/plasmoid/package/contents/ui/Connectivity.qml b/plasmoid/package/contents/ui/Connectivity.qml new file mode 100644 index 000000000..1f5ee223e --- /dev/null +++ b/plasmoid/package/contents/ui/Connectivity.qml @@ -0,0 +1,43 @@ +/** + * SPDX-FileCopyrightText: 2021 David Shlemayev + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +import QtQuick 2.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kdeconnect 1.0 + +QtObject { + + id: root + + property alias device: checker.device + readonly property alias available: checker.available + readonly property bool ready: connectivity && connectivity.cellularNetworkType != "Unknown" && connectivity.cellularNetworkStrength > -1 + + readonly property PluginChecker pluginChecker: PluginChecker { + id: checker + pluginName: "connectivity_report" + } + + property string networkType: connectivity ? connectivity.cellularNetworkType : i18n("Unknown") + property int signalStrength: connectivity ? connectivity.cellularNetworkStrength : -1 + property string displayString: { + if (ready) { + return `${networkType} ${signalStrength}/4`; + } else { + return i18n("No signal"); + } + } + property variant connectivity: null + + onAvailableChanged: { + if (available) { + connectivity = DeviceConnectivityReportDbusInterfaceFactory.create(device.id()) + } else { + connectivity = null + } + } +} diff --git a/plasmoid/package/contents/ui/DeviceDelegate.qml b/plasmoid/package/contents/ui/DeviceDelegate.qml index f136f8c40..2caced245 100644 --- a/plasmoid/package/contents/ui/DeviceDelegate.qml +++ b/plasmoid/package/contents/ui/DeviceDelegate.qml @@ -64,10 +64,31 @@ PlasmaComponents.ListItem device: root.device } + Connectivity { + id: connectivity + device: root.device + } + PlasmaComponents.Label { id: deviceName elide: Text.ElideRight - text: (battery.available && battery.charge > -1) ? i18n("%1 (%2)", display, battery.displayString) : display + text: { + let statuses = []; + + if (connectivity.available) { + statuses.push(connectivity.displayString); + } + + if (battery.available && battery.charge > -1) { + statuses.push(i18nc("Display the battery charge percentage with the label \"Battery:\" so the user knows what is being displayed", "Battery: %1", battery.displayString); + } + + if (statuses.length > 0) { + return i18n("%1 (%2)", display, statuses.join(", ")); + } else { + return display; + } + } Layout.fillWidth: true textFormat: Text.PlainText } diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index d33cfc660..8eea14130 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,6 +2,7 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kdeconnect-plugins\") add_subdirectory(ping) add_subdirectory(battery) +add_subdirectory(connectivity-report) add_subdirectory(remotecommands) add_subdirectory(remotecontrol) add_subdirectory(remotesystemvolume) diff --git a/plugins/connectivity-report/CMakeLists.txt b/plugins/connectivity-report/CMakeLists.txt new file mode 100644 index 000000000..a962d0cb2 --- /dev/null +++ b/plugins/connectivity-report/CMakeLists.txt @@ -0,0 +1,20 @@ +set(debug_file_SRCS) +ecm_qt_declare_logging_category( + debug_file_SRCS HEADER plugin_connectivity_report_debug.h + IDENTIFIER KDECONNECT_PLUGIN_CONNECTIVITY_REPORT CATEGORY_NAME kdeconnect.plugin.connectivity_report + DEFAULT_SEVERITY Warning + EXPORT kdeconnect-kde DESCRIPTION "kdeconnect (plugin connectivity_report)") + +set(kdeconnect_connectivity_report_SRCS + connectivity_reportplugin.cpp + ${debug_file_SRCS} +) + +kdeconnect_add_plugin(kdeconnect_connectivity_report JSON kdeconnect_connectivity_report.json SOURCES ${kdeconnect_connectivity_report_SRCS}) + +target_link_libraries(kdeconnect_connectivity_report + kdeconnectcore + Qt5::DBus + KF5::Solid + KF5::I18n +) diff --git a/plugins/connectivity-report/README b/plugins/connectivity-report/README new file mode 100644 index 000000000..e0f2e6083 --- /dev/null +++ b/plugins/connectivity-report/README @@ -0,0 +1,11 @@ + +This plugins receives packages with type "kdeconnect.connectivity_report" and reads the +following fields: + +signalStrengths (object): Maps each SIM (subscription ID) to the following object: + networkType (string): + One of "5G", "LTE", "CDMA", "EDGE", "GPRS", "GSM", "HSPA", "UMTS", "CDMA2000", "iDEN", "Unknown" + signalStrength (int) [0..=4]: The signal strength + +It also sends empty packages with type kdeconnect.connectivity_report.request +to ask the peer device to send a package like the mentioned above. diff --git a/plugins/connectivity-report/connectivity_reportplugin.cpp b/plugins/connectivity-report/connectivity_reportplugin.cpp new file mode 100644 index 000000000..8d6da36b8 --- /dev/null +++ b/plugins/connectivity-report/connectivity_reportplugin.cpp @@ -0,0 +1,60 @@ +/** + * SPDX-FileCopyrightText: 2021 David Shlemayev + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +#include "connectivity_reportplugin.h" + +#include +#include + +#include + +#include "plugin_connectivity_report_debug.h" + +K_PLUGIN_CLASS_WITH_JSON(ConnectivityReportPlugin, "kdeconnect_connectivity_report.json") + +ConnectivityReportPlugin::ConnectivityReportPlugin(QObject* parent, const QVariantList& args) + : KdeConnectPlugin(parent, args) +{ +} + +QString ConnectivityReportPlugin::cellularNetworkType() const +{ + return m_cellularNetworkType; +} + +int ConnectivityReportPlugin::cellularNetworkStrength() const +{ + return m_cellularNetworkStrength; +} + +void ConnectivityReportPlugin::connected() +{ + // We've just connected. Request connectivity_report information from the remote device... + NetworkPacket np(PACKET_TYPE_CONNECTIVITY_REPORT_REQUEST, {{QStringLiteral("request"),true}}); + sendPacket(np); +} + +bool ConnectivityReportPlugin::receivePacket(const NetworkPacket& np) +{ + if (np.type() == PACKET_TYPE_CONNECTIVITY_REPORT) { + auto subscriptions = np.get(QStringLiteral("signalStrengths"), QVariantMap()); + auto networkInfo = subscriptions.first().toMap(); + + m_cellularNetworkType = networkInfo.value(QStringLiteral("networkType")).toString(); + m_cellularNetworkStrength = networkInfo.value(QStringLiteral("signalStrength")).toInt(); + + Q_EMIT refreshed(m_cellularNetworkType, m_cellularNetworkStrength); + } + + return true; +} + +QString ConnectivityReportPlugin::dbusPath() const +{ + return QStringLiteral("/modules/kdeconnect/devices/") + device()->id() + QStringLiteral("/connectivity_report"); +} + +#include "connectivity_reportplugin.moc" diff --git a/plugins/connectivity-report/connectivity_reportplugin.h b/plugins/connectivity-report/connectivity_reportplugin.h new file mode 100644 index 000000000..3e8759175 --- /dev/null +++ b/plugins/connectivity-report/connectivity_reportplugin.h @@ -0,0 +1,68 @@ +/** + * SPDX-FileCopyrightText: 2021 David Shlemayev + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +#ifndef CONNECTIVITY_REPORT_H +#define CONNECTIVITY_REPORT_H + +#include + +/** + * Packet used to report the current connectivity state + *

+ * The body should contain a key "signalStrengths" which has a dict that maps + * a SubscriptionID (opaque value) to a dict with the connection info (See below) + *

+ * For example: + * { + * "signalStrengths": { + * "6": { + * "networkType": "4G", + * "signalStrength": 3 + * }, + * "17": { + * "networkType": "HSPA", + * "signalStrength": 2 + * }, + * ... + * } + * } + */ +#define PACKET_TYPE_CONNECTIVITY_REPORT QStringLiteral("kdeconnect.connectivity_report") + +/** + * Packet sent to request the current connectivity state + *

+ * The request packet shall contain no body + */ +#define PACKET_TYPE_CONNECTIVITY_REPORT_REQUEST QStringLiteral("kdeconnect.connectivity_report.request") + +class ConnectivityReportPlugin + : public KdeConnectPlugin +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.connectivity_report") + Q_PROPERTY(QString cellularNetworkType READ cellularNetworkType NOTIFY refreshed) + Q_PROPERTY(int cellularNetworkStrength READ cellularNetworkStrength NOTIFY refreshed) + +public: + explicit ConnectivityReportPlugin(QObject* parent, const QVariantList& args); + + bool receivePacket(const NetworkPacket& np) override; + void connected() override; + QString dbusPath() const override; + + QString cellularNetworkType() const; + int cellularNetworkStrength() const; + +Q_SIGNALS: + Q_SCRIPTABLE void refreshed(QString cellularNetworkType, int cellularNetworkStrength); + +private: + QString m_cellularNetworkType; + int m_cellularNetworkStrength = -1; +}; + +#endif diff --git a/plugins/connectivity-report/kdeconnect_connectivity_report.json b/plugins/connectivity-report/kdeconnect_connectivity_report.json new file mode 100644 index 000000000..8d37fc148 --- /dev/null +++ b/plugins/connectivity-report/kdeconnect_connectivity_report.json @@ -0,0 +1,27 @@ + +{ + "KPlugin": { + "Authors": [ + { + "Email": "david.shlemayev@gmail.com", + "Name": "David Shlemayev" + } + ], + "Description": "Show your phone's network signal strength", + "EnabledByDefault": true, + "Icon": "network-wireless", + "Id": "kdeconnect_connectivity_report", + "License": "GPL", + "Name": "Connectivity monitor", + "ServiceTypes": [ + "KdeConnect/Plugin" + ], + "Version": "1.0" + }, + "X-KdeConnect-OutgoingPacketType": [ + "kdeconnect.connectivity_report.request" + ], + "X-KdeConnect-SupportedPacketType": [ + "kdeconnect.connectivity_report" + ] +}