Add support for phone side telephony plugin on Linux.
## Summary Add support for Phone side (like in the Android and SailfishOS apps) to telephony plugin. this requires ModemManager to work. Call state notifications are currently supported, more capabilities are possible. Tested on PinePhone but should probably work on every linux Phone with ModemManager. to test, pair kdeconnect on your linux phone to desktop, and call your phone. you should get notification on the desktop, telling you that phone call is incoming.
This commit is contained in:
parent
17ab101e61
commit
7b1f10d4d5
7 changed files with 262 additions and 0 deletions
|
@ -27,3 +27,7 @@ Dependencies:
|
|||
'frameworks/kpackage': '@stable'
|
||||
'libraries/pulseaudio-qt': '@stable'
|
||||
'libraries/plasma-wayland-protocols': '@stable'
|
||||
|
||||
- 'on': ['Linux']
|
||||
'require':
|
||||
'frameworks/modemmanager-qt': '@stable'
|
||||
|
|
|
@ -38,6 +38,10 @@ if(NOT SAILFISHOS)
|
|||
add_subdirectory(screensaver-inhibit)
|
||||
add_subdirectory(virtualmonitor)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
add_subdirectory(mmtelephony)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
add_subdirectory(sendnotifications)
|
||||
endif()
|
||||
|
|
21
plugins/mmtelephony/CMakeLists.txt
Normal file
21
plugins/mmtelephony/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS ModemManagerQt)
|
||||
set(debug_file_SRCS)
|
||||
ecm_qt_declare_logging_category(
|
||||
debug_file_SRCS HEADER plugin_mmtelephony_debug.h
|
||||
IDENTIFIER KDECONNECT_PLUGIN_MMTELEPHONY CATEGORY_NAME kdeconnect.plugin.mmtelephony
|
||||
DEFAULT_SEVERITY Warning
|
||||
EXPORT kdeconnect-kde DESCRIPTION "kdeconnect (plugin mmtelephony)")
|
||||
|
||||
set(kdeconnect_mmtelephony_SRCS
|
||||
mmtelephonyplugin.cpp
|
||||
${debug_file_SRCS}
|
||||
)
|
||||
|
||||
kdeconnect_add_plugin(kdeconnect_mmtelephony SOURCES ${kdeconnect_mmtelephony_SRCS})
|
||||
|
||||
target_link_libraries(kdeconnect_mmtelephony
|
||||
kdeconnectcore
|
||||
Qt${QT_MAJOR_VERSION}::DBus
|
||||
KF5::ModemManagerQt
|
||||
KF5::I18n
|
||||
)
|
13
plugins/mmtelephony/README
Normal file
13
plugins/mmtelephony/README
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
This plugin will display a notification each time a package with type
|
||||
"kdeconnect.telephony" is received. The type of notification will change
|
||||
depending on the contents of the field "event" (string).
|
||||
|
||||
Valid contents for "event" are: "ringing", "talking", "missedCall" and "sms".
|
||||
|
||||
If the incoming package contains a "phoneNumber" string field, the notification
|
||||
will also display it. Note that "phoneNumber" can be a contact name instead
|
||||
of an actual phone number.
|
||||
|
||||
If the incoming package contains "isCancel" set to true, the package is ignored.
|
||||
|
28
plugins/mmtelephony/kdeconnect_mmtelephony.json
Normal file
28
plugins/mmtelephony/kdeconnect_mmtelephony.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "bhyoram@protonmail.com",
|
||||
"Name": "Yoram Bar-Haim"
|
||||
}
|
||||
],
|
||||
"Description": "Show notifications for incoming calls",
|
||||
"EnabledByDefault": true,
|
||||
"Icon": "call-start",
|
||||
"Id": "kdeconnect_mmtelephony",
|
||||
"License": "GPL",
|
||||
"Name": "ModemManager Telephony integration",
|
||||
"ServiceTypes": [
|
||||
"KdeConnect/Plugin"
|
||||
],
|
||||
"Version": "0.1",
|
||||
"Website": "https://kdeconnect.kde.org/"
|
||||
},
|
||||
"X-KdeConnect-OutgoingPacketType": [
|
||||
"kdeconnect.telephony"
|
||||
],
|
||||
"X-KdeConnect-SupportedPacketType": [
|
||||
"kdeconnect.telephony",
|
||||
"kdeconnect.telephony.request_mute"
|
||||
]
|
||||
}
|
135
plugins/mmtelephony/mmtelephonyplugin.cpp
Normal file
135
plugins/mmtelephony/mmtelephonyplugin.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Richard Liebscher <richard.liebscher@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2022 Yoram Bar Haim <bhyoram@protonmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "mmtelephonyplugin.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QDebug>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "plugin_mmtelephony_debug.h"
|
||||
#include <KPluginFactory>
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(MMTelephonyPlugin, "kdeconnect_mmtelephony.json")
|
||||
|
||||
static const QString PACKET_TYPE_TELEPHONY = QStringLiteral("kdeconnect.telephony");
|
||||
static const QString PACKET_TYPE_TELEPHONY_REQUEST_MUTE = QStringLiteral("kdeconnect.telephony.request_mute");
|
||||
|
||||
QSharedPointer<ModemManager::ModemVoice> _voiceInterface(const QSharedPointer<ModemManager::ModemDevice> modemDevice)
|
||||
{
|
||||
return modemDevice->interface(ModemManager::ModemDevice::VoiceInterface).objectCast<ModemManager::ModemVoice>();
|
||||
}
|
||||
|
||||
MMTelephonyPlugin::MMTelephonyPlugin(QObject *parent, const QVariantList &args)
|
||||
: KdeConnectPlugin(parent, args)
|
||||
{
|
||||
connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &MMTelephonyPlugin::onModemAdded);
|
||||
}
|
||||
|
||||
bool MMTelephonyPlugin::receivePacket(const NetworkPacket &np)
|
||||
{
|
||||
if (np.get<QString>(QStringLiteral("event")) == QLatin1String("mute")) {
|
||||
// TODO: mute code
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::onModemAdded(const QString &path)
|
||||
{
|
||||
auto modemDevice = ModemManager::findModemDevice(path);
|
||||
QSharedPointer<ModemManager::ModemVoice> vcm = _voiceInterface(modemDevice);
|
||||
auto voice = vcm.get();
|
||||
connect(voice, &ModemManager::ModemVoice::callAdded, this, [this, voice](const QString &uni) {
|
||||
auto call = voice->findCall(uni);
|
||||
onCallAdded(call);
|
||||
});
|
||||
connect(voice, &ModemManager::ModemVoice::callDeleted, this, [this, voice](const QString &uni) {
|
||||
auto call = voice->findCall(uni);
|
||||
onCallRemoved(call);
|
||||
});
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::onModemRemoved(const QString &path)
|
||||
{
|
||||
Q_UNUSED(path);
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::onCallAdded(ModemManager::Call::Ptr call)
|
||||
{
|
||||
qCDebug(KDECONNECT_PLUGIN_MMTELEPHONY) << "Call added" << call->number();
|
||||
|
||||
connect(call.get(), &ModemManager::Call::stateChanged, this, [=](MMCallState newState, MMCallState oldState, MMCallStateReason reason) {
|
||||
onCallStateChanged(call.get(), newState, oldState, reason);
|
||||
});
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::onCallRemoved(ModemManager::Call::Ptr call)
|
||||
{
|
||||
qCDebug(KDECONNECT_PLUGIN_MMTELEPHONY) << "Call removed" << call.get()->number();
|
||||
}
|
||||
|
||||
QString MMTelephonyPlugin::stateName(MMCallState state)
|
||||
{
|
||||
QString event;
|
||||
switch (state) {
|
||||
case MMCallState::MM_CALL_STATE_RINGING_IN:
|
||||
event = QStringLiteral("ringing");
|
||||
break;
|
||||
case MMCallState::MM_CALL_STATE_ACTIVE:
|
||||
event = QStringLiteral("talking");
|
||||
break;
|
||||
case MMCallState::MM_CALL_STATE_TERMINATED:
|
||||
event = QStringLiteral("disconnected");
|
||||
break;
|
||||
case MMCallState::MM_CALL_STATE_UNKNOWN:
|
||||
default:
|
||||
event = QStringLiteral("Unknown");
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::onCallStateChanged(ModemManager::Call *call, MMCallState newState, MMCallState oldState, MMCallStateReason reason)
|
||||
{
|
||||
Q_UNUSED(reason);
|
||||
auto event = stateName(newState);
|
||||
|
||||
qCDebug(KDECONNECT_PLUGIN_MMTELEPHONY) << "Call state changed" << call->uni() << event;
|
||||
if (newState != MMCallState::MM_CALL_STATE_TERMINATED)
|
||||
sendMMTelephonyPacket(call, event);
|
||||
else
|
||||
sendCancelMMTelephonyPacket(call, stateName(oldState));
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::sendMMTelephonyPacket(ModemManager::Call *call, const QString &state)
|
||||
{
|
||||
QString phoneNumber = call->number();
|
||||
|
||||
qCDebug(KDECONNECT_PLUGIN_MMTELEPHONY) << "Phone number is" << phoneNumber;
|
||||
NetworkPacket np{PACKET_TYPE_TELEPHONY,
|
||||
{
|
||||
{QStringLiteral("event"), state},
|
||||
{QStringLiteral("phoneNumber"), phoneNumber},
|
||||
{QStringLiteral("contactName"), phoneNumber},
|
||||
}};
|
||||
sendPacket(np);
|
||||
}
|
||||
|
||||
void MMTelephonyPlugin::sendCancelMMTelephonyPacket(ModemManager::Call *call, const QString &lastState)
|
||||
{
|
||||
QString phoneNumber = call->number();
|
||||
|
||||
NetworkPacket np{PACKET_TYPE_TELEPHONY,
|
||||
{{QStringLiteral("event"), lastState},
|
||||
{QStringLiteral("phoneNumber"), phoneNumber},
|
||||
{QStringLiteral("contactName"), phoneNumber},
|
||||
{QStringLiteral("isCancel"), true}}};
|
||||
sendPacket(np);
|
||||
}
|
||||
|
||||
#include "mmtelephonyplugin.moc"
|
57
plugins/mmtelephony/mmtelephonyplugin.h
Normal file
57
plugins/mmtelephony/mmtelephonyplugin.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2018 Simon Redman <simon@ergotech.com>
|
||||
* SPDX-FileCopyrightText: 2019 Richard Liebscher <richard.liebscher@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2022 Yoram Bar Haim <bhyoram@protonmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#ifndef TELEPHONYPLUGIN_H
|
||||
#define TELEPHONYPLUGIN_H
|
||||
|
||||
#include <KPluginFactory>
|
||||
#include <ModemManagerQt/Call>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/Modem>
|
||||
#include <ModemManagerQt/ModemVoice>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
|
||||
#include <core/kdeconnectplugin.h>
|
||||
|
||||
class QDBusPendingCallWatcher;
|
||||
class QDBusInterface;
|
||||
class QDBusError;
|
||||
class QDBusObjectPath;
|
||||
class QDBusVariant;
|
||||
|
||||
class MMTelephonyPlugin : public KdeConnectPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.telephony")
|
||||
|
||||
public:
|
||||
explicit MMTelephonyPlugin(QObject *parent, const QVariantList &args);
|
||||
~MMTelephonyPlugin() override = default;
|
||||
|
||||
bool receivePacket(const NetworkPacket &np) override;
|
||||
void connected() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void onCallAdded(ModemManager::Call::Ptr call);
|
||||
void onCallRemoved(ModemManager::Call::Ptr call);
|
||||
void onModemAdded(const QString &path);
|
||||
void onModemRemoved(const QString &path);
|
||||
void onCallStateChanged(ModemManager::Call *call, MMCallState newState, MMCallState oldState, MMCallStateReason reason);
|
||||
void sendMMTelephonyPacket(ModemManager::Call *call, const QString &state);
|
||||
void sendCancelMMTelephonyPacket(ModemManager::Call *call, const QString &lastState);
|
||||
static QString stateName(MMCallState state);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue