Merge lp:~phablet-team/telephony-service/async_send_message into lp:telephony-service
- async_send_message
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~phablet-team/telephony-service/async_send_message |
Merge into: | lp:telephony-service |
Prerequisite: | lp:~phablet-team/telephony-service/group-chat |
Diff against target: |
3029 lines (+1526/-851) 26 files modified
.bzrignore (+2/-0) Ubuntu/Telephony/components.cpp (+1/-1) handler/CMakeLists.txt (+5/-0) handler/ChatStartingJob.xml (+31/-0) handler/Handler.xml (+2/-1) handler/MessageSendingJob.xml (+36/-0) handler/chatstartingjob.cpp (+171/-0) handler/chatstartingjob.h (+69/-0) handler/handlerdbus.cpp (+22/-2) handler/handlerdbus.h (+7/-2) handler/main.cpp (+1/-3) handler/messagejob.cpp (+96/-0) handler/messagejob.h (+75/-0) handler/messagesendingjob.cpp (+390/-0) handler/messagesendingjob.h (+90/-0) handler/texthandler.cpp (+11/-438) handler/texthandler.h (+4/-16) libtelephonyservice/chatentry.cpp (+253/-78) libtelephonyservice/chatentry.h (+51/-17) libtelephonyservice/chatmanager.cpp (+132/-198) libtelephonyservice/chatmanager.h (+9/-22) libtelephonyservice/telepathyhelper.cpp (+6/-3) libtelephonyservice/telepathyhelper.h (+2/-2) tests/handler/HandlerTest.cpp (+40/-17) tests/libtelephonyservice/ChatEntryTest.cpp (+2/-0) tests/libtelephonyservice/ChatManagerTest.cpp (+18/-51) |
To merge this branch: | bzr merge lp:~phablet-team/telephony-service/async_send_message |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Approve | |
PS Jenkins bot | continuous-integration | Pending | |
Ubuntu Phablet Team | Pending | ||
Review via email:
|
This proposal supersedes a proposal from 2016-05-24.
This proposal has been superseded by a proposal from 2016-10-13.
Commit message
Make it possible to send messages asynchronously and still report the results.
Description of the change
Make it possible to send messages asynchronously and still report the results.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
- 1218. By Gustavo Pichorim Boiko
-
Set also the threadId in properties so that the channel gets
created correctly.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1218
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1219. By Gustavo Pichorim Boiko
-
If no accountId is given, match channels from all accounts.
- 1220. By Gustavo Pichorim Boiko
-
Only set the accountId in properties if we are trying to match a chatroom
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1220
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1221. By Gustavo Pichorim Boiko
-
We don't need to verify accounts here, it is done in a later stage if needed
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1221
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1222. By Gustavo Pichorim Boiko
-
merge parent
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1222
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1223. By Gustavo Pichorim Boiko
-
Do not delete the interface classes. They are destroyed together with the channel itself.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:1223
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1224. By Gustavo Pichorim Boiko
-
Update copyright headers.
- 1225. By Gustavo Pichorim Boiko
-
Merge parent
- 1226. By Gustavo Pichorim Boiko
-
Expose chatstarting to dbus
- 1227. By Gustavo Pichorim Boiko
-
Make startChat return the job's objectPath
- 1228. By Gustavo Pichorim Boiko
-
Remove wrongly committed changelog.
- 1229. By Tiago Salem Herrmann
-
merge parent branch
- 1230. By Tiago Salem Herrmann
-
merge parent branch
- 1231. By Tiago Salem Herrmann
-
merge parent branch
- 1232. By Gustavo Pichorim Boiko
-
Handle channel invalidation.
- 1233. By Tiago Salem Herrmann
-
merge parent branch
- 1234. By Tiago Salem Herrmann
-
merge parent branch
- 1235. By Tiago Salem Herrmann
-
merge parent branch
- 1236. By Tiago Salem Herrmann
-
merge parent branch
- 1237. By Tiago Salem Herrmann
-
fix handler test
- 1238. By Tiago Salem Herrmann
-
merge parent branch
- 1239. By Tiago Salem Herrmann
-
merge parent branch
- 1240. By Gustavo Pichorim Boiko
-
Add a FIXME on a disabled test
- 1241. By Gustavo Pichorim Boiko
-
Merge parent
Unmerged revisions
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2015-07-02 03:35:20 +0000 |
3 | +++ .bzrignore 2016-10-06 19:34:37 +0000 |
4 | @@ -30,6 +30,7 @@ |
5 | approver/*.service |
6 | approver/approveradaptor.* |
7 | handler/handleradaptor.* |
8 | +handler/messagesendingjobadaptor.* |
9 | indicator/*.desktop |
10 | indicator/*.service |
11 | indicator/NotificationsInterface.* |
12 | @@ -57,3 +58,4 @@ |
13 | tests/libtelephonyservice/GreeterContactsTestExe |
14 | tests/libtelephonyservice/GreeterContactsTestServerExe |
15 | tests/libtelephonyservice/*Mock |
16 | +tests/indicator/NotificationsInterface.* |
17 | |
18 | === modified file 'Ubuntu/Telephony/components.cpp' |
19 | --- Ubuntu/Telephony/components.cpp 2015-11-19 12:59:31 +0000 |
20 | +++ Ubuntu/Telephony/components.cpp 2016-10-06 19:34:37 +0000 |
21 | @@ -75,12 +75,12 @@ |
22 | // @uri Telephony |
23 | qmlRegisterUncreatableType<TelepathyHelper>(uri, 0, 1, "TelepathyHelper", "This is a singleton helper class"); |
24 | qmlRegisterUncreatableType<CallEntry>(uri, 0, 1, "CallEntry", "Objects of this type are created in CallManager and made available to QML for usage"); |
25 | - qmlRegisterUncreatableType<ChatEntry>(uri, 0, 1, "ChatEntry", "Objects of this type are created in ChatManager and made available to QML for usage"); |
26 | qmlRegisterUncreatableType<ContactChatState>(uri, 0, 1, "ContactChatState", "Objects of this type are created in ChatEntry and made available to QML"); |
27 | qmlRegisterUncreatableType<AudioOutput>(uri, 0, 1, "AudioOutput", "Objects of this type are created in CallEntry and made available to QML for usage"); |
28 | qmlRegisterUncreatableType<AccountEntry>(uri, 0, 1, "AccountEntry", "Objects of this type are created in TelepathyHelper and made available to QML"); |
29 | qmlRegisterUncreatableType<USSDManager>(uri, 0, 1, "USSDManager", "Objects of this type are created in AccountEntry and made available to QML"); |
30 | qmlRegisterUncreatableType<Protocol>(uri, 0, 1, "ProtocolManager", "Objects of this type are created in ProtocolManager and made available to QML"); |
31 | + qmlRegisterType<ChatEntry>(uri, 0, 1, "ChatEntry"); |
32 | qmlRegisterType<ContactWatcher>(uri, 0, 1, "ContactWatcher"); |
33 | qmlRegisterType<PresenceRequest>(uri, 0, 1, "PresenceRequest"); |
34 | qmlRegisterType<PhoneUtils>(uri, 0, 1, "PhoneUtils"); |
35 | |
36 | === modified file 'handler/CMakeLists.txt' |
37 | --- handler/CMakeLists.txt 2016-03-18 19:02:50 +0000 |
38 | +++ handler/CMakeLists.txt 2016-10-06 19:34:37 +0000 |
39 | @@ -1,13 +1,18 @@ |
40 | |
41 | set(qt_SRCS |
42 | callhandler.cpp |
43 | + chatstartingjob.cpp |
44 | handler.cpp |
45 | handlerdbus.cpp |
46 | + messagejob.cpp |
47 | + messagesendingjob.cpp |
48 | texthandler.cpp |
49 | ) |
50 | |
51 | set(handler_SRCS main.cpp ${qt_SRCS}) |
52 | qt5_add_dbus_adaptor(handler_SRCS Handler.xml handler/handlerdbus.h HandlerDBus) |
53 | +qt5_add_dbus_adaptor(handler_SRCS ChatStartingJob.xml handler/chatstartingjob.h ChatStartingJob) |
54 | +qt5_add_dbus_adaptor(handler_SRCS MessageSendingJob.xml handler/messagesendingjob.h MessageSendingJob) |
55 | |
56 | include_directories( |
57 | ${TP_QT5_INCLUDE_DIRS} |
58 | |
59 | === added file 'handler/ChatStartingJob.xml' |
60 | --- handler/ChatStartingJob.xml 1970-01-01 00:00:00 +0000 |
61 | +++ handler/ChatStartingJob.xml 2016-10-06 19:34:37 +0000 |
62 | @@ -0,0 +1,31 @@ |
63 | +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
64 | +<node xmlns:dox="http://www.ayatana.org/dbus/dox.dtd"> |
65 | + <dox:d><![CDATA[ |
66 | + @mainpage |
67 | + |
68 | + An interface to the asynchronous chat creation job |
69 | + ]]></dox:d> |
70 | + <interface name="com.canonical.TelephonyServiceHandler.ChatStartingJob" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd"> |
71 | + <dox:d> |
72 | + An interface to the phone handler helper application. |
73 | + </dox:d> |
74 | + <property name="accountId" type="s" access="read"/> |
75 | + <property name="channelObjectPath" type="s" access="read"/> |
76 | + <property name="objectPath" type="s" access="read"/> |
77 | + <property name="properties" type="a{sv}" access="read"> |
78 | + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/> |
79 | + </property> |
80 | + <property name="status" type="i" access="read"/> |
81 | + <property name="isFinished" type="b" access="read"/> |
82 | + <signal name="channelObjectPathChanged"> |
83 | + </signal> |
84 | + <signal name="statusChanged"> |
85 | + </signal> |
86 | + <signal name="isFinishedChanged"> |
87 | + </signal> |
88 | + <signal name="finished"> |
89 | + </signal> |
90 | + <method name="startJob"> |
91 | + </method> |
92 | + </interface> |
93 | +</node> |
94 | |
95 | === modified file 'handler/Handler.xml' |
96 | --- handler/Handler.xml 2016-10-06 19:34:36 +0000 |
97 | +++ handler/Handler.xml 2016-10-06 19:34:37 +0000 |
98 | @@ -18,10 +18,10 @@ |
99 | <arg name="accountId" type="s" direction="in"/> |
100 | <arg name="message" type="s" direction="in"/> |
101 | <arg name="attachments" type="a(sss)" direction="in"/> |
102 | - <arg name="accountIdOut" type="s" direction="out"/> |
103 | <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="AttachmentList"/> |
104 | <arg name="properties" type="a{sv}" direction="in"/> |
105 | <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/> |
106 | + <arg name="objectPath" type="s" direction="out"/> |
107 | </method> |
108 | <method name="AcknowledgeMessages"> |
109 | <dox:d><![CDATA[ |
110 | @@ -37,6 +37,7 @@ |
111 | <arg name="accountId" type="s" direction="in"/> |
112 | <arg name="properties" type="a{sv}" direction="in"/> |
113 | <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
114 | + <arg name="objectPath" type="s" direction="out"/> |
115 | </method> |
116 | <method name="AcknowledgeAllMessages"> |
117 | <dox:d><![CDATA[ |
118 | |
119 | === added file 'handler/MessageSendingJob.xml' |
120 | --- handler/MessageSendingJob.xml 1970-01-01 00:00:00 +0000 |
121 | +++ handler/MessageSendingJob.xml 2016-10-06 19:34:37 +0000 |
122 | @@ -0,0 +1,36 @@ |
123 | +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
124 | +<node xmlns:dox="http://www.ayatana.org/dbus/dox.dtd"> |
125 | + <dox:d><![CDATA[ |
126 | + @mainpage |
127 | + |
128 | + An interface to the asynchronous message sending job |
129 | + ]]></dox:d> |
130 | + <interface name="com.canonical.TelephonyServiceHandler.MessageSendingJob" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd"> |
131 | + <dox:d> |
132 | + An interface to the phone handler helper application. |
133 | + </dox:d> |
134 | + <property name="accountId" type="s" access="read"/> |
135 | + <property name="messageId" type="s" access="read"/> |
136 | + <property name="channelObjectPath" type="s" access="read"/> |
137 | + <property name="objectPath" type="s" access="read"/> |
138 | + <property name="properties" type="a{sv}" access="read"> |
139 | + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/> |
140 | + </property> |
141 | + <property name="status" type="i" access="read"/> |
142 | + <property name="isFinished" type="b" access="read"/> |
143 | + <signal name="accountIdChanged"> |
144 | + </signal> |
145 | + <signal name="messageIdChanged"> |
146 | + </signal> |
147 | + <signal name="channelObjectPathChanged"> |
148 | + </signal> |
149 | + <signal name="statusChanged"> |
150 | + </signal> |
151 | + <signal name="isFinishedChanged"> |
152 | + </signal> |
153 | + <signal name="finished"> |
154 | + </signal> |
155 | + <method name="startJob"> |
156 | + </method> |
157 | + </interface> |
158 | +</node> |
159 | |
160 | === added file 'handler/chatstartingjob.cpp' |
161 | --- handler/chatstartingjob.cpp 1970-01-01 00:00:00 +0000 |
162 | +++ handler/chatstartingjob.cpp 2016-10-06 19:34:37 +0000 |
163 | @@ -0,0 +1,171 @@ |
164 | +/* |
165 | + * Copyright (C) 2016 Canonical, Ltd. |
166 | + * |
167 | + * Authors: |
168 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
169 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
170 | + * |
171 | + * This file is part of telephony-service. |
172 | + * |
173 | + * telephony-service is free software; you can redistribute it and/or modify |
174 | + * it under the terms of the GNU General Public License as published by |
175 | + * the Free Software Foundation; version 3. |
176 | + * |
177 | + * telephony-service is distributed in the hope that it will be useful, |
178 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
179 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
180 | + * GNU General Public License for more details. |
181 | + * |
182 | + * You should have received a copy of the GNU General Public License |
183 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
184 | + */ |
185 | + |
186 | +#include "chatstartingjob.h" |
187 | +#include "chatstartingjobadaptor.h" |
188 | +#include "telepathyhelper.h" |
189 | +#include "texthandler.h" |
190 | +#include <TelepathyQt/PendingChannelRequest> |
191 | + |
192 | +ChatStartingJob::ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties) |
193 | +: MessageJob(new ChatStartingJobAdaptor(this), textHandler), mTextHandler(textHandler), mAccountId(accountId), mProperties(properties) |
194 | +{ |
195 | + qDebug() << __PRETTY_FUNCTION__; |
196 | + connect(this, &ChatStartingJob::textChannelChanged, &ChatStartingJob::channelObjectPathChanged); |
197 | +} |
198 | + |
199 | +QString ChatStartingJob::accountId() |
200 | +{ |
201 | + return mAccountId; |
202 | +} |
203 | + |
204 | +void ChatStartingJob::startJob() |
205 | +{ |
206 | + qDebug() << __PRETTY_FUNCTION__; |
207 | + setStatus(Running); |
208 | + |
209 | + // Request the contact to start chatting to |
210 | + // FIXME: make it possible to select which account to use, for now, pick the first one |
211 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(mAccountId); |
212 | + if (!account || !account->connected()) { |
213 | + qCritical() << "The selected account does not have a connection. AccountId:" << mAccountId; |
214 | + setStatus(Failed); |
215 | + scheduleDeletion(); |
216 | + return; |
217 | + } |
218 | + |
219 | + switch(mProperties["chatType"].toUInt()) { |
220 | + case Tp::HandleTypeNone: |
221 | + case Tp::HandleTypeContact: |
222 | + startTextChat(account->account(), mProperties); |
223 | + break; |
224 | + case Tp::HandleTypeRoom: |
225 | + startTextChatRoom(account->account(), mProperties); |
226 | + break; |
227 | + default: |
228 | + qCritical() << "Chat type not supported"; |
229 | + } |
230 | +} |
231 | + |
232 | +void ChatStartingJob::startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties) |
233 | +{ |
234 | + qDebug() << __PRETTY_FUNCTION__; |
235 | + Tp::PendingChannelRequest *op = NULL; |
236 | + QStringList participants = properties["participantIds"].toStringList(); |
237 | + switch(participants.size()) { |
238 | + case 0: |
239 | + qCritical() << "Error: No participant list provided"; |
240 | + break; |
241 | + case 1: |
242 | + op = account->ensureTextChat(participants[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
243 | + break; |
244 | + default: |
245 | + op = account->createConferenceTextChat(QList<Tp::ChannelPtr>(), participants, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
246 | + } |
247 | + |
248 | + if (!op) { |
249 | + setStatus(Failed); |
250 | + scheduleDeletion(); |
251 | + return; |
252 | + } |
253 | + |
254 | + connect(op, &Tp::PendingOperation::finished, |
255 | + this, &ChatStartingJob::onChannelRequestFinished); |
256 | +} |
257 | + |
258 | +void ChatStartingJob::startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties) |
259 | +{ |
260 | + qDebug() << __PRETTY_FUNCTION__; |
261 | + QString roomName = properties["threadId"].toString(); |
262 | + |
263 | + // these properties are still not used |
264 | + //QString server = properties["Server"].toString(); |
265 | + //QString creator = properties["Creator"].toString(); |
266 | + |
267 | + QVariantMap request; |
268 | + Tp::PendingChannelRequest *op = NULL; |
269 | + if (roomName.isEmpty()) { |
270 | + request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); |
271 | + request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeNone); |
272 | + QStringList initialInviteeIDs = properties["participantIds"].toStringList(); |
273 | + if (!initialInviteeIDs.isEmpty()) { |
274 | + request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"), initialInviteeIDs); |
275 | + } |
276 | + // the presence of RoomName indicates the returned channel must be of type Room |
277 | + request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"), QString()); |
278 | + |
279 | + // TODO use the instance returned by createChanne() to track when the channel creation is finished |
280 | + op = account->createChannel(request, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
281 | + } else { |
282 | + op = account->ensureTextChatroom(roomName, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler", request); |
283 | + } |
284 | + |
285 | + if (!op) { |
286 | + setStatus(Failed); |
287 | + scheduleDeletion(); |
288 | + return; |
289 | + } |
290 | + connect(op, &Tp::PendingOperation::finished, |
291 | + this, &ChatStartingJob::onChannelRequestFinished); |
292 | +} |
293 | + |
294 | +Tp::TextChannelPtr ChatStartingJob::textChannel() const |
295 | +{ |
296 | + qDebug() << __PRETTY_FUNCTION__; |
297 | + return mTextChannel; |
298 | +} |
299 | + |
300 | +QString ChatStartingJob::channelObjectPath() const |
301 | +{ |
302 | + if (mTextChannel.isNull()) { |
303 | + return QString::null; |
304 | + } |
305 | + return mTextChannel->objectPath(); |
306 | +} |
307 | + |
308 | +void ChatStartingJob::setTextChannel(Tp::TextChannelPtr channel) |
309 | +{ |
310 | + qDebug() << __PRETTY_FUNCTION__; |
311 | + mTextChannel = channel; |
312 | + Q_EMIT textChannelChanged(); |
313 | +} |
314 | + |
315 | +void ChatStartingJob::onChannelRequestFinished(Tp::PendingOperation *op) |
316 | +{ |
317 | + qDebug() << __PRETTY_FUNCTION__; |
318 | + Status status; |
319 | + if (op->isError()) { |
320 | + status = Failed; |
321 | + } else { |
322 | + Tp::PendingChannelRequest *channelRequest = qobject_cast<Tp::PendingChannelRequest*>(op); |
323 | + if (!channelRequest) { |
324 | + status = Failed; |
325 | + } else { |
326 | + setTextChannel(Tp::TextChannelPtr::dynamicCast(channelRequest->channelRequest()->channel())); |
327 | + status = Finished; |
328 | + } |
329 | + } |
330 | + |
331 | + setStatus(status); |
332 | + scheduleDeletion(); |
333 | +} |
334 | + |
335 | |
336 | === added file 'handler/chatstartingjob.h' |
337 | --- handler/chatstartingjob.h 1970-01-01 00:00:00 +0000 |
338 | +++ handler/chatstartingjob.h 2016-10-06 19:34:37 +0000 |
339 | @@ -0,0 +1,69 @@ |
340 | +/* |
341 | + * Copyright (C) 2016 Canonical, Ltd. |
342 | + * |
343 | + * Authors: |
344 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
345 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
346 | + * |
347 | + * This file is part of telephony-service. |
348 | + * |
349 | + * telephony-service is free software; you can redistribute it and/or modify |
350 | + * it under the terms of the GNU General Public License as published by |
351 | + * the Free Software Foundation; version 3. |
352 | + * |
353 | + * telephony-service is distributed in the hope that it will be useful, |
354 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
355 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
356 | + * GNU General Public License for more details. |
357 | + * |
358 | + * You should have received a copy of the GNU General Public License |
359 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
360 | + */ |
361 | + |
362 | +#ifndef CHATSTARTINGJOB_H |
363 | +#define CHATSTARTINGJOB_H |
364 | + |
365 | +#include <QObject> |
366 | +#include "messagejob.h" |
367 | +#include <TelepathyQt/Types> |
368 | +#include <TelepathyQt/PendingOperation> |
369 | + |
370 | +class TextHandler; |
371 | + |
372 | +class ChatStartingJob : public MessageJob |
373 | +{ |
374 | + Q_OBJECT |
375 | + Q_PROPERTY(QString accountId READ accountId CONSTANT) |
376 | + Q_PROPERTY(Tp::TextChannelPtr textChannel READ textChannel NOTIFY textChannelChanged) |
377 | + Q_PROPERTY(QString channelObjectPath READ channelObjectPath NOTIFY channelObjectPathChanged) |
378 | +public: |
379 | + ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties); |
380 | + |
381 | + QString accountId(); |
382 | + Tp::TextChannelPtr textChannel() const; |
383 | + QString channelObjectPath() const; |
384 | + |
385 | +public Q_SLOTS: |
386 | + virtual void startJob(); |
387 | + |
388 | +Q_SIGNALS: |
389 | + void textChannelChanged(); |
390 | + void channelObjectPathChanged(); |
391 | + |
392 | + |
393 | +protected Q_SLOTS: |
394 | + void startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties); |
395 | + void startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties); |
396 | + void setTextChannel(Tp::TextChannelPtr channel); |
397 | + |
398 | + void onChannelRequestFinished(Tp::PendingOperation *op); |
399 | + |
400 | +private: |
401 | + TextHandler *mTextHandler; |
402 | + QString mAccountId; |
403 | + QVariantMap mProperties; |
404 | + Tp::TextChannelPtr mTextChannel; |
405 | + |
406 | +}; |
407 | + |
408 | +#endif // CHATSTARTINGJOB_H |
409 | |
410 | === modified file 'handler/handlerdbus.cpp' |
411 | --- handler/handlerdbus.cpp 2016-10-06 19:34:36 +0000 |
412 | +++ handler/handlerdbus.cpp 2016-10-06 19:34:37 +0000 |
413 | @@ -81,6 +81,26 @@ |
414 | Q_EMIT CallIndicatorVisibleChanged(visible); |
415 | } |
416 | |
417 | +QString HandlerDBus::registerObject(QObject *object, const QString &path) |
418 | +{ |
419 | + QString fullPath = QString("%1/%2").arg(DBUS_OBJECT_PATH, path); |
420 | + if (QDBusConnection::sessionBus().registerObject(fullPath, object)) { |
421 | + return fullPath; |
422 | + } |
423 | + return QString::null; |
424 | +} |
425 | + |
426 | +void HandlerDBus::unregisterObject(const QString &path) |
427 | +{ |
428 | + QDBusConnection::sessionBus().unregisterObject(path); |
429 | +} |
430 | + |
431 | +HandlerDBus *HandlerDBus::instance() |
432 | +{ |
433 | + static HandlerDBus *self = new HandlerDBus; |
434 | + return self; |
435 | +} |
436 | + |
437 | bool HandlerDBus::connectToBus() |
438 | { |
439 | bool ok = QDBusConnection::sessionBus().registerService(DBUS_SERVICE); |
440 | @@ -103,9 +123,9 @@ |
441 | TextHandler::instance()->acknowledgeMessages(messages); |
442 | } |
443 | |
444 | -void HandlerDBus::StartChat(const QString &accountId, const QVariantMap &properties) |
445 | +QString HandlerDBus::StartChat(const QString &accountId, const QVariantMap &properties) |
446 | { |
447 | - TextHandler::instance()->startChat(accountId, properties); |
448 | + return TextHandler::instance()->startChat(accountId, properties); |
449 | } |
450 | |
451 | void HandlerDBus::AcknowledgeAllMessages(const QVariantMap &properties) |
452 | |
453 | === modified file 'handler/handlerdbus.h' |
454 | --- handler/handlerdbus.h 2016-10-06 19:34:36 +0000 |
455 | +++ handler/handlerdbus.h 2016-10-06 19:34:37 +0000 |
456 | @@ -30,7 +30,7 @@ |
457 | #include "dbustypes.h" |
458 | |
459 | /** |
460 | - * DBus interface for the phone approver |
461 | + * DBus interface for the phone handler |
462 | */ |
463 | class HandlerDBus : public QObject, protected QDBusContext |
464 | { |
465 | @@ -51,13 +51,18 @@ |
466 | bool callIndicatorVisible() const; |
467 | void setCallIndicatorVisible(bool visible); |
468 | |
469 | + QString registerObject(QObject *object, const QString &path); |
470 | + void unregisterObject(const QString &path); |
471 | + |
472 | + static HandlerDBus *instance(); |
473 | + |
474 | public Q_SLOTS: |
475 | bool connectToBus(); |
476 | |
477 | // messages related |
478 | QString SendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
479 | Q_NOREPLY void AcknowledgeMessages(const QVariantList &messages); |
480 | - Q_NOREPLY void StartChat(const QString &accountId, const QVariantMap &properties); |
481 | + QString StartChat(const QString &accountId, const QVariantMap &properties); |
482 | Q_NOREPLY void AcknowledgeAllMessages(const QVariantMap &properties); |
483 | |
484 | // call related |
485 | |
486 | === modified file 'handler/main.cpp' |
487 | --- handler/main.cpp 2016-03-18 19:02:50 +0000 |
488 | +++ handler/main.cpp 2016-10-06 19:34:37 +0000 |
489 | @@ -54,10 +54,8 @@ |
490 | QObject::connect(handler, SIGNAL(textChannelAvailable(Tp::TextChannelPtr)), |
491 | TextHandler::instance(), SLOT(onTextChannelAvailable(Tp::TextChannelPtr))); |
492 | |
493 | - HandlerDBus dbus; |
494 | - |
495 | QObject::connect(TelepathyHelper::instance(), SIGNAL(setupReady()), |
496 | - &dbus, SLOT(connectToBus())); |
497 | + HandlerDBus::instance(), SLOT(connectToBus())); |
498 | |
499 | return app.exec(); |
500 | } |
501 | |
502 | === added file 'handler/messagejob.cpp' |
503 | --- handler/messagejob.cpp 1970-01-01 00:00:00 +0000 |
504 | +++ handler/messagejob.cpp 2016-10-06 19:34:37 +0000 |
505 | @@ -0,0 +1,96 @@ |
506 | +/* |
507 | + * Copyright (C) 2016 Canonical, Ltd. |
508 | + * |
509 | + * Authors: |
510 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
511 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
512 | + * |
513 | + * This file is part of telephony-service. |
514 | + * |
515 | + * telephony-service is free software; you can redistribute it and/or modify |
516 | + * it under the terms of the GNU General Public License as published by |
517 | + * the Free Software Foundation; version 3. |
518 | + * |
519 | + * telephony-service is distributed in the hope that it will be useful, |
520 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
521 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
522 | + * GNU General Public License for more details. |
523 | + * |
524 | + * You should have received a copy of the GNU General Public License |
525 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
526 | + */ |
527 | + |
528 | +#include "messagejob.h" |
529 | +#include "handlerdbus.h" |
530 | +#include <QCoreApplication> |
531 | +#include <QTime> |
532 | +#include <QTimer> |
533 | +#include <QDebug> |
534 | + |
535 | +MessageJob::MessageJob(QDBusAbstractAdaptor *adaptor, QObject *parent) |
536 | +: QObject(parent), mStatus(Pending), mFinished(false), mAdaptor(adaptor) |
537 | +{ |
538 | + static ulong count = 0; |
539 | + // just to avoid overflowing |
540 | + if (count == ULONG_MAX) { |
541 | + count = 0; |
542 | + } |
543 | + mObjectPath = HandlerDBus::instance()->registerObject(this, QString("messagejob%1").arg(count++)); |
544 | +} |
545 | + |
546 | +MessageJob::~MessageJob() |
547 | +{ |
548 | + HandlerDBus::instance()->unregisterObject(mObjectPath); |
549 | +} |
550 | + |
551 | +MessageJob::Status MessageJob::status() const |
552 | +{ |
553 | + return mStatus; |
554 | +} |
555 | + |
556 | +bool MessageJob::isFinished() const |
557 | +{ |
558 | + return mFinished; |
559 | +} |
560 | + |
561 | +QString MessageJob::objectPath() const |
562 | +{ |
563 | + return mObjectPath; |
564 | +} |
565 | + |
566 | +void MessageJob::waitForFinished(int timeout) |
567 | +{ |
568 | + QTime time; |
569 | + time.start(); |
570 | + while (!mFinished && time.elapsed() < timeout) { |
571 | + QCoreApplication::processEvents(); |
572 | + } |
573 | +} |
574 | + |
575 | +void MessageJob::startJob() |
576 | +{ |
577 | + // the default implementation just sets the status to Finished |
578 | + setStatus(Finished); |
579 | +} |
580 | + |
581 | +void MessageJob::setStatus(MessageJob::Status status) |
582 | +{ |
583 | + mStatus = status; |
584 | + Q_EMIT statusChanged(); |
585 | + |
586 | + // update the isFinished property too |
587 | + bool wasFinished = mFinished; |
588 | + mFinished = mStatus == Finished || mStatus == Failed; |
589 | + if (wasFinished != mFinished) { |
590 | + Q_EMIT isFinishedChanged(); |
591 | + } |
592 | + if (mFinished) { |
593 | + Q_EMIT finished(); |
594 | + } |
595 | +} |
596 | + |
597 | +void MessageJob::scheduleDeletion(int timeout) |
598 | +{ |
599 | + QTimer::singleShot(timeout, this, &QObject::deleteLater); |
600 | +} |
601 | + |
602 | |
603 | === added file 'handler/messagejob.h' |
604 | --- handler/messagejob.h 1970-01-01 00:00:00 +0000 |
605 | +++ handler/messagejob.h 2016-10-06 19:34:37 +0000 |
606 | @@ -0,0 +1,75 @@ |
607 | +/* |
608 | + * Copyright (C) 2016 Canonical, Ltd. |
609 | + * |
610 | + * Authors: |
611 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
612 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
613 | + * |
614 | + * This file is part of telephony-service. |
615 | + * |
616 | + * telephony-service is free software; you can redistribute it and/or modify |
617 | + * it under the terms of the GNU General Public License as published by |
618 | + * the Free Software Foundation; version 3. |
619 | + * |
620 | + * telephony-service is distributed in the hope that it will be useful, |
621 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
622 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
623 | + * GNU General Public License for more details. |
624 | + * |
625 | + * You should have received a copy of the GNU General Public License |
626 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
627 | + */ |
628 | + |
629 | +#ifndef MESSAGEJOB_H |
630 | +#define MESSAGEJOB_H |
631 | + |
632 | +#include <QObject> |
633 | +#include <QDBusAbstractAdaptor> |
634 | +#include <QDBusContext> |
635 | + |
636 | +class MessageJob : public QObject, protected QDBusContext |
637 | +{ |
638 | + Q_OBJECT |
639 | + Q_PROPERTY(int status READ status NOTIFY statusChanged) |
640 | + Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged) |
641 | + Q_PROPERTY(QString objectPath READ objectPath CONSTANT) |
642 | + Q_ENUMS(Status) |
643 | +public: |
644 | + enum Status { |
645 | + Pending, |
646 | + Initialising, |
647 | + Running, |
648 | + Finished, |
649 | + Failed |
650 | + }; |
651 | + |
652 | + explicit MessageJob(QDBusAbstractAdaptor *adaptor, QObject *parent = 0); |
653 | + virtual ~MessageJob(); |
654 | + |
655 | + Status status() const; |
656 | + bool isFinished() const; |
657 | + |
658 | + QString objectPath() const; |
659 | + |
660 | + void waitForFinished(int timeout = 10000); |
661 | + |
662 | +Q_SIGNALS: |
663 | + void statusChanged(); |
664 | + void isFinishedChanged(); |
665 | + void finished(); |
666 | + |
667 | +public Q_SLOTS: |
668 | + virtual void startJob(); |
669 | + |
670 | +protected: |
671 | + void setStatus(Status status); |
672 | + void scheduleDeletion(int timeout = 60000); |
673 | + |
674 | +private: |
675 | + Status mStatus; |
676 | + bool mFinished; |
677 | + QString mObjectPath; |
678 | + QDBusAbstractAdaptor *mAdaptor; |
679 | +}; |
680 | + |
681 | +#endif // MESSAGEJOB_H |
682 | |
683 | === added file 'handler/messagesendingjob.cpp' |
684 | --- handler/messagesendingjob.cpp 1970-01-01 00:00:00 +0000 |
685 | +++ handler/messagesendingjob.cpp 2016-10-06 19:34:37 +0000 |
686 | @@ -0,0 +1,390 @@ |
687 | +/* |
688 | + * Copyright (C) 2016 Canonical, Ltd. |
689 | + * |
690 | + * Authors: |
691 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
692 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
693 | + * |
694 | + * This file is part of telephony-service. |
695 | + * |
696 | + * telephony-service is free software; you can redistribute it and/or modify |
697 | + * it under the terms of the GNU General Public License as published by |
698 | + * the Free Software Foundation; version 3. |
699 | + * |
700 | + * telephony-service is distributed in the hope that it will be useful, |
701 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
702 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
703 | + * GNU General Public License for more details. |
704 | + * |
705 | + * You should have received a copy of the GNU General Public License |
706 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
707 | + */ |
708 | + |
709 | +#include "accountentry.h" |
710 | +#include "chatstartingjob.h" |
711 | +#include "messagesendingjob.h" |
712 | +#include "messagesendingjobadaptor.h" |
713 | +#include "telepathyhelper.h" |
714 | +#include "texthandler.h" |
715 | +#include <TelepathyQt/ContactManager> |
716 | +#include <TelepathyQt/PendingContacts> |
717 | +#include <QImage> |
718 | + |
719 | +#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />" |
720 | +#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
721 | +#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
722 | +#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
723 | +#define SMIL_TEXT_PART "<par dur=\"3s\">\ |
724 | + <text src=\"cid:%1\" region=\"Text\" />\ |
725 | + </par>" |
726 | +#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\ |
727 | + <img src=\"cid:%1\" region=\"Image\" />\ |
728 | + </par>" |
729 | +#define SMIL_VIDEO_PART "<par>\ |
730 | + <video src=\"cid:%1\" region=\"Video\" />\ |
731 | + </par>" |
732 | +#define SMIL_AUDIO_PART "<par>\ |
733 | + <audio src=\"cid:%1\" region=\"Audio\" />\ |
734 | + </par>" |
735 | + |
736 | +#define SMIL_FILE "<smil>\ |
737 | + <head>\ |
738 | + <layout>\ |
739 | + %1\ |
740 | + </layout>\ |
741 | + </head>\ |
742 | + <body>\ |
743 | + %2\ |
744 | + </body>\ |
745 | + </smil>" |
746 | + |
747 | +MessageSendingJob::MessageSendingJob(TextHandler *textHandler, PendingMessage message) |
748 | +: MessageJob(new MessageSendingJobAdaptor(this), textHandler), mTextHandler(textHandler), mMessage(message), mFinished(false) |
749 | +{ |
750 | +} |
751 | + |
752 | +MessageSendingJob::~MessageSendingJob() |
753 | +{ |
754 | + qDebug() << __PRETTY_FUNCTION__; |
755 | +} |
756 | + |
757 | +QString MessageSendingJob::accountId() const |
758 | +{ |
759 | + qDebug() << __PRETTY_FUNCTION__; |
760 | + return mAccountId; |
761 | +} |
762 | + |
763 | +QString MessageSendingJob::messageId() const |
764 | +{ |
765 | + return mMessageId; |
766 | +} |
767 | + |
768 | +QString MessageSendingJob::channelObjectPath() const |
769 | +{ |
770 | + qDebug() << __PRETTY_FUNCTION__; |
771 | + return mChannelObjectPath; |
772 | +} |
773 | + |
774 | +QVariantMap MessageSendingJob::properties() const |
775 | +{ |
776 | + return mMessage.properties; |
777 | +} |
778 | + |
779 | +void MessageSendingJob::startJob() |
780 | +{ |
781 | + qDebug() << __PRETTY_FUNCTION__; |
782 | + qDebug() << "Getting account for id:" << mMessage.accountId; |
783 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(mMessage.accountId); |
784 | + if (!account) { |
785 | + setStatus(Failed); |
786 | + scheduleDeletion(); |
787 | + } |
788 | + |
789 | + setStatus(Running); |
790 | + |
791 | + // check if the message should be sent via multimedia account |
792 | + // we just use fallback to 1-1 chats |
793 | + if (account->type() == AccountEntry::PhoneAccount) { |
794 | + Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) { |
795 | + // TODO: we have to find the multimedia account that matches the same phone number, |
796 | + // but for now we just pick any multimedia connected account |
797 | + if (newAccount->type() != AccountEntry::MultimediaAccount) { |
798 | + continue; |
799 | + } |
800 | + // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of |
801 | + // accounts. Also, it needs to check connection capabilities to determine if we can send message |
802 | + // to offline contacts. |
803 | + bool shouldFallback = true; |
804 | + // if the account is offline, dont fallback to this account |
805 | + if (!newAccount->connected()) { |
806 | + continue; |
807 | + } |
808 | + QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(newAccount->accountId(), mMessage.properties); |
809 | + // check if we have a channel for this contact already and get the contact pointer from there, |
810 | + // this way we avoid doing the while(op->isFinished()) all the time |
811 | + if (!channels.isEmpty()) { |
812 | + // FIXME: we need to re-evaluate the rules to fallback |
813 | + // if the contact is known, force fallback to this account |
814 | + Q_FOREACH(const Tp::ContactPtr &contact, channels.first()->groupContacts(false)) { |
815 | + Tp::Presence presence = contact->presence(); |
816 | + shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
817 | + presence.type() == Tp::ConnectionPresenceTypeOffline); |
818 | + if (!shouldFallback) { |
819 | + break; |
820 | + } |
821 | + } |
822 | + } else { |
823 | + QStringList participantIds = mMessage.properties["participantIds"].toStringList(); |
824 | + Tp::PendingContacts *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(participantIds); |
825 | + while (!op->isFinished()) { |
826 | + qApp->processEvents(); |
827 | + } |
828 | + Q_FOREACH(const Tp::ContactPtr &contact, op->contacts()) { |
829 | + Tp::Presence presence = contact->presence(); |
830 | + shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
831 | + presence.type() == Tp::ConnectionPresenceTypeOffline); |
832 | + if (!shouldFallback) { |
833 | + break; |
834 | + } |
835 | + } |
836 | + } |
837 | + if (shouldFallback) { |
838 | + account = newAccount; |
839 | + break; |
840 | + } |
841 | + } |
842 | + } |
843 | + |
844 | + // save the account |
845 | + mAccount = account; |
846 | + setAccountId(mAccount->accountId()); |
847 | + |
848 | + if (!account->connected()) { |
849 | + connect(account, &AccountEntry::connectedChanged, [this, account]() { |
850 | + if (account->connected()) { |
851 | + findOrCreateChannel(); |
852 | + } |
853 | + }); |
854 | + return; |
855 | + } |
856 | + |
857 | + findOrCreateChannel(); |
858 | +} |
859 | + |
860 | +void MessageSendingJob::findOrCreateChannel() |
861 | +{ |
862 | + qDebug() << __PRETTY_FUNCTION__; |
863 | + // now that we know what account to use, find existing channels or request a new one |
864 | + QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(mAccount->accountId(), mMessage.properties); |
865 | + if (channels.isEmpty()) { |
866 | + ChatStartingJob *job = new ChatStartingJob(mTextHandler, mAccount->accountId(), mMessage.properties); |
867 | + connect(job, &MessageJob::finished, [this, job]() { |
868 | + if (job->status() == MessageJob::Failed) { |
869 | + setStatus(Failed); |
870 | + scheduleDeletion(); |
871 | + return; |
872 | + } |
873 | + |
874 | + mTextChannel = job->textChannel(); |
875 | + sendMessage(); |
876 | + }); |
877 | + job->startJob(); |
878 | + return; |
879 | + } |
880 | + |
881 | + mTextChannel = channels.last(); |
882 | + sendMessage(); |
883 | +} |
884 | + |
885 | +void MessageSendingJob::sendMessage() |
886 | +{ |
887 | + qDebug() << __PRETTY_FUNCTION__; |
888 | + Tp::PendingSendMessage *op = mTextChannel->send(buildMessage(mMessage)); |
889 | + connect(op, &Tp::PendingOperation::finished, [this, op]() { |
890 | + if (op->isError()) { |
891 | + setStatus(Failed); |
892 | + scheduleDeletion(); |
893 | + return; |
894 | + } |
895 | + |
896 | + setChannelObjectPath(mTextChannel->objectPath()); |
897 | + setMessageId(op->sentMessageToken()); |
898 | + setStatus(Finished); |
899 | + scheduleDeletion(); |
900 | + }); |
901 | +} |
902 | + |
903 | +void MessageSendingJob::setAccountId(const QString &accountId) |
904 | +{ |
905 | + qDebug() << __PRETTY_FUNCTION__; |
906 | + mAccountId = accountId; |
907 | + Q_EMIT accountIdChanged(); |
908 | +} |
909 | + |
910 | +void MessageSendingJob::setChannelObjectPath(const QString &objectPath) |
911 | +{ |
912 | + qDebug() << __PRETTY_FUNCTION__; |
913 | + mChannelObjectPath = objectPath; |
914 | + Q_EMIT channelObjectPathChanged(); |
915 | +} |
916 | + |
917 | +void MessageSendingJob::setMessageId(const QString &id) |
918 | +{ |
919 | + mMessageId = id; |
920 | + Q_EMIT messageIdChanged(); |
921 | +} |
922 | + |
923 | +Tp::MessagePartList MessageSendingJob::buildMessage(const PendingMessage &pendingMessage) |
924 | +{ |
925 | + qDebug() << __PRETTY_FUNCTION__; |
926 | + Tp::MessagePartList message; |
927 | + Tp::MessagePart header; |
928 | + QString smil, regions, parts; |
929 | + bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false; |
930 | + |
931 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId); |
932 | + if (!account) { |
933 | + // account does not exist |
934 | + return Tp::MessagePartList(); |
935 | + } |
936 | + |
937 | + bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") && |
938 | + pendingMessage.properties["x-canonical-tmp-files"].toBool()); |
939 | + |
940 | + // add the remaining properties to the message header |
941 | + QVariantMap::const_iterator it = pendingMessage.properties.begin(); |
942 | + for (; it != pendingMessage.properties.end(); ++it) { |
943 | + header[it.key()] = QDBusVariant(it.value()); |
944 | + } |
945 | + |
946 | + // check if this message should be sent as an MMS |
947 | + if (account->type() == AccountEntry::PhoneAccount) { |
948 | + isMMS = (pendingMessage.attachments.size() > 0 || |
949 | + (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) || |
950 | + (pendingMessage.properties["participantIds"].toStringList().size() > 1 && TelepathyHelper::instance()->mmsGroupChat())); |
951 | + if (isMMS) { |
952 | + header["x-canonical-mms"] = QDBusVariant(true); |
953 | + } |
954 | + } |
955 | + |
956 | + // this flag should not be in the message header, it's only useful for the handler |
957 | + header.remove("x-canonical-tmp-files"); |
958 | + header.remove("chatType"); |
959 | + header.remove("threadId"); |
960 | + header.remove("participantIds"); |
961 | + |
962 | + header["message-type"] = QDBusVariant(0); |
963 | + message << header; |
964 | + |
965 | + // convert AttachmentList struct into telepathy Message parts |
966 | + Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) { |
967 | + QByteArray fileData; |
968 | + QString newFilePath = QString(attachment.filePath).replace("file://", ""); |
969 | + QFile attachmentFile(newFilePath); |
970 | + if (!attachmentFile.open(QIODevice::ReadOnly)) { |
971 | + qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath; |
972 | + continue; |
973 | + } |
974 | + if (attachment.contentType.startsWith("image/")) { |
975 | + if (isMMS) { |
976 | + hasImage = true; |
977 | + parts += QString(SMIL_IMAGE_PART).arg(attachment.id); |
978 | + // check if we need to reduce de image size in case it's bigger than 300k |
979 | + // this check is only valid for MMS |
980 | + if (attachmentFile.size() > 307200) { |
981 | + QImage scaledImage(newFilePath); |
982 | + if (!scaledImage.isNull()) { |
983 | + QBuffer buffer(&fileData); |
984 | + buffer.open(QIODevice::WriteOnly); |
985 | + scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg"); |
986 | + } |
987 | + } else { |
988 | + fileData = attachmentFile.readAll(); |
989 | + } |
990 | + } |
991 | + } else if (attachment.contentType.startsWith("video/")) { |
992 | + if (isMMS) { |
993 | + hasVideo = true; |
994 | + parts += QString(SMIL_VIDEO_PART).arg(attachment.id); |
995 | + } |
996 | + } else if (attachment.contentType.startsWith("audio/")) { |
997 | + if (isMMS) { |
998 | + hasAudio = true; |
999 | + parts += QString(SMIL_AUDIO_PART).arg(attachment.id); |
1000 | + } |
1001 | + } else if (attachment.contentType.startsWith("text/plain")) { |
1002 | + if (isMMS) { |
1003 | + hasText = true; |
1004 | + parts += QString(SMIL_TEXT_PART).arg(attachment.id); |
1005 | + } |
1006 | + } else if (attachment.contentType.startsWith("text/vcard") || |
1007 | + attachment.contentType.startsWith("text/x-vcard")) { |
1008 | + } else if (isMMS) { |
1009 | + // for MMS we just support the contentTypes above |
1010 | + if (temporaryFiles) { |
1011 | + attachmentFile.remove(); |
1012 | + } |
1013 | + continue; |
1014 | + } |
1015 | + |
1016 | + if (fileData.isEmpty()) { |
1017 | + fileData = attachmentFile.readAll(); |
1018 | + } |
1019 | + |
1020 | + if (temporaryFiles) { |
1021 | + attachmentFile.remove(); |
1022 | + } |
1023 | + |
1024 | + if (hasVideo) { |
1025 | + regions += QString(SMIL_VIDEO_REGION); |
1026 | + } |
1027 | + |
1028 | + if (hasAudio) { |
1029 | + regions += QString(SMIL_AUDIO_REGION); |
1030 | + } |
1031 | + |
1032 | + if (hasText) { |
1033 | + regions += QString(SMIL_TEXT_REGION); |
1034 | + } |
1035 | + if (hasImage) { |
1036 | + regions += QString(SMIL_IMAGE_REGION); |
1037 | + } |
1038 | + |
1039 | + Tp::MessagePart part; |
1040 | + part["content-type"] = QDBusVariant(attachment.contentType); |
1041 | + part["identifier"] = QDBusVariant(attachment.id); |
1042 | + part["content"] = QDBusVariant(fileData); |
1043 | + part["size"] = QDBusVariant(fileData.size()); |
1044 | + |
1045 | + message << part; |
1046 | + } |
1047 | + |
1048 | + if (!pendingMessage.message.isEmpty()) { |
1049 | + Tp::MessagePart part; |
1050 | + QString tmpTextId("text_0.txt"); |
1051 | + part["content-type"] = QDBusVariant(QString("text/plain")); |
1052 | + part["identifier"] = QDBusVariant(tmpTextId); |
1053 | + part["content"] = QDBusVariant(pendingMessage.message); |
1054 | + part["size"] = QDBusVariant(pendingMessage.message.size()); |
1055 | + if (isMMS) { |
1056 | + parts += QString(SMIL_TEXT_PART).arg(tmpTextId); |
1057 | + regions += QString(SMIL_TEXT_REGION); |
1058 | + } |
1059 | + message << part; |
1060 | + } |
1061 | + |
1062 | + if (isMMS) { |
1063 | + Tp::MessagePart smilPart; |
1064 | + smil = QString(SMIL_FILE).arg(regions).arg(parts); |
1065 | + smilPart["content-type"] = QDBusVariant(QString("application/smil")); |
1066 | + smilPart["identifier"] = QDBusVariant(QString("smil.xml")); |
1067 | + smilPart["content"] = QDBusVariant(smil); |
1068 | + smilPart["size"] = QDBusVariant(smil.size()); |
1069 | + |
1070 | + message << smilPart; |
1071 | + } |
1072 | + |
1073 | + return message; |
1074 | +} |
1075 | + |
1076 | + |
1077 | |
1078 | === added file 'handler/messagesendingjob.h' |
1079 | --- handler/messagesendingjob.h 1970-01-01 00:00:00 +0000 |
1080 | +++ handler/messagesendingjob.h 2016-10-06 19:34:37 +0000 |
1081 | @@ -0,0 +1,90 @@ |
1082 | +/* |
1083 | + * Copyright (C) 2016 Canonical, Ltd. |
1084 | + * |
1085 | + * Authors: |
1086 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
1087 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
1088 | + * |
1089 | + * This file is part of telephony-service. |
1090 | + * |
1091 | + * telephony-service is free software; you can redistribute it and/or modify |
1092 | + * it under the terms of the GNU General Public License as published by |
1093 | + * the Free Software Foundation; version 3. |
1094 | + * |
1095 | + * telephony-service is distributed in the hope that it will be useful, |
1096 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1097 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1098 | + * GNU General Public License for more details. |
1099 | + * |
1100 | + * You should have received a copy of the GNU General Public License |
1101 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1102 | + */ |
1103 | + |
1104 | +#ifndef MESSAGESENDINGJOB_H |
1105 | +#define MESSAGESENDINGJOB_H |
1106 | + |
1107 | +#include <QObject> |
1108 | +#include <TelepathyQt/Types> |
1109 | +#include "dbustypes.h" |
1110 | +#include "messagejob.h" |
1111 | + |
1112 | +class AccountEntry; |
1113 | +class TextHandler; |
1114 | +class MessageSendingJobAdaptor; |
1115 | + |
1116 | +struct PendingMessage { |
1117 | + QString accountId; |
1118 | + QString message; |
1119 | + AttachmentList attachments; |
1120 | + QVariantMap properties; |
1121 | +}; |
1122 | +Q_DECLARE_METATYPE(PendingMessage) |
1123 | + |
1124 | +class MessageSendingJob : public MessageJob |
1125 | +{ |
1126 | + Q_OBJECT |
1127 | + Q_PROPERTY(QString accountId READ accountId NOTIFY accountIdChanged) |
1128 | + Q_PROPERTY(QString messageId READ messageId NOTIFY messageIdChanged) |
1129 | + Q_PROPERTY(QString channelObjectPath READ channelObjectPath NOTIFY channelObjectPathChanged) |
1130 | + Q_PROPERTY(QVariantMap properties READ properties CONSTANT) |
1131 | + |
1132 | +public: |
1133 | + explicit MessageSendingJob(TextHandler *textHandler, PendingMessage message); |
1134 | + ~MessageSendingJob(); |
1135 | + |
1136 | + QString accountId() const; |
1137 | + QString messageId() const; |
1138 | + QString channelObjectPath() const; |
1139 | + QVariantMap properties() const; |
1140 | + |
1141 | +Q_SIGNALS: |
1142 | + void accountIdChanged(); |
1143 | + void messageIdChanged(); |
1144 | + void channelObjectPathChanged(); |
1145 | + |
1146 | +public Q_SLOTS: |
1147 | + void startJob(); |
1148 | + |
1149 | +protected Q_SLOTS: |
1150 | + void findOrCreateChannel(); |
1151 | + void sendMessage(); |
1152 | + |
1153 | + void setAccountId(const QString &accountId); |
1154 | + void setChannelObjectPath(const QString &objectPath); |
1155 | + void setMessageId(const QString &id); |
1156 | + |
1157 | +private: |
1158 | + TextHandler *mTextHandler; |
1159 | + PendingMessage mMessage; |
1160 | + QString mAccountId; |
1161 | + QString mMessageId; |
1162 | + AccountEntry *mAccount; |
1163 | + QString mChannelObjectPath; |
1164 | + Tp::TextChannelPtr mTextChannel; |
1165 | + bool mFinished; |
1166 | + |
1167 | + Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage); |
1168 | + |
1169 | +}; |
1170 | + |
1171 | +#endif // MESSAGESENDINGJOB_H |
1172 | |
1173 | === modified file 'handler/texthandler.cpp' |
1174 | --- handler/texthandler.cpp 2016-10-06 19:34:36 +0000 |
1175 | +++ handler/texthandler.cpp 2016-10-06 19:34:37 +0000 |
1176 | @@ -26,87 +26,19 @@ |
1177 | #include "config.h" |
1178 | #include "dbustypes.h" |
1179 | #include "accountentry.h" |
1180 | +#include "chatstartingjob.h" |
1181 | |
1182 | #include <QImage> |
1183 | #include <TelepathyQt/ContactManager> |
1184 | #include <TelepathyQt/PendingContacts> |
1185 | #include <TelepathyQt/PendingChannelRequest> |
1186 | |
1187 | -#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />" |
1188 | -#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1189 | -#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1190 | -#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1191 | -#define SMIL_TEXT_PART "<par dur=\"3s\">\ |
1192 | - <text src=\"cid:%1\" region=\"Text\" />\ |
1193 | - </par>" |
1194 | -#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\ |
1195 | - <img src=\"cid:%1\" region=\"Image\" />\ |
1196 | - </par>" |
1197 | -#define SMIL_VIDEO_PART "<par>\ |
1198 | - <video src=\"cid:%1\" region=\"Video\" />\ |
1199 | - </par>" |
1200 | -#define SMIL_AUDIO_PART "<par>\ |
1201 | - <audio src=\"cid:%1\" region=\"Audio\" />\ |
1202 | - </par>" |
1203 | - |
1204 | -#define SMIL_FILE "<smil>\ |
1205 | - <head>\ |
1206 | - <layout>\ |
1207 | - %1\ |
1208 | - </layout>\ |
1209 | - </head>\ |
1210 | - <body>\ |
1211 | - %2\ |
1212 | - </body>\ |
1213 | - </smil>" |
1214 | - |
1215 | TextHandler::TextHandler(QObject *parent) |
1216 | : QObject(parent) |
1217 | { |
1218 | qDBusRegisterMetaType<AttachmentStruct>(); |
1219 | qDBusRegisterMetaType<AttachmentList>(); |
1220 | qRegisterMetaType<PendingMessage>(); |
1221 | - |
1222 | - // track when the account becomes available |
1223 | - connect(TelepathyHelper::instance(), |
1224 | - SIGNAL(setupReady()), |
1225 | - SLOT(onConnectedChanged())); |
1226 | -} |
1227 | - |
1228 | -void TextHandler::onConnectedChanged() |
1229 | -{ |
1230 | - if (!TelepathyHelper::instance()->ready()) { |
1231 | - return; |
1232 | - } |
1233 | - |
1234 | - // now check which accounts are connected |
1235 | - Q_FOREACH(AccountEntry *account, TelepathyHelper::instance()->accounts()) { |
1236 | - QString accountId = account->accountId(); |
1237 | - if (!account->connected()) { |
1238 | - continue; |
1239 | - } |
1240 | - |
1241 | - // create text channels to send the pending messages |
1242 | - QList<QStringList> recipientsList; |
1243 | - Q_FOREACH(const PendingMessage &pendingMessage, mPendingMessages) { |
1244 | - if (accountId != pendingMessage.accountId) { |
1245 | - continue; |
1246 | - } |
1247 | - bool found = false; |
1248 | - // avoid adding twice the same list of participants |
1249 | -/* Q_FOREACH(const QStringList &recipients, recipientsList) { |
1250 | - if (recipients == pendingMessage.recipients) { |
1251 | - found = true; |
1252 | - break; |
1253 | - } |
1254 | - } |
1255 | - if (!found) { |
1256 | - recipientsList << pendingMessage.recipients; |
1257 | - }*/ |
1258 | - // TODO AVOID CALLING TWICE FOR SAME CHANNEL |
1259 | - startChat(accountId, pendingMessage.properties); |
1260 | - } |
1261 | - } |
1262 | } |
1263 | |
1264 | TextHandler *TextHandler::instance() |
1265 | @@ -115,344 +47,20 @@ |
1266 | return handler; |
1267 | } |
1268 | |
1269 | -void TextHandler::startChat(const QString &accountId, const QVariantMap &properties) |
1270 | -{ |
1271 | - // Request the contact to start chatting to |
1272 | - // FIXME: make it possible to select which account to use, for now, pick the first one |
1273 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
1274 | - if (!account || !account->connected()) { |
1275 | - qCritical() << "The selected account does not have a connection. AccountId:" << accountId; |
1276 | - return; |
1277 | - } |
1278 | - |
1279 | - switch(properties["chatType"].toUInt()) { |
1280 | - case Tp::HandleTypeNone: |
1281 | - case Tp::HandleTypeContact: |
1282 | - startTextChat(account->account(), properties); |
1283 | - break; |
1284 | - case Tp::HandleTypeRoom: |
1285 | - startTextChatroom(account->account(), properties); |
1286 | - break; |
1287 | - default: |
1288 | - qCritical() << "Chat type not supported"; |
1289 | - } |
1290 | -} |
1291 | - |
1292 | -void TextHandler::startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties) |
1293 | -{ |
1294 | - QStringList participants = properties["participantIds"].toStringList(); |
1295 | - switch(participants.size()) { |
1296 | - case 0: |
1297 | - qCritical() << "Error: No participant list provided"; |
1298 | - break; |
1299 | - case 1: |
1300 | - account->ensureTextChat(participants[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
1301 | - break; |
1302 | - default: |
1303 | - account->createConferenceTextChat(QList<Tp::ChannelPtr>(), participants, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
1304 | - } |
1305 | -} |
1306 | - |
1307 | -Tp::TextChannelPtr TextHandler::startTextChatroom(const Tp::AccountPtr &account, const QVariantMap &properties) |
1308 | -{ |
1309 | - QString roomName = properties["threadId"].toString(); |
1310 | - |
1311 | - // these properties are still not used |
1312 | - //QString server = properties["Server"].toString(); |
1313 | - //QString creator = properties["Creator"].toString(); |
1314 | - |
1315 | - QVariantMap request; |
1316 | - Tp::PendingChannelRequest *op = NULL; |
1317 | - if (roomName.isEmpty()) { |
1318 | - request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); |
1319 | - request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeNone); |
1320 | - QStringList initialInviteeIDs = properties["participantIds"].toStringList(); |
1321 | - if (!initialInviteeIDs.isEmpty()) { |
1322 | - request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"), initialInviteeIDs); |
1323 | - } |
1324 | - // the presence of RoomName indicates the returned channel must be of type Room |
1325 | - request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"), QString()); |
1326 | - |
1327 | - // TODO use the instance returned by createChanne() to track when the channel creation is finished |
1328 | - op = account->createChannel(request, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
1329 | - } else { |
1330 | - |
1331 | - op = account->ensureTextChatroom(roomName, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler", request); |
1332 | - } |
1333 | - |
1334 | - if (!op) { |
1335 | - return Tp::TextChannelPtr(); |
1336 | - } |
1337 | - while (!op->isFinished()) { |
1338 | - qApp->processEvents(); |
1339 | - } |
1340 | - Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(op->channelRequest()->channel().data())); |
1341 | - return textChannel; |
1342 | -} |
1343 | - |
1344 | -Tp::MessagePartList TextHandler::buildMessage(const PendingMessage &pendingMessage) |
1345 | -{ |
1346 | - Tp::MessagePartList message; |
1347 | - Tp::MessagePart header; |
1348 | - QString smil, regions, parts; |
1349 | - bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false; |
1350 | - |
1351 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId); |
1352 | - if (!account) { |
1353 | - // account does not exist |
1354 | - return Tp::MessagePartList(); |
1355 | - } |
1356 | - |
1357 | - bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") && |
1358 | - pendingMessage.properties["x-canonical-tmp-files"].toBool()); |
1359 | - |
1360 | - // add the remaining properties to the message header |
1361 | - QVariantMap::const_iterator it = pendingMessage.properties.begin(); |
1362 | - for (; it != pendingMessage.properties.end(); ++it) { |
1363 | - header[it.key()] = QDBusVariant(it.value()); |
1364 | - } |
1365 | - |
1366 | - // check if this message should be sent as an MMS |
1367 | - if (account->type() == AccountEntry::PhoneAccount) { |
1368 | - isMMS = (pendingMessage.attachments.size() > 0 || |
1369 | - (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) || |
1370 | - (pendingMessage.properties["participantIds"].toStringList().size() > 1 && TelepathyHelper::instance()->mmsGroupChat())); |
1371 | - if (isMMS) { |
1372 | - header["x-canonical-mms"] = QDBusVariant(true); |
1373 | - } |
1374 | - } |
1375 | - |
1376 | - // this flag should not be in the message header, it's only useful for the handler |
1377 | - header.remove("x-canonical-tmp-files"); |
1378 | - header.remove("chatType"); |
1379 | - header.remove("threadId"); |
1380 | - header.remove("participantIds"); |
1381 | - |
1382 | - header["message-type"] = QDBusVariant(0); |
1383 | - message << header; |
1384 | - |
1385 | - // convert AttachmentList struct into telepathy Message parts |
1386 | - Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) { |
1387 | - QByteArray fileData; |
1388 | - QString newFilePath = QString(attachment.filePath).replace("file://", ""); |
1389 | - QFile attachmentFile(newFilePath); |
1390 | - if (!attachmentFile.open(QIODevice::ReadOnly)) { |
1391 | - qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath; |
1392 | - continue; |
1393 | - } |
1394 | - if (attachment.contentType.startsWith("image/")) { |
1395 | - if (isMMS) { |
1396 | - hasImage = true; |
1397 | - parts += QString(SMIL_IMAGE_PART).arg(attachment.id); |
1398 | - // check if we need to reduce de image size in case it's bigger than 300k |
1399 | - // this check is only valid for MMS |
1400 | - if (attachmentFile.size() > 307200) { |
1401 | - QImage scaledImage(newFilePath); |
1402 | - if (!scaledImage.isNull()) { |
1403 | - QBuffer buffer(&fileData); |
1404 | - buffer.open(QIODevice::WriteOnly); |
1405 | - scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg"); |
1406 | - } |
1407 | - } else { |
1408 | - fileData = attachmentFile.readAll(); |
1409 | - } |
1410 | - } |
1411 | - } else if (attachment.contentType.startsWith("video/")) { |
1412 | - if (isMMS) { |
1413 | - hasVideo = true; |
1414 | - parts += QString(SMIL_VIDEO_PART).arg(attachment.id); |
1415 | - } |
1416 | - } else if (attachment.contentType.startsWith("audio/")) { |
1417 | - if (isMMS) { |
1418 | - hasAudio = true; |
1419 | - parts += QString(SMIL_AUDIO_PART).arg(attachment.id); |
1420 | - } |
1421 | - } else if (attachment.contentType.startsWith("text/plain")) { |
1422 | - if (isMMS) { |
1423 | - hasText = true; |
1424 | - parts += QString(SMIL_TEXT_PART).arg(attachment.id); |
1425 | - } |
1426 | - } else if (attachment.contentType.startsWith("text/vcard") || |
1427 | - attachment.contentType.startsWith("text/x-vcard")) { |
1428 | - } else if (isMMS) { |
1429 | - // for MMS we just support the contentTypes above |
1430 | - if (temporaryFiles) { |
1431 | - attachmentFile.remove(); |
1432 | - } |
1433 | - continue; |
1434 | - } |
1435 | - |
1436 | - if (fileData.isEmpty()) { |
1437 | - fileData = attachmentFile.readAll(); |
1438 | - } |
1439 | - |
1440 | - if (temporaryFiles) { |
1441 | - attachmentFile.remove(); |
1442 | - } |
1443 | - |
1444 | - if (hasVideo) { |
1445 | - regions += QString(SMIL_VIDEO_REGION); |
1446 | - } |
1447 | - |
1448 | - if (hasAudio) { |
1449 | - regions += QString(SMIL_AUDIO_REGION); |
1450 | - } |
1451 | - |
1452 | - if (hasText) { |
1453 | - regions += QString(SMIL_TEXT_REGION); |
1454 | - } |
1455 | - if (hasImage) { |
1456 | - regions += QString(SMIL_IMAGE_REGION); |
1457 | - } |
1458 | - |
1459 | - Tp::MessagePart part; |
1460 | - part["content-type"] = QDBusVariant(attachment.contentType); |
1461 | - part["identifier"] = QDBusVariant(attachment.id); |
1462 | - part["content"] = QDBusVariant(fileData); |
1463 | - part["size"] = QDBusVariant(fileData.size()); |
1464 | - |
1465 | - message << part; |
1466 | - } |
1467 | - |
1468 | - if (!pendingMessage.message.isEmpty()) { |
1469 | - Tp::MessagePart part; |
1470 | - QString tmpTextId("text_0.txt"); |
1471 | - part["content-type"] = QDBusVariant(QString("text/plain")); |
1472 | - part["identifier"] = QDBusVariant(tmpTextId); |
1473 | - part["content"] = QDBusVariant(pendingMessage.message); |
1474 | - part["size"] = QDBusVariant(pendingMessage.message.size()); |
1475 | - if (isMMS) { |
1476 | - parts += QString(SMIL_TEXT_PART).arg(tmpTextId); |
1477 | - regions += QString(SMIL_TEXT_REGION); |
1478 | - } |
1479 | - message << part; |
1480 | - } |
1481 | - |
1482 | - if (isMMS) { |
1483 | - Tp::MessagePart smilPart; |
1484 | - smil = QString(SMIL_FILE).arg(regions).arg(parts); |
1485 | - smilPart["content-type"] = QDBusVariant(QString("application/smil")); |
1486 | - smilPart["identifier"] = QDBusVariant(QString("smil.xml")); |
1487 | - smilPart["content"] = QDBusVariant(smil); |
1488 | - smilPart["size"] = QDBusVariant(smil.size()); |
1489 | - |
1490 | - message << smilPart; |
1491 | - } |
1492 | - |
1493 | - return message; |
1494 | +QString TextHandler::startChat(const QString &accountId, const QVariantMap &properties) |
1495 | +{ |
1496 | + ChatStartingJob *job = new ChatStartingJob(this, accountId, properties); |
1497 | + job->startJob(); |
1498 | + return job->objectPath(); |
1499 | } |
1500 | |
1501 | QString TextHandler::sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
1502 | { |
1503 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
1504 | - if (!account) { |
1505 | - // account does not exist |
1506 | - return QString(); |
1507 | - } |
1508 | - |
1509 | - // check if the message should be sent via multimedia account |
1510 | - // we just use fallback to 1-1 chats |
1511 | - if (account->type() == AccountEntry::PhoneAccount) { |
1512 | - Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) { |
1513 | - // TODO: we have to find the multimedia account that matches the same phone number, |
1514 | - // but for now we just pick any multimedia connected account |
1515 | - if (newAccount->type() != AccountEntry::MultimediaAccount) { |
1516 | - continue; |
1517 | - } |
1518 | - // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of |
1519 | - // accounts. Also, it needs to check connection capabilities to determine if we can send message |
1520 | - // to offline contacts. |
1521 | - bool shouldFallback = true; |
1522 | - // if the account is offline, dont fallback to this account |
1523 | - if (!newAccount->connected()) { |
1524 | - continue; |
1525 | - } |
1526 | - QList<Tp::TextChannelPtr> channels = existingChannels(newAccount->accountId(), properties); |
1527 | - // check if we have a channel for this contact already and get the contact pointer from there, |
1528 | - // this way we avoid doing the while(op->isFinished()) all the time |
1529 | - if (!channels.isEmpty()) { |
1530 | - // if the contact is known, force fallback to this account |
1531 | - Q_FOREACH(const Tp::ContactPtr &contact, channels.first()->groupContacts(false)) { |
1532 | - Tp::Presence presence = contact->presence(); |
1533 | - shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
1534 | - presence.type() == Tp::ConnectionPresenceTypeOffline); |
1535 | - if (!shouldFallback) { |
1536 | - break; |
1537 | - } |
1538 | - } |
1539 | - } else { |
1540 | - QStringList participants = properties["participantIds"].toStringList(); |
1541 | - Tp::PendingOperation *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(participants); |
1542 | - while (!op->isFinished()) { |
1543 | - qApp->processEvents(); |
1544 | - } |
1545 | - Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op); |
1546 | - if (pc) { |
1547 | - Q_FOREACH(const Tp::ContactPtr &contact, pc->contacts()) { |
1548 | - Tp::Presence presence = contact->presence(); |
1549 | - shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
1550 | - presence.type() == Tp::ConnectionPresenceTypeOffline); |
1551 | - if (!shouldFallback) { |
1552 | - break; |
1553 | - } |
1554 | - } |
1555 | - } |
1556 | - } |
1557 | - if (shouldFallback) { |
1558 | - account = newAccount; |
1559 | - break; |
1560 | - } |
1561 | - } |
1562 | - } |
1563 | - |
1564 | - // keep recipient list always sorted to be able to compare |
1565 | - PendingMessage pendingMessage = {account->accountId(), message, attachments, properties}; |
1566 | - |
1567 | - if (!account->connected()) { |
1568 | - mPendingMessages.append(pendingMessage); |
1569 | - return account->accountId(); |
1570 | - } |
1571 | - |
1572 | - QList<Tp::TextChannelPtr> channels = existingChannels(account->accountId(), properties); |
1573 | - if (channels.isEmpty()) { |
1574 | - // temporary |
1575 | - switch(properties["chatType"].toUInt()) { |
1576 | - case Tp::HandleTypeNone: |
1577 | - case Tp::HandleTypeContact: |
1578 | - mPendingMessages.append(pendingMessage); |
1579 | - startTextChat(account->account(), pendingMessage.properties); |
1580 | - return account->accountId(); |
1581 | - case Tp::HandleTypeRoom: { |
1582 | - channels << startTextChatroom(account->account(), pendingMessage.properties); |
1583 | - qDebug() << "channel returned" << channels.last(); |
1584 | - |
1585 | - // multimedia fails if we send the message right away |
1586 | - QTimer *timer = new QTimer(this); |
1587 | - timer->setInterval(3000); |
1588 | - timer->setSingleShot(true); |
1589 | - QObject::connect(timer, &QTimer::timeout, [=]() { |
1590 | - qDebug() << "sending message" << channels.last(); |
1591 | - connect(channels.last()->send(buildMessage(pendingMessage)), |
1592 | - SIGNAL(finished(Tp::PendingOperation*)), |
1593 | - SLOT(onMessageSent(Tp::PendingOperation*))); |
1594 | - |
1595 | - timer->deleteLater(); |
1596 | - }); |
1597 | - timer->start(); |
1598 | - return account->accountId(); |
1599 | - break; |
1600 | - } |
1601 | - } |
1602 | - |
1603 | - //startChat(account->accountId(), pendingMessage.properties); |
1604 | - //return account->accountId(); |
1605 | - } |
1606 | - |
1607 | - connect(channels.last()->send(buildMessage(pendingMessage)), |
1608 | - SIGNAL(finished(Tp::PendingOperation*)), |
1609 | - SLOT(onMessageSent(Tp::PendingOperation*))); |
1610 | - |
1611 | - return account->accountId(); |
1612 | + PendingMessage pendingMessage = {accountId, message, attachments, properties}; |
1613 | + MessageSendingJob *job = new MessageSendingJob(this, pendingMessage); |
1614 | + job->startJob(); |
1615 | + |
1616 | + return job->objectPath(); |
1617 | } |
1618 | |
1619 | void TextHandler::acknowledgeMessages(const QVariantList &messages) |
1620 | @@ -508,41 +116,6 @@ |
1621 | |
1622 | QString accountId = account->accountId(); |
1623 | mChannels.append(channel); |
1624 | - |
1625 | - // check for pending messages for this channel |
1626 | - if (mPendingMessages.isEmpty()) { |
1627 | - return; |
1628 | - } |
1629 | - |
1630 | - QList<PendingMessage>::iterator it = mPendingMessages.begin(); |
1631 | - while (it != mPendingMessages.end()) { |
1632 | - bool found = false; |
1633 | - Q_FOREACH(const Tp::TextChannelPtr &existingChannel, existingChannels(it->accountId, it->properties)) { |
1634 | - if (existingChannel == channel) { |
1635 | - sendMessage(it->accountId, it->message, it->attachments, it->properties); |
1636 | - it = mPendingMessages.erase(it); |
1637 | - found = true; |
1638 | - break; |
1639 | - } |
1640 | - } |
1641 | - if (!found) { |
1642 | - ++it; |
1643 | - } |
1644 | - } |
1645 | -} |
1646 | - |
1647 | -void TextHandler::onMessageSent(Tp::PendingOperation *op) |
1648 | -{ |
1649 | - Tp::PendingSendMessage *psm = qobject_cast<Tp::PendingSendMessage*>(op); |
1650 | - if(!psm) { |
1651 | - qWarning() << "The pending object was not a pending operation:" << op; |
1652 | - return; |
1653 | - } |
1654 | - |
1655 | - if (psm->isError()) { |
1656 | - qWarning() << "Error sending message:" << psm->errorName() << psm->errorMessage(); |
1657 | - return; |
1658 | - } |
1659 | } |
1660 | |
1661 | QList<Tp::TextChannelPtr> TextHandler::existingChannels(const QString &accountId, const QVariantMap &properties) |
1662 | |
1663 | === modified file 'handler/texthandler.h' |
1664 | --- handler/texthandler.h 2016-10-06 19:34:36 +0000 |
1665 | +++ handler/texthandler.h 2016-10-06 19:34:37 +0000 |
1666 | @@ -27,23 +27,16 @@ |
1667 | #include <TelepathyQt/TextChannel> |
1668 | #include <TelepathyQt/ReceivedMessage> |
1669 | #include "dbustypes.h" |
1670 | - |
1671 | -struct PendingMessage { |
1672 | - QString accountId; |
1673 | - QString message; |
1674 | - AttachmentList attachments; |
1675 | - QVariantMap properties; |
1676 | -}; |
1677 | -Q_DECLARE_METATYPE(PendingMessage) |
1678 | +#include "messagesendingjob.h" |
1679 | |
1680 | class TextHandler : public QObject |
1681 | { |
1682 | Q_OBJECT |
1683 | public: |
1684 | static TextHandler *instance(); |
1685 | - void startChat(const QString &accountId, const QVariantMap &properties); |
1686 | - void startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties); |
1687 | - Tp::TextChannelPtr startTextChatroom(const Tp::AccountPtr &account, const QVariantMap &properties); |
1688 | + QString startChat(const QString &accountId, const QVariantMap &properties); |
1689 | + |
1690 | + friend class MessageSendingJob; |
1691 | |
1692 | public Q_SLOTS: |
1693 | QString sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
1694 | @@ -53,18 +46,13 @@ |
1695 | protected Q_SLOTS: |
1696 | void onTextChannelAvailable(Tp::TextChannelPtr channel); |
1697 | void onTextChannelInvalidated(); |
1698 | - void onMessageSent(Tp::PendingOperation *op); |
1699 | - void onConnectedChanged(); |
1700 | |
1701 | protected: |
1702 | QList<Tp::TextChannelPtr> existingChannels(const QString &accountId, const QVariantMap &properties); |
1703 | |
1704 | private: |
1705 | explicit TextHandler(QObject *parent = 0); |
1706 | - Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage); |
1707 | - |
1708 | QList<Tp::TextChannelPtr> mChannels; |
1709 | - QList<PendingMessage> mPendingMessages; |
1710 | }; |
1711 | |
1712 | #endif // TEXTHANDLER_H |
1713 | |
1714 | === modified file 'libtelephonyservice/chatentry.cpp' |
1715 | --- libtelephonyservice/chatentry.cpp 2016-10-06 19:34:36 +0000 |
1716 | +++ libtelephonyservice/chatentry.cpp 2016-10-06 19:34:37 +0000 |
1717 | @@ -1,8 +1,9 @@ |
1718 | /* |
1719 | - * Copyright (C) 2015 Canonical, Ltd. |
1720 | + * Copyright (C) 2015-2016 Canonical, Ltd. |
1721 | * |
1722 | * Authors: |
1723 | * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
1724 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
1725 | * |
1726 | * This file is part of telephony-service. |
1727 | * |
1728 | @@ -22,6 +23,10 @@ |
1729 | #include "telepathyhelper.h" |
1730 | #include "accountentry.h" |
1731 | #include "chatentry.h" |
1732 | +#include "chatmanager.h" |
1733 | + |
1734 | +// FIXME: move this class to libtelephonyservice |
1735 | +#include "handler/messagejob.h" |
1736 | |
1737 | #include <TelepathyQt/Contact> |
1738 | #include <TelepathyQt/PendingReady> |
1739 | @@ -29,51 +34,20 @@ |
1740 | |
1741 | Q_DECLARE_METATYPE(ContactChatStates) |
1742 | |
1743 | -ChatEntry::ChatEntry(const Tp::TextChannelPtr &channel, QObject *parent) : |
1744 | +ChatEntry::ChatEntry(QObject *parent) : |
1745 | QObject(parent), |
1746 | - mChannel(channel), |
1747 | + mChatType(ChatTypeNone), |
1748 | roomInterface(NULL), |
1749 | roomConfigInterface(NULL), |
1750 | subjectInterface(NULL) |
1751 | { |
1752 | qRegisterMetaType<ContactChatStates>(); |
1753 | - mAccount = TelepathyHelper::instance()->accountForConnection(mChannel->connection()); |
1754 | - Q_FOREACH (Tp::ContactPtr contact, mChannel->groupContacts(false)) { |
1755 | - ContactChatState *state = new ContactChatState(contact->id(), mChannel->chatState(contact)); |
1756 | - mChatStates[contact->id()] = state; |
1757 | - } |
1758 | - |
1759 | - roomInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>(); |
1760 | - roomConfigInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>(); |
1761 | - subjectInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>(); |
1762 | - |
1763 | - if (roomInterface) { |
1764 | - roomInterface->setMonitorProperties(true); |
1765 | - connect(roomInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1766 | - SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1767 | - } |
1768 | - if (roomConfigInterface) { |
1769 | - roomConfigInterface->setMonitorProperties(true); |
1770 | - connect(roomConfigInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1771 | - SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1772 | - } |
1773 | - if (subjectInterface) { |
1774 | - subjectInterface->setMonitorProperties(true); |
1775 | - connect(subjectInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1776 | - SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1777 | - } |
1778 | - |
1779 | - connect(channel.data(), SIGNAL(chatStateChanged(const Tp::ContactPtr &, Tp::ChannelChatState)), |
1780 | - this, SLOT(onChatStateChanged(const Tp::ContactPtr &,Tp::ChannelChatState))); |
1781 | - connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, |
1782 | - const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), this, SIGNAL(participantsChanged())); |
1783 | } |
1784 | |
1785 | void ChatEntry::onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated) |
1786 | { |
1787 | if (changed.contains("RoomName")) { |
1788 | - mRoomName = changed["RoomName"].toString(); |
1789 | - Q_EMIT roomNameChanged(); |
1790 | + setRoomName(changed["RoomName"].toString()); |
1791 | } |
1792 | if (changed.contains("Title")) { |
1793 | mTitle = changed["Title"].toString(); |
1794 | @@ -81,12 +55,52 @@ |
1795 | } |
1796 | } |
1797 | |
1798 | -QString ChatEntry::roomName() |
1799 | +void ChatEntry::onSendingMessageFinished() |
1800 | +{ |
1801 | + QDBusInterface *job = qobject_cast<QDBusInterface*>(sender()); |
1802 | + if (!job) { |
1803 | + return; |
1804 | + } |
1805 | + |
1806 | + QString accountId = job->property("accountId").toString(); |
1807 | + QString messageId = job->property("messageId").toString(); |
1808 | + QString channelObjectPath = job->property("channelObjectPath").toString(); |
1809 | + QVariantMap properties = job->property("properties").toMap(); |
1810 | + qDebug() << accountId << messageId << channelObjectPath << properties; |
1811 | + Tp::TextChannelPtr channel = ChatManager::instance()->channelForObjectPath(channelObjectPath); |
1812 | + |
1813 | + if (channel.isNull()) { |
1814 | + Q_EMIT messageSendingFailed(accountId, messageId, properties); |
1815 | + job->deleteLater(); |
1816 | + return; |
1817 | + } |
1818 | + |
1819 | + // even if sending the message fails, we can use the channel if available |
1820 | + addChannel(channel); |
1821 | + |
1822 | + if (job->property("status").toInt() == MessageJob::Failed || channel.isNull()) { |
1823 | + Q_EMIT messageSendingFailed(accountId, messageId, properties); |
1824 | + job->deleteLater(); |
1825 | + return; |
1826 | + } |
1827 | + |
1828 | + Q_EMIT messageSent(accountId, messageId, properties); |
1829 | + job->deleteLater(); |
1830 | +} |
1831 | + |
1832 | +QString ChatEntry::roomName() const |
1833 | { |
1834 | return mRoomName; |
1835 | } |
1836 | |
1837 | -QString ChatEntry::title() |
1838 | +void ChatEntry::setRoomName(const QString &name) |
1839 | +{ |
1840 | + mRoomName = name; |
1841 | + Q_EMIT roomNameChanged(); |
1842 | + // FIXME: we need to invalidate the existing channels & data and start fresh |
1843 | +} |
1844 | + |
1845 | +QString ChatEntry::title() const |
1846 | { |
1847 | return mTitle; |
1848 | } |
1849 | @@ -101,25 +115,32 @@ |
1850 | it.next(); |
1851 | delete it.value(); |
1852 | } |
1853 | - |
1854 | - if (roomInterface) { |
1855 | - roomInterface->deleteLater(); |
1856 | - } |
1857 | - if (roomConfigInterface) { |
1858 | - roomConfigInterface->deleteLater(); |
1859 | - } |
1860 | - if (subjectInterface) { |
1861 | - subjectInterface->deleteLater(); |
1862 | - } |
1863 | -} |
1864 | - |
1865 | -QString ChatEntry::chatId() |
1866 | -{ |
1867 | - if (mChannel) { |
1868 | - return mChannel->targetId(); |
1869 | - } |
1870 | - return QString(); |
1871 | -} |
1872 | +} |
1873 | + |
1874 | +QString ChatEntry::chatId() const |
1875 | +{ |
1876 | + return mChatId; |
1877 | +} |
1878 | + |
1879 | +void ChatEntry::setChatId(const QString &id) |
1880 | +{ |
1881 | + mChatId = id; |
1882 | + Q_EMIT chatIdChanged(); |
1883 | + // FIXME: we need to invalidate the existing channels & data and start fresh |
1884 | +} |
1885 | + |
1886 | +QString ChatEntry::accountId() const |
1887 | +{ |
1888 | + return mAccountId; |
1889 | +} |
1890 | + |
1891 | +void ChatEntry::setAccountId(const QString &id) |
1892 | +{ |
1893 | + mAccountId = id; |
1894 | + Q_EMIT accountIdChanged(); |
1895 | + // FIXME: we need to invalidate the existing channels & data and start fresh |
1896 | +} |
1897 | + |
1898 | |
1899 | void ChatEntry::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state) |
1900 | { |
1901 | @@ -133,28 +154,28 @@ |
1902 | Q_EMIT chatStatesChanged(); |
1903 | } |
1904 | |
1905 | -ChatEntry::ChatType ChatEntry::chatType() |
1906 | -{ |
1907 | - return (ChatType)mChannel->targetHandleType(); |
1908 | -} |
1909 | - |
1910 | -Tp::TextChannelPtr ChatEntry::channel() |
1911 | -{ |
1912 | - return mChannel; |
1913 | -} |
1914 | - |
1915 | -QStringList ChatEntry::participants() |
1916 | -{ |
1917 | - QStringList participantList; |
1918 | - Q_FOREACH (Tp::ContactPtr contact, mChannel->groupContacts(false)) { |
1919 | - participantList << contact->id(); |
1920 | - } |
1921 | - return participantList; |
1922 | -} |
1923 | - |
1924 | -AccountEntry *ChatEntry::account() |
1925 | -{ |
1926 | - return mAccount; |
1927 | +ChatEntry::ChatType ChatEntry::chatType() const |
1928 | +{ |
1929 | + return mChatType; |
1930 | +} |
1931 | + |
1932 | +void ChatEntry::setChatType(ChatEntry::ChatType type) |
1933 | +{ |
1934 | + mChatType = type; |
1935 | + Q_EMIT chatTypeChanged(); |
1936 | +} |
1937 | + |
1938 | +QStringList ChatEntry::participants() const |
1939 | +{ |
1940 | + return mParticipants; |
1941 | +} |
1942 | + |
1943 | +void ChatEntry::setParticipants(const QStringList &participants) |
1944 | +{ |
1945 | + mParticipants = participants; |
1946 | + Q_EMIT participantsChanged(); |
1947 | + |
1948 | + // FIXME: we need to invalidate the existing channels & data and start fresh |
1949 | } |
1950 | |
1951 | QQmlListProperty<ContactChatState> ChatEntry::chatStates() |
1952 | @@ -179,3 +200,157 @@ |
1953 | } |
1954 | return entry->mChatStates.values()[index]; |
1955 | } |
1956 | + |
1957 | +void ChatEntry::sendMessage(const QString &accountId, const QString &message, const QVariant &attachments, const QVariantMap &properties) |
1958 | +{ |
1959 | + QString objPath = ChatManager::instance()->sendMessage(accountId, message, attachments, properties); |
1960 | + QDBusInterface *sendingJob = new QDBusInterface(TelepathyHelper::instance()->handlerInterface()->service(), objPath, |
1961 | + "com.canonical.TelephonyServiceHandler.MessageSendingJob"); |
1962 | + qDebug() << sendingJob->isValid(); |
1963 | + sendingJob->dumpObjectInfo(); |
1964 | + connect(sendingJob, SIGNAL(finished()), SLOT(onSendingMessageFinished())); |
1965 | + QDBusReply<QString> reply = sendingJob->call("Introspect"); |
1966 | + qDebug() << reply.value(); |
1967 | +} |
1968 | + |
1969 | +void ChatEntry::classBegin() |
1970 | +{ |
1971 | + // nothing to do here |
1972 | +} |
1973 | + |
1974 | +void ChatEntry::componentComplete() |
1975 | +{ |
1976 | + QVariantMap properties = generateProperties(); |
1977 | + QList<Tp::TextChannelPtr> channels = ChatManager::instance()->channelForProperties(properties); |
1978 | + QList<AccountEntry*> accounts; |
1979 | + |
1980 | + if (!channels.isEmpty()) { |
1981 | + setChannels(channels); |
1982 | + } |
1983 | + |
1984 | + // now filter out the Phone accounts from the accounts list |
1985 | + Q_FOREACH(AccountEntry *account, TelepathyHelper::instance()->activeAccounts(true)) { |
1986 | + if (account->type() != AccountEntry::PhoneAccount) { |
1987 | + accounts << account; |
1988 | + } |
1989 | + } |
1990 | + |
1991 | + // now check that we have channels for all !Phone accounts |
1992 | + // we need channels to be able to show typing notifications |
1993 | + Q_FOREACH(const Tp::TextChannelPtr &channel, channels) { |
1994 | + AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection()); |
1995 | + accounts.removeAll(account); |
1996 | + } |
1997 | + |
1998 | + // if there is any remaining account, request to start chatting using the account |
1999 | + Q_FOREACH(AccountEntry *account, accounts) { |
2000 | + ChatManager::instance()->startChat(account->accountId(), properties); |
2001 | + } |
2002 | + |
2003 | + connect(ChatManager::instance(), &ChatManager::textChannelAvailable, |
2004 | + this, &ChatEntry::onTextChannelAvailable); |
2005 | +} |
2006 | + |
2007 | +void ChatEntry::setChannels(const QList<Tp::TextChannelPtr> &channels) |
2008 | +{ |
2009 | + Q_FOREACH(const Tp::TextChannelPtr &channel, channels) { |
2010 | + addChannel(channel); |
2011 | + } |
2012 | +} |
2013 | + |
2014 | +void ChatEntry::addChannel(const Tp::TextChannelPtr &channel) |
2015 | +{ |
2016 | + qDebug() << "adding channel" << channel->objectPath(); |
2017 | + if (mChannels.contains(channel)) { |
2018 | + return; |
2019 | + } |
2020 | + |
2021 | + roomInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>(); |
2022 | + roomConfigInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>(); |
2023 | + subjectInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>(); |
2024 | + |
2025 | + if (roomInterface) { |
2026 | + roomInterface->setProperty("channel", QVariant::fromValue(channel.data())); |
2027 | + roomInterface->setMonitorProperties(true); |
2028 | + connect(roomInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
2029 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
2030 | + } |
2031 | + if (roomConfigInterface) { |
2032 | + roomConfigInterface->setProperty("channel", QVariant::fromValue(channel.data())); |
2033 | + roomConfigInterface->setMonitorProperties(true); |
2034 | + connect(roomConfigInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
2035 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
2036 | + } |
2037 | + if (subjectInterface) { |
2038 | + subjectInterface->setProperty("channel", QVariant::fromValue(channel.data())); |
2039 | + subjectInterface->setMonitorProperties(true); |
2040 | + connect(subjectInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
2041 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
2042 | + } |
2043 | + |
2044 | + connect(channel.data(), SIGNAL(chatStateChanged(const Tp::ContactPtr &, Tp::ChannelChatState)), |
2045 | + this, SLOT(onChatStateChanged(const Tp::ContactPtr &,Tp::ChannelChatState))); |
2046 | + connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, |
2047 | + const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), this, SIGNAL(participantsChanged())); |
2048 | + connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)), |
2049 | + this, SLOT(onChannelInvalidated())); |
2050 | + |
2051 | + Q_FOREACH (Tp::ContactPtr contact, channel->groupContacts(false)) { |
2052 | + // FIXME: we should not create new chat states for contacts already found in previous channels |
2053 | + ContactChatState *state = new ContactChatState(contact->id(), channel->chatState(contact)); |
2054 | + mChatStates[contact->id()] = state; |
2055 | + } |
2056 | + |
2057 | + // now fill the properties with the data from the channel |
2058 | + if (chatType() != (ChatType)channel->targetHandleType()) { |
2059 | + setChatType((ChatType)channel->targetHandleType()); |
2060 | + } |
2061 | + if (chatType() == ChatTypeRoom && mChatId != channel->targetId()) { |
2062 | + setChatId(channel->targetId()); |
2063 | + } |
2064 | + |
2065 | + mChannels << channel; |
2066 | +} |
2067 | + |
2068 | +QVariantMap ChatEntry::generateProperties() const |
2069 | +{ |
2070 | + QVariantMap properties; |
2071 | + |
2072 | + properties["participantIds"] = participants(); |
2073 | + properties["chatType"] = (int)chatType(); |
2074 | + properties["chatId"] = chatId(); |
2075 | + properties["threadId"] = chatId(); |
2076 | + |
2077 | + if (chatType() == ChatEntry::ChatTypeRoom) { |
2078 | + properties["accountId"] = accountId(); |
2079 | + } |
2080 | + |
2081 | + return properties; |
2082 | +} |
2083 | + |
2084 | +void ChatEntry::onTextChannelAvailable(const Tp::TextChannelPtr &channel) |
2085 | +{ |
2086 | + if (ChatManager::channelMatchProperties(channel, generateProperties())) { |
2087 | + addChannel(channel); |
2088 | + } |
2089 | +} |
2090 | + |
2091 | +void ChatEntry::onChannelInvalidated() |
2092 | +{ |
2093 | + qDebug() << __PRETTY_FUNCTION__; |
2094 | + Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender())); |
2095 | + mChannels.removeAll(channel); |
2096 | + |
2097 | + if (roomInterface && roomInterface->property("channel").value<Tp::TextChannel*>() == channel.data()) { |
2098 | + roomInterface->disconnect(this); |
2099 | + roomInterface = 0; |
2100 | + } |
2101 | + if (roomConfigInterface && roomConfigInterface->property("channel").value<Tp::TextChannel*>() == channel.data()) { |
2102 | + roomConfigInterface->disconnect(this); |
2103 | + roomConfigInterface = 0; |
2104 | + } |
2105 | + if (subjectInterface && subjectInterface->property("channel").value<Tp::TextChannel*>() == channel.data()) { |
2106 | + subjectInterface->disconnect(this); |
2107 | + subjectInterface = 0; |
2108 | + } |
2109 | +} |
2110 | |
2111 | === modified file 'libtelephonyservice/chatentry.h' |
2112 | --- libtelephonyservice/chatentry.h 2016-10-06 19:34:36 +0000 |
2113 | +++ libtelephonyservice/chatentry.h 2016-10-06 19:34:37 +0000 |
2114 | @@ -1,8 +1,9 @@ |
2115 | /* |
2116 | - * Copyright (C) 2015 Canonical, Ltd. |
2117 | + * Copyright (C) 2015-2016 Canonical, Ltd. |
2118 | * |
2119 | * Authors: |
2120 | * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
2121 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
2122 | * |
2123 | * This file is part of telephony-service. |
2124 | * |
2125 | @@ -23,6 +24,7 @@ |
2126 | #define CHATENTRY_H |
2127 | |
2128 | #include <QObject> |
2129 | +#include <QQmlParserStatus> |
2130 | #include <TelepathyQt/TextChannel> |
2131 | |
2132 | class AccountEntry; |
2133 | @@ -42,6 +44,7 @@ |
2134 | } |
2135 | Q_SIGNALS: |
2136 | void stateChanged(); |
2137 | + |
2138 | private: |
2139 | QString mContactId; |
2140 | int mState; |
2141 | @@ -49,14 +52,15 @@ |
2142 | |
2143 | typedef QList<ContactChatState* > ContactChatStates; |
2144 | |
2145 | -class ChatEntry : public QObject |
2146 | +class ChatEntry : public QObject, public QQmlParserStatus |
2147 | { |
2148 | Q_OBJECT |
2149 | - Q_PROPERTY(AccountEntry* account READ account CONSTANT) |
2150 | - Q_PROPERTY(ChatType chatType READ chatType CONSTANT) |
2151 | - Q_PROPERTY(QStringList participants READ participants NOTIFY participantsChanged) |
2152 | - Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) |
2153 | - Q_PROPERTY(QString chatId READ chatId CONSTANT) |
2154 | + Q_INTERFACES(QQmlParserStatus) |
2155 | + Q_PROPERTY(ChatType chatType READ chatType WRITE setChatType NOTIFY chatTypeChanged) |
2156 | + Q_PROPERTY(QStringList participants READ participants WRITE setParticipants NOTIFY participantsChanged) |
2157 | + Q_PROPERTY(QString roomName READ roomName WRITE setRoomName NOTIFY roomNameChanged) |
2158 | + Q_PROPERTY(QString chatId READ chatId WRITE setChatId NOTIFY chatIdChanged) |
2159 | + Q_PROPERTY(QString accountId READ accountId WRITE setAccountId NOTIFY accountIdChanged) |
2160 | Q_PROPERTY(QString title READ title NOTIFY titleChanged) |
2161 | Q_PROPERTY(QQmlListProperty<ContactChatState> chatStates |
2162 | READ chatStates |
2163 | @@ -79,35 +83,65 @@ |
2164 | ChannelChatStateComposing = Tp::ChannelChatStateComposing |
2165 | }; |
2166 | |
2167 | - explicit ChatEntry(const Tp::TextChannelPtr &channel, QObject *parent = 0); |
2168 | + explicit ChatEntry(QObject *parent = 0); |
2169 | ~ChatEntry(); |
2170 | - Tp::TextChannelPtr channel(); |
2171 | - AccountEntry *account(); |
2172 | QQmlListProperty<ContactChatState> chatStates(); |
2173 | - QStringList participants(); |
2174 | - ChatType chatType(); |
2175 | - QString chatId(); |
2176 | - QString roomName(); |
2177 | - QString title(); |
2178 | + QStringList participants() const; |
2179 | + void setParticipants(const QStringList &participants); |
2180 | + ChatType chatType() const; |
2181 | + void setChatType(ChatType type); |
2182 | + QString chatId() const; |
2183 | + void setChatId(const QString &id); |
2184 | + QString accountId() const; |
2185 | + void setAccountId(const QString &id); |
2186 | + QString roomName() const; |
2187 | + void setRoomName(const QString &name); |
2188 | + QString title() const; |
2189 | static int chatStatesCount(QQmlListProperty<ContactChatState> *p); |
2190 | static ContactChatState *chatStatesAt(QQmlListProperty<ContactChatState> *p, int index); |
2191 | |
2192 | + // QML parser status |
2193 | + void classBegin(); |
2194 | + void componentComplete(); |
2195 | + |
2196 | +public Q_SLOTS: |
2197 | + // FIXME: void or return something? |
2198 | + void sendMessage(const QString &accountId, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap()); |
2199 | + |
2200 | +protected: |
2201 | + void setChannels(const QList<Tp::TextChannelPtr> &channels); |
2202 | + void addChannel(const Tp::TextChannelPtr &channel); |
2203 | + |
2204 | + QVariantMap generateProperties() const; |
2205 | + |
2206 | private Q_SLOTS: |
2207 | + void onTextChannelAvailable(const Tp::TextChannelPtr &channel); |
2208 | + void onChannelInvalidated(); |
2209 | void onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state); |
2210 | void onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated); |
2211 | + void onSendingMessageFinished(); |
2212 | |
2213 | Q_SIGNALS: |
2214 | + void chatTypeChanged(); |
2215 | + void chatIdChanged(); |
2216 | + void accountIdChanged(); |
2217 | void chatStatesChanged(); |
2218 | void participantsChanged(); |
2219 | void roomNameChanged(); |
2220 | void titleChanged(); |
2221 | |
2222 | + void messageSent(const QString &accountId, const QString &messageId, const QVariantMap &properties); |
2223 | + void messageSendingFailed(const QString &accountId, const QString &messageId, const QVariantMap &properties); |
2224 | + |
2225 | private: |
2226 | - AccountEntry *mAccount; |
2227 | - Tp::TextChannelPtr mChannel; |
2228 | + QList<Tp::TextChannelPtr> mChannels; |
2229 | + QStringList mParticipants; |
2230 | QMap<QString, ContactChatState*> mChatStates; |
2231 | QString mRoomName; |
2232 | QString mTitle; |
2233 | + QString mChatId; |
2234 | + QString mAccountId; |
2235 | + ChatType mChatType; |
2236 | Tp::Client::ChannelInterfaceRoomInterface *roomInterface; |
2237 | Tp::Client::ChannelInterfaceRoomConfigInterface *roomConfigInterface; |
2238 | Tp::Client::ChannelInterfaceSubjectInterface *subjectInterface; |
2239 | |
2240 | === modified file 'libtelephonyservice/chatmanager.cpp' |
2241 | --- libtelephonyservice/chatmanager.cpp 2016-10-06 19:34:36 +0000 |
2242 | +++ libtelephonyservice/chatmanager.cpp 2016-10-06 19:34:37 +0000 |
2243 | @@ -1,5 +1,5 @@ |
2244 | /* |
2245 | - * Copyright (C) 2012-2013 Canonical, Ltd. |
2246 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
2247 | * |
2248 | * Authors: |
2249 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
2250 | @@ -20,6 +20,7 @@ |
2251 | */ |
2252 | |
2253 | #include "chatmanager.h" |
2254 | +#include "chatentry.h" |
2255 | #include "telepathyhelper.h" |
2256 | #include "phoneutils.h" |
2257 | #include "config.h" |
2258 | @@ -61,8 +62,7 @@ |
2259 | } |
2260 | |
2261 | ChatManager::ChatManager(QObject *parent) |
2262 | -: QObject(parent), |
2263 | - mReady(TelepathyHelper::instance()->ready()) |
2264 | +: QObject(parent) |
2265 | { |
2266 | qDBusRegisterMetaType<AttachmentList>(); |
2267 | qDBusRegisterMetaType<AttachmentStruct>(); |
2268 | @@ -70,29 +70,13 @@ |
2269 | mMessagesAckTimer.setInterval(25); |
2270 | mMessagesAckTimer.setSingleShot(true); |
2271 | connect(TelepathyHelper::instance(), SIGNAL(channelObserverUnregistered()), SLOT(onChannelObserverUnregistered())); |
2272 | - connect(TelepathyHelper::instance(), SIGNAL(setupReady()), SLOT(onTelepathyReady())); |
2273 | connect(&mMessagesAckTimer, SIGNAL(timeout()), SLOT(onAckTimerTriggered())); |
2274 | connect(TelepathyHelper::instance(), SIGNAL(setupReady()), SLOT(onConnectedChanged())); |
2275 | } |
2276 | |
2277 | -void ChatManager::onTelepathyReady() |
2278 | -{ |
2279 | - mReady = true; |
2280 | - Q_FOREACH(const Tp::TextChannelPtr &channel, mPendingChannels) { |
2281 | - onTextChannelAvailable(channel); |
2282 | - } |
2283 | - mPendingChannels.clear(); |
2284 | -} |
2285 | - |
2286 | void ChatManager::onChannelObserverUnregistered() |
2287 | { |
2288 | - QList<ChatEntry*> tmp = mChatEntries; |
2289 | - mChatEntries.clear(); |
2290 | - Q_EMIT chatsChanged(); |
2291 | - Q_FOREACH(ChatEntry *entry, tmp) { |
2292 | - // for some reason deleteLater is not working |
2293 | - delete entry; |
2294 | - } |
2295 | + mTextChannels.clear(); |
2296 | } |
2297 | |
2298 | void ChatManager::onConnectedChanged() |
2299 | @@ -108,6 +92,13 @@ |
2300 | return manager; |
2301 | } |
2302 | |
2303 | +void ChatManager::startChat(const QString &accountId, const QVariantMap &properties) |
2304 | +{ |
2305 | + QVariantMap propMap = convertPropertiesForDBus(properties); |
2306 | + QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface(); |
2307 | + phoneAppHandler->asyncCall("StartChat", accountId, propMap); |
2308 | +} |
2309 | + |
2310 | QString ChatManager::sendMessage(const QString &accountId, const QString &message, const QVariant &attachments, const QVariantMap &properties) |
2311 | { |
2312 | AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
2313 | @@ -164,86 +155,138 @@ |
2314 | return QString(); |
2315 | } |
2316 | |
2317 | +QList<Tp::TextChannelPtr> ChatManager::channelForProperties(const QVariantMap &properties) |
2318 | +{ |
2319 | + // FIXME: remove before releasing |
2320 | + qDebug() << __PRETTY_FUNCTION__ << properties; |
2321 | + QList<Tp::TextChannelPtr> channels; |
2322 | + |
2323 | + |
2324 | + Q_FOREACH (Tp::TextChannelPtr channel, mTextChannels) { |
2325 | + if (channelMatchProperties(channel, properties)) { |
2326 | + channels << channel; |
2327 | + } |
2328 | + } |
2329 | + |
2330 | + return channels; |
2331 | +} |
2332 | + |
2333 | +Tp::TextChannelPtr ChatManager::channelForObjectPath(const QString &objectPath) |
2334 | +{ |
2335 | + Q_FOREACH(Tp::TextChannelPtr channel, mTextChannels) { |
2336 | + if (channel->objectPath() == objectPath) { |
2337 | + return channel; |
2338 | + } |
2339 | + } |
2340 | + return Tp::TextChannelPtr(); |
2341 | +} |
2342 | + |
2343 | +bool ChatManager::channelMatchProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties) |
2344 | +{ |
2345 | + QVariantMap propMap = properties; |
2346 | + ChatEntry::ChatType chatType = ChatEntry::ChatTypeNone; |
2347 | + |
2348 | + QStringList participants; |
2349 | + // participants coming from qml are variants |
2350 | + if (properties.contains("participantIds")) { |
2351 | + participants = properties["participantIds"].toStringList(); |
2352 | + if (!participants.isEmpty()) { |
2353 | + propMap["participantIds"] = participants; |
2354 | + } |
2355 | + } |
2356 | + |
2357 | + if (participants.isEmpty() && propMap.contains("participants")) { |
2358 | + // try to generate list of participants from "participants" |
2359 | + Q_FOREACH(const QVariant &participantMap, propMap["participants"].toList()) { |
2360 | + if (participantMap.toMap().contains("identifier")) { |
2361 | + participants << participantMap.toMap()["identifier"].toString(); |
2362 | + } |
2363 | + } |
2364 | + if (!participants.isEmpty()) { |
2365 | + propMap["participantIds"] = participants; |
2366 | + } |
2367 | + } |
2368 | + |
2369 | + if (properties.contains("chatType")) { |
2370 | + chatType = (ChatEntry::ChatType)properties["chatType"].toInt(); |
2371 | + } else { |
2372 | + if (participants.length() == 1) { |
2373 | + chatType = ChatEntry::ChatTypeContact; |
2374 | + } |
2375 | + } |
2376 | + |
2377 | + QString accountId; |
2378 | + if (propMap.contains("accountId")) { |
2379 | + accountId = propMap["accountId"].toString(); |
2380 | + } |
2381 | + |
2382 | + if (participants.count() == 0 && chatType == ChatEntry::ChatTypeContact) { |
2383 | + return false; |
2384 | + } |
2385 | + |
2386 | + AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection()); |
2387 | + if (!account) { |
2388 | + return false; |
2389 | + } |
2390 | + |
2391 | + // only channels of the correct type should be returned |
2392 | + if ((ChatEntry::ChatType)channel->targetHandleType() != chatType) { |
2393 | + return false; |
2394 | + } |
2395 | + |
2396 | + if (chatType == ChatEntry::ChatTypeRoom) { |
2397 | + QString chatId = propMap["threadId"].toString(); |
2398 | + if (!chatId.isEmpty() && channel->targetId() == chatId) { |
2399 | + // if we are filtering by one specific accountId, make sure it matches |
2400 | + if (!accountId.isEmpty() && accountId != account->accountId()) { |
2401 | + return false; |
2402 | + } |
2403 | + |
2404 | + return true; |
2405 | + } |
2406 | + return false; |
2407 | + } |
2408 | + |
2409 | + Tp::Contacts contacts = channel->groupContacts(false); |
2410 | + if (participants.count() != contacts.count()) { |
2411 | + return false; |
2412 | + } |
2413 | + int participantCount = 0; |
2414 | + // iterate over participants |
2415 | + Q_FOREACH (const Tp::ContactPtr &contact, contacts) { |
2416 | + if (account->type() == AccountEntry::PhoneAccount || account->type() == AccountEntry::MultimediaAccount) { |
2417 | + Q_FOREACH(const QString &participant, participants) { |
2418 | + if (PhoneUtils::comparePhoneNumbers(participant, contact->id()) > PhoneUtils::NO_MATCH) { |
2419 | + participantCount++; |
2420 | + break; |
2421 | + } |
2422 | + } |
2423 | + continue; |
2424 | + } |
2425 | + if (participants.contains(contact->id())) { |
2426 | + participantCount++; |
2427 | + } else { |
2428 | + break; |
2429 | + } |
2430 | + } |
2431 | + return (participantCount == participants.count()); |
2432 | +} |
2433 | + |
2434 | void ChatManager::onTextChannelAvailable(Tp::TextChannelPtr channel) |
2435 | { |
2436 | - if (!mReady) { |
2437 | - mPendingChannels.append(channel); |
2438 | - return; |
2439 | - } |
2440 | - ChatEntry *chatEntry = new ChatEntry(channel, this); |
2441 | - mChatEntries.append(chatEntry); |
2442 | - |
2443 | - connect(channel.data(), |
2444 | - SIGNAL(messageReceived(Tp::ReceivedMessage)), |
2445 | - SLOT(onMessageReceived(Tp::ReceivedMessage))); |
2446 | - connect(channel.data(), |
2447 | - SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), |
2448 | - SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))); |
2449 | + mTextChannels << channel; |
2450 | connect(channel.data(), |
2451 | SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)), |
2452 | SLOT(onChannelInvalidated())); |
2453 | |
2454 | - Q_FOREACH(const Tp::ReceivedMessage &message, channel->messageQueue()) { |
2455 | - onMessageReceived(message); |
2456 | - } |
2457 | - |
2458 | - Q_EMIT chatsChanged(); |
2459 | - Q_EMIT chatEntryCreated(chatEntry->account()->accountId(), chatEntry->participants(), chatEntry); |
2460 | + Q_EMIT textChannelAvailable(channel); |
2461 | } |
2462 | |
2463 | void ChatManager::onChannelInvalidated() |
2464 | { |
2465 | Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender())); |
2466 | - ChatEntry *chatEntry = chatEntryForChannel(channel); |
2467 | - if (chatEntry) { |
2468 | - mChatEntries.removeAll(chatEntry); |
2469 | - // for some reason deleteLater is not working |
2470 | - delete chatEntry; |
2471 | - Q_EMIT chatsChanged(); |
2472 | - } |
2473 | -} |
2474 | - |
2475 | -ChatEntry *ChatManager::chatEntryForChannel(const Tp::TextChannelPtr &channel) |
2476 | -{ |
2477 | - Q_FOREACH (ChatEntry *chatEntry, mChatEntries) { |
2478 | - if (channel == chatEntry->channel()) { |
2479 | - return chatEntry; |
2480 | - } |
2481 | - } |
2482 | - return NULL; |
2483 | -} |
2484 | - |
2485 | -void ChatManager::onMessageReceived(const Tp::ReceivedMessage &message) |
2486 | -{ |
2487 | - // ignore delivery reports for now |
2488 | - // FIXME: we need to handle errors on sending messages at some point |
2489 | - if (message.isDeliveryReport()) { |
2490 | - return; |
2491 | - } |
2492 | - |
2493 | - if (!message.sender()) { |
2494 | - return; |
2495 | - } |
2496 | - |
2497 | - Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true); |
2498 | -} |
2499 | - |
2500 | -void ChatManager::onMessageSent(const Tp::Message &sentMessage, const Tp::MessageSendingFlags flags, const QString &message) |
2501 | -{ |
2502 | - Q_UNUSED(message) |
2503 | - Q_UNUSED(flags) |
2504 | - |
2505 | - Tp::TextChannel *channel = qobject_cast<Tp::TextChannel*>(sender()); |
2506 | - if (!channel) { |
2507 | - return; |
2508 | - } |
2509 | - |
2510 | - QStringList recipients; |
2511 | - Q_FOREACH(const Tp::ContactPtr &contact, channel->groupContacts(false)) { |
2512 | - recipients << contact->id(); |
2513 | - } |
2514 | - |
2515 | - Q_EMIT messageSent(recipients, sentMessage.text()); |
2516 | + mTextChannels.removeAll(channel); |
2517 | + Q_EMIT textChannelInvalidated(channel); |
2518 | } |
2519 | |
2520 | void ChatManager::acknowledgeMessage(const QVariantMap &properties) |
2521 | @@ -267,112 +310,3 @@ |
2522 | |
2523 | mMessagesToAck.clear(); |
2524 | } |
2525 | - |
2526 | -QList<ChatEntry*> ChatManager::chatEntries() const |
2527 | -{ |
2528 | - return mChatEntries; |
2529 | -} |
2530 | - |
2531 | -ChatEntry *ChatManager::chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create) |
2532 | -{ |
2533 | - QVariantMap propMap = properties; |
2534 | - int chatType = 0; |
2535 | - |
2536 | - QStringList participants; |
2537 | - // participants coming from qml are variants |
2538 | - if (properties.contains("participantIds")) { |
2539 | - participants = properties["participantIds"].toStringList(); |
2540 | - if (!participants.isEmpty()) { |
2541 | - propMap["participantIds"] = participants; |
2542 | - } |
2543 | - } |
2544 | - |
2545 | - if (participants.isEmpty() && propMap.contains("participants")) { |
2546 | - // try to generate list of participants from "participants" |
2547 | - Q_FOREACH(const QVariant &participantMap, propMap["participants"].toList()) { |
2548 | - if (participantMap.toMap().contains("identifier")) { |
2549 | - participants << participantMap.toMap()["identifier"].toString(); |
2550 | - } |
2551 | - } |
2552 | - if (!participants.isEmpty()) { |
2553 | - propMap["participantIds"] = participants; |
2554 | - } |
2555 | - } |
2556 | - |
2557 | - if (properties.contains("chatType")) { |
2558 | - chatType = properties["chatType"].toInt(); |
2559 | - } else { |
2560 | - if (participants.length() == 1) { |
2561 | - chatType = 1; |
2562 | - } |
2563 | - } |
2564 | - |
2565 | - if ((participants.count() == 0 && chatType == 1) || accountId.isEmpty()) { |
2566 | - return NULL; |
2567 | - } |
2568 | - |
2569 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
2570 | - |
2571 | - if (!account) { |
2572 | - return NULL; |
2573 | - } |
2574 | - |
2575 | - Q_FOREACH (ChatEntry *chatEntry, mChatEntries) { |
2576 | - int participantCount = 0; |
2577 | - |
2578 | - if (chatType == 2) { |
2579 | - QString roomId = propMap["threadId"].toString(); |
2580 | - if (!roomId.isEmpty() && chatEntry->chatType() == 2 && roomId == chatEntry->chatId()) { |
2581 | - return chatEntry; |
2582 | - } |
2583 | - continue; |
2584 | - } |
2585 | - |
2586 | - Tp::Contacts contacts = chatEntry->channel()->groupContacts(false); |
2587 | - if (participants.count() != contacts.count()) { |
2588 | - continue; |
2589 | - } |
2590 | - // iterate over participants |
2591 | - Q_FOREACH (const Tp::ContactPtr &contact, contacts) { |
2592 | - if (account->type() == AccountEntry::PhoneAccount || account->type() == AccountEntry::MultimediaAccount) { |
2593 | - Q_FOREACH(const QString &participant, participants) { |
2594 | - if (PhoneUtils::comparePhoneNumbers(participant, contact->id()) > PhoneUtils::NO_MATCH) { |
2595 | - participantCount++; |
2596 | - break; |
2597 | - } |
2598 | - } |
2599 | - continue; |
2600 | - } |
2601 | - if (participants.contains(contact->id())) { |
2602 | - participantCount++; |
2603 | - } else { |
2604 | - break; |
2605 | - } |
2606 | - } |
2607 | - if (participantCount == participants.count()) { |
2608 | - return chatEntry; |
2609 | - } |
2610 | - } |
2611 | - |
2612 | - if (create) { |
2613 | - QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface(); |
2614 | - phoneAppHandler->call("StartChat", accountId, propMap); |
2615 | - } |
2616 | - return NULL; |
2617 | -} |
2618 | - |
2619 | -QQmlListProperty<ChatEntry> ChatManager::chats() |
2620 | -{ |
2621 | - return QQmlListProperty<ChatEntry>(this, 0, chatCount, chatAt); |
2622 | -} |
2623 | - |
2624 | -int ChatManager::chatCount(QQmlListProperty<ChatEntry> *p) |
2625 | -{ |
2626 | - return ChatManager::instance()->chatEntries().count(); |
2627 | -} |
2628 | - |
2629 | -ChatEntry *ChatManager::chatAt(QQmlListProperty<ChatEntry> *p, int index) |
2630 | -{ |
2631 | - return ChatManager::instance()->chatEntries()[index]; |
2632 | -} |
2633 | - |
2634 | |
2635 | === modified file 'libtelephonyservice/chatmanager.h' |
2636 | --- libtelephonyservice/chatmanager.h 2016-10-06 19:34:36 +0000 |
2637 | +++ libtelephonyservice/chatmanager.h 2016-10-06 19:34:37 +0000 |
2638 | @@ -1,5 +1,5 @@ |
2639 | /* |
2640 | - * Copyright (C) 2012 Canonical, Ltd. |
2641 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
2642 | * |
2643 | * Authors: |
2644 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
2645 | @@ -28,57 +28,44 @@ |
2646 | #include <TelepathyQt/TextChannel> |
2647 | #include <TelepathyQt/ReceivedMessage> |
2648 | #include "dbustypes.h" |
2649 | -#include "chatentry.h" |
2650 | |
2651 | class ChatManager : public QObject |
2652 | { |
2653 | Q_OBJECT |
2654 | - Q_PROPERTY(QQmlListProperty<ChatEntry> chats |
2655 | - READ chats |
2656 | - NOTIFY chatsChanged) |
2657 | public: |
2658 | static ChatManager *instance(); |
2659 | |
2660 | - Q_INVOKABLE QString sendMessage(const QString &accountId, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap()); |
2661 | - Q_INVOKABLE ChatEntry *chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create = false); |
2662 | + void startChat(const QString &accountId, const QVariantMap &properties); |
2663 | + QString sendMessage(const QString &accountId, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap()); |
2664 | + QList<Tp::TextChannelPtr> channelForProperties(const QVariantMap &properties); |
2665 | + Tp::TextChannelPtr channelForObjectPath(const QString &objectPath); |
2666 | |
2667 | - QQmlListProperty<ChatEntry> chats(); |
2668 | - static int chatCount(QQmlListProperty<ChatEntry> *p); |
2669 | - static ChatEntry* chatAt(QQmlListProperty<ChatEntry> *p, int index); |
2670 | + static bool channelMatchProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties); |
2671 | |
2672 | Q_SIGNALS: |
2673 | - void messageReceived(const QString &sender, const QString &message, const QDateTime ×tamp, const QString &messageId, bool unread); |
2674 | - void messageSent(const QStringList &recipients, const QString &message); |
2675 | - void chatsChanged(); |
2676 | - void chatEntryCreated(QString accountId, QStringList participants, ChatEntry *chatEntry); |
2677 | + void textChannelAvailable(Tp::TextChannelPtr); |
2678 | + void textChannelInvalidated(Tp::TextChannelPtr); |
2679 | |
2680 | public Q_SLOTS: |
2681 | void onTextChannelAvailable(Tp::TextChannelPtr channel); |
2682 | void onChannelInvalidated(); |
2683 | void onConnectedChanged(); |
2684 | - void onMessageReceived(const Tp::ReceivedMessage &message); |
2685 | - void onMessageSent(const Tp::Message &sentMessage, const Tp::MessageSendingFlags flags, const QString &message); |
2686 | |
2687 | void acknowledgeMessage(const QVariantMap &properties); |
2688 | void acknowledgeAllMessages(const QVariantMap &properties); |
2689 | |
2690 | private Q_SLOTS: |
2691 | void onChannelObserverUnregistered(); |
2692 | - void onTelepathyReady(); |
2693 | |
2694 | protected Q_SLOTS: |
2695 | void onAckTimerTriggered(); |
2696 | |
2697 | private: |
2698 | explicit ChatManager(QObject *parent = 0); |
2699 | - ChatEntry *chatEntryForChannel(const Tp::TextChannelPtr &channel); |
2700 | - QList<ChatEntry*> chatEntries() const; |
2701 | |
2702 | - mutable QList<ChatEntry*> mChatEntries; |
2703 | QVariantList mMessagesToAck; |
2704 | - QList<Tp::TextChannelPtr> mPendingChannels; |
2705 | + QList<Tp::TextChannelPtr> mTextChannels; |
2706 | QTimer mMessagesAckTimer; |
2707 | - bool mReady; |
2708 | }; |
2709 | |
2710 | #endif // CHATMANAGER_H |
2711 | |
2712 | === modified file 'libtelephonyservice/telepathyhelper.cpp' |
2713 | --- libtelephonyservice/telepathyhelper.cpp 2016-10-06 19:34:36 +0000 |
2714 | +++ libtelephonyservice/telepathyhelper.cpp 2016-10-06 19:34:37 +0000 |
2715 | @@ -1,5 +1,5 @@ |
2716 | /* |
2717 | - * Copyright (C) 2012-2015 Canonical, Ltd. |
2718 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
2719 | * |
2720 | * Authors: |
2721 | * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
2722 | @@ -149,11 +149,14 @@ |
2723 | return mAccounts; |
2724 | } |
2725 | |
2726 | -QList<AccountEntry*> TelepathyHelper::activeAccounts() const |
2727 | +QList<AccountEntry*> TelepathyHelper::activeAccounts(bool includeMultimedia) const |
2728 | { |
2729 | QList<AccountEntry*> activeAccountList; |
2730 | Q_FOREACH(AccountEntry *account, mAccounts) { |
2731 | - if (account->active() && account->type() != AccountEntry::MultimediaAccount) { |
2732 | + if (account->active()) { |
2733 | + if (account->type() == AccountEntry::MultimediaAccount && !includeMultimedia) { |
2734 | + continue; |
2735 | + } |
2736 | activeAccountList << account; |
2737 | } |
2738 | } |
2739 | |
2740 | === modified file 'libtelephonyservice/telepathyhelper.h' |
2741 | --- libtelephonyservice/telepathyhelper.h 2016-10-06 19:34:36 +0000 |
2742 | +++ libtelephonyservice/telepathyhelper.h 2016-10-06 19:34:37 +0000 |
2743 | @@ -1,5 +1,5 @@ |
2744 | /* |
2745 | - * Copyright (C) 2012 Canonical, Ltd. |
2746 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
2747 | * |
2748 | * Authors: |
2749 | * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
2750 | @@ -75,7 +75,7 @@ |
2751 | static TelepathyHelper *instance(); |
2752 | QList<AccountEntry*> accounts() const; |
2753 | QList<AccountEntry*> phoneAccounts() const; |
2754 | - QList<AccountEntry*> activeAccounts() const; |
2755 | + QList<AccountEntry*> activeAccounts(bool includeMultimedia=false) const; |
2756 | QQmlListProperty<AccountEntry> qmlAccounts(); |
2757 | QQmlListProperty<AccountEntry> qmlPhoneAccounts(); |
2758 | QQmlListProperty<AccountEntry> qmlActiveAccounts(); |
2759 | |
2760 | === modified file 'tests/handler/HandlerTest.cpp' |
2761 | --- tests/handler/HandlerTest.cpp 2016-10-06 19:34:36 +0000 |
2762 | +++ tests/handler/HandlerTest.cpp 2016-10-06 19:34:37 +0000 |
2763 | @@ -18,6 +18,7 @@ |
2764 | |
2765 | #include <QtCore/QObject> |
2766 | #include <QtTest/QtTest> |
2767 | +#include <QDBusInterface> |
2768 | #include "telepathytest.h" |
2769 | #include "chatmanager.h" |
2770 | #include "handlercontroller.h" |
2771 | @@ -27,6 +28,8 @@ |
2772 | #include "accountentryfactory.h" |
2773 | #include "telepathyhelper.h" |
2774 | |
2775 | +Q_DECLARE_METATYPE(Tp::TextChannelPtr) |
2776 | + |
2777 | class HandlerTest : public TelepathyTest |
2778 | { |
2779 | Q_OBJECT |
2780 | @@ -70,6 +73,8 @@ |
2781 | QSignalSpy setupReadySpy(TelepathyHelper::instance(), SIGNAL(setupReady())); |
2782 | TRY_COMPARE(setupReadySpy.count(), 1); |
2783 | |
2784 | + qRegisterMetaType<Tp::TextChannelPtr>(); |
2785 | + |
2786 | registerApprover(); |
2787 | } |
2788 | |
2789 | @@ -354,18 +359,24 @@ |
2790 | |
2791 | void HandlerTest::testAcknowledgeMessage() |
2792 | { |
2793 | + QString recipient("84376666"); |
2794 | + QString recipient2("+554184376666"); |
2795 | + QString message("Hello, world!"); |
2796 | + |
2797 | + QSignalSpy messageSentSpy(mMockController, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2798 | + // first send a message to a certain number so the handler request one channel |
2799 | + QString objectPath = HandlerController::instance()->sendMessage(mTpAccount->uniqueIdentifier(), QStringList() << recipient, message); |
2800 | + QDBusInterface *sendingJob = new QDBusInterface(TelepathyHelper::instance()->handlerInterface()->service(), objectPath, |
2801 | + "com.canonical.TelephonyServiceHandler.MessageSendingJob"); |
2802 | + QSignalSpy handlerHasChannel(sendingJob, SIGNAL(finished())); |
2803 | + |
2804 | + TRY_COMPARE(messageSentSpy.count(), 1); |
2805 | + TRY_COMPARE(handlerHasChannel.count(), 1); |
2806 | + |
2807 | // if we register the observer before this test, other tests fail |
2808 | - TelepathyHelper::instance()->registerChannelObserver(); |
2809 | - QString recipient("84376666"); |
2810 | - QString recipient2("+554184376666"); |
2811 | - QString message("Hello, world!"); |
2812 | - QSignalSpy messageSentSpy(mMockController, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2813 | - |
2814 | - // first send a message to a certain number so the handler request one channel |
2815 | - HandlerController::instance()->sendMessage(mTpAccount->uniqueIdentifier(), QStringList() << recipient, message); |
2816 | - TRY_COMPARE(messageSentSpy.count(), 1); |
2817 | - |
2818 | - QSignalSpy messageReceivedSpy(ChatManager::instance(), SIGNAL(messageReceived(QString,QString,QDateTime,QString,bool))); |
2819 | + TelepathyHelper::instance()->registerChannelObserver("TelephonyServiceTests"); |
2820 | + TRY_VERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(TP_QT_IFACE_CLIENT + ".TelephonyServiceTests")); |
2821 | + QSignalSpy textChannelAvailableSpy(ChatManager::instance(), SIGNAL(textChannelAvailable(Tp::TextChannelPtr))); |
2822 | |
2823 | // now receive a message from a very similar number so CM creates another |
2824 | // channel and the handler needs to deal with both |
2825 | @@ -374,8 +385,11 @@ |
2826 | properties["Recipients"] = (QStringList() << recipient2); |
2827 | mMockController->PlaceIncomingMessage(message, properties); |
2828 | |
2829 | - TRY_COMPARE(messageReceivedSpy.count(), 1); |
2830 | - QString receivedMessageId = messageReceivedSpy.first()[3].toString(); |
2831 | + TRY_COMPARE(textChannelAvailableSpy.count(), 2); |
2832 | + Tp::TextChannelPtr channel = textChannelAvailableSpy[1].first().value<Tp::TextChannelPtr>(); |
2833 | + QVERIFY(!channel.isNull()); |
2834 | + TRY_COMPARE(channel->messageQueue().count(), 1); |
2835 | + QString receivedMessageId = channel->messageQueue().first().messageToken(); |
2836 | |
2837 | // then acknowledge the message that arrived in the second channel and make sure handler |
2838 | // does the right thing |
2839 | @@ -404,7 +418,7 @@ |
2840 | HandlerController::instance()->sendMessage(mTpAccount->uniqueIdentifier(), QStringList() << recipient, message); |
2841 | TRY_COMPARE(messageSentSpy.count(), 1); |
2842 | |
2843 | - QSignalSpy messageReceivedSpy(ChatManager::instance(), SIGNAL(messageReceived(QString,QString,QDateTime,QString,bool))); |
2844 | + QSignalSpy textChannelAvailableSpy(ChatManager::instance(), SIGNAL(textChannelAvailable(Tp::TextChannelPtr))); |
2845 | |
2846 | // now receive some messages from a very similar number so CM creates another |
2847 | // channel and the handler needs to deal with both |
2848 | @@ -415,7 +429,11 @@ |
2849 | mMockController->PlaceIncomingMessage(message.arg(QString::number(i)), properties); |
2850 | } |
2851 | |
2852 | - TRY_COMPARE(messageReceivedSpy.count(), messageCount); |
2853 | + TRY_COMPARE(textChannelAvailableSpy.count(), 1); |
2854 | + Tp::TextChannelPtr channel = textChannelAvailableSpy.first().first().value<Tp::TextChannelPtr>(); |
2855 | + QVERIFY(!channel.isNull()); |
2856 | + TRY_COMPARE(channel->messageQueue().count(), messageCount); |
2857 | + QString receivedMessageId = channel->messageQueue().first().messageToken(); |
2858 | |
2859 | // then acknowledge the messages that arrived in the second channel and make sure handler |
2860 | // does the right thing |
2861 | @@ -491,8 +509,13 @@ |
2862 | QSignalSpy messageSentOfonoSpy(mOfonoMockController, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2863 | QSignalSpy messageSentMultimediaSpy(mMultimediaMockController, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2864 | |
2865 | - QString accountId = HandlerController::instance()->sendMessage(mOfonoTpAccount->uniqueIdentifier(), QStringList() << recipient, message); |
2866 | - QCOMPARE(accountId, mMultimediaTpAccount->uniqueIdentifier()); |
2867 | + QString jobObjectPath = HandlerController::instance()->sendMessage(mOfonoTpAccount->uniqueIdentifier(), QStringList() << recipient, message); |
2868 | + |
2869 | + QDBusInterface jobInterface(TelepathyHelper::instance()->handlerInterface()->service(), |
2870 | + jobObjectPath); |
2871 | + QSignalSpy finishedSpy(&jobInterface, SIGNAL(finished())); |
2872 | + TRY_COMPARE(finishedSpy.count(), 1); |
2873 | + QCOMPARE(jobInterface.property("accountId").toString(), mMultimediaTpAccount->uniqueIdentifier()); |
2874 | TRY_COMPARE(messageSentMultimediaSpy.count(), 1); |
2875 | QCOMPARE(messageSentOfonoSpy.count(), 0); |
2876 | QString sentMessage = messageSentMultimediaSpy.first().first().toString(); |
2877 | |
2878 | === modified file 'tests/libtelephonyservice/ChatEntryTest.cpp' |
2879 | --- tests/libtelephonyservice/ChatEntryTest.cpp 2016-10-06 19:34:36 +0000 |
2880 | +++ tests/libtelephonyservice/ChatEntryTest.cpp 2016-10-06 19:34:37 +0000 |
2881 | @@ -93,6 +93,7 @@ |
2882 | QFETCH(QString, accountId); |
2883 | QFETCH(QStringList, participants); |
2884 | |
2885 | + /* |
2886 | MockController *mockController = accountId.startsWith("mock/mock") ? mGenericMockController : mMultimediaMockController; |
2887 | |
2888 | QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *))); |
2889 | @@ -137,6 +138,7 @@ |
2890 | QTRY_COMPARE(chatStateChangedSpy2.count(), 1); |
2891 | QCOMPARE(contactChatState2->state(), (int)ChatEntry::ChannelChatStatePaused); |
2892 | } |
2893 | + */ |
2894 | } |
2895 | |
2896 | QTEST_MAIN(ChatEntryTest) |
2897 | |
2898 | === modified file 'tests/libtelephonyservice/ChatManagerTest.cpp' |
2899 | --- tests/libtelephonyservice/ChatManagerTest.cpp 2016-10-06 19:34:36 +0000 |
2900 | +++ tests/libtelephonyservice/ChatManagerTest.cpp 2016-10-06 19:34:37 +0000 |
2901 | @@ -24,6 +24,8 @@ |
2902 | #include "telepathyhelper.h" |
2903 | #include "mockcontroller.h" |
2904 | |
2905 | +Q_DECLARE_METATYPE(Tp::TextChannelPtr) |
2906 | + |
2907 | class ChatManagerTest : public TelepathyTest |
2908 | { |
2909 | Q_OBJECT |
2910 | @@ -36,9 +38,7 @@ |
2911 | void testSendMessage(); |
2912 | void testSendMessageWithAttachments_data(); |
2913 | void testSendMessageWithAttachments(); |
2914 | - void testMessageReceived(); |
2915 | void testAcknowledgeMessages(); |
2916 | - void testChatEntry(); |
2917 | |
2918 | private: |
2919 | Tp::AccountPtr mGenericTpAccount; |
2920 | @@ -54,6 +54,8 @@ |
2921 | TelepathyHelper::instance()->setMmsGroupChat(false); |
2922 | TelepathyHelper::instance()->registerChannelObserver(); |
2923 | |
2924 | + qRegisterMetaType<Tp::TextChannelPtr>(); |
2925 | + |
2926 | // just give telepathy some time to register the observer |
2927 | QTest::qWait(1000); |
2928 | } |
2929 | @@ -102,11 +104,15 @@ |
2930 | |
2931 | MockController *controller = accountId.startsWith("mock/mock") ? mGenericMockController : mPhoneMockController; |
2932 | QSignalSpy controllerMessageSentSpy(controller, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2933 | - QSignalSpy messageSentSpy(ChatManager::instance(), SIGNAL(messageSent(QStringList,QString))); |
2934 | |
2935 | QVariantMap properties; |
2936 | properties["participantIds"] = recipients; |
2937 | - ChatManager::instance()->sendMessage(accountId, message, QVariantMap(), properties); |
2938 | + QString jobObjectPath = ChatManager::instance()->sendMessage(accountId, message, QVariantMap(), properties); |
2939 | + |
2940 | + QDBusInterface iface(TelepathyHelper::instance()->handlerInterface()->service(), |
2941 | + jobObjectPath); |
2942 | + |
2943 | + QSignalSpy finishedSpy(&iface, SIGNAL(finished())); |
2944 | |
2945 | TRY_COMPARE(controllerMessageSentSpy.count(), 1); |
2946 | QString messageText = controllerMessageSentSpy.first()[0].toString(); |
2947 | @@ -116,34 +122,13 @@ |
2948 | QCOMPARE(messageText, message); |
2949 | QCOMPARE(messageRecipients, recipients); |
2950 | |
2951 | - TRY_COMPARE(messageSentSpy.count(), 1); |
2952 | - messageRecipients = messageSentSpy.first()[0].toStringList(); |
2953 | - qSort(messageRecipients); |
2954 | - messageText = messageSentSpy.first()[1].toString(); |
2955 | - QCOMPARE(messageText, message); |
2956 | - QCOMPARE(messageRecipients, recipients); |
2957 | -} |
2958 | - |
2959 | -void ChatManagerTest::testMessageReceived() |
2960 | -{ |
2961 | - QSignalSpy messageReceivedSpy(ChatManager::instance(), SIGNAL(messageReceived(QString,QString,QDateTime,QString,bool))); |
2962 | - |
2963 | - QVariantMap properties; |
2964 | - properties["Sender"] = "12345"; |
2965 | - properties["Recipients"] = (QStringList() << "12345"); |
2966 | - QString message("Hi there"); |
2967 | - mGenericMockController->PlaceIncomingMessage(message, properties); |
2968 | - |
2969 | - TRY_COMPARE(messageReceivedSpy.count(), 1); |
2970 | - QString sender = messageReceivedSpy.first()[0].toString(); |
2971 | - QString receivedMessage = messageReceivedSpy.first()[1].toString(); |
2972 | - QCOMPARE(sender, properties["Sender"].toString()); |
2973 | - QCOMPARE(receivedMessage, message); |
2974 | + // the rest of the properties are tested in the MessageSendingJob tests. |
2975 | + TRY_COMPARE(finishedSpy.count(), 1); |
2976 | } |
2977 | |
2978 | void ChatManagerTest::testAcknowledgeMessages() |
2979 | { |
2980 | - QSignalSpy messageReceivedSpy(ChatManager::instance(), SIGNAL(messageReceived(QString,QString,QDateTime,QString,bool))); |
2981 | + QSignalSpy textChannelAvailableSpy(ChatManager::instance(), SIGNAL(textChannelAvailable(Tp::TextChannelPtr))); |
2982 | |
2983 | QVariantMap properties; |
2984 | properties["Sender"] = "12345"; |
2985 | @@ -155,12 +140,14 @@ |
2986 | // the wait shouldn't be needed, but just in case |
2987 | QTest::qWait(50); |
2988 | } |
2989 | - TRY_COMPARE(messageReceivedSpy.count(), messages.count()); |
2990 | + TRY_COMPARE(textChannelAvailableSpy.count(), 1); |
2991 | + Tp::TextChannelPtr channel = textChannelAvailableSpy.first().first().value<Tp::TextChannelPtr>(); |
2992 | + QVERIFY(!channel.isNull()); |
2993 | |
2994 | + TRY_COMPARE(channel->messageQueue().count(), messages.count()); |
2995 | QStringList messageIds; |
2996 | for (int i = 0; i < messages.count(); ++i) { |
2997 | - QString messageId = messageReceivedSpy[i][3].toString(); |
2998 | - messageIds << messageId; |
2999 | + messageIds << channel->messageQueue()[i].messageToken(); |
3000 | } |
3001 | |
3002 | QSignalSpy messageReadSpy(mGenericMockController, SIGNAL(MessageRead(QString))); |
3003 | @@ -183,26 +170,6 @@ |
3004 | QCOMPARE(receivedIds, messageIds); |
3005 | } |
3006 | |
3007 | -void ChatManagerTest::testChatEntry() |
3008 | -{ |
3009 | - QStringList recipients; |
3010 | - recipients << "user@domain.com" << "user2@domain.com"; |
3011 | - QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *))); |
3012 | - QVariantMap properties; |
3013 | - properties["participantIds"] = recipients; |
3014 | - |
3015 | - ChatEntry *entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, true); |
3016 | - QVERIFY(entry == NULL); |
3017 | - QTRY_COMPARE(chatEntryCreatedSpy.count(), 1); |
3018 | - |
3019 | - entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, false); |
3020 | - QVERIFY(entry != NULL); |
3021 | - QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst(); |
3022 | - QCOMPARE(QString("mock/mock/account0"), arguments.at(0).toString()); |
3023 | - QCOMPARE(recipients.toSet(), arguments.at(1).toStringList().toSet()); |
3024 | - QCOMPARE(entry, arguments.at(2).value<ChatEntry*>()); |
3025 | -} |
3026 | - |
3027 | void ChatManagerTest::testSendMessageWithAttachments_data() |
3028 | { |
3029 | QTest::addColumn<QStringList>("recipients"); |
FAILED: Continuous integration, rev:1217 /jenkins. canonical. com/system- apps/job/ lp-telephony- service- ci/2/ /jenkins. canonical. com/system- apps/job/ build/521/ console /jenkins. canonical. com/system- apps/job/ build-0- fetch/521 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= vivid+overlay/ 514 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= xenial/ 514 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 509/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial/ 509/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 509 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 509/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial/ 509 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial/ 509/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 509/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial/ 509/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-telephony- service- ci/2/rebuild
https:/