Initial Import
[profile/ivi/hfdialer.git] / src / callmanager.cpp
1 /*
2  * hfdialer - Hands Free Voice Call Manager
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is licensed under the terms and conditions of the
6  * Apache License, version 2.0.  The full text of the Apache License is at
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  */
10
11 #include "common.h"
12 #include "callmanager.h"
13
14 class CallManagerPrivate
15 {
16 public:
17     //ResourceProxy *resource;
18     QHash<QString, CallItem *>  callItems;
19 };
20
21 CallManager::CallManager(const QString &modemPath, QObject *parent)
22     : OfonoVoiceCallManager(OfonoModem::AutomaticSelect, modemPath, parent),
23       d(new CallManagerPrivate)
24 {
25     TRACE;
26
27     // Transform existing calls list, into list of CallItems
28     updateCallItems();
29
30     // Begin tracking calls
31     connect(this, SIGNAL(callAdded(const QString)),
32             this, SLOT(addCall(const QString)));
33     connect(this, SIGNAL(callRemoved(const QString)),
34             this, SLOT(removeCall(const QString)));
35
36     // Hook into parent class signals
37     connect(this, SIGNAL(dialComplete(const bool)),
38             this, SLOT(dialFinished(const bool)));
39     connect(this, SIGNAL(swapCallsComplete(const bool)),
40             this, SLOT(swapFinished(const bool)));
41     connect(this, SIGNAL(hangupAllComplete(const bool)),
42             this, SLOT(hangupAllFinished(const bool)));
43     connect(this, SIGNAL(sendTonesComplete(const bool)),
44             this, SLOT(sendTonesFinished(const bool)));
45     connect(this, SIGNAL(holdAndAnswerComplete(const bool)),
46             this, SLOT(holdAndAnswerFinished(const bool)));
47     connect(this, SIGNAL(transferComplete(const bool)),
48             this, SLOT(transferFinished(const bool)));
49     connect(this, SIGNAL(releaseAndAnswerComplete(const bool)),
50             this, SLOT(releaseAndAnswerFinished(const bool)));
51     connect(this, SIGNAL(privateChatComplete(const bool)),
52             this, SLOT(privateChatFinished(const bool)));
53     connect(this, SIGNAL(createMultipartyComplete(const bool)),
54             this, SLOT(createMultipartyFinished(const bool)));
55     connect(this, SIGNAL(hangupMultipartyComplete(const bool)),
56             this, SLOT(hangupMultipartyFinished(const bool)));
57
58     connect(this,SIGNAL(callsChanged()),this,SLOT(callChangedSlot()));
59
60     connect(this, SIGNAL(validityChanged(bool)), this, SLOT(modemValidityChanged(bool)) );
61
62     if (isValid())
63         emit connected();
64 }
65
66 CallManager::~CallManager()
67 {
68     TRACE;
69     // FIXME: Do something here!!!
70     qDebug() << QString("Destroying VoiceCallManager");
71     qDebug() << QString("Purging all CallItems");
72     foreach (CallItem *item, d->callItems) {
73         disconnect(item, SIGNAL(stateChanged()));
74         disconnect(item, SIGNAL(dataChanged()));
75         delete item;
76     }
77     if (d->callItems.size() > 0)
78         emit callsChanged();
79     d->callItems.clear();
80 }
81
82 void CallManager::modemValidityChanged(bool valid)
83 {
84     TRACE;
85     if (valid)
86         emit connected();
87 }
88
89 QList<CallItem *> CallManager::getCallItems() const
90 {
91     TRACE;
92     return d->callItems.values();
93 }
94
95 int CallManager::callCount() const
96 {
97     TRACE;
98     qDebug()<<"call count is currently = "<<d->callItems.size();
99     return d->callItems.size();
100 }
101
102 int CallManager::multipartyCallCount() const
103 {
104     TRACE;
105     int call_count = 0;
106     foreach (CallItem *c, d->callItems) {
107         if(c->multiparty()) {
108             call_count++;
109         }
110     }
111     return call_count;
112 }
113
114 CallItem *CallManager::activeCall() const
115 {
116     TRACE;
117     if (d->callItems.size())
118         foreach (CallItem *c, d->callItems)
119             if (c->state() == STATE_ACTIVE)
120                 return c;
121     return NULL;
122 }
123
124 CallItem *CallManager::heldCall() const
125 {
126     TRACE;
127     if (d->callItems.size())
128         foreach (CallItem *c, d->callItems)
129             if (c->state() == STATE_HELD)
130                 return c;
131     return NULL;
132 }
133
134 CallItem *CallManager::dialingCall() const
135 {
136     TRACE;
137     if (d->callItems.size())
138         foreach (CallItem *c, d->callItems)
139             if (c->state() == STATE_DIALING)
140                 return c;
141     return NULL;
142 }
143
144 CallItem *CallManager::incomingCall() const
145 {
146     TRACE;
147     if (d->callItems.size())
148         foreach (CallItem *c, d->callItems)
149             if (c->state() == STATE_INCOMING)
150                 return c;
151     return NULL;
152 }
153
154 CallItem *CallManager::waitingCall() const
155 {
156     TRACE;
157     if (d->callItems.size())
158         foreach (CallItem *c, d->callItems)
159             if (c->state() == STATE_WAITING)
160                 return c;
161     return NULL;
162 }
163
164 CallItem *CallManager::alertingCall() const
165 {
166     TRACE;
167     if (d->callItems.size())
168         foreach (CallItem *c, d->callItems)
169             if (c->state() == STATE_ALERTING)
170                 return c;
171     return NULL;
172 }
173
174 void CallManager::setActiveCall(const CallItem &call)
175 {
176     TRACE;
177     swapCalls();
178 }
179
180 void CallManager::dial(const QString &number)
181 {
182     TRACE;
183     // Nothing to do if the modem is not powered up
184
185     if(!modem()->powered()) {
186         emit callsChanged();
187         return;
188     }
189
190     // If not online (flight mode?), check if the requested number is
191     // one of the allowed EmergencyNumbers, in which case, continue.
192     // Otherwise, notify that only Emergency calls are permitted.
193     if(!modem()->online()) {
194         if(modem()->powered() && !emergencyNumbers().contains(number)) {
195             emit callsChanged();
196             emit onlyEmergencyCalls();
197             return;
198         }
199     }
200
201     proceedCallDial(number);
202 }
203
204 void CallManager::privateChat(const CallItem &call)
205 {
206     TRACE;
207 }
208
209 /*
210  * Resource Policy Manager Handler slots
211  */
212 void CallManager::deniedCallDial()
213 {
214     TRACE;
215     qCritical() << QString("Denied: Dial resource");
216 }
217
218 void CallManager::lostCallDial()
219 {
220     TRACE;
221     qCritical() << QString("Lost: Dial resource");
222     hangupAll();
223 }
224
225 void CallManager::proceedCallDial(const QString number)
226 {
227     TRACE;
228     OfonoVoiceCallManager::dial(stripLineID(number), QString());
229 }
230
231 void CallManager::deniedCallAnswer()
232 {
233     TRACE;
234     qCritical() << QString("Denied: Call resource");
235     hangupAll();
236 }
237
238 void CallManager::deniedIncomingCall(CallItem *call)
239 {
240     TRACE;
241
242     qCritical() << QString("Denied: Incoming Call resource");
243     qDebug() << QString("Insert new CallItem %1").arg(call->path());
244     emit callsChanged();
245     emit incomingCall(call);
246 }
247
248 void CallManager::lostIncomingCall(CallItem *call)
249 {
250     TRACE;
251     Q_UNUSED(call)
252         qCritical() << QString("Lost: Incoming Call resource");
253 }
254
255 void CallManager::proceedIncomingCall(CallItem *call)
256 {
257     TRACE;
258     qDebug() << QString("Acquired: Incoming Call resource");
259     qDebug() << QString("Insert new CallItem %1").arg(call->path());
260     emit callsChanged();
261     emit incomingCall(call);
262 }
263
264 /*
265  * Private slots for async replies
266  */
267
268 void CallManager::updateCallItems()
269 {
270     TRACE;
271     bool changed = false;
272
273     // If ofono call list is empty (no calls), empty our CallItem list too.
274     if (getCalls().isEmpty() && !d->callItems.isEmpty()) {
275         qDebug() << QString("Purging all CallItems");
276         foreach (CallItem *item, d->callItems)
277             delete item;
278         d->callItems.clear();
279         emit callsChanged();
280         return;
281     }
282
283     // Remove CallItems that are not in the ofono "calls" list
284     QMutableHashIterator<QString, CallItem*> iter(d->callItems);
285     while (iter.hasNext()) {
286         CallItem *item = iter.next().value();
287         // This item is not in the ofono list, remove it
288         if (!getCalls().contains(item->path())) {
289             qDebug() << QString("Removing old CallItem %1").arg(item->path());
290             delete item;
291             iter.remove();
292             changed = true;
293         }
294     }
295
296     // Insert new CallItems for paths in the ofono "calls" list we are missing
297     foreach (QString path, getCalls()) {
298         // Insert a new CallItem
299         if (!d->callItems.contains(path)) {
300             qDebug() << QString("Inserting new CallItem %1").arg(path);
301             CallItem *call = new CallItem(path);
302             connect (call, SIGNAL(stateChanged()),
303                      this, SLOT(callStateChanged()));
304             connect (call, SIGNAL(multipartyChanged()),
305                      this, SLOT(callMultipartyChanged()));
306             d->callItems.insert(path, call);
307
308             // NOTE: Must explicity bubble this up since incoming and waiting
309             //       calls do not "changeState" unless they are handled or
310             //       timeout
311             if ((call->state() == STATE_INCOMING) ||
312                 (call->state() == STATE_WAITING)) {
313                 proceedIncomingCall(call);
314             } else {
315                 changed = true;
316             }
317         }
318     }
319
320     if (changed)
321         emit callsChanged();
322 }
323
324 void CallManager::addCall(const QString &path)
325 {
326     TRACE;
327     qDebug() << QString("CallAdded: \"%1\"").arg(path);
328     qDebug() <<"Call number is now "<< callCount();
329     updateCallItems();
330     emit callCountChanged(callCount());
331 }
332
333 void CallManager::removeCall(const QString &path)
334 {
335     TRACE;
336     qDebug() << QString("CallRemoved: \"%1\"").arg(path);
337     qDebug() <<"Call number is now "<< callCount();
338     updateCallItems();
339     emit callCountChanged(callCount());
340 }
341
342 void CallManager::dialFinished(const bool status)
343 {
344     TRACE;
345     qDebug() <<"Call number is now "<< callCount();
346  
347     if (!status) {
348         qCritical() << QString("dial() Failed: %1 - %2")
349             .arg(errorName())
350             .arg(errorMessage());
351         // Fix BMC#10848:
352         // Notify that state of the call has changed when the dialing fails
353         emit callsChanged();
354     }
355 }
356
357 void CallManager::hangupAllFinished(const bool status)
358 {
359     TRACE;
360     if (!status)
361         qCritical() << QString("hangupAll() Failed: %1 - %2")
362             .arg(errorName())
363             .arg(errorMessage());
364
365     //If there are still calls for some reason, delete them.
366     if (callCount() > 0)
367         {
368             foreach (CallItem *item, d->callItems) {
369                 disconnect(item, SIGNAL(stateChanged()));
370                 disconnect(item, SIGNAL(dataChanged()));
371                 delete item;
372             }
373     
374             d->callItems.clear();
375             callCount();
376             emit callsChanged();
377         }
378     callCount();
379 }
380
381 void CallManager::swapFinished(const bool status)
382 {
383     TRACE;
384     if (!status)
385         qCritical() << QString("swapCalls() Failed: %1 - %2")
386             .arg(errorName())
387             .arg(errorMessage());
388 }
389
390 void CallManager::holdAndAnswerFinished(const bool status)
391 {
392     TRACE;
393     if (!status)
394         qCritical() << QString("HoldAndAnswer() Failed: %1 - %2")
395             .arg(errorName())
396             .arg(errorMessage());
397 }
398
399 void CallManager::transferFinished(const bool status)
400 {
401     TRACE;
402     if (!status)
403         qCritical() << QString("Transfer() Failed: %1 - %2")
404             .arg(errorName())
405             .arg(errorMessage());
406 }
407
408 void CallManager::releaseAndAnswerFinished(const bool status)
409 {
410     TRACE;
411     if (!status)
412         qCritical() << QString("ReleaseAndAnswer() Failed: %1 - %2")
413             .arg(errorName())
414             .arg(errorMessage());
415 }
416
417 void CallManager::privateChatFinished(const bool status)
418 {
419     TRACE;
420     if (!status)
421         qCritical() << QString("PrivateChat() Failed: %1 - %2")
422             .arg(errorName())
423             .arg(errorMessage());
424 }
425
426 void CallManager::createMultipartyFinished(const bool status)
427 {
428     TRACE;
429     if (!status)
430         qCritical() << QString("CreateMultiparty() Failed: %1 - %2")
431             .arg(errorName())
432             .arg(errorMessage());
433 }
434
435 void CallManager::hangupMultipartyFinished(const bool status)
436 {
437     TRACE;
438     if (!status)
439         qCritical() << QString("HangupMultiparty() Failed: %1 - %2")
440             .arg(errorName())
441             .arg(errorMessage());
442 }
443
444 void CallManager::sendTonesFinished(const bool status)
445 {
446     TRACE;
447     if (!status)
448         qCritical() << QString("SendTones() Failed: %1 - %2")
449             .arg(errorName())
450             .arg(errorMessage());
451 }
452
453 void CallManager::callStateChanged()
454 {
455     CallItem *call = dynamic_cast<CallItem *>(sender());
456     qDebug() << QString("%1 (%2) state has changed to %3")
457         .arg(call->path())
458         .arg(call->lineID())
459         .arg(call->state());
460     qDebug() << "number of calls "<< callCount();
461     emit callsChanged();
462 }
463
464 void CallManager::callMultipartyChanged()
465 {
466     TRACE;
467     emit callsChanged();
468     emit multipartyCallCountChanged(multipartyCallCount());
469 }
470
471 void CallManager::callChangedSlot()
472 {
473     TRACE
474     qDebug()<<"callChanged called!";
475 }
476
477 /* Local Variables:      */
478 /* mode:c++              */
479 /* c-basic-offset:4      */
480 /* indent-tabs-mode: nil */
481 /* End:                  */