40
40
CallManager::CallManager(QObject *parent)
41
: QObject(parent), mNeedsUpdate(false)
41
: QObject(parent), mNeedsUpdate(false), mConferenceCall(0)
43
43
connect(TelepathyHelper::instance(), SIGNAL(connectedChanged()), SLOT(onConnectedChanged()));
44
44
connect(TelepathyHelper::instance(), SIGNAL(channelObserverUnregistered()), SLOT(onChannelObserverUnregistered()));
45
45
connect(this, SIGNAL(hasCallsChanged()), SIGNAL(callsChanged()));
48
QList<CallEntry *> CallManager::takeCalls(const QList<Tp::ChannelPtr> callChannels)
50
qDebug() << __PRETTY_FUNCTION__;
51
QList<CallEntry*> entries;
53
// run through the current calls and check which ones we find
54
Q_FOREACH(CallEntry *entry, mCallEntries) {
55
if (callChannels.contains(entry->channel())) {
56
mCallEntries.removeAll(entry);
58
entry->disconnect(this);
62
// FIXME: check which of those signals we really need to emit here
63
Q_EMIT hasCallsChanged();
64
Q_EMIT hasBackgroundCallChanged();
65
Q_EMIT foregroundCallChanged();
66
Q_EMIT backgroundCallChanged();
71
void CallManager::addCalls(const QList<CallEntry *> entries)
73
Q_FOREACH (CallEntry *entry, entries) {
74
if (!mCallEntries.contains(entry)) {
75
mCallEntries << entry;
77
setupCallEntry(entry);
80
// FIXME: check which of those signals we really need to emit here
81
Q_EMIT hasCallsChanged();
82
Q_EMIT hasBackgroundCallChanged();
83
Q_EMIT foregroundCallChanged();
84
Q_EMIT backgroundCallChanged();
87
void CallManager::setupCallEntry(CallEntry *entry)
93
SIGNAL(heldChanged()),
94
SIGNAL(foregroundCallChanged()));
96
SIGNAL(activeChanged()),
97
SIGNAL(foregroundCallChanged()));
99
SIGNAL(heldChanged()),
100
SIGNAL(backgroundCallChanged()));
102
SIGNAL(activeChanged()),
103
SIGNAL(hasBackgroundCallChanged()));
105
SIGNAL(activeChanged()),
106
SIGNAL(hasCallsChanged()));
48
109
void CallManager::onChannelObserverUnregistered()
50
111
// do not clear the manager right now, wait until the observer is re-registered
97
158
// if we have only one call, return it as being always in foreground
98
159
// even if it is held
99
if (mCallEntries.count() == 1) {
100
call = mCallEntries.first();
160
QList<CallEntry*> calls = activeCalls();
161
if (calls.count() == 1) {
162
call = calls.first();
102
Q_FOREACH(CallEntry *entry, mCallEntries) {
164
Q_FOREACH(CallEntry *entry, calls) {
103
165
if (entry->isActive() && !entry->isHeld()) {
114
// incoming but not yet answered calls cant be considered foreground calls
115
if (call->ringing()) {
122
175
CallEntry *CallManager::backgroundCall() const
177
QList<CallEntry*> calls = activeCalls();
124
178
// if we have only one call, assume there is no call in background
125
179
// even if the foreground call is held
126
if (mCallEntries.count() == 1) {
180
if (calls.count() == 1) {
130
Q_FOREACH(CallEntry *entry, mCallEntries) {
184
Q_FOREACH(CallEntry *entry, calls) {
131
185
if (entry->isHeld()) {
203
265
entry->setVoicemail(true);
206
mCallEntries.append(entry);
209
SLOT(onCallEnded()));
211
SIGNAL(heldChanged()),
212
SIGNAL(foregroundCallChanged()));
214
SIGNAL(activeChanged()),
215
SIGNAL(foregroundCallChanged()));
217
SIGNAL(heldChanged()),
218
SIGNAL(backgroundCallChanged()));
220
SIGNAL(activeChanged()),
221
SIGNAL(hasBackgroundCallChanged()));
268
if (entry->isConference()) {
269
// assume there can be only one conference call at any time for now
270
mConferenceCall = entry;
272
// check if any of the existing channels belong to the conference
273
// if they do, move them to the conference
274
QList<CallEntry*> entries = takeCalls(channel->conferenceChannels());
275
Q_FOREACH(CallEntry *entry, entries) {
276
mConferenceCall->addCall(entry);
278
setupCallEntry(mConferenceCall);
279
} else if (mConferenceCall && mConferenceCall->channel()->conferenceChannels().contains(channel)){
280
// if the call channel belongs to the conference, don't add it here, move it to the conference itself
281
mConferenceCall->addCall(entry);
283
mCallEntries.append(entry);
284
setupCallEntry(entry);
223
287
// FIXME: check which of those signals we really need to emit here
224
288
Q_EMIT hasCallsChanged();
238
303
// at this point the entry should be removed
239
mCallEntries.removeAll(entry);
304
if (entry == mConferenceCall) {
307
mCallEntries.removeAll(entry);
241
notifyEndedCall(entry->channel());
310
Q_EMIT callEnded(entry);
242
311
Q_EMIT hasCallsChanged();
243
312
Q_EMIT hasBackgroundCallChanged();
244
313
Q_EMIT foregroundCallChanged();
251
320
return mVoicemailNumber;
255
void CallManager::notifyEndedCall(const Tp::CallChannelPtr &channel)
257
Tp::Contacts contacts = channel->remoteMembers();
258
Tp::AccountPtr account = TelepathyHelper::instance()->accountForConnection(channel->connection());
259
if (contacts.isEmpty() || !account) {
260
qWarning() << "Call channel had no remote contacts:" << channel;
265
// FIXME: handle conference call
266
Q_FOREACH(const Tp::ContactPtr &contact, contacts) {
267
phoneNumber = contact->id();
271
// fill the call info
272
QDateTime timestamp = channel->property("timestamp").toDateTime();
273
bool incoming = channel->initiatorContact() != account->connection()->selfContact();
274
QTime duration(0, 0, 0);
275
bool missed = incoming && channel->callStateReason().reason == Tp::CallStateChangeReasonNoAnswer;
278
QDateTime activeTime = channel->property("activeTimestamp").toDateTime();
279
duration = duration.addSecs(activeTime.secsTo(QDateTime::currentDateTime()));
282
// and finally add the entry
283
// just mark it as new if it is missed
284
Q_EMIT callEnded(phoneNumber, incoming, timestamp, duration, missed, missed);
323
void CallManager::mergeCalls(CallEntry *firstCall, CallEntry *secondCall)
325
QDBusInterface *handlerInterface = TelepathyHelper::instance()->handlerInterface();
326
// if there is already a conference call, just merge the remaining channels
327
// in the existing conference
328
if (firstCall->isConference() || secondCall->isConference()) {
329
CallEntry *conferenceCall = firstCall->isConference() ? firstCall : secondCall;
330
CallEntry *otherCall = firstCall->isConference() ? secondCall : firstCall;
331
handlerInterface->call("MergeCall", conferenceCall->channel()->objectPath(), otherCall->channel()->objectPath());
333
handlerInterface->call("CreateConferenceCall", QStringList() << firstCall->channel()->objectPath()
334
<< secondCall->channel()->objectPath());
338
void CallManager::splitCall(CallEntry *callEntry)
340
QDBusInterface *handlerInterface = TelepathyHelper::instance()->handlerInterface();
341
handlerInterface->call("SplitCall", callEntry->channel()->objectPath());