~mterry/telephony-service/start-on

« back to all changes in this revision

Viewing changes to libtelephonyservice/callmanager.cpp

  • Committer: CI bot
  • Author(s): Gustavo Pichorim Boiko
  • Date: 2014-04-02 12:41:29 UTC
  • mfrom: (765.2.24 telephony-service-conf_call)
  • Revision ID: ps-jenkins@lists.canonical.com-20140402124129-oywt8u6u9f4253bg
Add support for handling conference calls. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
}
39
39
 
40
40
CallManager::CallManager(QObject *parent)
41
 
: QObject(parent), mNeedsUpdate(false)
 
41
: QObject(parent), mNeedsUpdate(false), mConferenceCall(0)
42
42
{
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()));
46
46
}
47
47
 
 
48
QList<CallEntry *> CallManager::takeCalls(const QList<Tp::ChannelPtr> callChannels)
 
49
{
 
50
    qDebug() << __PRETTY_FUNCTION__;
 
51
    QList<CallEntry*> entries;
 
52
 
 
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);
 
57
            entries << entry;
 
58
            entry->disconnect(this);
 
59
        }
 
60
    }
 
61
 
 
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();
 
67
 
 
68
    return entries;
 
69
}
 
70
 
 
71
void CallManager::addCalls(const QList<CallEntry *> entries)
 
72
{
 
73
    Q_FOREACH (CallEntry *entry, entries) {
 
74
        if (!mCallEntries.contains(entry)) {
 
75
            mCallEntries << entry;
 
76
        }
 
77
        setupCallEntry(entry);
 
78
    }
 
79
 
 
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();
 
85
}
 
86
 
 
87
void CallManager::setupCallEntry(CallEntry *entry)
 
88
{
 
89
    connect(entry,
 
90
            SIGNAL(callEnded()),
 
91
            SLOT(onCallEnded()));
 
92
    connect(entry,
 
93
            SIGNAL(heldChanged()),
 
94
            SIGNAL(foregroundCallChanged()));
 
95
    connect(entry,
 
96
            SIGNAL(activeChanged()),
 
97
            SIGNAL(foregroundCallChanged()));
 
98
    connect(entry,
 
99
            SIGNAL(heldChanged()),
 
100
            SIGNAL(backgroundCallChanged()));
 
101
    connect(entry,
 
102
            SIGNAL(activeChanged()),
 
103
            SIGNAL(hasBackgroundCallChanged()));
 
104
    connect(entry,
 
105
            SIGNAL(activeChanged()),
 
106
            SIGNAL(hasCallsChanged()));
 
107
}
 
108
 
48
109
void CallManager::onChannelObserverUnregistered()
49
110
{
50
111
    // do not clear the manager right now, wait until the observer is re-registered
96
157
 
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();
101
163
    } else {
102
 
        Q_FOREACH(CallEntry *entry, mCallEntries) {
 
164
        Q_FOREACH(CallEntry *entry, calls) {
103
165
            if (entry->isActive() && !entry->isHeld()) {
104
166
                call = entry;
105
167
                break;
107
169
        }
108
170
    }
109
171
 
110
 
    if (!call) {
111
 
        return 0;
112
 
    }
113
 
 
114
 
    // incoming but not yet answered calls cant be considered foreground calls
115
 
    if (call->ringing()) {
116
 
        return 0;
117
 
    }
118
 
 
119
172
    return call;
120
173
}
121
174
 
122
175
CallEntry *CallManager::backgroundCall() const
123
176
{
 
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) {
127
181
        return 0;
128
182
    }
129
183
 
130
 
    Q_FOREACH(CallEntry *entry, mCallEntries) {
 
184
    Q_FOREACH(CallEntry *entry, calls) {
131
185
        if (entry->isHeld()) {
132
186
            return entry;
133
187
        }
139
193
QList<CallEntry *> CallManager::activeCalls() const
140
194
{
141
195
    QList<CallEntry*> calls;
 
196
    if (mConferenceCall) {
 
197
        calls << mConferenceCall;
 
198
    }
 
199
 
142
200
    Q_FOREACH(CallEntry *entry, mCallEntries) {
143
201
        if (entry->isActive() || entry->dialing()) {
144
202
            calls << entry;
195
253
            entry->deleteLater();
196
254
        }
197
255
        mCallEntries.clear();
 
256
        if (mConferenceCall) {
 
257
            mConferenceCall->deleteLater();
 
258
            mConferenceCall = 0;
 
259
        }
198
260
        mNeedsUpdate = false;
199
261
    }
200
262
 
203
265
        entry->setVoicemail(true);
204
266
    }
205
267
 
206
 
    mCallEntries.append(entry);
207
 
    connect(entry,
208
 
            SIGNAL(callEnded()),
209
 
            SLOT(onCallEnded()));
210
 
    connect(entry,
211
 
            SIGNAL(heldChanged()),
212
 
            SIGNAL(foregroundCallChanged()));
213
 
    connect(entry,
214
 
            SIGNAL(activeChanged()),
215
 
            SIGNAL(foregroundCallChanged()));
216
 
    connect(entry,
217
 
            SIGNAL(heldChanged()),
218
 
            SIGNAL(backgroundCallChanged()));
219
 
    connect(entry,
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;
 
271
 
 
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);
 
277
        }
 
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);
 
282
    } else {
 
283
        mCallEntries.append(entry);
 
284
        setupCallEntry(entry);
 
285
    }
222
286
 
223
287
    // FIXME: check which of those signals we really need to emit here
224
288
    Q_EMIT hasCallsChanged();
229
293
 
230
294
void CallManager::onCallEnded()
231
295
{
 
296
    qDebug() << __PRETTY_FUNCTION__;
232
297
    // FIXME: handle multiple calls
233
298
    CallEntry *entry = qobject_cast<CallEntry*>(sender());
234
299
    if (!entry) {
236
301
    }
237
302
 
238
303
    // at this point the entry should be removed
239
 
    mCallEntries.removeAll(entry);
 
304
    if (entry == mConferenceCall) {
 
305
        mConferenceCall = 0;
 
306
    } else {
 
307
        mCallEntries.removeAll(entry);
 
308
    }
240
309
 
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;
252
321
}
253
322
 
254
 
 
255
 
void CallManager::notifyEndedCall(const Tp::CallChannelPtr &channel)
256
 
{
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;
261
 
        return;
262
 
    }
263
 
 
264
 
    QString phoneNumber;
265
 
    // FIXME: handle conference call
266
 
    Q_FOREACH(const Tp::ContactPtr &contact, contacts) {
267
 
        phoneNumber = contact->id();
268
 
        break;
269
 
    }
270
 
 
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;
276
 
 
277
 
    if (!missed) {
278
 
        QDateTime activeTime = channel->property("activeTimestamp").toDateTime();
279
 
        duration = duration.addSecs(activeTime.secsTo(QDateTime::currentDateTime()));
280
 
    }
281
 
 
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)
 
324
{
 
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());
 
332
    } else {
 
333
        handlerInterface->call("CreateConferenceCall", QStringList() << firstCall->channel()->objectPath()
 
334
                                                                     << secondCall->channel()->objectPath());
 
335
    }
 
336
}
 
337
 
 
338
void CallManager::splitCall(CallEntry *callEntry)
 
339
{
 
340
    QDBusInterface *handlerInterface = TelepathyHelper::instance()->handlerInterface();
 
341
    handlerInterface->call("SplitCall", callEntry->channel()->objectPath());
285
342
}