Merge lp:~mterry/telephony-service/greeter-contacts into lp:telephony-service

Proposed by Michael Terry on 2013-12-21
Status: Merged
Approved by: Michael Terry on 2014-01-29
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
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2014-01-29
Gustavo Pichorim Boiko (community) 2013-12-21 Approve on 2014-01-27
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/share/evolution is not openable by the lightdm user. So when we are updating AccountsService, we also copy the relevant contact photo to ~/.telephony-service-contact-image. There are two problems with this: (1) it is readable by the world (though to be fair, the world can see it on the screen when a call is happening) and (2) if the user's directory is encrypted, it won't be accessible. The proper fix for both of these is for LightDM to provide a /run/user-style space for persistent data sharing between sessions and the greeter. But that's a separate bug, and I'm looking into it. For now, the photo in the home dir is good enough, since Touch doesn't support encrypted home dirs yet.

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://wiki.ubuntu.com/Process/Merges/TestPlan/<package-name>) on device or emulator?
- 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

To post a comment you must log in.
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.

review: Approve
764. By Michael Terry on 2014-01-29

Merge from trunk

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://wiki.ubuntu.com/Process/Merges/TestPlan/<package-name>) on device or emulator?
YES

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

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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>();

Subscribers

People subscribed via source and target branches