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

Proposed by Michael Terry
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
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/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.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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!

Revision history for this message
Gustavo Pichorim Boiko (boiko) wrote :

Code looks good and after testing no regressions were found.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
764. By Michael Terry

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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
=== added file 'approver/50-com.canonical.TelephonyServiceApprover.pkla'
--- approver/50-com.canonical.TelephonyServiceApprover.pkla 1970-01-01 00:00:00 +0000
+++ approver/50-com.canonical.TelephonyServiceApprover.pkla 2014-01-29 15:16:53 +0000
@@ -0,0 +1,6 @@
1[Allow LightDM to read TelephonyServiceApprover fields]
2Identity=unix-user:lightdm
3Action=com.canonical.TelephonyServiceApprover.ReadAny
4ResultAny=no
5ResultInactive=yes
6ResultActive=yes
07
=== modified file 'approver/CMakeLists.txt'
--- approver/CMakeLists.txt 2013-08-22 22:41:13 +0000
+++ approver/CMakeLists.txt 2014-01-29 15:16:53 +0000
@@ -2,6 +2,7 @@
2set(qt_SRCS2set(qt_SRCS
3 approver.cpp3 approver.cpp
4 approverdbus.cpp4 approverdbus.cpp
5 greetercontacts.cpp
5 )6 )
67
7set(approver_SRCS main.cpp ${qt_SRCS})8set(approver_SRCS main.cpp ${qt_SRCS})
@@ -18,6 +19,7 @@
18link_directories(${MESSAGING_MENU_LIBRARY_DIRS})19link_directories(${MESSAGING_MENU_LIBRARY_DIRS})
1920
20add_executable(telephony-service-approver ${approver_SRCS} ${approver_HDRS})21add_executable(telephony-service-approver ${approver_SRCS} ${approver_HDRS})
22set_target_properties(telephony-service-approver PROPERTIES COMPILE_DEFINITIONS AS_BUSNAME=systemBus)
21qt5_use_modules(telephony-service-approver Contacts Core DBus Gui Multimedia Qml)23qt5_use_modules(telephony-service-approver Contacts Core DBus Gui Multimedia Qml)
2224
23target_link_libraries(telephony-service-approver25target_link_libraries(telephony-service-approver
@@ -31,3 +33,14 @@
31install(TARGETS telephony-service-approver RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})33install(TARGETS telephony-service-approver RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
32install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.TelephonyServiceApprover.service DESTINATION share/dbus-1/services)34install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.TelephonyServiceApprover.service DESTINATION share/dbus-1/services)
33install(FILES TelephonyServiceApprover.client DESTINATION share/telepathy/clients)35install(FILES TelephonyServiceApprover.client DESTINATION share/telepathy/clients)
36install(FILES 50-com.canonical.TelephonyServiceApprover.pkla DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1/localauthority/10-vendor.d")
37install(FILES com.canonical.TelephonyServiceApprover.policy DESTINATION share/polkit-1/actions)
38install(FILES com.canonical.TelephonyServiceApprover.xml DESTINATION share/dbus-1/interfaces)
39
40# Create accountsservice symlink for above dbus interface
41install(CODE "
42execute_process(COMMAND mkdir -p \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces\")
43execute_process(COMMAND ln -sf ../../dbus-1/interfaces/com.canonical.TelephonyServiceApprover.xml \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces\")
44 ")
45
46add_subdirectory(tests)
3447
=== modified file 'approver/approver.cpp'
--- approver/approver.cpp 2013-12-03 15:20:30 +0000
+++ approver/approver.cpp 2014-01-29 15:16:53 +0000
@@ -25,6 +25,7 @@
25#include "chatmanager.h"25#include "chatmanager.h"
26#include "config.h"26#include "config.h"
27#include "contactutils.h"27#include "contactutils.h"
28#include "greetercontacts.h"
28#include "ringtone.h"29#include "ringtone.h"
2930
30#include <QContactAvatar>31#include <QContactAvatar>
@@ -48,8 +49,12 @@
4849
49Approver::Approver()50Approver::Approver()
50: Tp::AbstractClientApprover(channelFilters()),51: Tp::AbstractClientApprover(channelFilters()),
51 mPendingSnapDecision(NULL)52 mPendingSnapDecision(NULL),
53 mGreeterContacts(NULL)
52{54{
55 mDefaultTitle = C::gettext("Unknown caller");
56 mDefaultIcon = QUrl(telephonyServiceDir() + "assets/avatar-default@18.png").toEncoded();
57
53 ApproverDBus *dbus = new ApproverDBus();58 ApproverDBus *dbus = new ApproverDBus();
54 connect(dbus,59 connect(dbus,
55 SIGNAL(acceptCallRequested()),60 SIGNAL(acceptCallRequested()),
@@ -58,6 +63,12 @@
58 SIGNAL(rejectCallRequested()),63 SIGNAL(rejectCallRequested()),
59 SLOT(onRejectCallRequested()));64 SLOT(onRejectCallRequested()));
60 dbus->connectToBus();65 dbus->connectToBus();
66
67 if (qgetenv("XDG_SESSION_CLASS") == "greeter") {
68 mGreeterContacts = new GreeterContacts(this);
69 connect(mGreeterContacts, SIGNAL(contactUpdated(QtContacts::QContact)),
70 this, SLOT(updateNotification(QtContacts::QContact)));
71 }
61}72}
6273
63Approver::~Approver()74Approver::~Approver()
@@ -167,6 +178,34 @@
167 delete (EventData*) data;178 delete (EventData*) data;
168}179}
169180
181void Approver::updateNotification(const QContact &contact)
182{
183 if (!mPendingSnapDecision)
184 return;
185
186 QString displayLabel = ContactUtils::formatContactName(contact);
187 QString avatar = contact.detail<QContactAvatar>().imageUrl().toEncoded();
188
189 if (displayLabel.isEmpty()) {
190 displayLabel = mDefaultTitle;
191 }
192
193 if (avatar.isEmpty()) {
194 avatar = mDefaultIcon;
195 }
196
197 notify_notification_update(mPendingSnapDecision,
198 displayLabel.toStdString().c_str(),
199 mCachedBody.toStdString().c_str(),
200 avatar.toStdString().c_str());
201
202 GError *error = NULL;
203 if (!notify_notification_show(mPendingSnapDecision, &error)) {
204 qWarning() << "Failed to show snap decision:" << error->message;
205 g_error_free (error);
206 }
207}
208
170void Approver::onChannelReady(Tp::PendingOperation *op)209void Approver::onChannelReady(Tp::PendingOperation *op)
171{210{
172 Tp::PendingReady *pr = qobject_cast<Tp::PendingReady*>(op);211 Tp::PendingReady *pr = qobject_cast<Tp::PendingReady*>(op);
@@ -210,25 +249,21 @@
210 data->dispatchOp = dispatchOp;249 data->dispatchOp = dispatchOp;
211 data->channel = channel;250 data->channel = channel;
212251
213 QString title = C::gettext("Unknown caller");
214 QString icon = QUrl(telephonyServiceDir() + "assets/avatar-default@18.png").toEncoded();
215 QString body;
216
217 if (!contact->id().isEmpty()) {252 if (!contact->id().isEmpty()) {
218 if (contact->id().startsWith("x-ofono-private")) {253 if (contact->id().startsWith("x-ofono-private")) {
219 body = QString::fromUtf8(C::gettext("Calling from private number"));254 mCachedBody = QString::fromUtf8(C::gettext("Calling from private number"));
220 } else if (contact->id().startsWith("x-ofono-unknown")) {255 } else if (contact->id().startsWith("x-ofono-unknown")) {
221 body = QString::fromUtf8(C::gettext("Calling from unknown number"));256 mCachedBody = QString::fromUtf8(C::gettext("Calling from unknown number"));
222 } else {257 } else {
223 body = QString::fromUtf8(C::gettext("Calling from %1")).arg(contact->id());258 mCachedBody = QString::fromUtf8(C::gettext("Calling from %1")).arg(contact->id());
224 }259 }
225 } else {260 } else {
226 body = C::gettext("Caller number is not available");261 mCachedBody = C::gettext("Caller number is not available");
227 }262 }
228263
229 notification = notify_notification_new (title.toStdString().c_str(),264 notification = notify_notification_new (mDefaultTitle.toStdString().c_str(),
230 body.toStdString().c_str(),265 mCachedBody.toStdString().c_str(),
231 icon.toStdString().c_str());266 mDefaultIcon.toStdString().c_str());
232 notify_notification_set_hint_string(notification,267 notify_notification_set_hint_string(notification,
233 "x-canonical-snap-decisions",268 "x-canonical-snap-decisions",
234 "true");269 "true");
@@ -251,41 +286,29 @@
251286
252 mPendingSnapDecision = notification;287 mPendingSnapDecision = notification;
253288
254 // try to match the contact info289 if (mGreeterContacts) { // we're in the greeter's session
255 QContactFetchRequest *request = new QContactFetchRequest(this);290 mGreeterContacts->setFilter(QContactPhoneNumber::match(contact->id()));
256 request->setFilter(QContactPhoneNumber::match(contact->id()));291 } else {
257292 // try to match the contact info
258 // lambda function to update the notification293 QContactFetchRequest *request = new QContactFetchRequest(this);
259 QObject::connect(request, &QContactAbstractRequest::resultsAvailable, [request, notification, title, body, icon]() {294 request->setFilter(QContactPhoneNumber::match(contact->id()));
260 if (request && request->contacts().size() > 0) {295
261 // use the first match296 // lambda function to update the notification
262 QContact contact = request->contacts().at(0);297 QObject::connect(request, &QContactAbstractRequest::resultsAvailable, [this, request]() {
263 QString displayLabel = ContactUtils::formatContactName(contact);298 if (request && request->contacts().size() > 0) {
264 QString avatar = contact.detail<QContactAvatar>().imageUrl().toEncoded();299 // use the first match
265300 QContact contact = request->contacts().at(0);
266 if (displayLabel.isEmpty()) {301
267 displayLabel = title;302 updateNotification(contact);
268 }303
269304 // Also notify greeter via AccountsService
270 if (avatar.isEmpty()) {305 GreeterContacts::emitContact(contact);
271 avatar = icon;306 }
272 }307 });
273308
274 notify_notification_update(notification,309 request->setManager(ContactUtils::sharedManager());
275 displayLabel.toStdString().c_str(),310 request->start();
276 body.toStdString().c_str(),311 }
277 avatar.toStdString().c_str());
278
279 GError *error = NULL;
280 if (!notify_notification_show(notification, &error)) {
281 qWarning() << "Failed to show snap decision:" << error->message;
282 g_error_free (error);
283 }
284 }
285 });
286
287 request->setManager(ContactUtils::sharedManager());
288 request->start();
289312
290 GError *error = NULL;313 GError *error = NULL;
291 if (!notify_notification_show(notification, &error)) {314 if (!notify_notification_show(notification, &error)) {
292315
=== modified file 'approver/approver.h'
--- approver/approver.h 2013-10-04 21:15:46 +0000
+++ approver/approver.h 2014-01-29 15:16:53 +0000
@@ -26,11 +26,14 @@
26#include <unistd.h>26#include <unistd.h>
27#include <libnotify/notify.h>27#include <libnotify/notify.h>
2828
29#include <QContact>
29#include <QMap>30#include <QMap>
30#include <TelepathyQt/AbstractClientApprover>31#include <TelepathyQt/AbstractClientApprover>
31#include <TelepathyQt/PendingReady>32#include <TelepathyQt/PendingReady>
32#include <TelepathyQt/ChannelDispatchOperation>33#include <TelepathyQt/ChannelDispatchOperation>
3334
35class GreeterContacts;
36
34class Approver : public QObject, public Tp::AbstractClientApprover37class Approver : public QObject, public Tp::AbstractClientApprover
35{38{
36 Q_OBJECT39 Q_OBJECT
@@ -59,11 +62,16 @@
59 void closeSnapDecision();62 void closeSnapDecision();
60 void onAcceptCallRequested();63 void onAcceptCallRequested();
61 void onRejectCallRequested();64 void onRejectCallRequested();
65 void updateNotification(const QtContacts::QContact &contact);
6266
63private:67private:
64 QList<Tp::ChannelDispatchOperationPtr> mDispatchOps;68 QList<Tp::ChannelDispatchOperationPtr> mDispatchOps;
65 QMap<Tp::PendingOperation*,Tp::ChannelPtr> mChannels;69 QMap<Tp::PendingOperation*,Tp::ChannelPtr> mChannels;
66 NotifyNotification* mPendingSnapDecision;70 NotifyNotification* mPendingSnapDecision;
71 GreeterContacts *mGreeterContacts;
72 QString mDefaultTitle;
73 QString mDefaultIcon;
74 QString mCachedBody;
67};75};
6876
69#endif // APPROVER_H77#endif // APPROVER_H
7078
=== added file 'approver/com.canonical.TelephonyServiceApprover.policy'
--- approver/com.canonical.TelephonyServiceApprover.policy 1970-01-01 00:00:00 +0000
+++ approver/com.canonical.TelephonyServiceApprover.policy 2014-01-29 15:16:53 +0000
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<policyconfig>
4 <action id="com.canonical.TelephonyServiceApprover.ChangeOwn">
5 <defaults>
6 <allow_any>no</allow_any>
7 <allow_inactive>yes</allow_inactive>
8 <allow_active>yes</allow_active>
9 </defaults>
10 </action>
11
12 <action id="com.canonical.TelephonyServiceApprover.ReadAny">
13 <defaults>
14 <allow_any>no</allow_any>
15 <allow_inactive>no</allow_inactive>
16 <allow_active>no</allow_active>
17 </defaults>
18 </action>
19</policyconfig>
020
=== added file 'approver/com.canonical.TelephonyServiceApprover.xml'
--- approver/com.canonical.TelephonyServiceApprover.xml 1970-01-01 00:00:00 +0000
+++ approver/com.canonical.TelephonyServiceApprover.xml 2014-01-29 15:16:53 +0000
@@ -0,0 +1,17 @@
1<node>
2 <interface name="com.canonical.TelephonyServiceApprover">
3
4 <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/>
5
6 <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn"
7 value="com.canonical.TelephonyServiceApprover.ChangeOwn"/>
8
9 <annotation name="org.freedesktop.Accounts.Authentication.ReadAny"
10 value="com.canonical.TelephonyServiceApprover.ReadAny"/>
11
12 <property name="CurrentContact" type="a{sv}" access="readwrite">
13 <annotation name="org.freedesktop.Accounts.DefaultValue" value="{}"/>
14 </property>
15
16 </interface>
17</node>
018
=== added file 'approver/greetercontacts.cpp'
--- approver/greetercontacts.cpp 1970-01-01 00:00:00 +0000
+++ approver/greetercontacts.cpp 2014-01-29 15:16:53 +0000
@@ -0,0 +1,275 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * Authors:
5 * Michael Terry <michael.terry@canonical.com>
6 *
7 * This file is part of telephony-service.
8 *
9 * telephony-service is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 3.
12 *
13 * telephony-service is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "greetercontacts.h"
23
24#include <pwd.h>
25#include <QContactAvatar>
26#include <QContactInvalidFilter>
27#include <QContactManagerEngine>
28#include <QContactName>
29#include <QContactPhoneNumber>
30#include <QDBusInterface>
31#include <QDBusPendingCall>
32#include <QDBusPendingReply>
33#include <QDir>
34#include <QFile>
35#include <unistd.h>
36
37QTCONTACTS_USE_NAMESPACE
38
39GreeterContacts::GreeterContacts(QObject *parent)
40: QObject(parent),
41 mFilter(QContactInvalidFilter()),
42 mActiveUser(),
43 mContacts()
44{
45 // Watch for changes
46
47 QDBusConnection connection = QDBusConnection::sessionBus();
48 connection.connect("com.canonical.UnityGreeter",
49 "/list",
50 "org.freedesktop.DBus.Properties",
51 "PropertiesChanged",
52 this,
53 SLOT(greeterPropertiesChanged(QString, QVariantMap, QStringList)));
54
55 connection = QDBusConnection::AS_BUSNAME();
56 connection.connect("org.freedesktop.Accounts",
57 nullptr,
58 "org.freedesktop.DBus.Properties",
59 "PropertiesChanged",
60 this,
61 SLOT(accountsPropertiesChanged(QString, QVariantMap, QStringList, QDBusMessage)));
62
63 // Start initial queries
64
65 queryEntry();
66
67 QDBusInterface iface("org.freedesktop.Accounts",
68 "/org/freedesktop/Accounts",
69 "org.freedesktop.Accounts",
70 QDBusConnection::AS_BUSNAME());
71 QDBusPendingCall call = iface.asyncCall("ListCachedUsers");
72 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
73 connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
74 this, SLOT(accountsGetUsersReply(QDBusPendingCallWatcher *)));
75}
76
77GreeterContacts::~GreeterContacts()
78{
79}
80
81void GreeterContacts::setFilter(const QContactFilter &filter)
82{
83 mFilter = filter;
84 signalIfNeeded();
85}
86
87void GreeterContacts::greeterPropertiesChanged(const QString &interface,
88 const QVariantMap &changed,
89 const QStringList &invalidated)
90{
91 if (interface == "com.canonical.UnityGreeter.List") {
92 if (changed.contains("ActiveEntry")) {
93 updateActiveUser(changed.value("ActiveEntry").toString());
94 } else if (invalidated.contains("ActiveEntry")) {
95 queryEntry();
96 }
97 }
98}
99
100void GreeterContacts::accountsPropertiesChanged(const QString &interface,
101 const QVariantMap &changed,
102 const QStringList &invalidated,
103 const QDBusMessage &message)
104{
105 if (interface == "com.canonical.TelephonyServiceApprover") {
106 if (changed.contains("CurrentContact")) {
107 mContacts.insert(message.path(), qdbus_cast<QVariantMap>(changed.value("CurrentContact")));
108 signalIfNeeded();
109 } else if (invalidated.contains("CurrentContact")) {
110 queryContact(message.path());
111 }
112 }
113}
114
115void GreeterContacts::greeterGetEntryReply(QDBusPendingCallWatcher *watcher)
116{
117 QDBusPendingReply<QVariant> reply = *watcher;
118 if (!reply.isError()) {
119 updateActiveUser(reply.argumentAt<0>().toString());
120 } else {
121 qWarning() << "Failed to get active entry from Unity Greeter:" << reply.error().message();
122 }
123 watcher->deleteLater();
124}
125
126void GreeterContacts::accountsGetUsersReply(QDBusPendingCallWatcher *watcher)
127{
128 QDBusPendingReply<QList<QDBusObjectPath>> reply = *watcher;
129 if (!reply.isError()) {
130 Q_FOREACH (const QDBusObjectPath &user, reply.argumentAt<0>()) {
131 queryContact(user.path());
132 }
133 } else {
134 qWarning() << "Failed to get user list from AccountsService:" << reply.error().message();
135 }
136 watcher->deleteLater();
137}
138
139void GreeterContacts::accountsGetContactReply(QDBusPendingCallWatcher *watcher)
140{
141 QDBusPendingReply<QVariant> reply = *watcher;
142 if (!reply.isError()) {
143 mContacts.insert(watcher->property("telepathyPath").toString(), qdbus_cast<QVariantMap>(reply.argumentAt<0>()));
144 signalIfNeeded();
145 } else {
146 qWarning() << "Failed to get user's contact from AccountsService:" << reply.error().message();
147 }
148 watcher->deleteLater();
149}
150
151void GreeterContacts::queryEntry()
152{
153 QDBusInterface iface("com.canonical.UnityGreeter",
154 "/list",
155 "org.freedesktop.DBus.Properties",
156 QDBusConnection::sessionBus());
157 QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.UnityGreeter.List", "ActiveEntry");
158 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
159 connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
160 this, SLOT(greeterGetEntryReply(QDBusPendingCallWatcher *)));
161}
162
163void GreeterContacts::queryContact(const QString &user)
164{
165 QDBusInterface iface("org.freedesktop.Accounts",
166 user,
167 "org.freedesktop.DBus.Properties",
168 QDBusConnection::AS_BUSNAME());
169 QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.TelephonyServiceApprover", "CurrentContact");
170 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
171 watcher->setProperty("telepathyPath", QVariant(user));
172 connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
173 this, SLOT(accountsGetContactReply(QDBusPendingCallWatcher *)));
174}
175
176void GreeterContacts::updateActiveUser(const QString &username)
177{
178 struct passwd *pwinfo = getpwnam(username.toLatin1());
179 if (pwinfo) {
180 mActiveUser = "/org/freedesktop/Accounts/User" + QString::number(pwinfo->pw_uid);
181 signalIfNeeded();
182 }
183}
184
185QContact GreeterContacts::lookupContact()
186{
187 // For now, only ever look at active user's contact info. In future,
188 // maybe we should search all users for any matching info.
189 QVariantMap contactInfo = mContacts.value(mActiveUser);
190 if (!contactInfo.empty()) {
191 QContact contact = mapToContact(contactInfo);
192 if (QContactManagerEngine::testFilter(mFilter, contact)) {
193 return contact;
194 }
195 }
196
197 return QContact();
198}
199
200void GreeterContacts::signalIfNeeded()
201{
202 QContact contact = lookupContact();
203 if (!contact.isEmpty()) {
204 Q_EMIT contactUpdated(contact);
205 }
206}
207
208void GreeterContacts::emitContact(const QContact &contact)
209{
210 QString uid = QString::number(getuid());
211 QVariantMap map = contactToMap(contact);
212
213 if (!map.value("Image").toString().isEmpty()) {
214 // OK, so we want to tell LightDM about our contact. But LightDM won't
215 // have access to our image file in their normal location managed by
216 // evolution. And rather than give world-readable permissions to our
217 // evolution dir, we minimize the damage by copying the image to a new
218 // more accessible location.
219 // TODO: This is not ideal because this new location is still
220 // world-readable and thus leaks a contact picture and because if the
221 // user's home directory is encrypted, LightDM can't read it.
222 // Hopefully LightDM will soon allow a /run/user style location for
223 // users to share data with it.
224 QFile imageFile(QDir::home().filePath(".telephony-service-contact-image"));
225 imageFile.remove();
226 if (QFile(map.value("Image").toString()).copy(imageFile.fileName())) {
227 map.insert("Image", imageFile.fileName());
228 }
229 }
230
231 QDBusInterface iface("org.freedesktop.Accounts",
232 "/org/freedesktop/Accounts/User" + uid,
233 "org.freedesktop.DBus.Properties",
234 QDBusConnection::AS_BUSNAME());
235 iface.asyncCall("Set", "com.canonical.TelephonyServiceApprover", "CurrentContact", QVariant::fromValue(QDBusVariant(QVariant(map))));
236}
237
238QVariantMap GreeterContacts::contactToMap(const QContact &contact)
239{
240 QVariantMap map;
241
242 QContactAvatar avatarDetail = contact.detail<QContactAvatar>();
243 map.insert("Image", avatarDetail.imageUrl().toLocalFile());
244
245 QContactName nameDetail = contact.detail<QContactName>();
246 map.insert("FirstName", nameDetail.firstName());
247 map.insert("LastName", nameDetail.lastName());
248
249 QContactPhoneNumber numberDetail = contact.detail<QContactPhoneNumber>();
250 map.insert("PhoneNumber", numberDetail.number());
251
252 return map;
253}
254
255QContact GreeterContacts::mapToContact(const QVariantMap &map)
256{
257 QContact contact;
258
259 QContactAvatar avatarDetail;
260 avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(map.value("Image").toString()));
261 contact.saveDetail(&avatarDetail);
262
263 // We only use FirstName and LastName right now in ContactUtils::formatContactName().
264 // If/When we use more, we should save more detail values here.
265 QContactName nameDetail;
266 nameDetail.setValue(QContactName::FieldFirstName, map.value("FirstName"));
267 nameDetail.setValue(QContactName::FieldLastName, map.value("LastName"));
268 contact.saveDetail(&nameDetail);
269
270 QContactPhoneNumber numberDetail;
271 numberDetail.setValue(QContactPhoneNumber::FieldNumber, map.value("PhoneNumber"));
272 contact.saveDetail(&numberDetail);
273
274 return contact;
275}
0276
=== added file 'approver/greetercontacts.h'
--- approver/greetercontacts.h 1970-01-01 00:00:00 +0000
+++ approver/greetercontacts.h 2014-01-29 15:16:53 +0000
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * Authors:
5 * Michael Terry <michael.terry@canonical.com>
6 *
7 * This file is part of telephony-service.
8 *
9 * telephony-service is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 3.
12 *
13 * telephony-service is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#ifndef GREETERCONTACTS_H
23#define GREETERCONTACTS_H
24
25#include <QContact>
26#include <QContactFilter>
27#include <QDBusMessage>
28#include <QObject>
29
30class QDBusPendingCallWatcher;
31
32/**
33 * When running under the greeter, we don't have our own contacts database.
34 * Instead, we query AccountsService for the information.
35 */
36class GreeterContacts : public QObject
37{
38 Q_OBJECT
39
40public:
41 GreeterContacts(QObject *parent = 0);
42 ~GreeterContacts();
43
44 void setFilter(const QtContacts::QContactFilter &filter);
45
46 // Records contact info for currently-logged-in user
47 static void emitContact(const QtContacts::QContact &contact);
48
49 // These are really implementation details, but are public for ease of unit testing
50 static QVariantMap contactToMap(const QtContacts::QContact &contact);
51 static QtContacts::QContact mapToContact(const QVariantMap &map);
52
53Q_SIGNALS:
54 void contactUpdated(const QtContacts::QContact &contact);
55
56private Q_SLOTS:
57 void greeterPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated);
58 void accountsPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated, const QDBusMessage &message);
59
60 void greeterGetEntryReply(QDBusPendingCallWatcher *watcher);
61 void accountsGetUsersReply(QDBusPendingCallWatcher *watcher);
62 void accountsGetContactReply(QDBusPendingCallWatcher *watcher);
63
64private:
65 void queryEntry();
66 void queryContact(const QString &user);
67 void updateActiveUser(const QString &username);
68 QtContacts::QContact lookupContact();
69 void signalIfNeeded();
70
71 QtContacts::QContactFilter mFilter;
72 QString mActiveUser;
73 QMap<QString, QVariantMap> mContacts;
74};
75
76#endif // GREETERCONTACTS_H
077
=== added directory 'approver/tests'
=== added file 'approver/tests/CMakeLists.txt'
--- approver/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ approver/tests/CMakeLists.txt 2014-01-29 15:16:53 +0000
@@ -0,0 +1,28 @@
1include_directories(
2 ${CMAKE_CURRENT_BINARY_DIR}
3 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}/..
5 )
6
7add_library(GreeterContactsLibSystem MODULE libsystem.c)
8set_target_properties(GreeterContactsLibSystem PROPERTIES OUTPUT_NAME system)
9
10add_executable(GreeterContactsTestServerExe GreeterContactsTestServer.cpp)
11qt5_use_modules(GreeterContactsTestServerExe Core DBus)
12
13add_executable(GreeterContactsTestExe GreeterContactsTest.cpp ../greetercontacts.cpp)
14set_target_properties(GreeterContactsTestExe PROPERTIES COMPILE_DEFINITIONS "AS_BUSNAME=sessionBus;CMAKE_SOURCE_DIR=\"${CMAKE_SOURCE_DIR}\"")
15qt5_use_modules(GreeterContactsTestExe Contacts Core DBus Test)
16
17add_test(NAME GreeterContactsTest
18 COMMAND env
19 LD_PRELOAD=${CMAKE_CURRENT_BINARY_DIR}/libsystem.so
20 dbus-test-runner
21 --task ${CMAKE_CURRENT_BINARY_DIR}/GreeterContactsTestServerExe
22 --task-name server
23 --ignore-return
24 --task ${CMAKE_CURRENT_BINARY_DIR}/GreeterContactsTestExe
25 --task-name test
26 --wait-for org.freedesktop.Accounts
27 DEPENDENCIES GreeterContactsTestServerExe GreeterContactsTestExe GreeterContactsLibSystem
28 )
029
=== added file 'approver/tests/GreeterContactsTest.cpp'
--- approver/tests/GreeterContactsTest.cpp 1970-01-01 00:00:00 +0000
+++ approver/tests/GreeterContactsTest.cpp 2014-01-29 15:16:53 +0000
@@ -0,0 +1,291 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This file is part of telephony-service.
5 *
6 * telephony-service is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * telephony-service is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "greetercontacts.h"
20
21#include <QContact>
22#include <QContactAvatar>
23#include <QContactName>
24#include <QContactPhoneNumber>
25#include <QDBusInterface>
26#include <QDBusPendingCallWatcher>
27#include <QDBusReply>
28#include <QObject>
29#include <QtTest>
30#include <QUrl>
31
32Q_DECLARE_METATYPE(QtContacts::QContact) // for QVariant's benefit
33
34QTCONTACTS_USE_NAMESPACE
35
36class GreeterContactsTest : public QObject
37{
38 Q_OBJECT
39
40public:
41 GreeterContactsTest();
42
43public Q_SLOTS:
44 void setFilter();
45
46private Q_SLOTS:
47 void initTestCase();
48 void cleanup();
49 void testContactToMap();
50 void testMapToContact();
51 void testInitialValues();
52 void testSignalOnFilter();
53 void testSignalOnEntry();
54 void testSignalOnEntryInvalidated();
55 void testSignalOnContacts();
56 void testSignalOnContactsInvalidated();
57 void testEmitContact();
58
59private:
60 void waitForUpdatedSignal(bool convertedPath = false);
61 void makeGreeterContacts();
62 void waitForInitialQuery();
63 QContact makeTestContact(bool convertedPath = false);
64 QVariantMap makeTestMap();
65 void setActiveEntry(const QString &entry);
66 void setCurrentContact(const QVariantMap &map);
67 void setUseInvalidated(const QString &path, const QString &interface, bool useInvalidated);
68
69 GreeterContacts *mGreeterContacts;
70 QSignalSpy *mSpy;
71};
72
73
74
75GreeterContactsTest::GreeterContactsTest()
76: QObject()
77{
78}
79
80void GreeterContactsTest::initTestCase()
81{
82 mGreeterContacts = NULL;
83 mSpy = NULL;
84 qRegisterMetaType<QContact>();
85}
86
87void GreeterContactsTest::cleanup()
88{
89 if (mSpy) {
90 delete mSpy;
91 mSpy = NULL;
92 }
93 if (mGreeterContacts) {
94 delete mGreeterContacts;
95 mGreeterContacts = NULL;
96 }
97
98 setActiveEntry("");
99 setCurrentContact(QVariantMap());
100 setUseInvalidated("/list", "com.canonical.UnityGreeter.List", false);
101 setUseInvalidated("/org/freedesktop/Accounts/User12345", "com.canonical.TelephonyServiceApprover", false);
102}
103
104void GreeterContactsTest::testContactToMap()
105{
106 QVariantMap map = GreeterContacts::contactToMap(makeTestContact());
107 QVariantMap expectedMap = makeTestMap();
108 QCOMPARE(map, expectedMap);
109}
110
111void GreeterContactsTest::testMapToContact()
112{
113 QContact contact = GreeterContacts::mapToContact(makeTestMap());
114 QContact expectedContact = makeTestContact();
115 QCOMPARE(contact, expectedContact);
116}
117
118void GreeterContactsTest::testInitialValues()
119{
120 setActiveEntry("testuser");
121 setCurrentContact(makeTestMap());
122 makeGreeterContacts();
123 setFilter();
124 waitForUpdatedSignal();
125}
126
127void GreeterContactsTest::testSignalOnFilter()
128{
129 setActiveEntry("testuser");
130 setCurrentContact(makeTestMap());
131 makeGreeterContacts();
132 waitForInitialQuery();
133 // setFilter might immediately send the signal, so wait until we can start the spy
134 QTimer::singleShot(0, this, SLOT(setFilter()));
135 waitForUpdatedSignal();
136}
137
138void GreeterContactsTest::testSignalOnEntry()
139{
140 setCurrentContact(makeTestMap());
141 makeGreeterContacts();
142 setFilter();
143 waitForInitialQuery();
144 setActiveEntry("testuser");
145 waitForUpdatedSignal();
146}
147
148void GreeterContactsTest::testSignalOnEntryInvalidated()
149{
150 setCurrentContact(makeTestMap());
151 makeGreeterContacts();
152 setFilter();
153 waitForInitialQuery();
154 setUseInvalidated("/list", "com.canonical.UnityGreeter.List", true);
155 setActiveEntry("testuser");
156 waitForUpdatedSignal();
157}
158
159void GreeterContactsTest::testSignalOnContacts()
160{
161 setActiveEntry("testuser");
162 makeGreeterContacts();
163 setFilter();
164 waitForInitialQuery();
165 setCurrentContact(makeTestMap());
166 waitForUpdatedSignal();
167}
168
169void GreeterContactsTest::testSignalOnContactsInvalidated()
170{
171 setActiveEntry("testuser");
172 makeGreeterContacts();
173 setFilter();
174 waitForInitialQuery();
175 setUseInvalidated("/org/freedesktop/Accounts/User12345", "com.canonical.TelephonyServiceApprover", true);
176 setCurrentContact(makeTestMap());
177 waitForUpdatedSignal();
178}
179
180void GreeterContactsTest::testEmitContact()
181{
182 setActiveEntry("testuser");
183 makeGreeterContacts();
184 setFilter();
185 waitForInitialQuery();
186 // this next line acts like setCurrentContact() because uid is set to 12345
187 GreeterContacts::emitContact(makeTestContact());
188 waitForUpdatedSignal(true);
189}
190
191QVariantMap GreeterContactsTest::makeTestMap()
192{
193 QVariantMap map;
194 map.insert("FirstName", QVariant("First"));
195 map.insert("Image", QVariant(CMAKE_SOURCE_DIR "/icons/hicolor/48x48/apps/telephony-service-call.png"));
196 map.insert("LastName", QVariant("Last"));
197 map.insert("PhoneNumber", QVariant("555"));
198 return map;
199}
200
201QContact GreeterContactsTest::makeTestContact(bool convertedPath)
202{
203 // This is the same contact that the test server will give out.
204 QContact contact;
205
206 QContactAvatar avatarDetail;
207 QString imagePath;
208 if (convertedPath) {
209 imagePath = QDir::home().filePath(".telephony-service-contact-image");
210 } else {
211 imagePath = CMAKE_SOURCE_DIR "/icons/hicolor/48x48/apps/telephony-service-call.png";
212 }
213 avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(imagePath));
214 contact.saveDetail(&avatarDetail);
215
216 QContactName nameDetail;
217 nameDetail.setValue(QContactName::FieldFirstName, "First");
218 nameDetail.setValue(QContactName::FieldLastName, "Last");
219 contact.saveDetail(&nameDetail);
220
221 QContactPhoneNumber numberDetail;
222 numberDetail.setValue(QContactPhoneNumber::FieldNumber, "555");
223 contact.saveDetail(&numberDetail);
224
225 return contact;
226}
227
228void GreeterContactsTest::setFilter()
229{
230 mGreeterContacts->setFilter(QContactPhoneNumber::match("555"));
231}
232
233void GreeterContactsTest::setActiveEntry(const QString &entry)
234{
235 QDBusInterface iface("com.canonical.UnityGreeter",
236 "/list",
237 "org.freedesktop.DBus.Properties",
238 QDBusConnection::sessionBus());
239 QDBusReply<void> reply = iface.call("Set", "com.canonical.UnityGreeter.List", "ActiveEntry", QVariant::fromValue(QDBusVariant(QVariant(entry))));
240 QVERIFY(reply.isValid());
241}
242
243void GreeterContactsTest::setCurrentContact(const QVariantMap &map)
244{
245 QDBusInterface iface("org.freedesktop.Accounts",
246 "/org/freedesktop/Accounts/User12345",
247 "org.freedesktop.DBus.Properties",
248 QDBusConnection::sessionBus());
249 QDBusReply<void> reply = iface.call("Set", "com.canonical.TelephonyServiceApprover", "CurrentContact", QVariant::fromValue(QDBusVariant(QVariant(map))));
250 QVERIFY(reply.isValid());
251}
252
253void GreeterContactsTest::waitForInitialQuery()
254{
255 QDBusInterface iface("org.freedesktop.Accounts",
256 "/org/freedesktop/Accounts/User12345",
257 "com.canonical.TelephonyServiceApprover",
258 QDBusConnection::sessionBus());
259 QSignalSpy spy(&iface, SIGNAL(InitialQueriesDone()));
260 QVERIFY(spy.wait());
261 QCOMPARE(spy.count(), 1);
262}
263
264void GreeterContactsTest::makeGreeterContacts()
265{
266 mGreeterContacts = new GreeterContacts();
267 mSpy = new QSignalSpy(mGreeterContacts, SIGNAL(contactUpdated(QtContacts::QContact)));
268}
269
270void GreeterContactsTest::waitForUpdatedSignal(bool convertedPath)
271{
272 QVERIFY(mSpy->wait());
273 QCOMPARE(mSpy->count(), 1);
274
275 QList<QVariant> arguments = mSpy->takeFirst();
276 QContact expectedContact = makeTestContact(convertedPath);
277 QCOMPARE(arguments.at(0).value<QContact>(), expectedContact);
278}
279
280void GreeterContactsTest::setUseInvalidated(const QString &path, const QString &interface, bool useInvalidated)
281{
282 QDBusInterface iface("org.freedesktop.Accounts",
283 path,
284 interface,
285 QDBusConnection::sessionBus());
286 QDBusReply<void> reply = iface.call("SetUseInvalidated", useInvalidated);
287 QVERIFY(reply.isValid());
288}
289
290QTEST_MAIN(GreeterContactsTest)
291#include "GreeterContactsTest.moc"
0292
=== added file 'approver/tests/GreeterContactsTestServer.cpp'
--- approver/tests/GreeterContactsTestServer.cpp 1970-01-01 00:00:00 +0000
+++ approver/tests/GreeterContactsTestServer.cpp 2014-01-29 15:16:53 +0000
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This file is part of telephony-service.
5 *
6 * telephony-service is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * telephony-service is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <QCoreApplication>
20#include <QDBusConnection>
21#include <QDBusMessage>
22#include <QDBusObjectPath>
23#include <QObject>
24#include <QStringList>
25
26
27#include <QDebug>
28bool listGetCalled = false;
29bool userGetCalled = false;
30
31class AccountsInterface : public QObject
32{
33 Q_OBJECT
34 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Accounts")
35
36public:
37 AccountsInterface(QObject *parent = 0);
38
39 Q_SCRIPTABLE QList<QDBusObjectPath> ListCachedUsers() const;
40};
41
42
43class TelepathyInterface : public QObject
44{
45 Q_OBJECT
46 Q_CLASSINFO("D-Bus Interface", "com.canonical.TelephonyServiceApprover")
47
48 Q_PROPERTY(QVariantMap CurrentContact READ CurrentContact WRITE SetCurrentContact)
49
50Q_SIGNALS:
51 Q_SCRIPTABLE void InitialQueriesDone(); // Only for testing
52
53public:
54 TelepathyInterface(QObject *parent = 0);
55
56 QVariantMap CurrentContact();
57 void SetCurrentContact(const QVariantMap &map);
58
59 Q_SCRIPTABLE void SetUseInvalidated(bool useInvalidated); // only for testing
60 bool mGetCalled; // only for testing
61
62private:
63 QVariantMap mCurrentContact;
64 bool mUseInvalidated;
65};
66
67
68class ListInterface : public QObject
69{
70 Q_OBJECT
71 Q_CLASSINFO("D-Bus Interface", "com.canonical.UnityGreeter.List")
72
73 Q_PROPERTY(QString ActiveEntry READ ActiveEntry WRITE SetActiveEntry)
74
75public:
76 ListInterface(TelepathyInterface *telepathyInterface, QObject *parent = 0);
77
78 QString ActiveEntry() const;
79 void SetActiveEntry(const QString &entry);
80
81 Q_SCRIPTABLE void SetUseInvalidated(bool useInvalidated); // only for testing
82 bool mGetCalled; // only for testing
83
84private:
85 QString mActiveEntry;
86 TelepathyInterface *mTelepathyInterface;
87 bool mUseInvalidated;
88};
89
90
91
92AccountsInterface::AccountsInterface(QObject *parent)
93: QObject(parent)
94{
95}
96
97QList<QDBusObjectPath> AccountsInterface::ListCachedUsers() const
98{
99 return QList<QDBusObjectPath>() << QDBusObjectPath("/org/freedesktop/Accounts/User12345");
100}
101
102TelepathyInterface::TelepathyInterface(QObject *parent)
103: QObject(parent),
104 mCurrentContact(),
105 mUseInvalidated(false)
106{
107}
108
109QVariantMap TelepathyInterface::CurrentContact()
110{
111 userGetCalled = true;
112 if (userGetCalled && listGetCalled)
113 Q_EMIT InitialQueriesDone();
114 return mCurrentContact;
115}
116
117void TelepathyInterface::SetCurrentContact(const QVariantMap &map)
118{
119 mCurrentContact = map;
120
121 // Now send out a manual changed signal, since Qt won't do it for us.
122 QDBusMessage message;
123 message = QDBusMessage::createSignal("/org/freedesktop/Accounts/User12345",
124 "org.freedesktop.DBus.Properties",
125 "PropertiesChanged");
126 message << "com.canonical.TelephonyServiceApprover";
127 if (mUseInvalidated) {
128 QStringList invalidatedProps;
129 invalidatedProps << "CurrentContact";
130 message << QVariantMap();
131 message << invalidatedProps;
132 } else {
133 QVariantMap changedProps;
134 changedProps.insert("CurrentContact", QVariant(map));
135 message << changedProps;
136 message << QStringList();
137 }
138
139 QDBusConnection::sessionBus().send(message);
140}
141
142void TelepathyInterface::SetUseInvalidated(bool useInvalidated)
143{
144 mUseInvalidated = useInvalidated;
145}
146
147ListInterface::ListInterface(TelepathyInterface *telepathyInterface, QObject *parent)
148: QObject(parent),
149 mActiveEntry(),
150 mTelepathyInterface(telepathyInterface),
151 mUseInvalidated(false)
152{
153}
154
155QString ListInterface::ActiveEntry() const
156{
157 listGetCalled = true;
158 if (userGetCalled && listGetCalled && mTelepathyInterface)
159 Q_EMIT mTelepathyInterface->InitialQueriesDone();
160 return mActiveEntry;
161}
162
163void ListInterface::SetActiveEntry(const QString &entry)
164{
165 mActiveEntry = entry;
166
167 // Now send out a manual changed signal, since Qt won't do it for us.
168 QDBusMessage message;
169 message = QDBusMessage::createSignal("/list",
170 "org.freedesktop.DBus.Properties",
171 "PropertiesChanged");
172 message << "com.canonical.UnityGreeter.List";
173 if (mUseInvalidated) {
174 QStringList invalidatedProps;
175 invalidatedProps << "ActiveEntry";
176 message << QVariantMap();
177 message << invalidatedProps;
178 } else {
179 QVariantMap changedProps;
180 changedProps.insert("ActiveEntry", QVariant(entry));
181 message << changedProps;
182 message << QStringList();
183 }
184
185 QDBusConnection::sessionBus().send(message);
186}
187
188void ListInterface::SetUseInvalidated(bool useInvalidated)
189{
190 mUseInvalidated = useInvalidated;
191}
192
193int main(int argc, char *argv[])
194{
195 QCoreApplication a(argc, argv);
196
197 QDBusConnection connection = QDBusConnection::sessionBus();
198
199 AccountsInterface accounts;
200 connection.registerObject("/org/freedesktop/Accounts", &accounts, QDBusConnection::ExportScriptableContents);
201
202 TelepathyInterface telepathy;
203 connection.registerObject("/org/freedesktop/Accounts/User12345", &telepathy, QDBusConnection::ExportScriptableContents);
204
205 ListInterface list(&telepathy);
206 connection.registerObject("/list", &list, QDBusConnection::ExportScriptableContents);
207
208 connection.registerService("com.canonical.UnityGreeter");
209 connection.registerService("org.freedesktop.Accounts");
210
211 return a.exec();
212}
213
214#include "GreeterContactsTestServer.moc"
0215
=== added file 'approver/tests/libsystem.c'
--- approver/tests/libsystem.c 1970-01-01 00:00:00 +0000
+++ approver/tests/libsystem.c 2014-01-29 15:16:53 +0000
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This file is part of telephony-service.
5 *
6 * telephony-service is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * telephony-service is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <pwd.h>
20
21struct passwd *
22getpwnam (const char *name)
23{
24 if (strcmp(name, "testuser") != 0)
25 return 0;
26
27 static struct passwd user_passwd = {0};
28 user_passwd.pw_name = "testuser";
29 user_passwd.pw_uid = 12345;
30 user_passwd.pw_gid = 12345;
31
32 return &user_passwd;
33}
34
35uid_t getuid ()
36{
37 return 12345;
38}
039
=== modified file 'debian/rules'
--- debian/rules 2014-01-20 10:05:58 +0000
+++ debian/rules 2014-01-29 15:16:53 +0000
@@ -12,7 +12,10 @@
12 dh $@ --parallel --with translations12 dh $@ --parallel --with translations
1313
14override_dh_auto_configure:14override_dh_auto_configure:
15 dh_auto_configure -- -DCMAKE_BUILD_TYPE=Debug15 # Debian defines CMAKE_INSTALL_LOCALSTATEDIR as /usr/var, which is wrong.
16 # So until Debian bug 719148 is fixed, do it ourselves.
17 dh_auto_configure -- -DCMAKE_BUILD_TYPE=Debug \
18 -DCMAKE_INSTALL_LOCALSTATEDIR="/var"
1619
17override_dh_auto_test:20override_dh_auto_test:
18 QT_QPA_PLATFORM=minimal CTEST_OUTPUT_ON_FAILURE=1 make -C obj-$(DEB_HOST_GNU_TYPE) test21 QT_QPA_PLATFORM=minimal CTEST_OUTPUT_ON_FAILURE=1 make -C obj-$(DEB_HOST_GNU_TYPE) test
1922
=== modified file 'debian/telephony-service.install'
--- debian/telephony-service.install 2013-08-23 10:54:40 +0000
+++ debian/telephony-service.install 2014-01-29 15:16:53 +0000
@@ -1,6 +1,8 @@
1usr/bin/*telephony-service*1usr/bin/*telephony-service*
2usr/bin/ofono-setup2usr/bin/ofono-setup
3usr/share/accountsservice/interfaces/*TelephonyService*.xml
3usr/share/applications/telephony-service*.desktop4usr/share/applications/telephony-service*.desktop
5usr/share/dbus-1/interfaces/*TelephonyService*.xml
4usr/share/dbus-1/services/*TelephonyService*.service6usr/share/dbus-1/services/*TelephonyService*.service
5usr/share/icons/hicolor/*/apps/telephony-service*.png7usr/share/icons/hicolor/*/apps/telephony-service*.png
6usr/share/icons/ubuntu-mono-dark/status/*/indicator-call.svg8usr/share/icons/ubuntu-mono-dark/status/*/indicator-call.svg
@@ -9,5 +11,7 @@
9usr/share/notify-osd/icons/gnome/scalable/status/notification-group-call.svg11usr/share/notify-osd/icons/gnome/scalable/status/notification-group-call.svg
10usr/share/notify-osd/icons/gnome/scalable/status/notification-unavailable-image-call.svg12usr/share/notify-osd/icons/gnome/scalable/status/notification-unavailable-image-call.svg
11usr/share/notify-osd/icons/gnome/scalable/status/notification-unknown-call.svg13usr/share/notify-osd/icons/gnome/scalable/status/notification-unknown-call.svg
14usr/share/polkit-1/actions/*TelephonyService*.policy
12usr/share/telepathy/clients/TelephonyService*.client15usr/share/telepathy/clients/TelephonyService*.client
13usr/share/telephony-service/assets/*16usr/share/telephony-service/assets/*
17var/lib/polkit-1/localauthority/10-vendor.d/*TelephonyService*.pkla
1418
=== modified file 'libtelephonyservice/contactutils.cpp'
--- libtelephonyservice/contactutils.cpp 2013-08-13 22:25:18 +0000
+++ libtelephonyservice/contactutils.cpp 2014-01-29 15:16:53 +0000
@@ -33,6 +33,8 @@
33 return instance;33 return instance;
34}34}
3535
36// Note: update GreeterContacts::mapToContact() if this function is modified
37// to use more than just first and last names.
36QString formatContactName(const QContact &contact)38QString formatContactName(const QContact &contact)
37{39{
38 QContactName name = contact.detail<QContactName>();40 QContactName name = contact.detail<QContactName>();

Subscribers

People subscribed via source and target branches