mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-27 14:33:08 +00:00
272 lines
10 KiB
C++
272 lines
10 KiB
C++
/*
|
|
Copyright (C) 2012 George Kiagiadakis <kiagiadakis.george@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "call-manager.h"
|
|
#include "dialerutils.h"
|
|
#include <QTimer>
|
|
|
|
#include <KNotification>
|
|
#include <KLocalizedString>
|
|
// #include "call-window.h"
|
|
// #include "approver.h"
|
|
// #include "../libktpcall/call-channel-handler.h"
|
|
// #include "ktp_call_ui_debug.h"
|
|
|
|
// #include <KTp/telepathy-handler-application.h>
|
|
|
|
struct CallManager::Private
|
|
{
|
|
Tp::CallChannelPtr callChannel;
|
|
// CallChannelHandler *channelHandler;
|
|
// QPointer<CallWindow> callWindow;
|
|
// QPointer<Approver> approver;
|
|
DialerUtils *dialerUtils;
|
|
KNotification *ringingNotification;
|
|
KNotification *callsNotification;
|
|
uint missedCalls;
|
|
QTimer *callTimer;
|
|
};
|
|
|
|
CallManager::CallManager(const Tp::CallChannelPtr &callChannel, DialerUtils *dialerUtils, QObject *parent)
|
|
: QObject(parent), d(new Private)
|
|
{
|
|
// KTp::TelepathyHandlerApplication::newJob();
|
|
|
|
d->dialerUtils = dialerUtils;
|
|
d->callChannel = callChannel;
|
|
connect(callChannel.data(), SIGNAL(callStateChanged(Tp::CallState)),
|
|
SLOT(onCallStateChanged(Tp::CallState)));
|
|
|
|
connect(d->dialerUtils, &DialerUtils::acceptCall, this, &CallManager::onCallAccepted);
|
|
connect(d->dialerUtils, &DialerUtils::rejectCall, this, &CallManager::onCallRejected);
|
|
connect(d->dialerUtils, &DialerUtils::hangUp, this, &CallManager::onHangUpRequested);
|
|
connect(d->callChannel.data(), &Tp::CallChannel::invalidated, this, [=]() {
|
|
qDebug() << "Channel invalidated";
|
|
d->dialerUtils->setCallState("idle");
|
|
d->dialerUtils->emitCallEnded();
|
|
deleteLater();
|
|
});
|
|
|
|
d->ringingNotification = nullptr;
|
|
d->callsNotification = nullptr;
|
|
d->callTimer = nullptr;
|
|
|
|
//create the channel handler
|
|
// d->channelHandler = new CallChannelHandler(callChannel, this);
|
|
|
|
//delete the CallManager when the channel has closed
|
|
//and the farstream side has safely shut down.
|
|
//NOTE this MUST be used with Qt::QueuedConnection because of
|
|
// https://bugreports.qt-project.org/browse/QTBUG-24571
|
|
// connect(d->channelHandler, SIGNAL(channelClosed()),
|
|
// this, SLOT(deleteLater()), Qt::QueuedConnection);
|
|
|
|
//bring us up-to-date with the current call state
|
|
onCallStateChanged(d->callChannel->callState());
|
|
}
|
|
|
|
CallManager::~CallManager()
|
|
{
|
|
qDebug() << "Deleting CallManager";
|
|
|
|
//delete the window just in case CallManager was deleted
|
|
//before the channel entered CallStateEnded
|
|
// delete d->callWindow.data();
|
|
// delete d;
|
|
|
|
// KTp::TelepathyHandlerApplication::jobFinished();
|
|
}
|
|
|
|
void CallManager::onCallStateChanged(Tp::CallState state)
|
|
{
|
|
qDebug() << "new call state:" << state;
|
|
|
|
if (d->callChannel->targetContact()) {
|
|
d->dialerUtils->setCallContactAlias(d->callChannel->targetContact()->alias());
|
|
d->dialerUtils->setCallContactNumber(d->callChannel->targetContact()->id());
|
|
}
|
|
|
|
if (d->callChannel->isValid()) {
|
|
d->dialerUtils->setIsIncomingCall(!d->callChannel->isRequested());
|
|
}
|
|
|
|
switch (state) {
|
|
case Tp::CallStatePendingInitiator:
|
|
Q_ASSERT(d->callChannel->isRequested());
|
|
(void) d->callChannel->accept();
|
|
break;
|
|
case Tp::CallStateInitialising:
|
|
if (d->callChannel->isRequested()) {
|
|
d->dialerUtils->setCallState("dialing");
|
|
|
|
//show status that the call is conneting
|
|
// ensureCallWindow();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusConnecting);
|
|
} else {
|
|
qDebug() << "Call is initialising";
|
|
}
|
|
break;
|
|
case Tp::CallStateInitialised:
|
|
if (d->callChannel->isRequested()) {
|
|
d->dialerUtils->setCallState("dialing");
|
|
//show status that the remote end is ringing
|
|
// ensureCallWindow();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusRemoteRinging);
|
|
} else {
|
|
d->dialerUtils->setCallState("incoming");
|
|
|
|
//show approver;
|
|
(void) d->callChannel->setRinging();
|
|
if (!d->ringingNotification) {
|
|
d->ringingNotification = new KNotification("ringing", KNotification::Persistent | KNotification::LoopSound, 0);
|
|
d->ringingNotification->setComponentName("plasma_dialer");
|
|
}
|
|
d->ringingNotification->sendEvent();
|
|
}
|
|
break;
|
|
case Tp::CallStateAccepted:
|
|
if (d->callChannel->isRequested()) {
|
|
d->dialerUtils->setCallState("answered");
|
|
//show status that the remote end accepted the call
|
|
// ensureCallWindow();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusRemoteAccepted);
|
|
} else {
|
|
//hide approver & show call window
|
|
if (d->ringingNotification) {
|
|
d->ringingNotification->close();
|
|
}
|
|
// delete d->approver.data();
|
|
// ensureCallWindow();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusConnecting);
|
|
}
|
|
break;
|
|
case Tp::CallStateActive:
|
|
//normally the approver is already deleted and the call window
|
|
//already exists at this point, but we just want to be safe
|
|
//in case the CM decides to do a weird state jump
|
|
if (!d->callChannel->isRequested()) {
|
|
// delete d->approver.data();
|
|
}
|
|
d->dialerUtils->setCallState("active");
|
|
d->callTimer = new QTimer(this);
|
|
connect(d->callTimer, &QTimer::timeout, [=]() {
|
|
d->dialerUtils->setCallDuration(d->dialerUtils->callDuration() + 1);
|
|
});
|
|
d->callTimer->start(1000);
|
|
|
|
// ensureCallWindow();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusActive);
|
|
break;
|
|
case Tp::CallStateEnded:
|
|
d->dialerUtils->setCallState("ended");
|
|
if (d->ringingNotification) {
|
|
d->ringingNotification->close();
|
|
}
|
|
//FIXME this is defined in the spec, but try to find a proper enum value for it
|
|
if (d->callChannel->callStateReason().reason == 5) {
|
|
qDebug() << "Adding notification";
|
|
d->missedCalls++;
|
|
if (!d->callsNotification) {
|
|
d->callsNotification = new KNotification("callMissed", KNotification::Persistent, 0);
|
|
}
|
|
d->callsNotification->setComponentName("plasma_dialer");
|
|
d->callsNotification->setIconName("call-start");
|
|
if (d->missedCalls == 1) {
|
|
d->callsNotification->setTitle(i18n("Missed call from %1", d->callChannel->targetContact()->alias()));
|
|
d->callsNotification->setText(QTime::currentTime().toString("HH:mm"));
|
|
} else {
|
|
d->callsNotification->setTitle(i18n("%1 calls missed", d->missedCalls));
|
|
d->callsNotification->setText(i18n("Last call: %1", QTime::currentTime().toString("HH:mm")));
|
|
}
|
|
|
|
if (d->missedCalls == 1) {
|
|
d->callsNotification->sendEvent();
|
|
} else {
|
|
d->callsNotification->update();
|
|
}
|
|
}
|
|
|
|
if (d->callTimer) {
|
|
d->callTimer->stop();
|
|
d->callTimer->deleteLater();
|
|
d->callTimer = nullptr;
|
|
}
|
|
//if we requested the call, make sure we have a window to show the error (if any)
|
|
// if (d->callChannel->isRequested()) {
|
|
// ensureCallWindow();
|
|
// }
|
|
|
|
// if (d->callWindow) {
|
|
// Tp::CallStateReason reason = d->callChannel->callStateReason();
|
|
// d->callWindow.data()->setStatus(CallWindow::StatusDisconnected, reason);
|
|
//
|
|
// //kill the call manager when the call window is closed,
|
|
// //after shutting down the channelHandler
|
|
// connect(d->callWindow.data(), SIGNAL(destroyed()), d->channelHandler, SLOT(shutdown()));
|
|
// } else {
|
|
// //missed the call
|
|
// qCDebug(KTP_CALL_UI) << "missed call";
|
|
// delete d->approver.data();
|
|
// d->channelHandler->shutdown();
|
|
// }
|
|
break;
|
|
default:
|
|
Q_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
void CallManager::onCallAccepted()
|
|
{
|
|
(void) d->callChannel->accept();
|
|
}
|
|
|
|
void CallManager::onCallRejected()
|
|
{
|
|
(void) d->callChannel->hangup(Tp::CallStateChangeReasonRejected, TP_QT_ERROR_REJECTED);
|
|
}
|
|
|
|
void CallManager::onHangUpRequested()
|
|
{
|
|
if (d->callChannel && d->callChannel->isValid()) {
|
|
qDebug() << "Hanging up";
|
|
Tp::PendingOperation *op = d->callChannel->hangup();
|
|
connect(op, &Tp::PendingOperation::finished, [=]() {
|
|
if (op->isError()) {
|
|
qWarning() << "Unable to hang up:" << op->errorMessage();
|
|
}
|
|
// d->callChannel->requestClose();
|
|
});
|
|
}
|
|
}
|
|
|
|
void CallManager::ensureCallWindow()
|
|
{
|
|
// if (!d->callWindow) {
|
|
// d->callWindow = new CallWindow(d->callChannel);
|
|
// d->callWindow.data()->show();
|
|
// d->callWindow.data()->setAttribute(Qt::WA_DeleteOnClose);
|
|
//
|
|
// connect(d->channelHandler, SIGNAL(contentAdded(CallContentHandler*)),
|
|
// d->callWindow.data(), SLOT(onContentAdded(CallContentHandler*)));
|
|
// connect(d->channelHandler, SIGNAL(contentRemoved(CallContentHandler*)),
|
|
// d->callWindow.data(), SLOT(onContentRemoved(CallContentHandler*)));
|
|
//
|
|
// //inform the ui about already existing contents
|
|
// Q_FOREACH(CallContentHandler *content, d->channelHandler->contents()) {
|
|
// d->callWindow.data()->onContentAdded(content);
|
|
// }
|
|
// }
|
|
}
|