From 0f3d090bd1dc9a6b912eb0b1e587602573304b4a Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Wed, 17 Feb 2016 20:41:52 +0100 Subject: First attempt at QML hacking. Main and ServiceControl adapted. Project files --- rockworkd/jsfiles.qrc | 2 - rockworkd/libpebble/watchconnection.cpp | 18 +- .../sailfish/callchannelobserver.cpp | 9 +- .../sailfish/callchannelobserver.h | 2 +- .../sailfish/sailfishplatform.h | 6 +- .../sailfish/voicecallhandler.cpp | 372 +++++++++++++++++++++ .../sailfish/voicecallhandler.h | 96 ++++++ .../sailfish/voicecallmanager.cpp | 315 +++++++++++++++++ .../sailfish/voicecallmanager.h | 111 ++++++ rockworkd/rockworkd.pro | 23 +- 10 files changed, 926 insertions(+), 28 deletions(-) delete mode 100644 rockworkd/jsfiles.qrc create mode 100644 rockworkd/platformintegration/sailfish/voicecallhandler.cpp create mode 100644 rockworkd/platformintegration/sailfish/voicecallhandler.h create mode 100644 rockworkd/platformintegration/sailfish/voicecallmanager.cpp create mode 100644 rockworkd/platformintegration/sailfish/voicecallmanager.h (limited to 'rockworkd') diff --git a/rockworkd/jsfiles.qrc b/rockworkd/jsfiles.qrc deleted file mode 100644 index 807350d..0000000 --- a/rockworkd/jsfiles.qrc +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/rockworkd/libpebble/watchconnection.cpp b/rockworkd/libpebble/watchconnection.cpp index 0778a1d..dabacf4 100644 --- a/rockworkd/libpebble/watchconnection.cpp +++ b/rockworkd/libpebble/watchconnection.cpp @@ -32,7 +32,7 @@ UploadManager *WatchConnection::uploadManager() const void WatchConnection::scheduleReconnect() { - if (m_connectionAttempts == 0) { + if (m_connectionAttempts < 2) { reconnect(); } else if (m_connectionAttempts < 25) { qDebug() << "Attempting to reconnect in 10 seconds"; @@ -49,21 +49,27 @@ void WatchConnection::scheduleReconnect() void WatchConnection::reconnect() { QBluetoothLocalDevice localBtDev; + qDebug() << "Reconnection"; if (localBtDev.pairingStatus(m_pebbleAddress) == QBluetoothLocalDevice::Unpaired) { // Try again in one 10 secs, give the user some time to pair it + qDebug() << "Unpaired."; m_connectionAttempts = 1; scheduleReconnect(); return; } if (m_socket) { + qDebug() << "Socket exists."; if (m_socket->state() == QBluetoothSocket::ConnectedState) { qDebug() << "Already connected."; return; } - delete m_socket; + m_socket->deleteLater(); } + m_connectionAttempts++; + + qDebug() << "Creating socket."; m_socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this); connect(m_socket, &QBluetoothSocket::connected, this, &WatchConnection::pebbleConnected); connect(m_socket, &QBluetoothSocket::readyRead, this, &WatchConnection::readyRead); @@ -71,7 +77,6 @@ void WatchConnection::reconnect() connect(m_socket, &QBluetoothSocket::disconnected, this, &WatchConnection::pebbleDisconnected); //connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(onBytesWritten(qint64))); - m_connectionAttempts++; // FIXME: Assuming port 1 (with Pebble) m_socket->connectToService(m_pebbleAddress, 1); @@ -141,8 +146,12 @@ void WatchConnection::pebbleConnected() void WatchConnection::pebbleDisconnected() { qDebug() << "Disconnected"; - m_socket->close(); + emit watchDisconnected(); + QBluetoothSocket *socket = qobject_cast(sender()); + if (!socket) return; + + socket->deleteLater(); if (!m_reconnectTimer.isActive()) { scheduleReconnect(); } @@ -152,7 +161,6 @@ void WatchConnection::socketError(QBluetoothSocket::SocketError error) { Q_UNUSED(error); // We seem to get UnknownError anyways all the time qDebug() << "SocketError" << error; - m_socket->close(); emit watchConnectionFailed(); if (!m_reconnectTimer.isActive()) { scheduleReconnect(); diff --git a/rockworkd/platformintegration/sailfish/callchannelobserver.cpp b/rockworkd/platformintegration/sailfish/callchannelobserver.cpp index 534c360..a9f41f3 100644 --- a/rockworkd/platformintegration/sailfish/callchannelobserver.cpp +++ b/rockworkd/platformintegration/sailfish/callchannelobserver.cpp @@ -15,9 +15,10 @@ TelepathyMonitor::TelepathyMonitor(QObject *parent): QObject(parent) { Tp::registerTypes(); - QTimer::singleShot(0, this, SLOT(accountManagerSetup)); - m_contactManager = new QContactManager("org.nemomobile.contacts.sqlite"); - m_contactManager->setParent(this); + QTimer::singleShot(0, this, SLOT(accountManagerSetup())); + QMap parameters; + parameters.insert(QString::fromLatin1("mergePresenceChanges"), QString::fromLatin1("false")); + m_contactManager = new QContactManager("", parameters, this); } void TelepathyMonitor::hangupCall(uint cookie) @@ -42,7 +43,7 @@ void TelepathyMonitor::accountManagerReady(Tp::PendingOperation* operation) { if (operation->isError()) { qDebug() << "TelepathyMonitor: accountManager init error."; - QTimer::singleShot(1000, this, SLOT(TelepathyMonitor::accountManagerSetup)); // again + QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again return; } qDebug() << "Telepathy account manager ready"; diff --git a/rockworkd/platformintegration/sailfish/callchannelobserver.h b/rockworkd/platformintegration/sailfish/callchannelobserver.h index cc2b7aa..ba3415d 100644 --- a/rockworkd/platformintegration/sailfish/callchannelobserver.h +++ b/rockworkd/platformintegration/sailfish/callchannelobserver.h @@ -27,7 +27,7 @@ public: signals: void callStarted(Tp::CallChannelPtr callChannel); -// void callEnded(); + void callEnded(); private: Tp::AccountPtr mAccount; diff --git a/rockworkd/platformintegration/sailfish/sailfishplatform.h b/rockworkd/platformintegration/sailfish/sailfishplatform.h index dd4f56d..e18b986 100644 --- a/rockworkd/platformintegration/sailfish/sailfishplatform.h +++ b/rockworkd/platformintegration/sailfish/sailfishplatform.h @@ -1,5 +1,5 @@ -#ifndef UBUNTUPLATFORM_H -#define UBUNTUPLATFORM_H +#ifndef SAILFISHPLATFORM_H +#define SAILFISHPLATFORM_H #include "libpebble/platforminterface.h" #include "libpebble/enums.h" @@ -55,4 +55,4 @@ private: QTimer m_syncTimer; }; -#endif // UBUNTUPLATFORM_H +#endif // SAILFISHPLATFORM_H diff --git a/rockworkd/platformintegration/sailfish/voicecallhandler.cpp b/rockworkd/platformintegration/sailfish/voicecallhandler.cpp new file mode 100644 index 0000000..2ae5087 --- /dev/null +++ b/rockworkd/platformintegration/sailfish/voicecallhandler.cpp @@ -0,0 +1,372 @@ +#include "voicecallhandler.h" + +#include +#include +#include +#include +#include + +/*! + \class VoiceCallHandler + \brief This is the D-Bus proxy for communicating with the voice call manager + from a declarative context, this interface specifically interfaces with + the managers' voice call handler instances. +*/ +class VoiceCallHandlerPrivate +{ + Q_DECLARE_PUBLIC(VoiceCallHandler) + +public: + VoiceCallHandlerPrivate(VoiceCallHandler *q, const QString &pHandlerId) + : q_ptr(q), handlerId(pHandlerId), interface(NULL) + , duration(0), status(0), emergency(false), incoming(false) + , multiparty(false) , forwarded(false), remoteHeld(false) + { /* ... */ } + + VoiceCallHandler *q_ptr; + + QString handlerId; + + QDBusInterface *interface; + + int duration; + int status; + QString statusText; + QString lineId; + QString providerId; + QDateTime startedAt; + bool emergency; + bool incoming; + bool multiparty; + bool forwarded; + bool remoteHeld; +}; + +/*! + Constructs a new proxy interface for the provided voice call handlerId. +*/ +VoiceCallHandler::VoiceCallHandler(const QString &handlerId, QObject *parent) + : QObject(parent), l(metaObject()->className()), d_ptr(new VoiceCallHandlerPrivate(this, handlerId)) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << QString("Creating D-Bus interface to: ") + handlerId; + d->interface = new QDBusInterface("org.nemomobile.voicecall", + "/calls/" + handlerId, + "org.nemomobile.voicecall.VoiceCall", + QDBusConnection::sessionBus(), + this); + this->initialize(true); +} + +VoiceCallHandler::~VoiceCallHandler() +{ + Q_D(VoiceCallHandler); + delete d; +} + +void VoiceCallHandler::initialize(bool notifyError) +{ + Q_D(VoiceCallHandler); + + if (d->interface->isValid()) { + if (getProperties()) { + emit durationChanged(); + emit statusChanged(); + emit lineIdChanged(); + emit startedAtChanged(); + emit multipartyChanged(); + emit emergencyChanged(); + emit forwardedChanged(); + + connect(d->interface, SIGNAL(error(QString)), SIGNAL(error(QString))); + connect(d->interface, SIGNAL(statusChanged(int, QString)), SLOT(onStatusChanged(int, QString))); + connect(d->interface, SIGNAL(lineIdChanged(QString)), SLOT(onLineIdChanged(QString))); + connect(d->interface, SIGNAL(durationChanged(int)), SLOT(onDurationChanged(int))); + connect(d->interface, SIGNAL(startedAtChanged(QDateTime)), SLOT(onStartedAtChanged(QDateTime))); + connect(d->interface, SIGNAL(emergencyChanged(bool)), SLOT(onEmergencyChanged(bool))); + connect(d->interface, SIGNAL(multipartyChanged(bool)), SLOT(onMultipartyChanged(bool))); + connect(d->interface, SIGNAL(forwardedChanged(bool)), SLOT(onForwardedChanged(bool))); + connect(d->interface, SIGNAL(remoteHeldChanged(bool)), SLOT(onRemoteHeldChanged(bool))); + } + else { + if (notifyError) emit this->error("Failed to get VoiceCall properties from VCM D-Bus service."); + } + } + else { + qCCritical(l) << d->interface->lastError().name() << d->interface->lastError().message(); + } +} + +bool VoiceCallHandler::getProperties() +{ + Q_D(VoiceCallHandler); + + QDBusInterface props(d->interface->service(), d->interface->path(), + "org.freedesktop.DBus.Properties", d->interface->connection()); + + QDBusReply reply = props.call("GetAll", d->interface->interface()); + if (reply.isValid()) { + QVariantMap props = reply.value(); + qCDebug(l) << props; + d->providerId = props["providerId"].toString(); + d->duration = props["duration"].toInt(); + d->status = props["status"].toInt(); + d->statusText = props["statusText"].toString(); + d->lineId = props["lineId"].toString(); + d->startedAt = QDateTime::fromMSecsSinceEpoch(props["startedAt"].toULongLong()); + d->multiparty = props["isMultiparty"].toBool(); + d->emergency = props["isEmergency"].toBool(); + d->forwarded = props["isForwarded"].toBool(); + d->incoming = props["isIncoming"].toBool(); + d->remoteHeld = props["isIncoming"].toBool(); + return true; + } + else { + qCCritical(l) << "Failed to get VoiceCall properties from VCM D-Bus service."; + return false; + } +} + +void VoiceCallHandler::onDurationChanged(int duration) +{ + Q_D(VoiceCallHandler); + //qCDebug(l) <<"onDurationChanged"<duration = duration; + emit durationChanged(); +} + +void VoiceCallHandler::onStatusChanged(int status, QString statusText) +{ + Q_D(VoiceCallHandler); + qCDebug(l) <<"onStatusChanged" << status << statusText; + d->status = status; + d->statusText = statusText; + if (status) getProperties(); // make sure all properties are present + emit statusChanged(); +} + +void VoiceCallHandler::onLineIdChanged(QString lineId) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onLineIdChanged" << lineId; + d->lineId = lineId; + emit lineIdChanged(); +} + +void VoiceCallHandler::onStartedAtChanged(const QDateTime &startedAt) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onStartedAtChanged" << startedAt; + d->startedAt = d->interface->property("startedAt").toDateTime(); + emit startedAtChanged(); +} + +void VoiceCallHandler::onEmergencyChanged(bool isEmergency) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onEmergencyChanged" << isEmergency; + d->emergency = isEmergency; + emit emergencyChanged(); +} + +void VoiceCallHandler::onMultipartyChanged(bool isMultiparty) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onMultipartyChanged" << isMultiparty; + d->multiparty = isMultiparty; + emit multipartyChanged(); +} + +void VoiceCallHandler::onForwardedChanged(bool isForwarded) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onForwardedChanged" << isForwarded; + d->forwarded = isForwarded; + emit forwardedChanged(); +} + +void VoiceCallHandler::onRemoteHeldChanged(bool isRemoteHeld) +{ + Q_D(VoiceCallHandler); + qCDebug(l) << "onRemoteHeldChanged" << isRemoteHeld; + d->forwarded = isRemoteHeld; + emit remoteHeldChanged(); +} + +/*! + Returns this voice calls' handler id. + */ +QString VoiceCallHandler::handlerId() const +{ + Q_D(const VoiceCallHandler); + return d->handlerId; +} + +/*! + Returns this voice calls' provider id. + */ +QString VoiceCallHandler::providerId() const +{ + Q_D(const VoiceCallHandler); + return d->providerId; +} + +/*! + Returns this voice calls' call status. + */ +int VoiceCallHandler::status() const +{ + Q_D(const VoiceCallHandler); + return d->status; +} + +/*! + Returns this voice calls' call status as a symbolic string. + */ +QString VoiceCallHandler::statusText() const +{ + Q_D(const VoiceCallHandler); + return d->statusText; +} + +/*! + Returns this voice calls' remote end-point line id. + */ +QString VoiceCallHandler::lineId() const +{ + Q_D(const VoiceCallHandler); + return d->lineId; +} + +/*! + Returns this voice calls' started at property. + */ +QDateTime VoiceCallHandler::startedAt() const +{ + Q_D(const VoiceCallHandler); + return d->startedAt; +} + +/*! + Returns this voice calls' duration property. + */ +int VoiceCallHandler::duration() const +{ + Q_D(const VoiceCallHandler); + return d->duration; +} + +/*! + Returns this voice calls' incoming call flag property. + */ +bool VoiceCallHandler::isIncoming() const +{ + Q_D(const VoiceCallHandler); + return d->incoming; +} + +/*! + Returns this voice calls' multiparty flag property. + */ +bool VoiceCallHandler::isMultiparty() const +{ + Q_D(const VoiceCallHandler); + return d->multiparty; +} + +/*! + Returns this voice calls' forwarded flag property. + */ +bool VoiceCallHandler::isForwarded() const +{ + Q_D(const VoiceCallHandler); + return d->forwarded; +} + +/*! + Returns this voice calls' emergency flag property. + */ +bool VoiceCallHandler::isEmergency() const +{ + Q_D(const VoiceCallHandler); + return d->emergency; +} + +/*! + Returns this voice calls' remoteHeld flag property. + */ +bool VoiceCallHandler::isRemoteHeld() const +{ + Q_D(const VoiceCallHandler); + return d->remoteHeld; +} + +/*! + Initiates answering this call, if the call is an incoming call. + */ +void VoiceCallHandler::answer() +{ + Q_D(VoiceCallHandler); + QDBusPendingCall call = d->interface->asyncCall("answer"); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +/*! + Initiates droping the call, unless the call is disconnected. + */ +void VoiceCallHandler::hangup() +{ + Q_D(VoiceCallHandler); + QDBusPendingCall call = d->interface->asyncCall("hangup"); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +/*! + Initiates holding the call, unless the call is disconnected. + */ +void VoiceCallHandler::hold(bool on) +{ + Q_D(VoiceCallHandler); + QDBusPendingCall call = d->interface->asyncCall("hold", on); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +/*! + Initiates deflecting the call to the provided target phone number. + */ +void VoiceCallHandler::deflect(const QString &target) +{ + Q_D(VoiceCallHandler); + QDBusPendingCall call = d->interface->asyncCall("deflect", target); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +void VoiceCallHandler::sendDtmf(const QString &tones) +{ + Q_D(VoiceCallHandler); + QDBusPendingCall call = d->interface->asyncCall("sendDtmf", tones); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +void VoiceCallHandler::onPendingCallFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + + if (reply.isError()) { + qCCritical(l) << QString::fromLatin1("Received error reply for member: %1 (%2)").arg(reply.reply().member()).arg(reply.error().message()); + emit this->error(reply.error().message()); + watcher->deleteLater(); + } else { + qCDebug(l) << QString::fromLatin1("Received successful reply for member: %1").arg(reply.reply().member()); + } +} diff --git a/rockworkd/platformintegration/sailfish/voicecallhandler.h b/rockworkd/platformintegration/sailfish/voicecallhandler.h new file mode 100644 index 0000000..e718abb --- /dev/null +++ b/rockworkd/platformintegration/sailfish/voicecallhandler.h @@ -0,0 +1,96 @@ +#ifndef VOICECALLHANDLER_H +#define VOICECALLHANDLER_H + +#include +#include +#include +#include + +class VoiceCallHandler : public QObject +{ + Q_OBJECT + QLoggingCategory l; + + Q_ENUMS(VoiceCallStatus) + + Q_PROPERTY(QString handlerId READ handlerId CONSTANT) + Q_PROPERTY(QString providerId READ providerId CONSTANT) + Q_PROPERTY(int status READ status NOTIFY statusChanged) + Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged) + Q_PROPERTY(QString lineId READ lineId NOTIFY lineIdChanged) + Q_PROPERTY(QDateTime startedAt READ startedAt NOTIFY startedAtChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + Q_PROPERTY(bool isIncoming READ isIncoming CONSTANT) + Q_PROPERTY(bool isEmergency READ isEmergency NOTIFY emergencyChanged) + Q_PROPERTY(bool isMultiparty READ isMultiparty NOTIFY multipartyChanged) + Q_PROPERTY(bool isForwarded READ isForwarded NOTIFY forwardedChanged) + Q_PROPERTY(bool isRemoteHeld READ isRemoteHeld NOTIFY remoteHeldChanged) + +public: + enum VoiceCallStatus { + STATUS_NULL, + STATUS_ACTIVE, + STATUS_HELD, + STATUS_DIALING, + STATUS_ALERTING, + STATUS_INCOMING, + STATUS_WAITING, + STATUS_DISCONNECTED + }; + + explicit VoiceCallHandler(const QString &handlerId, QObject *parent = 0); + ~VoiceCallHandler(); + + QString handlerId() const; + QString providerId() const; + int status() const; + QString statusText() const; + QString lineId() const; + QDateTime startedAt() const; + int duration() const; + bool isIncoming() const; + bool isMultiparty() const; + bool isEmergency() const; + bool isForwarded() const; + bool isRemoteHeld() const; + +Q_SIGNALS: + void error(const QString &error); + void statusChanged(); + void lineIdChanged(); + void durationChanged(); + void startedAtChanged(); + void emergencyChanged(); + void multipartyChanged(); + void forwardedChanged(); + void remoteHeldChanged(); + +public Q_SLOTS: + void answer(); + void hangup(); + void hold(bool on); + void deflect(const QString &target); + void sendDtmf(const QString &tones); + +protected Q_SLOTS: + void initialize(bool notifyError = false); + bool getProperties(); + + void onPendingCallFinished(QDBusPendingCallWatcher *watcher); + void onDurationChanged(int duration); + void onStatusChanged(int status, QString statusText); + void onLineIdChanged(QString lineId); + void onStartedAtChanged(const QDateTime &startedAt); + void onEmergencyChanged(bool isEmergency); + void onMultipartyChanged(bool isMultiparty); + void onForwardedChanged(bool isForwarded); + void onRemoteHeldChanged(bool isRemoteHeld); + +private: + class VoiceCallHandlerPrivate *d_ptr; + + Q_DISABLE_COPY(VoiceCallHandler) + Q_DECLARE_PRIVATE(VoiceCallHandler) +}; + +#endif // VOICECALLHANDLER_H diff --git a/rockworkd/platformintegration/sailfish/voicecallmanager.cpp b/rockworkd/platformintegration/sailfish/voicecallmanager.cpp new file mode 100644 index 0000000..afb3629 --- /dev/null +++ b/rockworkd/platformintegration/sailfish/voicecallmanager.cpp @@ -0,0 +1,315 @@ +#include "voicecallmanager.h" + +#include +#include +#include +#include + +class VoiceCallManagerPrivate +{ + Q_DECLARE_PUBLIC(VoiceCallManager) + +public: + VoiceCallManagerPrivate(VoiceCallManager *q) + : q_ptr(q), + interface(NULL), + activeVoiceCall(NULL), + connected(false) + { /*...*/ } + + VoiceCallManager *q_ptr; + + QDBusInterface *interface; + + QList voicecalls; + QHash providers; + + VoiceCallHandler* activeVoiceCall; + + bool connected; +}; + +VoiceCallManager::VoiceCallManager(Settings *settings, QObject *parent) + : QObject(parent), l(metaObject()->className()), d_ptr(new VoiceCallManagerPrivate(this)), settings(settings) +{ + this->initialize(); +} + +VoiceCallManager::~VoiceCallManager() +{ + Q_D(VoiceCallManager); + delete d; +} + +void VoiceCallManager::initialize(bool notifyError) +{ + Q_D(VoiceCallManager); + bool success = false; + + delete d->interface; + d->interface = new QDBusInterface("org.nemomobile.voicecall", + "/", + "org.nemomobile.voicecall.VoiceCallManager", + QDBusConnection::sessionBus(), + this); + + if(d->interface->isValid()) + { + success = true; + success &= (bool)QObject::connect(d->interface, SIGNAL(error(QString)), SIGNAL(error(QString))); + success &= (bool)QObject::connect(d->interface, SIGNAL(voiceCallsChanged()), SLOT(onVoiceCallsChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(providersChanged()), SLOT(onProvidersChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(activeVoiceCallChanged()), SLOT(onActiveVoiceCallChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(audioModeChanged()), SIGNAL(audioModeChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(audioRoutedChanged()), SIGNAL(audioRoutedChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(microphoneMutedChanged()), SIGNAL(microphoneMutedChanged())); + success &= (bool)QObject::connect(d->interface, SIGNAL(speakerMutedChanged()), SIGNAL(speakerMutedChanged())); + + onVoiceCallsChanged(); + onActiveVoiceCallChanged(); + } + + if(!(d->connected = success)) + { + QTimer::singleShot(2000, this, SLOT(initialize())); + if(notifyError) emit this->error("Failed to connect to VCM D-Bus service."); + } +} + +QDBusInterface* VoiceCallManager::interface() const +{ + Q_D(const VoiceCallManager); + return d->interface; +} + +VoiceCallHandlerList VoiceCallManager::voiceCalls() const +{ + Q_D(const VoiceCallManager); + return d->voicecalls; +} + +VoiceCallProviderHash VoiceCallManager::providers() const +{ + Q_D(const VoiceCallManager); + return d->providers; +} + +QString VoiceCallManager::defaultProviderId() const +{ + Q_D(const VoiceCallManager); + if(d->providers.count() == 0) { + qCDebug(l) << Q_FUNC_INFO << "No provider added"; + return QString::null; + } + + QStringList keys = d->providers.keys(); + qSort(keys); + + VoiceCallProviderData provider = d->providers.value(keys.value(0)); + return provider.id; +} + +VoiceCallHandler* VoiceCallManager::activeVoiceCall() const +{ + Q_D(const VoiceCallManager); + return d->activeVoiceCall; +} + +QString VoiceCallManager::audioMode() const +{ + Q_D(const VoiceCallManager); + return d->interface->property("audioMode").toString(); +} + +bool VoiceCallManager::isAudioRouted() const +{ + Q_D(const VoiceCallManager); + return d->interface->property("isAudioRouted").toBool(); +} + +bool VoiceCallManager::isMicrophoneMuted() const +{ + Q_D(const VoiceCallManager); + return d->interface->property("isMicrophoneMuted").toBool(); +} + +bool VoiceCallManager::isSpeakerMuted() const +{ + Q_D(const VoiceCallManager); + return d->interface->property("isSpeakerMuted").toBool(); +} + +void VoiceCallManager::dial(const QString &provider, const QString &msisdn) +{ + Q_D(VoiceCallManager); + QDBusPendingCall call = d->interface->asyncCall("dial", provider, msisdn); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingCallFinished(QDBusPendingCallWatcher*))); +} + +void VoiceCallManager::hangupAll() +{ + foreach (VoiceCallHandler* handler, voiceCalls()) { + handler->hangup(); + } +} + +void VoiceCallManager::silenceRingtone() +{ + Q_D(const VoiceCallManager); + QDBusPendingCall call = d->interface->asyncCall("silenceRingtone"); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onPendingSilenceFinished(QDBusPendingCallWatcher*))); +} + +/* + - Use of method calls instead of property setters to allow status checking. + */ +bool VoiceCallManager::setAudioMode(const QString &mode) +{ + Q_D(const VoiceCallManager); + QDBusPendingReply reply = d->interface->call("setAudioMode", mode); + return reply.isError() ? false : reply.value(); +} + +bool VoiceCallManager::setAudioRouted(bool on) +{ + Q_D(const VoiceCallManager); + QDBusPendingReply reply = d->interface->call("setAudioRouted", on); + return reply.isError() ? false : reply.value(); +} + +bool VoiceCallManager::setMuteMicrophone(bool on) +{ + Q_D(VoiceCallManager); + QDBusPendingReply reply = d->interface->call("setMuteMicrophone", on); + return reply.isError() ? false : reply.value(); +} + +bool VoiceCallManager::setMuteSpeaker(bool on) +{ + Q_D(VoiceCallManager); + QDBusPendingReply reply = d->interface->call("setMuteSpeaker", on); + return reply.isError() ? false : reply.value(); +} + +void VoiceCallManager::onVoiceCallsChanged() +{ + Q_D(VoiceCallManager); + QStringList nIds = d->interface->property("voiceCalls").toStringList(); + QStringList oIds; + + QStringList added; + QStringList removed; + + // Map current call handlers to handler ids for easy indexing. + foreach(VoiceCallHandler *handler, d->voicecalls) + { + oIds.append(handler->handlerId()); + } + + // Index new handlers to be added. + foreach(QString nId, nIds) + { + if(!oIds.contains(nId)) added.append(nId); + } + + // Index old handlers to be removed. + foreach(QString oId, oIds) + { + if(!nIds.contains(oId)) removed.append(oId); + } + + // Remove handlers that need to be removed. + foreach(QString removeId, removed) + { + for (int i = 0; i < d->voicecalls.count(); ++i) { + VoiceCallHandler *handler = d->voicecalls.at(i); + if(handler->handlerId() == removeId) + { + handler->disconnect(this); + d->voicecalls.removeAt(i); + handler->deleteLater(); + break; + } + } + } + + // Add handlers that need to be added. + foreach(QString addId, added) + { + VoiceCallHandler *handler = new VoiceCallHandler(addId, this); + d->voicecalls.append(handler); + } + + emit this->voiceCallsChanged(); +} + +void VoiceCallManager::onProvidersChanged() +{ + Q_D(VoiceCallManager); + d->providers.clear(); + foreach(QString provider, d->interface->property("providers").toStringList()) + { + QStringList parts = provider.split(':'); + d->providers.insert(parts.first(), VoiceCallProviderData(parts.first(), + parts.last(), + parts.first())); + } + + emit this->providersChanged(); +} + +void VoiceCallManager::onActiveVoiceCallChanged() +{ + Q_D(VoiceCallManager); + QString voiceCallId = d->interface->property("activeVoiceCall").toString(); + + if(d->voicecalls.count() == 0 || voiceCallId.isNull() || voiceCallId.isEmpty()) + { + d->activeVoiceCall = NULL; + } + else + { + bool found = false; + d->activeVoiceCall = NULL; + foreach(VoiceCallHandler* handler, d->voicecalls) + { + if(handler->handlerId() == voiceCallId) + { + d->activeVoiceCall = handler; + found = true; + } + if(!found) d->activeVoiceCall = NULL; + } + } + + emit this->activeVoiceCallChanged(); +} + +void VoiceCallManager::onPendingCallFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + + if (reply.isError()) { + emit this->error(reply.error().message()); + } else { + qCDebug(l) << QString("Received successful reply for member: ") + reply.reply().member(); + } + + watcher->deleteLater(); +} + +void VoiceCallManager::onPendingSilenceFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply<> reply = *watcher; + + if (reply.isError()) { + emit this->error(reply.error().message()); + } else { + qCDebug(l) << QString("Received successful reply for member: ") + reply.reply().member(); + } + + watcher->deleteLater(); +} diff --git a/rockworkd/platformintegration/sailfish/voicecallmanager.h b/rockworkd/platformintegration/sailfish/voicecallmanager.h new file mode 100644 index 0000000..ec51230 --- /dev/null +++ b/rockworkd/platformintegration/sailfish/voicecallmanager.h @@ -0,0 +1,111 @@ +#ifndef VOICECALLMANAGER_H +#define VOICECALLMANAGER_H + +#include "voicecallhandler.h" +#include "settings.h" + +#include +#include +#include +#include + +class VoiceCallProviderData +{ +public: + VoiceCallProviderData() {/*..*/} + VoiceCallProviderData(const QString &pId, const QString &pType, const QString &pLabel) + : id(pId), type(pType), label(pLabel) {/*...*/} + + QString id; + QString type; + QString label; +}; + +typedef QHash VoiceCallProviderHash; + +typedef QList VoiceCallHandlerList; + +class VoiceCallManager : public QObject +{ + Q_OBJECT + QLoggingCategory l; + + Q_PROPERTY(QDBusInterface* interface READ interface) + + Q_PROPERTY(VoiceCallHandlerList voiceCalls READ voiceCalls NOTIFY voiceCallsChanged) + Q_PROPERTY(VoiceCallProviderHash providers READ providers NOTIFY providersChanged) + + Q_PROPERTY(QString defaultProviderId READ defaultProviderId NOTIFY defaultProviderChanged) + + Q_PROPERTY(VoiceCallHandler* activeVoiceCall READ activeVoiceCall NOTIFY activeVoiceCallChanged) + + Q_PROPERTY(QString audioMode READ audioMode WRITE setAudioMode NOTIFY audioModeChanged) + Q_PROPERTY(bool isAudioRouted READ isAudioRouted WRITE setAudioRouted NOTIFY audioRoutedChanged) + Q_PROPERTY(bool isMicrophoneMuted READ isMicrophoneMuted WRITE setMuteMicrophone NOTIFY microphoneMutedChanged) + Q_PROPERTY(bool isSpeakerMuted READ isSpeakerMuted WRITE setMuteSpeaker NOTIFY speakerMutedChanged) + +public: + explicit VoiceCallManager(Settings *settings, QObject *parent = 0); + ~VoiceCallManager(); + + QDBusInterface* interface() const; + + VoiceCallHandlerList voiceCalls() const; + VoiceCallProviderHash providers() const; + + QString defaultProviderId() const; + + VoiceCallHandler* activeVoiceCall() const; + + QString audioMode() const; + bool isAudioRouted() const; + + bool isMicrophoneMuted() const; + bool isSpeakerMuted() const; + +Q_SIGNALS: + void error(const QString &message); + + void providersChanged(); + void voiceCallsChanged(); + + void defaultProviderChanged(); + + void activeVoiceCallChanged(); + + void audioModeChanged(); + void audioRoutedChanged(); + void microphoneMutedChanged(); + void speakerMutedChanged(); + +public Q_SLOTS: + void dial(const QString &providerId, const QString &msisdn); + void hangupAll(); + + void silenceRingtone(); + + bool setAudioMode(const QString &mode); + bool setAudioRouted(bool on); + bool setMuteMicrophone(bool on = true); + bool setMuteSpeaker(bool on = true); + +protected Q_SLOTS: + void initialize(bool notifyError = false); + + void onProvidersChanged(); + void onVoiceCallsChanged(); + void onActiveVoiceCallChanged(); + + void onPendingCallFinished(QDBusPendingCallWatcher *watcher); + void onPendingSilenceFinished(QDBusPendingCallWatcher *watcher); + +private: + class VoiceCallManagerPrivate *d_ptr; + + Settings *settings; + + Q_DISABLE_COPY(VoiceCallManager) + Q_DECLARE_PRIVATE(VoiceCallManager) +}; + +#endif // VOICECALLMANAGER_H diff --git a/rockworkd/rockworkd.pro b/rockworkd/rockworkd.pro index a15d64d..888fefc 100644 --- a/rockworkd/rockworkd.pro +++ b/rockworkd/rockworkd.pro @@ -4,14 +4,12 @@ QT -= gui include(../version.pri) TARGET = rockpoold -CONFIG += c++11 -#CONFIG -= app_bundle - -TEMPLATE = app -INCLUDEPATH += /usr/lib/arm-linux-gnueabihf/glib-2.0/include /usr/lib/x86_64-linux-gnu/glib-2.0/include/ /usr/include/glib-2.0/ +CONFIG += c++11 +CONFIG += console +CONFIG += link_pkgconfig -INCLUDEPATH += /usr/include/telepathy-qt5/ /usr/include/quazip/ +INCLUDEPATH += /usr/include/telepathy-qt5/ $$[QT_HOST_PREFIX]/include/quazip/ LIBS += -lquazip -ltelepathy-qt5 SOURCES += main.cpp \ @@ -48,6 +46,8 @@ SOURCES += main.cpp \ # Platform integration part platformintegration/sailfish/sailfishplatform.cpp \ platformintegration/sailfish/callchannelobserver.cpp \ +# platformintegration/sailfish/voicecallmanager.cpp \ +# platformintegration/sailfish/voicecallhandler.cpp \ libpebble/blobdb.cpp \ libpebble/timelineitem.cpp \ libpebble/notification.cpp \ @@ -99,6 +99,8 @@ HEADERS += \ # Platform integration part platformintegration/sailfish/sailfishplatform.h \ platformintegration/sailfish/callchannelobserver.h \ +# platformintegration/sailfish/voicecallmanager.h \ +# platformintegration/sailfish/voicecallhandler.h \ libpebble/blobdb.h \ libpebble/timelineitem.h \ libpebble/notification.h \ @@ -124,19 +126,14 @@ testing: { QT += qml quick } -libs.files = /usr/lib/arm-linux-gnueabihf/libQt5Bluetooth.so.5.4.1 \ - /usr/lib/arm-linux-gnueabihf/libQt5Bluetooth.so.5 \ - /usr/lib/arm-linux-gnueabihf/libquazip-qt5.so.1.0.0 \ - /usr/lib/arm-linux-gnueabihf/libquazip-qt5.so.1 -libs.path = /usr/ -INSTALLS += libs +INSTALLS += target systemd systemd.files = $${TARGET}.service systemd.path = /usr/lib/systemd/user # Default rules for deployment. target.path = /usr/bin -INSTALLS+=target RESOURCES += \ libpebble/jskit/jsfiles.qrc + -- cgit v1.2.3