Merge lp:~mterry/telephony-service/greeter-contacts into lp:telephony-service
- greeter-contacts
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michael Terry |
Approved revision: | 764 |
Merged at revision: | 769 |
Proposed branch: | lp:~mterry/telephony-service/greeter-contacts |
Merge into: | lp:telephony-service |
Diff against target: |
1302 lines (+1065/-48) 15 files modified
approver/50-com.canonical.TelephonyServiceApprover.pkla (+6/-0) approver/CMakeLists.txt (+13/-0) approver/approver.cpp (+70/-47) approver/approver.h (+8/-0) approver/com.canonical.TelephonyServiceApprover.policy (+19/-0) approver/com.canonical.TelephonyServiceApprover.xml (+17/-0) approver/greetercontacts.cpp (+275/-0) approver/greetercontacts.h (+76/-0) approver/tests/CMakeLists.txt (+28/-0) approver/tests/GreeterContactsTest.cpp (+291/-0) approver/tests/GreeterContactsTestServer.cpp (+214/-0) approver/tests/libsystem.c (+38/-0) debian/rules (+4/-1) debian/telephony-service.install (+4/-0) libtelephonyservice/contactutils.cpp (+2/-0) |
To merge this branch: | bzr merge lp:~mterry/telephony-service/greeter-contacts |
Related bugs: | |
Related blueprints: |
Make Fake Phablet Greeter a Real One
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Gustavo Pichorim Boiko (community) | Approve | ||
Review via email: mp+199910@code.launchpad.net |
Commit message
Share current call contact info with the greeter.
Description of the change
Share current call contact info with the greeter.
When we split the unity8 greeter out into a separate process, it will no longer be able to see the user's contact database. So it will need to query the active session for the information.
Here's how this branch does that:
* Adds a custom DBus property to AccountsService that can only be read by the greeter and set by the user.
* When a call comes in and telephony-service notifies the user, it also sets the AccountsService property.
* The greeter sees the call, notifies the user and watches the currently selected user's AccountsService property for updates. If contact information is set for the current incoming phone number, it will update the notification.
* One interesting issue is that the contact photo can't be read by the greeter because ~/.local/
I added tests and manually tested on the device (which is kinda tricky, since you need several other branches to get the split greeter to be in effect -- if interested, can provide info).
This branch shouldn't hurt anything to land now, before the split greeter happens. It will just be updating the DBus field without anyone to read it. No big deal.
** Checklist **
Are there any related MPs required for this MP to build/function as expected? Please list.
- No (note that this branch is not really helpful before the split greeter lands; but it does its job fine without other branches)
Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)
- Yes
Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?
- Yes, with split branches installed
Did you successfully run all tests found in your component's Test Plan (https:/
- Yeah
If you changed the UI, was the change specified/approved by design?
- N/A
If you changed the packaging (debian), did you subscribe a core-dev to this MP?
- I am core-dev
PS Jenkins bot (ps-jenkins) wrote : | # |
Michael Terry (mterry) wrote : | # |
As discussed, this strategy is back to being useful, since we'll run a telephony stack in the greeter. Please review!
Gustavo Pichorim Boiko (boiko) wrote : | # |
Code looks good and after testing no regressions were found.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
- 764. By Michael Terry
-
Merge from trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:764
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
Review comments:
Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?
YES
Did you successfully run all tests found in your component's Test Plan (https:/
YES
Did CI run pass? If not, please explain why.
YES
Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
YES
Preview Diff
1 | === added file 'approver/50-com.canonical.TelephonyServiceApprover.pkla' |
2 | --- approver/50-com.canonical.TelephonyServiceApprover.pkla 1970-01-01 00:00:00 +0000 |
3 | +++ approver/50-com.canonical.TelephonyServiceApprover.pkla 2014-01-29 15:16:53 +0000 |
4 | @@ -0,0 +1,6 @@ |
5 | +[Allow LightDM to read TelephonyServiceApprover fields] |
6 | +Identity=unix-user:lightdm |
7 | +Action=com.canonical.TelephonyServiceApprover.ReadAny |
8 | +ResultAny=no |
9 | +ResultInactive=yes |
10 | +ResultActive=yes |
11 | |
12 | === modified file 'approver/CMakeLists.txt' |
13 | --- approver/CMakeLists.txt 2013-08-22 22:41:13 +0000 |
14 | +++ approver/CMakeLists.txt 2014-01-29 15:16:53 +0000 |
15 | @@ -2,6 +2,7 @@ |
16 | set(qt_SRCS |
17 | approver.cpp |
18 | approverdbus.cpp |
19 | + greetercontacts.cpp |
20 | ) |
21 | |
22 | set(approver_SRCS main.cpp ${qt_SRCS}) |
23 | @@ -18,6 +19,7 @@ |
24 | link_directories(${MESSAGING_MENU_LIBRARY_DIRS}) |
25 | |
26 | add_executable(telephony-service-approver ${approver_SRCS} ${approver_HDRS}) |
27 | +set_target_properties(telephony-service-approver PROPERTIES COMPILE_DEFINITIONS AS_BUSNAME=systemBus) |
28 | qt5_use_modules(telephony-service-approver Contacts Core DBus Gui Multimedia Qml) |
29 | |
30 | target_link_libraries(telephony-service-approver |
31 | @@ -31,3 +33,14 @@ |
32 | install(TARGETS telephony-service-approver RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |
33 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.TelephonyServiceApprover.service DESTINATION share/dbus-1/services) |
34 | install(FILES TelephonyServiceApprover.client DESTINATION share/telepathy/clients) |
35 | +install(FILES 50-com.canonical.TelephonyServiceApprover.pkla DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1/localauthority/10-vendor.d") |
36 | +install(FILES com.canonical.TelephonyServiceApprover.policy DESTINATION share/polkit-1/actions) |
37 | +install(FILES com.canonical.TelephonyServiceApprover.xml DESTINATION share/dbus-1/interfaces) |
38 | + |
39 | +# Create accountsservice symlink for above dbus interface |
40 | +install(CODE " |
41 | +execute_process(COMMAND mkdir -p \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces\") |
42 | +execute_process(COMMAND ln -sf ../../dbus-1/interfaces/com.canonical.TelephonyServiceApprover.xml \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces\") |
43 | + ") |
44 | + |
45 | +add_subdirectory(tests) |
46 | |
47 | === modified file 'approver/approver.cpp' |
48 | --- approver/approver.cpp 2013-12-03 15:20:30 +0000 |
49 | +++ approver/approver.cpp 2014-01-29 15:16:53 +0000 |
50 | @@ -25,6 +25,7 @@ |
51 | #include "chatmanager.h" |
52 | #include "config.h" |
53 | #include "contactutils.h" |
54 | +#include "greetercontacts.h" |
55 | #include "ringtone.h" |
56 | |
57 | #include <QContactAvatar> |
58 | @@ -48,8 +49,12 @@ |
59 | |
60 | Approver::Approver() |
61 | : Tp::AbstractClientApprover(channelFilters()), |
62 | - mPendingSnapDecision(NULL) |
63 | + mPendingSnapDecision(NULL), |
64 | + mGreeterContacts(NULL) |
65 | { |
66 | + mDefaultTitle = C::gettext("Unknown caller"); |
67 | + mDefaultIcon = QUrl(telephonyServiceDir() + "assets/avatar-default@18.png").toEncoded(); |
68 | + |
69 | ApproverDBus *dbus = new ApproverDBus(); |
70 | connect(dbus, |
71 | SIGNAL(acceptCallRequested()), |
72 | @@ -58,6 +63,12 @@ |
73 | SIGNAL(rejectCallRequested()), |
74 | SLOT(onRejectCallRequested())); |
75 | dbus->connectToBus(); |
76 | + |
77 | + if (qgetenv("XDG_SESSION_CLASS") == "greeter") { |
78 | + mGreeterContacts = new GreeterContacts(this); |
79 | + connect(mGreeterContacts, SIGNAL(contactUpdated(QtContacts::QContact)), |
80 | + this, SLOT(updateNotification(QtContacts::QContact))); |
81 | + } |
82 | } |
83 | |
84 | Approver::~Approver() |
85 | @@ -167,6 +178,34 @@ |
86 | delete (EventData*) data; |
87 | } |
88 | |
89 | +void Approver::updateNotification(const QContact &contact) |
90 | +{ |
91 | + if (!mPendingSnapDecision) |
92 | + return; |
93 | + |
94 | + QString displayLabel = ContactUtils::formatContactName(contact); |
95 | + QString avatar = contact.detail<QContactAvatar>().imageUrl().toEncoded(); |
96 | + |
97 | + if (displayLabel.isEmpty()) { |
98 | + displayLabel = mDefaultTitle; |
99 | + } |
100 | + |
101 | + if (avatar.isEmpty()) { |
102 | + avatar = mDefaultIcon; |
103 | + } |
104 | + |
105 | + notify_notification_update(mPendingSnapDecision, |
106 | + displayLabel.toStdString().c_str(), |
107 | + mCachedBody.toStdString().c_str(), |
108 | + avatar.toStdString().c_str()); |
109 | + |
110 | + GError *error = NULL; |
111 | + if (!notify_notification_show(mPendingSnapDecision, &error)) { |
112 | + qWarning() << "Failed to show snap decision:" << error->message; |
113 | + g_error_free (error); |
114 | + } |
115 | +} |
116 | + |
117 | void Approver::onChannelReady(Tp::PendingOperation *op) |
118 | { |
119 | Tp::PendingReady *pr = qobject_cast<Tp::PendingReady*>(op); |
120 | @@ -210,25 +249,21 @@ |
121 | data->dispatchOp = dispatchOp; |
122 | data->channel = channel; |
123 | |
124 | - QString title = C::gettext("Unknown caller"); |
125 | - QString icon = QUrl(telephonyServiceDir() + "assets/avatar-default@18.png").toEncoded(); |
126 | - QString body; |
127 | - |
128 | if (!contact->id().isEmpty()) { |
129 | if (contact->id().startsWith("x-ofono-private")) { |
130 | - body = QString::fromUtf8(C::gettext("Calling from private number")); |
131 | + mCachedBody = QString::fromUtf8(C::gettext("Calling from private number")); |
132 | } else if (contact->id().startsWith("x-ofono-unknown")) { |
133 | - body = QString::fromUtf8(C::gettext("Calling from unknown number")); |
134 | + mCachedBody = QString::fromUtf8(C::gettext("Calling from unknown number")); |
135 | } else { |
136 | - body = QString::fromUtf8(C::gettext("Calling from %1")).arg(contact->id()); |
137 | + mCachedBody = QString::fromUtf8(C::gettext("Calling from %1")).arg(contact->id()); |
138 | } |
139 | } else { |
140 | - body = C::gettext("Caller number is not available"); |
141 | + mCachedBody = C::gettext("Caller number is not available"); |
142 | } |
143 | |
144 | - notification = notify_notification_new (title.toStdString().c_str(), |
145 | - body.toStdString().c_str(), |
146 | - icon.toStdString().c_str()); |
147 | + notification = notify_notification_new (mDefaultTitle.toStdString().c_str(), |
148 | + mCachedBody.toStdString().c_str(), |
149 | + mDefaultIcon.toStdString().c_str()); |
150 | notify_notification_set_hint_string(notification, |
151 | "x-canonical-snap-decisions", |
152 | "true"); |
153 | @@ -251,41 +286,29 @@ |
154 | |
155 | mPendingSnapDecision = notification; |
156 | |
157 | - // try to match the contact info |
158 | - QContactFetchRequest *request = new QContactFetchRequest(this); |
159 | - request->setFilter(QContactPhoneNumber::match(contact->id())); |
160 | - |
161 | - // lambda function to update the notification |
162 | - QObject::connect(request, &QContactAbstractRequest::resultsAvailable, [request, notification, title, body, icon]() { |
163 | - if (request && request->contacts().size() > 0) { |
164 | - // use the first match |
165 | - QContact contact = request->contacts().at(0); |
166 | - QString displayLabel = ContactUtils::formatContactName(contact); |
167 | - QString avatar = contact.detail<QContactAvatar>().imageUrl().toEncoded(); |
168 | - |
169 | - if (displayLabel.isEmpty()) { |
170 | - displayLabel = title; |
171 | - } |
172 | - |
173 | - if (avatar.isEmpty()) { |
174 | - avatar = icon; |
175 | - } |
176 | - |
177 | - notify_notification_update(notification, |
178 | - displayLabel.toStdString().c_str(), |
179 | - body.toStdString().c_str(), |
180 | - avatar.toStdString().c_str()); |
181 | - |
182 | - GError *error = NULL; |
183 | - if (!notify_notification_show(notification, &error)) { |
184 | - qWarning() << "Failed to show snap decision:" << error->message; |
185 | - g_error_free (error); |
186 | - } |
187 | - } |
188 | - }); |
189 | - |
190 | - request->setManager(ContactUtils::sharedManager()); |
191 | - request->start(); |
192 | + if (mGreeterContacts) { // we're in the greeter's session |
193 | + mGreeterContacts->setFilter(QContactPhoneNumber::match(contact->id())); |
194 | + } else { |
195 | + // try to match the contact info |
196 | + QContactFetchRequest *request = new QContactFetchRequest(this); |
197 | + request->setFilter(QContactPhoneNumber::match(contact->id())); |
198 | + |
199 | + // lambda function to update the notification |
200 | + QObject::connect(request, &QContactAbstractRequest::resultsAvailable, [this, request]() { |
201 | + if (request && request->contacts().size() > 0) { |
202 | + // use the first match |
203 | + QContact contact = request->contacts().at(0); |
204 | + |
205 | + updateNotification(contact); |
206 | + |
207 | + // Also notify greeter via AccountsService |
208 | + GreeterContacts::emitContact(contact); |
209 | + } |
210 | + }); |
211 | + |
212 | + request->setManager(ContactUtils::sharedManager()); |
213 | + request->start(); |
214 | + } |
215 | |
216 | GError *error = NULL; |
217 | if (!notify_notification_show(notification, &error)) { |
218 | |
219 | === modified file 'approver/approver.h' |
220 | --- approver/approver.h 2013-10-04 21:15:46 +0000 |
221 | +++ approver/approver.h 2014-01-29 15:16:53 +0000 |
222 | @@ -26,11 +26,14 @@ |
223 | #include <unistd.h> |
224 | #include <libnotify/notify.h> |
225 | |
226 | +#include <QContact> |
227 | #include <QMap> |
228 | #include <TelepathyQt/AbstractClientApprover> |
229 | #include <TelepathyQt/PendingReady> |
230 | #include <TelepathyQt/ChannelDispatchOperation> |
231 | |
232 | +class GreeterContacts; |
233 | + |
234 | class Approver : public QObject, public Tp::AbstractClientApprover |
235 | { |
236 | Q_OBJECT |
237 | @@ -59,11 +62,16 @@ |
238 | void closeSnapDecision(); |
239 | void onAcceptCallRequested(); |
240 | void onRejectCallRequested(); |
241 | + void updateNotification(const QtContacts::QContact &contact); |
242 | |
243 | private: |
244 | QList<Tp::ChannelDispatchOperationPtr> mDispatchOps; |
245 | QMap<Tp::PendingOperation*,Tp::ChannelPtr> mChannels; |
246 | NotifyNotification* mPendingSnapDecision; |
247 | + GreeterContacts *mGreeterContacts; |
248 | + QString mDefaultTitle; |
249 | + QString mDefaultIcon; |
250 | + QString mCachedBody; |
251 | }; |
252 | |
253 | #endif // APPROVER_H |
254 | |
255 | === added file 'approver/com.canonical.TelephonyServiceApprover.policy' |
256 | --- approver/com.canonical.TelephonyServiceApprover.policy 1970-01-01 00:00:00 +0000 |
257 | +++ approver/com.canonical.TelephonyServiceApprover.policy 2014-01-29 15:16:53 +0000 |
258 | @@ -0,0 +1,19 @@ |
259 | +<?xml version="1.0" encoding="UTF-8"?> |
260 | + |
261 | +<policyconfig> |
262 | + <action id="com.canonical.TelephonyServiceApprover.ChangeOwn"> |
263 | + <defaults> |
264 | + <allow_any>no</allow_any> |
265 | + <allow_inactive>yes</allow_inactive> |
266 | + <allow_active>yes</allow_active> |
267 | + </defaults> |
268 | + </action> |
269 | + |
270 | + <action id="com.canonical.TelephonyServiceApprover.ReadAny"> |
271 | + <defaults> |
272 | + <allow_any>no</allow_any> |
273 | + <allow_inactive>no</allow_inactive> |
274 | + <allow_active>no</allow_active> |
275 | + </defaults> |
276 | + </action> |
277 | +</policyconfig> |
278 | |
279 | === added file 'approver/com.canonical.TelephonyServiceApprover.xml' |
280 | --- approver/com.canonical.TelephonyServiceApprover.xml 1970-01-01 00:00:00 +0000 |
281 | +++ approver/com.canonical.TelephonyServiceApprover.xml 2014-01-29 15:16:53 +0000 |
282 | @@ -0,0 +1,17 @@ |
283 | +<node> |
284 | + <interface name="com.canonical.TelephonyServiceApprover"> |
285 | + |
286 | + <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/> |
287 | + |
288 | + <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn" |
289 | + value="com.canonical.TelephonyServiceApprover.ChangeOwn"/> |
290 | + |
291 | + <annotation name="org.freedesktop.Accounts.Authentication.ReadAny" |
292 | + value="com.canonical.TelephonyServiceApprover.ReadAny"/> |
293 | + |
294 | + <property name="CurrentContact" type="a{sv}" access="readwrite"> |
295 | + <annotation name="org.freedesktop.Accounts.DefaultValue" value="{}"/> |
296 | + </property> |
297 | + |
298 | + </interface> |
299 | +</node> |
300 | |
301 | === added file 'approver/greetercontacts.cpp' |
302 | --- approver/greetercontacts.cpp 1970-01-01 00:00:00 +0000 |
303 | +++ approver/greetercontacts.cpp 2014-01-29 15:16:53 +0000 |
304 | @@ -0,0 +1,275 @@ |
305 | +/* |
306 | + * Copyright (C) 2013 Canonical, Ltd. |
307 | + * |
308 | + * Authors: |
309 | + * Michael Terry <michael.terry@canonical.com> |
310 | + * |
311 | + * This file is part of telephony-service. |
312 | + * |
313 | + * telephony-service is free software; you can redistribute it and/or modify |
314 | + * it under the terms of the GNU General Public License as published by |
315 | + * the Free Software Foundation; version 3. |
316 | + * |
317 | + * telephony-service is distributed in the hope that it will be useful, |
318 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
319 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
320 | + * GNU General Public License for more details. |
321 | + * |
322 | + * You should have received a copy of the GNU General Public License |
323 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
324 | + */ |
325 | + |
326 | +#include "greetercontacts.h" |
327 | + |
328 | +#include <pwd.h> |
329 | +#include <QContactAvatar> |
330 | +#include <QContactInvalidFilter> |
331 | +#include <QContactManagerEngine> |
332 | +#include <QContactName> |
333 | +#include <QContactPhoneNumber> |
334 | +#include <QDBusInterface> |
335 | +#include <QDBusPendingCall> |
336 | +#include <QDBusPendingReply> |
337 | +#include <QDir> |
338 | +#include <QFile> |
339 | +#include <unistd.h> |
340 | + |
341 | +QTCONTACTS_USE_NAMESPACE |
342 | + |
343 | +GreeterContacts::GreeterContacts(QObject *parent) |
344 | +: QObject(parent), |
345 | + mFilter(QContactInvalidFilter()), |
346 | + mActiveUser(), |
347 | + mContacts() |
348 | +{ |
349 | + // Watch for changes |
350 | + |
351 | + QDBusConnection connection = QDBusConnection::sessionBus(); |
352 | + connection.connect("com.canonical.UnityGreeter", |
353 | + "/list", |
354 | + "org.freedesktop.DBus.Properties", |
355 | + "PropertiesChanged", |
356 | + this, |
357 | + SLOT(greeterPropertiesChanged(QString, QVariantMap, QStringList))); |
358 | + |
359 | + connection = QDBusConnection::AS_BUSNAME(); |
360 | + connection.connect("org.freedesktop.Accounts", |
361 | + nullptr, |
362 | + "org.freedesktop.DBus.Properties", |
363 | + "PropertiesChanged", |
364 | + this, |
365 | + SLOT(accountsPropertiesChanged(QString, QVariantMap, QStringList, QDBusMessage))); |
366 | + |
367 | + // Start initial queries |
368 | + |
369 | + queryEntry(); |
370 | + |
371 | + QDBusInterface iface("org.freedesktop.Accounts", |
372 | + "/org/freedesktop/Accounts", |
373 | + "org.freedesktop.Accounts", |
374 | + QDBusConnection::AS_BUSNAME()); |
375 | + QDBusPendingCall call = iface.asyncCall("ListCachedUsers"); |
376 | + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); |
377 | + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), |
378 | + this, SLOT(accountsGetUsersReply(QDBusPendingCallWatcher *))); |
379 | +} |
380 | + |
381 | +GreeterContacts::~GreeterContacts() |
382 | +{ |
383 | +} |
384 | + |
385 | +void GreeterContacts::setFilter(const QContactFilter &filter) |
386 | +{ |
387 | + mFilter = filter; |
388 | + signalIfNeeded(); |
389 | +} |
390 | + |
391 | +void GreeterContacts::greeterPropertiesChanged(const QString &interface, |
392 | + const QVariantMap &changed, |
393 | + const QStringList &invalidated) |
394 | +{ |
395 | + if (interface == "com.canonical.UnityGreeter.List") { |
396 | + if (changed.contains("ActiveEntry")) { |
397 | + updateActiveUser(changed.value("ActiveEntry").toString()); |
398 | + } else if (invalidated.contains("ActiveEntry")) { |
399 | + queryEntry(); |
400 | + } |
401 | + } |
402 | +} |
403 | + |
404 | +void GreeterContacts::accountsPropertiesChanged(const QString &interface, |
405 | + const QVariantMap &changed, |
406 | + const QStringList &invalidated, |
407 | + const QDBusMessage &message) |
408 | +{ |
409 | + if (interface == "com.canonical.TelephonyServiceApprover") { |
410 | + if (changed.contains("CurrentContact")) { |
411 | + mContacts.insert(message.path(), qdbus_cast<QVariantMap>(changed.value("CurrentContact"))); |
412 | + signalIfNeeded(); |
413 | + } else if (invalidated.contains("CurrentContact")) { |
414 | + queryContact(message.path()); |
415 | + } |
416 | + } |
417 | +} |
418 | + |
419 | +void GreeterContacts::greeterGetEntryReply(QDBusPendingCallWatcher *watcher) |
420 | +{ |
421 | + QDBusPendingReply<QVariant> reply = *watcher; |
422 | + if (!reply.isError()) { |
423 | + updateActiveUser(reply.argumentAt<0>().toString()); |
424 | + } else { |
425 | + qWarning() << "Failed to get active entry from Unity Greeter:" << reply.error().message(); |
426 | + } |
427 | + watcher->deleteLater(); |
428 | +} |
429 | + |
430 | +void GreeterContacts::accountsGetUsersReply(QDBusPendingCallWatcher *watcher) |
431 | +{ |
432 | + QDBusPendingReply<QList<QDBusObjectPath>> reply = *watcher; |
433 | + if (!reply.isError()) { |
434 | + Q_FOREACH (const QDBusObjectPath &user, reply.argumentAt<0>()) { |
435 | + queryContact(user.path()); |
436 | + } |
437 | + } else { |
438 | + qWarning() << "Failed to get user list from AccountsService:" << reply.error().message(); |
439 | + } |
440 | + watcher->deleteLater(); |
441 | +} |
442 | + |
443 | +void GreeterContacts::accountsGetContactReply(QDBusPendingCallWatcher *watcher) |
444 | +{ |
445 | + QDBusPendingReply<QVariant> reply = *watcher; |
446 | + if (!reply.isError()) { |
447 | + mContacts.insert(watcher->property("telepathyPath").toString(), qdbus_cast<QVariantMap>(reply.argumentAt<0>())); |
448 | + signalIfNeeded(); |
449 | + } else { |
450 | + qWarning() << "Failed to get user's contact from AccountsService:" << reply.error().message(); |
451 | + } |
452 | + watcher->deleteLater(); |
453 | +} |
454 | + |
455 | +void GreeterContacts::queryEntry() |
456 | +{ |
457 | + QDBusInterface iface("com.canonical.UnityGreeter", |
458 | + "/list", |
459 | + "org.freedesktop.DBus.Properties", |
460 | + QDBusConnection::sessionBus()); |
461 | + QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.UnityGreeter.List", "ActiveEntry"); |
462 | + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); |
463 | + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), |
464 | + this, SLOT(greeterGetEntryReply(QDBusPendingCallWatcher *))); |
465 | +} |
466 | + |
467 | +void GreeterContacts::queryContact(const QString &user) |
468 | +{ |
469 | + QDBusInterface iface("org.freedesktop.Accounts", |
470 | + user, |
471 | + "org.freedesktop.DBus.Properties", |
472 | + QDBusConnection::AS_BUSNAME()); |
473 | + QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.TelephonyServiceApprover", "CurrentContact"); |
474 | + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); |
475 | + watcher->setProperty("telepathyPath", QVariant(user)); |
476 | + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), |
477 | + this, SLOT(accountsGetContactReply(QDBusPendingCallWatcher *))); |
478 | +} |
479 | + |
480 | +void GreeterContacts::updateActiveUser(const QString &username) |
481 | +{ |
482 | + struct passwd *pwinfo = getpwnam(username.toLatin1()); |
483 | + if (pwinfo) { |
484 | + mActiveUser = "/org/freedesktop/Accounts/User" + QString::number(pwinfo->pw_uid); |
485 | + signalIfNeeded(); |
486 | + } |
487 | +} |
488 | + |
489 | +QContact GreeterContacts::lookupContact() |
490 | +{ |
491 | + // For now, only ever look at active user's contact info. In future, |
492 | + // maybe we should search all users for any matching info. |
493 | + QVariantMap contactInfo = mContacts.value(mActiveUser); |
494 | + if (!contactInfo.empty()) { |
495 | + QContact contact = mapToContact(contactInfo); |
496 | + if (QContactManagerEngine::testFilter(mFilter, contact)) { |
497 | + return contact; |
498 | + } |
499 | + } |
500 | + |
501 | + return QContact(); |
502 | +} |
503 | + |
504 | +void GreeterContacts::signalIfNeeded() |
505 | +{ |
506 | + QContact contact = lookupContact(); |
507 | + if (!contact.isEmpty()) { |
508 | + Q_EMIT contactUpdated(contact); |
509 | + } |
510 | +} |
511 | + |
512 | +void GreeterContacts::emitContact(const QContact &contact) |
513 | +{ |
514 | + QString uid = QString::number(getuid()); |
515 | + QVariantMap map = contactToMap(contact); |
516 | + |
517 | + if (!map.value("Image").toString().isEmpty()) { |
518 | + // OK, so we want to tell LightDM about our contact. But LightDM won't |
519 | + // have access to our image file in their normal location managed by |
520 | + // evolution. And rather than give world-readable permissions to our |
521 | + // evolution dir, we minimize the damage by copying the image to a new |
522 | + // more accessible location. |
523 | + // TODO: This is not ideal because this new location is still |
524 | + // world-readable and thus leaks a contact picture and because if the |
525 | + // user's home directory is encrypted, LightDM can't read it. |
526 | + // Hopefully LightDM will soon allow a /run/user style location for |
527 | + // users to share data with it. |
528 | + QFile imageFile(QDir::home().filePath(".telephony-service-contact-image")); |
529 | + imageFile.remove(); |
530 | + if (QFile(map.value("Image").toString()).copy(imageFile.fileName())) { |
531 | + map.insert("Image", imageFile.fileName()); |
532 | + } |
533 | + } |
534 | + |
535 | + QDBusInterface iface("org.freedesktop.Accounts", |
536 | + "/org/freedesktop/Accounts/User" + uid, |
537 | + "org.freedesktop.DBus.Properties", |
538 | + QDBusConnection::AS_BUSNAME()); |
539 | + iface.asyncCall("Set", "com.canonical.TelephonyServiceApprover", "CurrentContact", QVariant::fromValue(QDBusVariant(QVariant(map)))); |
540 | +} |
541 | + |
542 | +QVariantMap GreeterContacts::contactToMap(const QContact &contact) |
543 | +{ |
544 | + QVariantMap map; |
545 | + |
546 | + QContactAvatar avatarDetail = contact.detail<QContactAvatar>(); |
547 | + map.insert("Image", avatarDetail.imageUrl().toLocalFile()); |
548 | + |
549 | + QContactName nameDetail = contact.detail<QContactName>(); |
550 | + map.insert("FirstName", nameDetail.firstName()); |
551 | + map.insert("LastName", nameDetail.lastName()); |
552 | + |
553 | + QContactPhoneNumber numberDetail = contact.detail<QContactPhoneNumber>(); |
554 | + map.insert("PhoneNumber", numberDetail.number()); |
555 | + |
556 | + return map; |
557 | +} |
558 | + |
559 | +QContact GreeterContacts::mapToContact(const QVariantMap &map) |
560 | +{ |
561 | + QContact contact; |
562 | + |
563 | + QContactAvatar avatarDetail; |
564 | + avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(map.value("Image").toString())); |
565 | + contact.saveDetail(&avatarDetail); |
566 | + |
567 | + // We only use FirstName and LastName right now in ContactUtils::formatContactName(). |
568 | + // If/When we use more, we should save more detail values here. |
569 | + QContactName nameDetail; |
570 | + nameDetail.setValue(QContactName::FieldFirstName, map.value("FirstName")); |
571 | + nameDetail.setValue(QContactName::FieldLastName, map.value("LastName")); |
572 | + contact.saveDetail(&nameDetail); |
573 | + |
574 | + QContactPhoneNumber numberDetail; |
575 | + numberDetail.setValue(QContactPhoneNumber::FieldNumber, map.value("PhoneNumber")); |
576 | + contact.saveDetail(&numberDetail); |
577 | + |
578 | + return contact; |
579 | +} |
580 | |
581 | === added file 'approver/greetercontacts.h' |
582 | --- approver/greetercontacts.h 1970-01-01 00:00:00 +0000 |
583 | +++ approver/greetercontacts.h 2014-01-29 15:16:53 +0000 |
584 | @@ -0,0 +1,76 @@ |
585 | +/* |
586 | + * Copyright (C) 2013 Canonical, Ltd. |
587 | + * |
588 | + * Authors: |
589 | + * Michael Terry <michael.terry@canonical.com> |
590 | + * |
591 | + * This file is part of telephony-service. |
592 | + * |
593 | + * telephony-service is free software; you can redistribute it and/or modify |
594 | + * it under the terms of the GNU General Public License as published by |
595 | + * the Free Software Foundation; version 3. |
596 | + * |
597 | + * telephony-service is distributed in the hope that it will be useful, |
598 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
599 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
600 | + * GNU General Public License for more details. |
601 | + * |
602 | + * You should have received a copy of the GNU General Public License |
603 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
604 | + */ |
605 | + |
606 | +#ifndef GREETERCONTACTS_H |
607 | +#define GREETERCONTACTS_H |
608 | + |
609 | +#include <QContact> |
610 | +#include <QContactFilter> |
611 | +#include <QDBusMessage> |
612 | +#include <QObject> |
613 | + |
614 | +class QDBusPendingCallWatcher; |
615 | + |
616 | +/** |
617 | + * When running under the greeter, we don't have our own contacts database. |
618 | + * Instead, we query AccountsService for the information. |
619 | + */ |
620 | +class GreeterContacts : public QObject |
621 | +{ |
622 | + Q_OBJECT |
623 | + |
624 | +public: |
625 | + GreeterContacts(QObject *parent = 0); |
626 | + ~GreeterContacts(); |
627 | + |
628 | + void setFilter(const QtContacts::QContactFilter &filter); |
629 | + |
630 | + // Records contact info for currently-logged-in user |
631 | + static void emitContact(const QtContacts::QContact &contact); |
632 | + |
633 | + // These are really implementation details, but are public for ease of unit testing |
634 | + static QVariantMap contactToMap(const QtContacts::QContact &contact); |
635 | + static QtContacts::QContact mapToContact(const QVariantMap &map); |
636 | + |
637 | +Q_SIGNALS: |
638 | + void contactUpdated(const QtContacts::QContact &contact); |
639 | + |
640 | +private Q_SLOTS: |
641 | + void greeterPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); |
642 | + void accountsPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated, const QDBusMessage &message); |
643 | + |
644 | + void greeterGetEntryReply(QDBusPendingCallWatcher *watcher); |
645 | + void accountsGetUsersReply(QDBusPendingCallWatcher *watcher); |
646 | + void accountsGetContactReply(QDBusPendingCallWatcher *watcher); |
647 | + |
648 | +private: |
649 | + void queryEntry(); |
650 | + void queryContact(const QString &user); |
651 | + void updateActiveUser(const QString &username); |
652 | + QtContacts::QContact lookupContact(); |
653 | + void signalIfNeeded(); |
654 | + |
655 | + QtContacts::QContactFilter mFilter; |
656 | + QString mActiveUser; |
657 | + QMap<QString, QVariantMap> mContacts; |
658 | +}; |
659 | + |
660 | +#endif // GREETERCONTACTS_H |
661 | |
662 | === added directory 'approver/tests' |
663 | === added file 'approver/tests/CMakeLists.txt' |
664 | --- approver/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
665 | +++ approver/tests/CMakeLists.txt 2014-01-29 15:16:53 +0000 |
666 | @@ -0,0 +1,28 @@ |
667 | +include_directories( |
668 | + ${CMAKE_CURRENT_BINARY_DIR} |
669 | + ${CMAKE_CURRENT_SOURCE_DIR} |
670 | + ${CMAKE_CURRENT_SOURCE_DIR}/.. |
671 | + ) |
672 | + |
673 | +add_library(GreeterContactsLibSystem MODULE libsystem.c) |
674 | +set_target_properties(GreeterContactsLibSystem PROPERTIES OUTPUT_NAME system) |
675 | + |
676 | +add_executable(GreeterContactsTestServerExe GreeterContactsTestServer.cpp) |
677 | +qt5_use_modules(GreeterContactsTestServerExe Core DBus) |
678 | + |
679 | +add_executable(GreeterContactsTestExe GreeterContactsTest.cpp ../greetercontacts.cpp) |
680 | +set_target_properties(GreeterContactsTestExe PROPERTIES COMPILE_DEFINITIONS "AS_BUSNAME=sessionBus;CMAKE_SOURCE_DIR=\"${CMAKE_SOURCE_DIR}\"") |
681 | +qt5_use_modules(GreeterContactsTestExe Contacts Core DBus Test) |
682 | + |
683 | +add_test(NAME GreeterContactsTest |
684 | + COMMAND env |
685 | + LD_PRELOAD=${CMAKE_CURRENT_BINARY_DIR}/libsystem.so |
686 | + dbus-test-runner |
687 | + --task ${CMAKE_CURRENT_BINARY_DIR}/GreeterContactsTestServerExe |
688 | + --task-name server |
689 | + --ignore-return |
690 | + --task ${CMAKE_CURRENT_BINARY_DIR}/GreeterContactsTestExe |
691 | + --task-name test |
692 | + --wait-for org.freedesktop.Accounts |
693 | + DEPENDENCIES GreeterContactsTestServerExe GreeterContactsTestExe GreeterContactsLibSystem |
694 | + ) |
695 | |
696 | === added file 'approver/tests/GreeterContactsTest.cpp' |
697 | --- approver/tests/GreeterContactsTest.cpp 1970-01-01 00:00:00 +0000 |
698 | +++ approver/tests/GreeterContactsTest.cpp 2014-01-29 15:16:53 +0000 |
699 | @@ -0,0 +1,291 @@ |
700 | +/* |
701 | + * Copyright (C) 2013 Canonical, Ltd. |
702 | + * |
703 | + * This file is part of telephony-service. |
704 | + * |
705 | + * telephony-service is free software; you can redistribute it and/or modify |
706 | + * it under the terms of the GNU General Public License as published by |
707 | + * the Free Software Foundation; version 3. |
708 | + * |
709 | + * telephony-service is distributed in the hope that it will be useful, |
710 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
711 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
712 | + * GNU General Public License for more details. |
713 | + * |
714 | + * You should have received a copy of the GNU General Public License |
715 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
716 | + */ |
717 | + |
718 | +#include "greetercontacts.h" |
719 | + |
720 | +#include <QContact> |
721 | +#include <QContactAvatar> |
722 | +#include <QContactName> |
723 | +#include <QContactPhoneNumber> |
724 | +#include <QDBusInterface> |
725 | +#include <QDBusPendingCallWatcher> |
726 | +#include <QDBusReply> |
727 | +#include <QObject> |
728 | +#include <QtTest> |
729 | +#include <QUrl> |
730 | + |
731 | +Q_DECLARE_METATYPE(QtContacts::QContact) // for QVariant's benefit |
732 | + |
733 | +QTCONTACTS_USE_NAMESPACE |
734 | + |
735 | +class GreeterContactsTest : public QObject |
736 | +{ |
737 | + Q_OBJECT |
738 | + |
739 | +public: |
740 | + GreeterContactsTest(); |
741 | + |
742 | +public Q_SLOTS: |
743 | + void setFilter(); |
744 | + |
745 | +private Q_SLOTS: |
746 | + void initTestCase(); |
747 | + void cleanup(); |
748 | + void testContactToMap(); |
749 | + void testMapToContact(); |
750 | + void testInitialValues(); |
751 | + void testSignalOnFilter(); |
752 | + void testSignalOnEntry(); |
753 | + void testSignalOnEntryInvalidated(); |
754 | + void testSignalOnContacts(); |
755 | + void testSignalOnContactsInvalidated(); |
756 | + void testEmitContact(); |
757 | + |
758 | +private: |
759 | + void waitForUpdatedSignal(bool convertedPath = false); |
760 | + void makeGreeterContacts(); |
761 | + void waitForInitialQuery(); |
762 | + QContact makeTestContact(bool convertedPath = false); |
763 | + QVariantMap makeTestMap(); |
764 | + void setActiveEntry(const QString &entry); |
765 | + void setCurrentContact(const QVariantMap &map); |
766 | + void setUseInvalidated(const QString &path, const QString &interface, bool useInvalidated); |
767 | + |
768 | + GreeterContacts *mGreeterContacts; |
769 | + QSignalSpy *mSpy; |
770 | +}; |
771 | + |
772 | + |
773 | + |
774 | +GreeterContactsTest::GreeterContactsTest() |
775 | +: QObject() |
776 | +{ |
777 | +} |
778 | + |
779 | +void GreeterContactsTest::initTestCase() |
780 | +{ |
781 | + mGreeterContacts = NULL; |
782 | + mSpy = NULL; |
783 | + qRegisterMetaType<QContact>(); |
784 | +} |
785 | + |
786 | +void GreeterContactsTest::cleanup() |
787 | +{ |
788 | + if (mSpy) { |
789 | + delete mSpy; |
790 | + mSpy = NULL; |
791 | + } |
792 | + if (mGreeterContacts) { |
793 | + delete mGreeterContacts; |
794 | + mGreeterContacts = NULL; |
795 | + } |
796 | + |
797 | + setActiveEntry(""); |
798 | + setCurrentContact(QVariantMap()); |
799 | + setUseInvalidated("/list", "com.canonical.UnityGreeter.List", false); |
800 | + setUseInvalidated("/org/freedesktop/Accounts/User12345", "com.canonical.TelephonyServiceApprover", false); |
801 | +} |
802 | + |
803 | +void GreeterContactsTest::testContactToMap() |
804 | +{ |
805 | + QVariantMap map = GreeterContacts::contactToMap(makeTestContact()); |
806 | + QVariantMap expectedMap = makeTestMap(); |
807 | + QCOMPARE(map, expectedMap); |
808 | +} |
809 | + |
810 | +void GreeterContactsTest::testMapToContact() |
811 | +{ |
812 | + QContact contact = GreeterContacts::mapToContact(makeTestMap()); |
813 | + QContact expectedContact = makeTestContact(); |
814 | + QCOMPARE(contact, expectedContact); |
815 | +} |
816 | + |
817 | +void GreeterContactsTest::testInitialValues() |
818 | +{ |
819 | + setActiveEntry("testuser"); |
820 | + setCurrentContact(makeTestMap()); |
821 | + makeGreeterContacts(); |
822 | + setFilter(); |
823 | + waitForUpdatedSignal(); |
824 | +} |
825 | + |
826 | +void GreeterContactsTest::testSignalOnFilter() |
827 | +{ |
828 | + setActiveEntry("testuser"); |
829 | + setCurrentContact(makeTestMap()); |
830 | + makeGreeterContacts(); |
831 | + waitForInitialQuery(); |
832 | + // setFilter might immediately send the signal, so wait until we can start the spy |
833 | + QTimer::singleShot(0, this, SLOT(setFilter())); |
834 | + waitForUpdatedSignal(); |
835 | +} |
836 | + |
837 | +void GreeterContactsTest::testSignalOnEntry() |
838 | +{ |
839 | + setCurrentContact(makeTestMap()); |
840 | + makeGreeterContacts(); |
841 | + setFilter(); |
842 | + waitForInitialQuery(); |
843 | + setActiveEntry("testuser"); |
844 | + waitForUpdatedSignal(); |
845 | +} |
846 | + |
847 | +void GreeterContactsTest::testSignalOnEntryInvalidated() |
848 | +{ |
849 | + setCurrentContact(makeTestMap()); |
850 | + makeGreeterContacts(); |
851 | + setFilter(); |
852 | + waitForInitialQuery(); |
853 | + setUseInvalidated("/list", "com.canonical.UnityGreeter.List", true); |
854 | + setActiveEntry("testuser"); |
855 | + waitForUpdatedSignal(); |
856 | +} |
857 | + |
858 | +void GreeterContactsTest::testSignalOnContacts() |
859 | +{ |
860 | + setActiveEntry("testuser"); |
861 | + makeGreeterContacts(); |
862 | + setFilter(); |
863 | + waitForInitialQuery(); |
864 | + setCurrentContact(makeTestMap()); |
865 | + waitForUpdatedSignal(); |
866 | +} |
867 | + |
868 | +void GreeterContactsTest::testSignalOnContactsInvalidated() |
869 | +{ |
870 | + setActiveEntry("testuser"); |
871 | + makeGreeterContacts(); |
872 | + setFilter(); |
873 | + waitForInitialQuery(); |
874 | + setUseInvalidated("/org/freedesktop/Accounts/User12345", "com.canonical.TelephonyServiceApprover", true); |
875 | + setCurrentContact(makeTestMap()); |
876 | + waitForUpdatedSignal(); |
877 | +} |
878 | + |
879 | +void GreeterContactsTest::testEmitContact() |
880 | +{ |
881 | + setActiveEntry("testuser"); |
882 | + makeGreeterContacts(); |
883 | + setFilter(); |
884 | + waitForInitialQuery(); |
885 | + // this next line acts like setCurrentContact() because uid is set to 12345 |
886 | + GreeterContacts::emitContact(makeTestContact()); |
887 | + waitForUpdatedSignal(true); |
888 | +} |
889 | + |
890 | +QVariantMap GreeterContactsTest::makeTestMap() |
891 | +{ |
892 | + QVariantMap map; |
893 | + map.insert("FirstName", QVariant("First")); |
894 | + map.insert("Image", QVariant(CMAKE_SOURCE_DIR "/icons/hicolor/48x48/apps/telephony-service-call.png")); |
895 | + map.insert("LastName", QVariant("Last")); |
896 | + map.insert("PhoneNumber", QVariant("555")); |
897 | + return map; |
898 | +} |
899 | + |
900 | +QContact GreeterContactsTest::makeTestContact(bool convertedPath) |
901 | +{ |
902 | + // This is the same contact that the test server will give out. |
903 | + QContact contact; |
904 | + |
905 | + QContactAvatar avatarDetail; |
906 | + QString imagePath; |
907 | + if (convertedPath) { |
908 | + imagePath = QDir::home().filePath(".telephony-service-contact-image"); |
909 | + } else { |
910 | + imagePath = CMAKE_SOURCE_DIR "/icons/hicolor/48x48/apps/telephony-service-call.png"; |
911 | + } |
912 | + avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(imagePath)); |
913 | + contact.saveDetail(&avatarDetail); |
914 | + |
915 | + QContactName nameDetail; |
916 | + nameDetail.setValue(QContactName::FieldFirstName, "First"); |
917 | + nameDetail.setValue(QContactName::FieldLastName, "Last"); |
918 | + contact.saveDetail(&nameDetail); |
919 | + |
920 | + QContactPhoneNumber numberDetail; |
921 | + numberDetail.setValue(QContactPhoneNumber::FieldNumber, "555"); |
922 | + contact.saveDetail(&numberDetail); |
923 | + |
924 | + return contact; |
925 | +} |
926 | + |
927 | +void GreeterContactsTest::setFilter() |
928 | +{ |
929 | + mGreeterContacts->setFilter(QContactPhoneNumber::match("555")); |
930 | +} |
931 | + |
932 | +void GreeterContactsTest::setActiveEntry(const QString &entry) |
933 | +{ |
934 | + QDBusInterface iface("com.canonical.UnityGreeter", |
935 | + "/list", |
936 | + "org.freedesktop.DBus.Properties", |
937 | + QDBusConnection::sessionBus()); |
938 | + QDBusReply<void> reply = iface.call("Set", "com.canonical.UnityGreeter.List", "ActiveEntry", QVariant::fromValue(QDBusVariant(QVariant(entry)))); |
939 | + QVERIFY(reply.isValid()); |
940 | +} |
941 | + |
942 | +void GreeterContactsTest::setCurrentContact(const QVariantMap &map) |
943 | +{ |
944 | + QDBusInterface iface("org.freedesktop.Accounts", |
945 | + "/org/freedesktop/Accounts/User12345", |
946 | + "org.freedesktop.DBus.Properties", |
947 | + QDBusConnection::sessionBus()); |
948 | + QDBusReply<void> reply = iface.call("Set", "com.canonical.TelephonyServiceApprover", "CurrentContact", QVariant::fromValue(QDBusVariant(QVariant(map)))); |
949 | + QVERIFY(reply.isValid()); |
950 | +} |
951 | + |
952 | +void GreeterContactsTest::waitForInitialQuery() |
953 | +{ |
954 | + QDBusInterface iface("org.freedesktop.Accounts", |
955 | + "/org/freedesktop/Accounts/User12345", |
956 | + "com.canonical.TelephonyServiceApprover", |
957 | + QDBusConnection::sessionBus()); |
958 | + QSignalSpy spy(&iface, SIGNAL(InitialQueriesDone())); |
959 | + QVERIFY(spy.wait()); |
960 | + QCOMPARE(spy.count(), 1); |
961 | +} |
962 | + |
963 | +void GreeterContactsTest::makeGreeterContacts() |
964 | +{ |
965 | + mGreeterContacts = new GreeterContacts(); |
966 | + mSpy = new QSignalSpy(mGreeterContacts, SIGNAL(contactUpdated(QtContacts::QContact))); |
967 | +} |
968 | + |
969 | +void GreeterContactsTest::waitForUpdatedSignal(bool convertedPath) |
970 | +{ |
971 | + QVERIFY(mSpy->wait()); |
972 | + QCOMPARE(mSpy->count(), 1); |
973 | + |
974 | + QList<QVariant> arguments = mSpy->takeFirst(); |
975 | + QContact expectedContact = makeTestContact(convertedPath); |
976 | + QCOMPARE(arguments.at(0).value<QContact>(), expectedContact); |
977 | +} |
978 | + |
979 | +void GreeterContactsTest::setUseInvalidated(const QString &path, const QString &interface, bool useInvalidated) |
980 | +{ |
981 | + QDBusInterface iface("org.freedesktop.Accounts", |
982 | + path, |
983 | + interface, |
984 | + QDBusConnection::sessionBus()); |
985 | + QDBusReply<void> reply = iface.call("SetUseInvalidated", useInvalidated); |
986 | + QVERIFY(reply.isValid()); |
987 | +} |
988 | + |
989 | +QTEST_MAIN(GreeterContactsTest) |
990 | +#include "GreeterContactsTest.moc" |
991 | |
992 | === added file 'approver/tests/GreeterContactsTestServer.cpp' |
993 | --- approver/tests/GreeterContactsTestServer.cpp 1970-01-01 00:00:00 +0000 |
994 | +++ approver/tests/GreeterContactsTestServer.cpp 2014-01-29 15:16:53 +0000 |
995 | @@ -0,0 +1,214 @@ |
996 | +/* |
997 | + * Copyright (C) 2013 Canonical, Ltd. |
998 | + * |
999 | + * This file is part of telephony-service. |
1000 | + * |
1001 | + * telephony-service is free software; you can redistribute it and/or modify |
1002 | + * it under the terms of the GNU General Public License as published by |
1003 | + * the Free Software Foundation; version 3. |
1004 | + * |
1005 | + * telephony-service is distributed in the hope that it will be useful, |
1006 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1007 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1008 | + * GNU General Public License for more details. |
1009 | + * |
1010 | + * You should have received a copy of the GNU General Public License |
1011 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1012 | + */ |
1013 | + |
1014 | +#include <QCoreApplication> |
1015 | +#include <QDBusConnection> |
1016 | +#include <QDBusMessage> |
1017 | +#include <QDBusObjectPath> |
1018 | +#include <QObject> |
1019 | +#include <QStringList> |
1020 | + |
1021 | + |
1022 | +#include <QDebug> |
1023 | +bool listGetCalled = false; |
1024 | +bool userGetCalled = false; |
1025 | + |
1026 | +class AccountsInterface : public QObject |
1027 | +{ |
1028 | + Q_OBJECT |
1029 | + Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Accounts") |
1030 | + |
1031 | +public: |
1032 | + AccountsInterface(QObject *parent = 0); |
1033 | + |
1034 | + Q_SCRIPTABLE QList<QDBusObjectPath> ListCachedUsers() const; |
1035 | +}; |
1036 | + |
1037 | + |
1038 | +class TelepathyInterface : public QObject |
1039 | +{ |
1040 | + Q_OBJECT |
1041 | + Q_CLASSINFO("D-Bus Interface", "com.canonical.TelephonyServiceApprover") |
1042 | + |
1043 | + Q_PROPERTY(QVariantMap CurrentContact READ CurrentContact WRITE SetCurrentContact) |
1044 | + |
1045 | +Q_SIGNALS: |
1046 | + Q_SCRIPTABLE void InitialQueriesDone(); // Only for testing |
1047 | + |
1048 | +public: |
1049 | + TelepathyInterface(QObject *parent = 0); |
1050 | + |
1051 | + QVariantMap CurrentContact(); |
1052 | + void SetCurrentContact(const QVariantMap &map); |
1053 | + |
1054 | + Q_SCRIPTABLE void SetUseInvalidated(bool useInvalidated); // only for testing |
1055 | + bool mGetCalled; // only for testing |
1056 | + |
1057 | +private: |
1058 | + QVariantMap mCurrentContact; |
1059 | + bool mUseInvalidated; |
1060 | +}; |
1061 | + |
1062 | + |
1063 | +class ListInterface : public QObject |
1064 | +{ |
1065 | + Q_OBJECT |
1066 | + Q_CLASSINFO("D-Bus Interface", "com.canonical.UnityGreeter.List") |
1067 | + |
1068 | + Q_PROPERTY(QString ActiveEntry READ ActiveEntry WRITE SetActiveEntry) |
1069 | + |
1070 | +public: |
1071 | + ListInterface(TelepathyInterface *telepathyInterface, QObject *parent = 0); |
1072 | + |
1073 | + QString ActiveEntry() const; |
1074 | + void SetActiveEntry(const QString &entry); |
1075 | + |
1076 | + Q_SCRIPTABLE void SetUseInvalidated(bool useInvalidated); // only for testing |
1077 | + bool mGetCalled; // only for testing |
1078 | + |
1079 | +private: |
1080 | + QString mActiveEntry; |
1081 | + TelepathyInterface *mTelepathyInterface; |
1082 | + bool mUseInvalidated; |
1083 | +}; |
1084 | + |
1085 | + |
1086 | + |
1087 | +AccountsInterface::AccountsInterface(QObject *parent) |
1088 | +: QObject(parent) |
1089 | +{ |
1090 | +} |
1091 | + |
1092 | +QList<QDBusObjectPath> AccountsInterface::ListCachedUsers() const |
1093 | +{ |
1094 | + return QList<QDBusObjectPath>() << QDBusObjectPath("/org/freedesktop/Accounts/User12345"); |
1095 | +} |
1096 | + |
1097 | +TelepathyInterface::TelepathyInterface(QObject *parent) |
1098 | +: QObject(parent), |
1099 | + mCurrentContact(), |
1100 | + mUseInvalidated(false) |
1101 | +{ |
1102 | +} |
1103 | + |
1104 | +QVariantMap TelepathyInterface::CurrentContact() |
1105 | +{ |
1106 | + userGetCalled = true; |
1107 | + if (userGetCalled && listGetCalled) |
1108 | + Q_EMIT InitialQueriesDone(); |
1109 | + return mCurrentContact; |
1110 | +} |
1111 | + |
1112 | +void TelepathyInterface::SetCurrentContact(const QVariantMap &map) |
1113 | +{ |
1114 | + mCurrentContact = map; |
1115 | + |
1116 | + // Now send out a manual changed signal, since Qt won't do it for us. |
1117 | + QDBusMessage message; |
1118 | + message = QDBusMessage::createSignal("/org/freedesktop/Accounts/User12345", |
1119 | + "org.freedesktop.DBus.Properties", |
1120 | + "PropertiesChanged"); |
1121 | + message << "com.canonical.TelephonyServiceApprover"; |
1122 | + if (mUseInvalidated) { |
1123 | + QStringList invalidatedProps; |
1124 | + invalidatedProps << "CurrentContact"; |
1125 | + message << QVariantMap(); |
1126 | + message << invalidatedProps; |
1127 | + } else { |
1128 | + QVariantMap changedProps; |
1129 | + changedProps.insert("CurrentContact", QVariant(map)); |
1130 | + message << changedProps; |
1131 | + message << QStringList(); |
1132 | + } |
1133 | + |
1134 | + QDBusConnection::sessionBus().send(message); |
1135 | +} |
1136 | + |
1137 | +void TelepathyInterface::SetUseInvalidated(bool useInvalidated) |
1138 | +{ |
1139 | + mUseInvalidated = useInvalidated; |
1140 | +} |
1141 | + |
1142 | +ListInterface::ListInterface(TelepathyInterface *telepathyInterface, QObject *parent) |
1143 | +: QObject(parent), |
1144 | + mActiveEntry(), |
1145 | + mTelepathyInterface(telepathyInterface), |
1146 | + mUseInvalidated(false) |
1147 | +{ |
1148 | +} |
1149 | + |
1150 | +QString ListInterface::ActiveEntry() const |
1151 | +{ |
1152 | + listGetCalled = true; |
1153 | + if (userGetCalled && listGetCalled && mTelepathyInterface) |
1154 | + Q_EMIT mTelepathyInterface->InitialQueriesDone(); |
1155 | + return mActiveEntry; |
1156 | +} |
1157 | + |
1158 | +void ListInterface::SetActiveEntry(const QString &entry) |
1159 | +{ |
1160 | + mActiveEntry = entry; |
1161 | + |
1162 | + // Now send out a manual changed signal, since Qt won't do it for us. |
1163 | + QDBusMessage message; |
1164 | + message = QDBusMessage::createSignal("/list", |
1165 | + "org.freedesktop.DBus.Properties", |
1166 | + "PropertiesChanged"); |
1167 | + message << "com.canonical.UnityGreeter.List"; |
1168 | + if (mUseInvalidated) { |
1169 | + QStringList invalidatedProps; |
1170 | + invalidatedProps << "ActiveEntry"; |
1171 | + message << QVariantMap(); |
1172 | + message << invalidatedProps; |
1173 | + } else { |
1174 | + QVariantMap changedProps; |
1175 | + changedProps.insert("ActiveEntry", QVariant(entry)); |
1176 | + message << changedProps; |
1177 | + message << QStringList(); |
1178 | + } |
1179 | + |
1180 | + QDBusConnection::sessionBus().send(message); |
1181 | +} |
1182 | + |
1183 | +void ListInterface::SetUseInvalidated(bool useInvalidated) |
1184 | +{ |
1185 | + mUseInvalidated = useInvalidated; |
1186 | +} |
1187 | + |
1188 | +int main(int argc, char *argv[]) |
1189 | +{ |
1190 | + QCoreApplication a(argc, argv); |
1191 | + |
1192 | + QDBusConnection connection = QDBusConnection::sessionBus(); |
1193 | + |
1194 | + AccountsInterface accounts; |
1195 | + connection.registerObject("/org/freedesktop/Accounts", &accounts, QDBusConnection::ExportScriptableContents); |
1196 | + |
1197 | + TelepathyInterface telepathy; |
1198 | + connection.registerObject("/org/freedesktop/Accounts/User12345", &telepathy, QDBusConnection::ExportScriptableContents); |
1199 | + |
1200 | + ListInterface list(&telepathy); |
1201 | + connection.registerObject("/list", &list, QDBusConnection::ExportScriptableContents); |
1202 | + |
1203 | + connection.registerService("com.canonical.UnityGreeter"); |
1204 | + connection.registerService("org.freedesktop.Accounts"); |
1205 | + |
1206 | + return a.exec(); |
1207 | +} |
1208 | + |
1209 | +#include "GreeterContactsTestServer.moc" |
1210 | |
1211 | === added file 'approver/tests/libsystem.c' |
1212 | --- approver/tests/libsystem.c 1970-01-01 00:00:00 +0000 |
1213 | +++ approver/tests/libsystem.c 2014-01-29 15:16:53 +0000 |
1214 | @@ -0,0 +1,38 @@ |
1215 | +/* |
1216 | + * Copyright (C) 2013 Canonical, Ltd. |
1217 | + * |
1218 | + * This file is part of telephony-service. |
1219 | + * |
1220 | + * telephony-service is free software; you can redistribute it and/or modify |
1221 | + * it under the terms of the GNU General Public License as published by |
1222 | + * the Free Software Foundation; version 3. |
1223 | + * |
1224 | + * telephony-service is distributed in the hope that it will be useful, |
1225 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1226 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1227 | + * GNU General Public License for more details. |
1228 | + * |
1229 | + * You should have received a copy of the GNU General Public License |
1230 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1231 | + */ |
1232 | + |
1233 | +#include <pwd.h> |
1234 | + |
1235 | +struct passwd * |
1236 | +getpwnam (const char *name) |
1237 | +{ |
1238 | + if (strcmp(name, "testuser") != 0) |
1239 | + return 0; |
1240 | + |
1241 | + static struct passwd user_passwd = {0}; |
1242 | + user_passwd.pw_name = "testuser"; |
1243 | + user_passwd.pw_uid = 12345; |
1244 | + user_passwd.pw_gid = 12345; |
1245 | + |
1246 | + return &user_passwd; |
1247 | +} |
1248 | + |
1249 | +uid_t getuid () |
1250 | +{ |
1251 | + return 12345; |
1252 | +} |
1253 | |
1254 | === modified file 'debian/rules' |
1255 | --- debian/rules 2014-01-20 10:05:58 +0000 |
1256 | +++ debian/rules 2014-01-29 15:16:53 +0000 |
1257 | @@ -12,7 +12,10 @@ |
1258 | dh $@ --parallel --with translations |
1259 | |
1260 | override_dh_auto_configure: |
1261 | - dh_auto_configure -- -DCMAKE_BUILD_TYPE=Debug |
1262 | + # Debian defines CMAKE_INSTALL_LOCALSTATEDIR as /usr/var, which is wrong. |
1263 | + # So until Debian bug 719148 is fixed, do it ourselves. |
1264 | + dh_auto_configure -- -DCMAKE_BUILD_TYPE=Debug \ |
1265 | + -DCMAKE_INSTALL_LOCALSTATEDIR="/var" |
1266 | |
1267 | override_dh_auto_test: |
1268 | QT_QPA_PLATFORM=minimal CTEST_OUTPUT_ON_FAILURE=1 make -C obj-$(DEB_HOST_GNU_TYPE) test |
1269 | |
1270 | === modified file 'debian/telephony-service.install' |
1271 | --- debian/telephony-service.install 2013-08-23 10:54:40 +0000 |
1272 | +++ debian/telephony-service.install 2014-01-29 15:16:53 +0000 |
1273 | @@ -1,6 +1,8 @@ |
1274 | usr/bin/*telephony-service* |
1275 | usr/bin/ofono-setup |
1276 | +usr/share/accountsservice/interfaces/*TelephonyService*.xml |
1277 | usr/share/applications/telephony-service*.desktop |
1278 | +usr/share/dbus-1/interfaces/*TelephonyService*.xml |
1279 | usr/share/dbus-1/services/*TelephonyService*.service |
1280 | usr/share/icons/hicolor/*/apps/telephony-service*.png |
1281 | usr/share/icons/ubuntu-mono-dark/status/*/indicator-call.svg |
1282 | @@ -9,5 +11,7 @@ |
1283 | usr/share/notify-osd/icons/gnome/scalable/status/notification-group-call.svg |
1284 | usr/share/notify-osd/icons/gnome/scalable/status/notification-unavailable-image-call.svg |
1285 | usr/share/notify-osd/icons/gnome/scalable/status/notification-unknown-call.svg |
1286 | +usr/share/polkit-1/actions/*TelephonyService*.policy |
1287 | usr/share/telepathy/clients/TelephonyService*.client |
1288 | usr/share/telephony-service/assets/* |
1289 | +var/lib/polkit-1/localauthority/10-vendor.d/*TelephonyService*.pkla |
1290 | |
1291 | === modified file 'libtelephonyservice/contactutils.cpp' |
1292 | --- libtelephonyservice/contactutils.cpp 2013-08-13 22:25:18 +0000 |
1293 | +++ libtelephonyservice/contactutils.cpp 2014-01-29 15:16:53 +0000 |
1294 | @@ -33,6 +33,8 @@ |
1295 | return instance; |
1296 | } |
1297 | |
1298 | +// Note: update GreeterContacts::mapToContact() if this function is modified |
1299 | +// to use more than just first and last names. |
1300 | QString formatContactName(const QContact &contact) |
1301 | { |
1302 | QContactName name = contact.detail<QContactName>(); |
PASSED: Continuous integration, rev:763 jenkins. qa.ubuntu. com/job/ telephony- service- ci/83/ jenkins. qa.ubuntu. com/job/ telephony- service- trusty- amd64-ci/ 7 jenkins. qa.ubuntu. com/job/ telephony- service- trusty- armhf-ci/ 7 jenkins. qa.ubuntu. com/job/ telephony- service- trusty- armhf-ci/ 7/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ telephony- service- trusty- i386-ci/ 7
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/telephony- service- ci/83/rebuild
http://