Merge lp:~boiko/telephony-service/fix_call_duration into lp:telephony-service

Proposed by Gustavo Pichorim Boiko
Status: Merged
Approved by: Bill Filler
Approved revision: 769
Merged at revision: 770
Proposed branch: lp:~boiko/telephony-service/fix_call_duration
Merge into: lp:telephony-service
Diff against target: 502 lines (+223/-5)
10 files modified
handler/Handler.xml (+17/-0)
handler/callhandler.cpp (+51/-0)
handler/callhandler.h (+5/-0)
handler/handlerdbus.cpp (+8/-0)
handler/handlerdbus.h (+3/-0)
handler/tests/HandlerTest.cpp (+56/-0)
handler/tests/handlercontroller.cpp (+15/-0)
handler/tests/handlercontroller.h (+5/-0)
libtelephonyservice/callentry.cpp (+55/-4)
libtelephonyservice/callentry.h (+8/-1)
To merge this branch: bzr merge lp:~boiko/telephony-service/fix_call_duration
Reviewer Review Type Date Requested Status
Bill Filler (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+204256@code.launchpad.net

Commit message

Get the active timestamp for calls from the handler, as the observer is unregistered every time the application goes out of focus. This ensures that the call duration will always be correct.
Save also the DTMF string so that the application can restore that info too after it is send to background and back to foreground.

Description of the change

Get the active timestamp for calls from the handler, as the observer is unregistered every time the application goes out of focus. This ensures that the call duration will always be correct.
Save also the DTMF string so that the application can restore that info too after it is send to background and back to foreground.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
769. By Gustavo Pichorim Boiko

Merge latest changes from trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gustavo Pichorim Boiko (boiko) wrote :

Are there any related MPs required for this MP to build/function as expected? Please list: No
Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes): Yes
Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?: Yes
Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/telephony-service) on device or emulator? Yes
If you changed the UI, was the change specified/approved by design? No UI changes.
If you changed the packaging (debian), did you subscribe a core-dev to this MP? No packaging changes.

Revision history for this message
Bill Filler (bfiller) wrote :

Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?
YES

Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/<package-name>) on device or emulator?
YES

Did CI run pass? If not, please explain why.
YES

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
YES

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'handler/Handler.xml'
2--- handler/Handler.xml 2013-07-17 18:06:28 +0000
3+++ handler/Handler.xml 2014-01-31 15:23:33 +0000
4@@ -67,5 +67,22 @@
5 <arg name="objectPath" type="s" direction="in"/>
6 <arg name="key" type="s" direction="in"/>
7 </method>
8+ <method name="GetCallProperties">
9+ <dox:d><![CDATA[
10+ Get the properties of a given call channel
11+ ]]></dox:d>
12+ <arg name="objectPath" type="s" direction="in"/>
13+ <arg name="properties" type="a{sv}" direction="out"/>
14+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
15+ </method>
16+ <signal name="CallPropertiesChanged">
17+ <dox:d><![CDATA[
18+ The properties of a given call changed.
19+ ]]></dox:d>
20+ <arg name="objectPath" type="s"/>
21+ <arg name="properties" type="a{sv}"/>
22+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
23+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
24+ </signal>
25 </interface>
26 </node>
27
28=== modified file 'handler/callhandler.cpp'
29--- handler/callhandler.cpp 2013-11-11 14:54:50 +0000
30+++ handler/callhandler.cpp 2014-01-31 15:23:33 +0000
31@@ -39,6 +39,31 @@
32 return self;
33 }
34
35+QVariantMap CallHandler::getCallProperties(const QString &objectPath)
36+{
37+ QVariantMap properties;
38+ Tp::CallChannelPtr channel = callFromObjectPath(objectPath);
39+ if (!channel) {
40+ return properties;
41+ }
42+
43+ QVariant property = channel->property("timestamp");
44+ if (property.isValid()) {
45+ properties["timestamp"] = property;
46+ }
47+
48+ property = channel->property("activeTimestamp");
49+ if (property.isValid()) {
50+ properties["activeTimestamp"] = property;
51+ }
52+ property = channel->property("dtmfString");
53+ if (property.isValid()) {
54+ properties["dtmfString"] = property;
55+ }
56+
57+ return properties;
58+}
59+
60 CallHandler::CallHandler(QObject *parent)
61 : QObject(parent)
62 {
63@@ -116,6 +141,11 @@
64 return;
65 }
66
67+ // save the dtmfString to send to clients that request it
68+ QString dtmfString = channel->property("dtmfString").toString();
69+ dtmfString += key;
70+ channel->setProperty("dtmfString", dtmfString);
71+
72 Q_FOREACH(const Tp::CallContentPtr &content, channel->contents()) {
73 if (content->supportsDTMF()) {
74 bool ok;
75@@ -133,6 +163,8 @@
76 content->startDTMFTone(event);
77 }
78 }
79+
80+ Q_EMIT callPropertiesChanged(channel->objectPath(), getCallProperties(channel->objectPath()));
81 }
82
83 void CallHandler::onCallChannelAvailable(Tp::CallChannelPtr channel)
84@@ -145,10 +177,14 @@
85 QVariantList args = reply.arguments();
86 QMap<QString, QVariant> map = qdbus_cast<QMap<QString, QVariant> >(args[0]);
87 channel->setProperty("hasSpeakerProperty", map.contains(PROPERTY_SPEAKERMODE));
88+ channel->setProperty("timestamp", QDateTime::currentDateTimeUtc());
89
90 connect(channel.data(),
91 SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
92 SLOT(onCallChannelInvalidated()));
93+ connect(channel.data(),
94+ SIGNAL(callStateChanged(Tp::CallState)),
95+ SLOT(onCallStateChanged(Tp::CallState)));
96
97 mCallChannels.append(channel);
98 }
99@@ -198,6 +234,21 @@
100 mCallChannels.removeAll(channel);
101 }
102
103+void CallHandler::onCallStateChanged(Tp::CallState state)
104+{
105+ Tp::CallChannelPtr channel(qobject_cast<Tp::CallChannel*>(sender()));
106+ if (!channel) {
107+ return;
108+ }
109+
110+ switch (state) {
111+ case Tp::CallStateActive:
112+ channel->setProperty("activeTimestamp", QDateTime::currentDateTimeUtc());
113+ Q_EMIT callPropertiesChanged(channel->objectPath(), getCallProperties(channel->objectPath()));
114+ break;
115+ }
116+}
117+
118 Tp::CallChannelPtr CallHandler::existingCall(const QString &phoneNumber)
119 {
120 Tp::CallChannelPtr channel;
121
122=== modified file 'handler/callhandler.h'
123--- handler/callhandler.h 2013-07-18 17:02:10 +0000
124+++ handler/callhandler.h 2014-01-31 15:23:33 +0000
125@@ -35,6 +35,7 @@
126
127 public:
128 static CallHandler *instance();
129+ QVariantMap getCallProperties(const QString &objectPath);
130
131 public Q_SLOTS:
132 void onCallChannelAvailable(Tp::CallChannelPtr channel);
133@@ -45,6 +46,9 @@
134 void setSpeakerMode(const QString &objectPath, bool enabled);
135 void sendDTMF(const QString &objectPath, const QString &key);
136
137+Q_SIGNALS:
138+ void callPropertiesChanged(const QString &objectPath, const QVariantMap &properties);
139+
140 protected:
141 Tp::CallChannelPtr existingCall(const QString &phoneNumber);
142 Tp::CallChannelPtr callFromObjectPath(const QString &objectPath);
143@@ -53,6 +57,7 @@
144 void onContactsAvailable(Tp::PendingOperation *op);
145 void onCallHangupFinished(Tp::PendingOperation *op);
146 void onCallChannelInvalidated();
147+ void onCallStateChanged(Tp::CallState state);
148
149 private:
150 explicit CallHandler(QObject *parent = 0);
151
152=== modified file 'handler/handlerdbus.cpp'
153--- handler/handlerdbus.cpp 2013-07-18 17:02:10 +0000
154+++ handler/handlerdbus.cpp 2014-01-31 15:23:33 +0000
155@@ -34,12 +34,20 @@
156
157 HandlerDBus::HandlerDBus(QObject* parent) : QObject(parent)
158 {
159+ connect(CallHandler::instance(),
160+ SIGNAL(callPropertiesChanged(QString,QVariantMap)),
161+ SIGNAL(CallPropertiesChanged(QString,QVariantMap)));
162 }
163
164 HandlerDBus::~HandlerDBus()
165 {
166 }
167
168+QVariantMap HandlerDBus::GetCallProperties(const QString &objectPath)
169+{
170+ return CallHandler::instance()->getCallProperties(objectPath);
171+}
172+
173 bool HandlerDBus::connectToBus()
174 {
175 bool ok = QDBusConnection::sessionBus().registerService(DBUS_SERVICE);
176
177=== modified file 'handler/handlerdbus.h'
178--- handler/handlerdbus.h 2013-07-18 17:02:10 +0000
179+++ handler/handlerdbus.h 2014-01-31 15:23:33 +0000
180@@ -39,6 +39,8 @@
181 HandlerDBus(QObject* parent=0);
182 ~HandlerDBus();
183
184+ QVariantMap GetCallProperties(const QString &objectPath);
185+
186 public Q_SLOTS:
187 bool connectToBus();
188
189@@ -56,6 +58,7 @@
190
191 Q_SIGNALS:
192 void onMessageSent(const QString &number, const QString &message);
193+ void CallPropertiesChanged(const QString &objectPath, const QVariantMap &properties);
194 };
195
196 #endif // HANDLERDBUS_H
197
198=== modified file 'handler/tests/HandlerTest.cpp'
199--- handler/tests/HandlerTest.cpp 2014-01-22 19:44:38 +0000
200+++ handler/tests/HandlerTest.cpp 2014-01-31 15:23:33 +0000
201@@ -32,6 +32,7 @@
202 void testMakingCalls();
203 void testHangUpCall();
204 void testCallHold();
205+ void testCallProperties();
206 void testSendMessage();
207
208 private:
209@@ -124,6 +125,61 @@
210 MockController::instance()->hangupCall(callerId);
211 }
212
213+void HandlerTest::testCallProperties()
214+{
215+ QString callerId("7654321");
216+
217+ QVariantMap properties;
218+ properties["Caller"] = callerId;
219+ properties["State"] = "incoming";
220+
221+ QSignalSpy approverCallSpy(mApprover, SIGNAL(newCall()));
222+ QSignalSpy handlerCallPropertiesSpy(HandlerController::instance(), SIGNAL(callPropertiesChanged(QString,QVariantMap)));
223+ MockController::instance()->placeCall(properties);
224+
225+ // wait for the channel to hit the approver
226+ QTRY_COMPARE(approverCallSpy.count(), 1);
227+ mApprover->acceptCall();
228+
229+ // wait until the call properties are changed
230+ QTRY_COMPARE(handlerCallPropertiesSpy.count(), 1);
231+ QString objectPath = handlerCallPropertiesSpy.first()[0].toString();
232+ QVariantMap propsFromSignal = handlerCallPropertiesSpy.first()[1].toMap();
233+ QVERIFY(!propsFromSignal.isEmpty());
234+ QDateTime activeTimestampFromSignal;
235+ QDateTime timestampFromSignal;
236+ propsFromSignal["activeTimestamp"].value<QDBusArgument>() >> activeTimestampFromSignal;
237+ propsFromSignal["timestamp"].value<QDBusArgument>() >> timestampFromSignal;
238+ QVERIFY(activeTimestampFromSignal.isValid());
239+ QVERIFY(timestampFromSignal.isValid());
240+
241+ // and try to get the properties using the method
242+ QVariantMap propsFromMethod = HandlerController::instance()->getCallProperties(objectPath);
243+ QVERIFY(!propsFromMethod.isEmpty());
244+ QDateTime activeTimestampFromMethod;
245+ QDateTime timestampFromMethod;
246+ propsFromMethod["activeTimestamp"].value<QDBusArgument>() >> activeTimestampFromMethod;
247+ propsFromMethod["timestamp"].value<QDBusArgument>() >> timestampFromMethod;
248+ QCOMPARE(activeTimestampFromSignal, activeTimestampFromMethod);
249+ QCOMPARE(timestampFromSignal, timestampFromMethod);
250+
251+ // now send some DTMF tones and check if the property is properly updated
252+ handlerCallPropertiesSpy.clear();
253+ QString dtmfString("1234*#");
254+ for (int i = 0; i < dtmfString.length(); ++i) {
255+ HandlerController::instance()->sendDTMF(objectPath, QString(dtmfString[i]));
256+ }
257+ QTRY_COMPARE(handlerCallPropertiesSpy.count(), dtmfString.length());
258+ propsFromSignal = handlerCallPropertiesSpy.last()[1].toMap();
259+ propsFromMethod = HandlerController::instance()->getCallProperties(objectPath);
260+ QString dtmfStringFromSignal = propsFromSignal["dtmfString"].toString();
261+ QString dtmfStringFromMethod = propsFromMethod["dtmfString"].toString();
262+ QCOMPARE(dtmfStringFromSignal, dtmfString);
263+ QCOMPARE(dtmfStringFromMethod, dtmfString);
264+
265+ HandlerController::instance()->hangUpCall(objectPath);
266+}
267+
268 void HandlerTest::testSendMessage()
269 {
270 QString recipient("22222222");
271
272=== modified file 'handler/tests/handlercontroller.cpp'
273--- handler/tests/handlercontroller.cpp 2014-01-15 17:35:58 +0000
274+++ handler/tests/handlercontroller.cpp 2014-01-31 15:23:33 +0000
275@@ -18,6 +18,7 @@
276 */
277
278 #include "handlercontroller.h"
279+#include <QDBusReply>
280
281 #define HANDLER_SERVICE "com.canonical.TelephonyServiceHandler"
282 #define HANDLER_OBJECT "/com/canonical/TelephonyServiceHandler"
283@@ -33,6 +34,20 @@
284 QObject(parent),
285 mHandlerInterface(HANDLER_SERVICE, HANDLER_OBJECT, HANDLER_INTERFACE)
286 {
287+ connect(&mHandlerInterface,
288+ SIGNAL(CallPropertiesChanged(QString, QVariantMap)),
289+ SIGNAL(callPropertiesChanged(QString, QVariantMap)));
290+}
291+
292+QVariantMap HandlerController::getCallProperties(const QString &objectPath)
293+{
294+ QVariantMap properties;
295+ QDBusReply<QVariantMap> reply = mHandlerInterface.call("GetCallProperties", objectPath);
296+ if (reply.isValid()) {
297+ properties = reply.value();
298+ }
299+
300+ return properties;
301 }
302
303 void HandlerController::startCall(const QString &number)
304
305=== modified file 'handler/tests/handlercontroller.h'
306--- handler/tests/handlercontroller.h 2014-01-15 17:35:58 +0000
307+++ handler/tests/handlercontroller.h 2014-01-31 15:23:33 +0000
308@@ -29,6 +29,8 @@
309 public:
310 static HandlerController *instance();
311
312+ QVariantMap getCallProperties(const QString &objectPath);
313+
314 public Q_SLOTS:
315 void startCall(const QString &number);
316 void hangUpCall(const QString &objectPath);
317@@ -40,6 +42,9 @@
318 void sendMessage(const QString &number, const QString &message);
319 void acknowledgeMessages(const QString &number, const QStringList &messageIds);
320
321+Q_SIGNALS:
322+ void callPropertiesChanged(const QString &objectPath, const QVariantMap &properties);
323+
324 private:
325 explicit HandlerController(QObject *parent = 0);
326 QDBusInterface mHandlerInterface;
327
328=== modified file 'libtelephonyservice/callentry.cpp'
329--- libtelephonyservice/callentry.cpp 2013-09-18 19:52:43 +0000
330+++ libtelephonyservice/callentry.cpp 2014-01-31 15:23:33 +0000
331@@ -23,6 +23,7 @@
332 #include "callentry.h"
333 #include "telepathyhelper.h"
334
335+#include <QDBusReply>
336 #include <QTime>
337 #include <TelepathyQt/Contact>
338 #include <TelepathyQt/PendingReady>
339@@ -38,7 +39,6 @@
340 mChannel(channel),
341 mVoicemail(false),
342 mLocalMuteState(false),
343- mElapsedTime(QTime::currentTime()),
344 mMuteInterface(channel->busName(), channel->objectPath(), TELEPATHY_MUTE_IFACE),
345 mSpeakerInterface(channel->busName(), channel->objectPath(), CANONICAL_TELEPHONY_SPEAKER_IFACE),
346 mHasSpeakerProperty(false),
347@@ -46,6 +46,11 @@
348 {
349 setupCallChannel();
350
351+ // connect to the DBus signal
352+ connect(TelepathyHelper::instance()->handlerInterface(),
353+ SIGNAL(CallPropertiesChanged(QString, QVariantMap)),
354+ SLOT(onCallPropertiesChanged(QString,QVariantMap)));
355+
356 Q_EMIT incomingChanged();
357 }
358
359@@ -55,6 +60,14 @@
360 Q_EMIT speakerChanged();
361 }
362
363+void CallEntry::onCallPropertiesChanged(const QString &objectPath, const QVariantMap &properties)
364+{
365+ if (objectPath != mChannel->objectPath()) {
366+ return;
367+ }
368+ updateChannelProperties(properties);
369+}
370+
371 void CallEntry::setupCallChannel()
372 {
373 connect(mChannel.data(),
374@@ -85,6 +98,35 @@
375 Q_EMIT dialingChanged();
376 }
377
378+void CallEntry::updateChannelProperties(const QVariantMap &properties)
379+{
380+ QVariantMap props = properties;
381+ // fetch the properties if the map is empty
382+ if (props.isEmpty()) {
383+ QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
384+ QDBusReply<QVariantMap> reply = phoneAppHandler->call("GetCallProperties", mChannel->objectPath());
385+ if (!reply.isValid()) {
386+ return;
387+ }
388+
389+ props = reply.value();
390+ }
391+
392+ QDateTime timestamp;
393+ if (props.contains("timestamp")) {
394+ props["timestamp"].value<QDBusArgument>() >> timestamp;
395+ }
396+ if (props.contains("activeTimestamp")) {
397+ props["activeTimestamp"].value<QDBusArgument>() >> mActiveTimestamp;
398+ }
399+
400+ mChannel->setProperty("dtmfString", props["dtmfString"]);
401+ mChannel->setProperty("timestamp", timestamp);
402+ mChannel->setProperty("activeTimestamp", mActiveTimestamp);
403+
404+ Q_EMIT dtmfStringChanged();
405+}
406+
407 void CallEntry::timerEvent(QTimerEvent *event)
408 {
409 Q_EMIT elapsedTimeChanged();
410@@ -140,6 +182,11 @@
411 return mChannel->targetContact()->id();
412 }
413
414+QString CallEntry::dtmfString() const
415+{
416+ return mChannel->property("dtmfString").toString();
417+}
418+
419 void CallEntry::sendDTMF(const QString &key)
420 {
421 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
422@@ -194,14 +241,15 @@
423
424 void CallEntry::onCallStateChanged(Tp::CallState state)
425 {
426+ // fetch the channel properties from the handler
427+ updateChannelProperties();
428+
429 switch (state) {
430 case Tp::CallStateEnded:
431 Q_EMIT callEnded();
432 break;
433 case Tp::CallStateActive:
434- mChannel->setProperty("activeTimestamp", QDateTime::currentDateTime());
435 startTimer(1000);
436- mElapsedTime.start();
437 Q_EMIT callActive();
438 Q_EMIT activeChanged();
439 break;
440@@ -230,7 +278,10 @@
441
442 int CallEntry::elapsedTime() const
443 {
444- return mElapsedTime.secsTo(QTime::currentTime());
445+ if (!mActiveTimestamp.isValid()) {
446+ return 0;
447+ }
448+ return mActiveTimestamp.secsTo(QDateTime::currentDateTimeUtc());
449 }
450
451 bool CallEntry::isActive() const
452
453=== modified file 'libtelephonyservice/callentry.h'
454--- libtelephonyservice/callentry.h 2013-07-30 18:20:45 +0000
455+++ libtelephonyservice/callentry.h 2014-01-31 15:23:33 +0000
456@@ -66,6 +66,9 @@
457 READ isSpeakerOn
458 WRITE setSpeaker
459 NOTIFY speakerChanged)
460+ Q_PROPERTY(QString dtmfString
461+ READ dtmfString
462+ NOTIFY dtmfStringChanged)
463
464 public:
465 explicit CallEntry(const Tp::CallChannelPtr &channel, QObject *parent = 0);
466@@ -90,6 +93,7 @@
467 bool incoming() const;
468 bool ringing() const;
469 QString phoneNumber() const;
470+ QString dtmfString() const;
471
472 Q_INVOKABLE void sendDTMF(const QString &key);
473 Q_INVOKABLE void endCall();
474@@ -101,9 +105,11 @@
475 void onCallFlagsChanged(Tp::CallFlags flags);
476 void onMutedChanged(uint state);
477 void onSpeakerChanged(bool active);
478+ void onCallPropertiesChanged(const QString &objectPath, const QVariantMap &properties);
479
480 protected:
481 void setupCallChannel();
482+ void updateChannelProperties(const QVariantMap &properties = QVariantMap());
483
484 Q_SIGNALS:
485 void callEnded();
486@@ -113,6 +119,7 @@
487 void mutedChanged();
488 void voicemailChanged();
489 void phoneNumberChanged();
490+ void dtmfStringChanged();
491 void dialingChanged();
492 void incomingChanged();
493 void ringingChanged();
494@@ -128,7 +135,7 @@
495 QMap<QString, QVariant> mProperties;
496 bool mVoicemail;
497 bool mLocalMuteState;
498- QTime mElapsedTime;
499+ QDateTime mActiveTimestamp;
500 bool mHasSpeakerProperty;
501 bool mSpeakerMode;
502 };

Subscribers

People subscribed via source and target branches