on xenial help sign in
Refactor AccountsService plugin to use less boilerplate
commitac766b5c4d7d6b2cfdbc78e96d4d19c370c53c8c authorMichael Terry <michael.terry@canonical.com> dateThu 4 Feb 2016, 16:54 (11 years ago) parentd1a47e5
9 files changed+198−371
plugins/AccountsService/AccountsService.cpp+137−342 plugins/AccountsService/AccountsService.h+22−20 plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+9 plugins/AccountsService/AccountsServiceDBusAdaptor.h+1 tests/plugins/AccountsService/CMakeLists.txt+2 tests/plugins/AccountsService/PropertiesServer.cpp+12 tests/plugins/AccountsService/PropertiesServer.h+1 tests/plugins/AccountsService/client.cpp+9−9 tests/plugins/AccountsService/interfaces.xml+5
plugins/AccountsService/AccountsService.cpp+137−342
@@ -24,17 +24,29 @@
2424#include <QStringList>
2525#include <QDebug>
2626
27+#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User")
28+#define IFACE_LOCATION_HERE QStringLiteral("com.ubuntu.location.providers.here.AccountsService")
29+#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input")
30+#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy")
31+#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy")
32+#define IFACE_UNITY QStringLiteral("com.canonical.unity.AccountsService")
33+#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private")
34+
35+#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
36+#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
37+#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked")
38+#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked")
39+#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins")
40+#define PROP_LICENSE_ACCEPTED QStringLiteral("LicenseAccepted")
41+#define PROP_LICENSE_BASE_PATH QStringLiteral("LicenseBasePath")
42+#define PROP_MOUSE_CURSOR_SPEED QStringLiteral("MouseCursorSpeed")
43+#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
44+#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
45+#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
46+
2747AccountsService::AccountsService(QObject* parent, const QString &user)
28− : QObject(parent),
29− m_service(new AccountsServiceDBusAdaptor(this)),
30− m_demoEdges(false),
31− m_enableLauncherWhileLocked(false),
32− m_enableIndicatorsWhileLocked(false),
33− m_statsWelcomeScreen(false),
34− m_passwordDisplayHint(Keyboard),
35− m_failedLogins(0),
36− m_hereEnabled(false),
37− m_hereLicensePath() // null means not set yet
48+ : QObject(parent)
49+ , m_service(new AccountsServiceDBusAdaptor(this))
3850{
3951 m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"),
4052 QStringLiteral("/com/canonical/Unity/Input"),
@@ -44,6 +56,21 @@ AccountsService::AccountsService(QObject* parent, const QString &user)
4456 connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
4557 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
4658
59+ registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
60+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
61+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
62+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
63+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
64+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged"));
65+ registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged"));
66+ registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged"));
67+ registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged"));
68+
69+ registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED,
70+ m_unityInput, QStringLiteral("setMouseCursorSpeed"));
71+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED,
72+ m_unityInput, QStringLiteral("setTouchpadCursorSpeed"));
73+
4774 setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER")));
4875}
4976
@@ -57,410 +84,193 @@ void AccountsService::setUser(const QString &user)
5784 if (user.isEmpty() || m_user == user)
5885 return;
5986
87+ bool wasEmpty = m_user.isEmpty();
88+
6089 m_user = user;
6190 Q_EMIT userChanged();
6291
63− updateDemoEdges(false);
64− updateEnableLauncherWhileLocked(false);
65− updateEnableIndicatorsWhileLocked(false);
66− updateBackgroundFile(false);
67− updateMouseCursorSpeed();
68− updateTouchpadCursorSpeed();
69− updateStatsWelcomeScreen(false);
70− updatePasswordDisplayHint(false);
71− updateFailedLogins(false);
72− updateHereEnabled(false);
73− updateHereLicensePath(false);
92+ // Do the first update synchronously, as a cheap way to block rendering
93+ // until we have the right values on bootup.
94+ refresh(!wasEmpty);
7495}
7596
7697bool AccountsService::demoEdges() const
7798{
78− return m_demoEdges;
99+ auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES);
100+ return value.toBool();
79101}
80102
81103void AccountsService::setDemoEdges(bool demoEdges)
82104{
83− if (m_demoEdges != demoEdges) {
84− m_demoEdges = demoEdges;
85− m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService"), QStringLiteral("demo-edges"), demoEdges);
86−
87− Q_EMIT demoEdgesChanged();
88− }
105+ setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges);
89106}
90107
91108bool AccountsService::enableLauncherWhileLocked() const
92109{
93− return m_enableLauncherWhileLocked;
110+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED);
111+ return value.toBool();
94112}
95113
96114bool AccountsService::enableIndicatorsWhileLocked() const
97115{
98− return m_enableIndicatorsWhileLocked;
116+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED);
117+ return value.toBool();
99118}
100119
101120QString AccountsService::backgroundFile() const
102121{
103− return m_backgroundFile;
122+ auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE);
123+ return value.toString();
104124}
105125
106126bool AccountsService::statsWelcomeScreen() const
107127{
108− return m_statsWelcomeScreen;
128+ auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN);
129+ return value.toBool();
109130}
110131
111132AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
112133{
113− return m_passwordDisplayHint;
134+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT);
135+ return (PasswordDisplayHint)value.toInt();
114136}
115137
116138bool AccountsService::hereEnabled() const
117139{
118− return m_hereEnabled;
140+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
141+ return value.toBool();
119142}
120143
121144void AccountsService::setHereEnabled(bool enabled)
122145{
123− if (m_hereEnabled != enabled) {
124− m_hereEnabled = enabled;
125− m_service->setUserPropertyAsync(m_user, QStringLiteral("com.ubuntu.location.providers.here.AccountsService"), QStringLiteral("LicenseAccepted"), enabled);
126−
127− Q_EMIT hereEnabledChanged();
128− }
146+ setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
129147}
130148
131149QString AccountsService::hereLicensePath() const
132150{
133− return m_hereLicensePath;
151+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
152+ QString hereLicensePath = value.toString();
153+ if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
154+ hereLicensePath.clear();
155+ return hereLicensePath;
134156}
135157
136158bool AccountsService::hereLicensePathValid() const
137159{
138− return !m_hereLicensePath.isNull();
160+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
161+ return !value.toString().isNull();
139162}
140163
141−void AccountsService::updateDemoEdges(bool async)
164+uint AccountsService::failedLogins() const
142165{
143− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
144− QStringLiteral("com.canonical.unity.AccountsService"),
145− QStringLiteral("demo-edges"));
146− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
147−
148− connect(watcher, &QDBusPendingCallWatcher::finished,
149− this, [this](QDBusPendingCallWatcher* watcher) {
150−
151− QDBusPendingReply<QDBusVariant> reply = *watcher;
152− watcher->deleteLater();
153− if (reply.isError()) {
154− qWarning() << "Failed to get 'demo-edges' property - " << reply.error().message();
155− return;
156− }
157−
158− auto demoEdges = reply.value().variant().toBool();
159− if (m_demoEdges != demoEdges) {
160− m_demoEdges = demoEdges;
161− Q_EMIT demoEdgesChanged();
162− }
163− });
164− if (!async) {
165− watcher->waitForFinished();
166− delete watcher;
167− }
166+ return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
168167}
169168
170−void AccountsService::updateEnableLauncherWhileLocked(bool async)
169+void AccountsService::setFailedLogins(uint failedLogins)
171170{
172− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
173− QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
174− QStringLiteral("EnableLauncherWhileLocked"));
175− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
176−
177− connect(watcher, &QDBusPendingCallWatcher::finished,
178− this, [this](QDBusPendingCallWatcher* watcher) {
179−
180− QDBusPendingReply<QVariant> reply = *watcher;
181− watcher->deleteLater();
182− if (reply.isError()) {
183− qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message();
184− return;
185− }
186−
187− const bool enableLauncherWhileLocked = reply.value().toBool();
188− if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
189− m_enableLauncherWhileLocked = enableLauncherWhileLocked;
190− Q_EMIT enableLauncherWhileLockedChanged();
191− }
192− });
193− if (!async) {
194− watcher->waitForFinished();
195− delete watcher;
196− }
171+ setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins);
197172}
198173
199−void AccountsService::updateEnableIndicatorsWhileLocked(bool async)
200−{
201− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
202− QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
203− QStringLiteral("EnableIndicatorsWhileLocked"));
204− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
174+// ====================================================
175+// Everything below this line is generic helper methods
176+// ====================================================
205177
206− connect(watcher, &QDBusPendingCallWatcher::finished,
207− this, [this](QDBusPendingCallWatcher* watcher) {
208−
209− QDBusPendingReply<QVariant> reply = *watcher;
210− watcher->deleteLater();
211− if (reply.isError()) {
212− qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message();
213− return;
214− }
215−
216− const bool enableIndicatorsWhileLocked = reply.value().toBool();
217− if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
218− m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
219− Q_EMIT enableIndicatorsWhileLockedChanged();
220− }
221− });
222− if (!async) {
223− watcher->waitForFinished();
224− delete watcher;
225− }
226−}
227−
228−void AccountsService::updateBackgroundFile(bool async)
178+void AccountsService::emitChangedForProperty(const QString &interface, const QString &property)
229179{
230− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
231− QStringLiteral("org.freedesktop.Accounts.User"),
232− QStringLiteral("BackgroundFile"));
233− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
234−
235− connect(watcher, &QDBusPendingCallWatcher::finished,
236− this, [this](QDBusPendingCallWatcher* watcher) {
237−
238− QDBusPendingReply<QVariant> reply = *watcher;
239− watcher->deleteLater();
240− if (reply.isError()) {
241− qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message();
242− return;
243− }
244−
245− const QString backgroundFile = reply.value().toString();
246− if (m_backgroundFile != backgroundFile) {
247− m_backgroundFile = backgroundFile;
248− Q_EMIT backgroundFileChanged();
249− }
250− });
251− if (!async) {
252− watcher->waitForFinished();
253− delete watcher;
254− }
180+ QString signalName = m_properties[interface][property].signal;
181+ QMetaObject::invokeMethod(this, signalName.toUtf8().data());
255182}
256183
257−void AccountsService::updateMouseCursorSpeed()
184+QVariant AccountsService::getProperty(const QString &interface, const QString &property) const
258185{
259− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
260− QStringLiteral("com.ubuntu.AccountsService.Input"),
261− QStringLiteral("MouseCursorSpeed"));
262− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
263−
264− connect(watcher, &QDBusPendingCallWatcher::finished,
265− this, [this](QDBusPendingCallWatcher* watcher) {
266−
267− QDBusPendingReply<QVariant> reply = *watcher;
268− watcher->deleteLater();
269− if (reply.isError()) {
270− qWarning() << "Failed to get 'MouseCursorSpeed' property - " << reply.error().message();
271− return;
272− }
273−
274− // Merely proxy this along to USC. We don't care about keeping a copy
275− // or exporting it internally.
276− m_unityInput->asyncCall(QStringLiteral("setMouseCursorSpeed"), reply.value());
277− });
186+ return m_properties[interface][property].value;
278187}
279188
280−void AccountsService::updateTouchpadCursorSpeed()
189+void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value)
281190{
282− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
283− QStringLiteral("com.ubuntu.AccountsService.Input"),
284− QStringLiteral("TouchpadCursorSpeed"));
285− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
286−
287− connect(watcher, &QDBusPendingCallWatcher::finished,
288− this, [this](QDBusPendingCallWatcher* watcher) {
289−
290− QDBusPendingReply<QVariant> reply = *watcher;
291− watcher->deleteLater();
292− if (reply.isError()) {
293− qWarning() << "Failed to get 'TouchpadCursorSpeed' property - " << reply.error().message();
294− return;
295− }
296−
297− // Merely proxy this along to USC. We don't care about keeping a copy
298− // or exporting it internally.
299− m_unityInput->asyncCall(QStringLiteral("setTouchpadCursorSpeed"), reply.value());
300− });
301−}
302−
303−void AccountsService::updateStatsWelcomeScreen(bool async)
304−{
305− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
306− QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy"),
307− QStringLiteral("StatsWelcomeScreen"));
308− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
309−
310− connect(watcher, &QDBusPendingCallWatcher::finished,
311− this, [this](QDBusPendingCallWatcher* watcher) {
312−
313− QDBusPendingReply<QVariant> reply = *watcher;
314− watcher->deleteLater();
315− if (reply.isError()) {
316− qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message();
317− return;
318− }
319−
320− const bool statsWelcomeScreen = reply.value().toBool();
321− if (m_statsWelcomeScreen != statsWelcomeScreen) {
322− m_statsWelcomeScreen = statsWelcomeScreen;
323− Q_EMIT statsWelcomeScreenChanged();
324− }
325− });
326− if (!async) {
327− watcher->waitForFinished();
328− delete watcher;
191+ if (m_properties[interface][property].value != value) {
192+ m_properties[interface][property].value = value;
193+ m_service->setUserPropertyAsync(m_user, interface, property, value);
194+ emitChangedForProperty(interface, property);
329195 }
330196}
331197
332−void AccountsService::updatePasswordDisplayHint(bool async)
198+void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value)
333199{
334− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
335− QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
336− QStringLiteral("PasswordDisplayHint"));
337− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
338−
339− connect(watcher, &QDBusPendingCallWatcher::finished,
340− this, [this](QDBusPendingCallWatcher* watcher) {
200+ PropertyInfo &info = m_properties[interface][property];
341201
342− QDBusPendingReply<QVariant> reply = *watcher;
343− watcher->deleteLater();
344− if (reply.isError()) {
345− qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message();
346− return;
347− }
348−
349− const PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().toInt();
350− if (m_passwordDisplayHint != passwordDisplayHint) {
351− m_passwordDisplayHint = passwordDisplayHint;
352− Q_EMIT passwordDisplayHintChanged();
353− }
354− });
355− if (!async) {
356− watcher->waitForFinished();
357− delete watcher;
202+ if (info.proxyInterface) {
203+ info.proxyInterface->asyncCall(info.proxyMethod, value);
204+ return; // don't bother saving a copy
358205 }
359−}
360−
361−void AccountsService::updateFailedLogins(bool async)
362−{
363− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
364− QStringLiteral("com.canonical.unity.AccountsService.Private"),
365− QStringLiteral("FailedLogins"));
366− QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
367−
368− connect(watcher, &QDBusPendingCallWatcher::finished,
369− this, [this](QDBusPendingCallWatcher* watcher) {
370−
371− QDBusPendingReply<QVariant> reply = *watcher;
372− watcher->deleteLater();
373− if (reply.isError()) {
374− qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message();
375− return;
376− }
377206
378− const uint failedLogins = reply.value().toUInt();
379− if (m_failedLogins != failedLogins) {
380− m_failedLogins = failedLogins;
381− Q_EMIT failedLoginsChanged();
382− }
383− });
384− if (!async) {
385− watcher->waitForFinished();
386− delete watcher;
207+ if (info.value != value) {
208+ info.value = value;
209+ emitChangedForProperty(interface, property);
387210 }
388211}
389212
390−void AccountsService::updateHereEnabled(bool async)
213+void AccountsService::updateProperty(const QString &interface, const QString &property)
391214{
392215 QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
393− QStringLiteral("com.ubuntu.location.providers.here.AccountsService"),
394− QStringLiteral("LicenseAccepted"));
216+ interface,
217+ property);
395218 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
396219
397220 connect(watcher, &QDBusPendingCallWatcher::finished,
398− this, [this](QDBusPendingCallWatcher* watcher) {
221+ this, [this, interface, property](QDBusPendingCallWatcher* watcher) {
399222
400223 QDBusPendingReply<QVariant> reply = *watcher;
401224 watcher->deleteLater();
402225 if (reply.isError()) {
403− qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message();
226+ qWarning() << "Failed to get '" << property << "' property:" << reply.error().message();
404227 return;
405228 }
406229
407− const bool hereEnabled = reply.value().toBool();
408− if (m_hereEnabled != hereEnabled) {
409− m_hereEnabled = hereEnabled;
410− Q_EMIT hereEnabledChanged();
411− }
230+ updateCache(interface, property, reply.value());
412231 });
413− if (!async) {
414− watcher->waitForFinished();
415− delete watcher;
416− }
417232}
418233
419−void AccountsService::updateHereLicensePath(bool async)
234+void AccountsService::updateAllProperties(const QString &interface, bool async)
420235{
421− QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
422− QStringLiteral("com.ubuntu.location.providers.here.AccountsService"),
423− QStringLiteral("LicenseBasePath"));
236+ QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user,
237+ interface);
424238 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
425239
426240 connect(watcher, &QDBusPendingCallWatcher::finished,
427− this, [this](QDBusPendingCallWatcher* watcher) {
241+ this, [this, interface](QDBusPendingCallWatcher* watcher) {
428242
429− QDBusPendingReply<QVariant> reply = *watcher;
243+ QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher;
430244 watcher->deleteLater();
431245 if (reply.isError()) {
432− qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message();
246+ qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message();
433247 return;
434248 }
435249
436− QString hereLicensePath = reply.value().toString();
437− if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
438− hereLicensePath = QLatin1String("");
439−
440− if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) {
441− m_hereLicensePath = hereLicensePath;
442− Q_EMIT hereLicensePathChanged();
250+ auto valueHash = reply.value();
251+ auto i = valueHash.constBegin();
252+ while (i != valueHash.constEnd()) {
253+ updateCache(interface, i.key(), i.value());
254+ ++i;
443255 }
444256 });
445257 if (!async) {
446258 watcher->waitForFinished();
447− delete watcher;
448259 }
449260}
450261
451−uint AccountsService::failedLogins() const
262+void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method)
452263{
453− return m_failedLogins;
264+ registerProperty(interface, property, nullptr);
265+
266+ m_properties[interface][property].proxyInterface = iface;
267+ m_properties[interface][property].proxyMethod = method;
454268}
455269
456−void AccountsService::setFailedLogins(uint failedLogins)
270+void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal)
457271{
458− if (m_failedLogins != failedLogins) {
459− m_failedLogins = failedLogins;
460− m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService.Private"), QStringLiteral("FailedLogins"), failedLogins);
461−
462− Q_EMIT failedLoginsChanged();
463− }
272+ m_properties[interface][property] = PropertyInfo();
273+ m_properties[interface][property].signal = signal;
464274}
465275
466276void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
@@ -469,42 +279,13 @@ void AccountsService::onPropertiesChanged(const QString &user, const QString &in
469279 return;
470280 }
471281
472− if (interface == QLatin1String("com.canonical.unity.AccountsService")) {
473− if (changed.contains(QStringLiteral("demo-edges"))) {
474− updateDemoEdges();
475− }
476− } else if (interface == QLatin1String("com.canonical.unity.AccountsService.Private")) {
477− if (changed.contains(QStringLiteral("FailedLogins"))) {
478− updateFailedLogins();
479− }
480− } else if (interface == QLatin1String("com.ubuntu.AccountsService.Input")) {
481− if (changed.contains(QStringLiteral("MouseCursorSpeed"))) {
482− updateMouseCursorSpeed();
483− }
484− if (changed.contains(QStringLiteral("TouchpadCursorSpeed"))) {
485− updateTouchpadCursorSpeed();
486− }
487− } else if (interface == QLatin1String("com.ubuntu.touch.AccountsService.SecurityPrivacy")) {
488− if (changed.contains(QStringLiteral("StatsWelcomeScreen"))) {
489− updateStatsWelcomeScreen();
490− }
491− } else if (interface == QLatin1String("com.ubuntu.AccountsService.SecurityPrivacy")) {
492− if (changed.contains(QStringLiteral("PasswordDisplayHint"))) {
493− updatePasswordDisplayHint();
494− }
495− if (changed.contains(QStringLiteral("EnableLauncherWhileLocked"))) {
496− updateEnableLauncherWhileLocked();
497− }
498− if (changed.contains(QStringLiteral("EnableIndicatorsWhileLocked"))) {
499− updateEnableIndicatorsWhileLocked();
500− }
501− } else if (interface == QLatin1String("com.ubuntu.location.providers.here.AccountsService")) {
502− if (changed.contains(QStringLiteral("LicenseAccepted"))) {
503− updateHereEnabled();
504− }
505− if (changed.contains(QStringLiteral("LicenseBasePath"))) {
506− updateHereLicensePath();
282+ auto propHash = m_properties.value(interface);
283+ auto i = propHash.constBegin();
284+ while (i != propHash.constEnd()) {
285+ if (changed.contains(i.key())) {
286+ updateProperty(interface, i.key());
507287 }
288+ ++i;
508289 }
509290}
510291
@@ -514,6 +295,20 @@ void AccountsService::onMaybeChanged(const QString &user)
514295 return;
515296 }
516297
517− // Standard properties might have changed
518− updateBackgroundFile();
298+ // Any of the standard properties might have changed!
299+ auto propHash = m_properties.value(IFACE_ACCOUNTS_USER);
300+ auto i = propHash.constBegin();
301+ while (i != propHash.constEnd()) {
302+ updateProperty(IFACE_ACCOUNTS_USER, i.key());
303+ ++i;
304+ }
305+}
306+
307+void AccountsService::refresh(bool async)
308+{
309+ auto i = m_properties.constBegin();
310+ while (i != m_properties.constEnd()) {
311+ updateAllProperties(i.key(), async);
312+ ++i;
313+ }
519314}
plugins/AccountsService/AccountsService.h+22−20
@@ -19,8 +19,10 @@
1919#ifndef UNITY_ACCOUNTSSERVICE_H
2020#define UNITY_ACCOUNTSSERVICE_H
2121
22+#include <QHash>
2223#include <QObject>
2324#include <QString>
25+#include <QVariant>
2426
2527class AccountsServiceDBusAdaptor;
2628class QDBusInterface;
@@ -109,30 +111,30 @@ private Q_SLOTS:
109111 void onMaybeChanged(const QString &user);
110112
111113private:
112− void updateDemoEdges(bool async = true);
113− void updateEnableLauncherWhileLocked(bool async = true);
114− void updateEnableIndicatorsWhileLocked(bool async = true);
115− void updateBackgroundFile(bool async = true);
116− void updateMouseCursorSpeed();
117− void updateTouchpadCursorSpeed();
118− void updateStatsWelcomeScreen(bool async = true);
119− void updatePasswordDisplayHint(bool async = true);
120− void updateFailedLogins(bool async = true);
121− void updateHereEnabled(bool async = true);
122− void updateHereLicensePath(bool async = true);
114+ void refresh(bool async);
115+ void registerProperty(const QString &interface, const QString &property, const QString &signal);
116+ void registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method);
123117
118+ void updateAllProperties(const QString &interface, bool async);
119+ void updateProperty(const QString &interface, const QString &property);
120+ void updateCache(const QString &interface, const QString &property, const QVariant &value);
121+
122+ void setProperty(const QString &interface, const QString &property, const QVariant &value);
123+ QVariant getProperty(const QString &interface, const QString &property) const;
124+
125+ void emitChangedForProperty(const QString &interface, const QString &property);
126+
127+ struct PropertyInfo {
128+ QVariant value{};
129+ QString signal{};
130+ QDBusInterface *proxyInterface{};
131+ QString proxyMethod{};
132+ };
133+ typedef QHash< QString, QHash<QString, PropertyInfo> > PropertyHash;
134+ PropertyHash m_properties;
124135 AccountsServiceDBusAdaptor *m_service;
125136 QDBusInterface *m_unityInput;
126137 QString m_user;
127− bool m_demoEdges;
128− bool m_enableLauncherWhileLocked;
129− bool m_enableIndicatorsWhileLocked;
130− QString m_backgroundFile;
131− bool m_statsWelcomeScreen;
132− PasswordDisplayHint m_passwordDisplayHint;
133− uint m_failedLogins;
134− bool m_hereEnabled;
135− QString m_hereLicensePath;
136138};
137139
138140#endif
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+9
@@ -37,6 +37,15 @@ AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
3737 connection, this);
3838}
3939
40+QDBusPendingReply<QVariantMap> AccountsServiceDBusAdaptor::getAllPropertiesAsync(const QString &user, const QString &interface)
41+{
42+ QDBusInterface *iface = getUserInterface(user);
43+ if (iface != nullptr && iface->isValid()) {
44+ return iface->asyncCall(QStringLiteral("GetAll"), interface);
45+ }
46+ return QDBusPendingReply<QVariantMap>(QDBusMessage::createError(QDBusError::Other, QStringLiteral("Invalid Interface")));
47+}
48+
4049QDBusPendingReply<QVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property)
4150{
4251 QDBusInterface *iface = getUserInterface(user);
plugins/AccountsService/AccountsServiceDBusAdaptor.h+1
@@ -35,6 +35,7 @@ public:
3535 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
3636 ~AccountsServiceDBusAdaptor() = default;
3737
38+ QDBusPendingReply<QVariantMap> getAllPropertiesAsync(const QString &user, const QString &interface);
3839 Q_INVOKABLE QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
3940 Q_INVOKABLE QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
4041
tests/plugins/AccountsService/CMakeLists.txt+2
@@ -10,6 +10,7 @@ macro(make_dbus_class NAME INTERFACE)
1010endmacro(make_dbus_class)
1111
1212make_dbus_class(Accounts org.freedesktop.Accounts)
13+make_dbus_class(Input com.ubuntu.AccountsService.Input)
1314make_dbus_class(Properties org.freedesktop.DBus.Properties)
1415make_dbus_class(SecurityPrivacy com.ubuntu.touch.AccountsService.SecurityPrivacy)
1516make_dbus_class(Location com.ubuntu.location.providers.here.AccountsService)
@@ -27,6 +28,7 @@ add_executable(mock-server
2728 ${CMAKE_CURRENT_BINARY_DIR}/AccountsAdaptor.cpp
2829 ${CMAKE_CURRENT_BINARY_DIR}/AccountsPrivateAdaptor.cpp
2930 ${CMAKE_CURRENT_BINARY_DIR}/AccountsUserAdaptor.cpp
31+ ${CMAKE_CURRENT_BINARY_DIR}/InputAdaptor.cpp
3032 ${CMAKE_CURRENT_BINARY_DIR}/PropertiesAdaptor.cpp
3133 ${CMAKE_CURRENT_BINARY_DIR}/LocationAdaptor.cpp
3234 ${CMAKE_CURRENT_BINARY_DIR}/SecurityPrivacyAdaptor.cpp
tests/plugins/AccountsService/PropertiesServer.cpp+12
@@ -42,6 +42,16 @@ QDBusVariant PropertiesServer::Get(const QString &interface, const QString &prop
4242 }
4343}
4444
45+QVariantMap PropertiesServer::GetAll(const QString &interface)
46+{
47+ if (m_properties.contains(interface)) {
48+ return m_properties[interface];
49+ } else {
50+ sendErrorReply(QDBusError::InvalidArgs, "Bad interface");
51+ return QVariantMap();
52+ }
53+}
54+
4555void PropertiesServer::Set(const QString &interface, const QString &property, const QDBusVariant &variant)
4656{
4757 QVariant newValue = variant.variant();
@@ -82,6 +92,8 @@ void PropertiesServer::Reset()
8292 m_properties["com.canonical.unity.AccountsService"]["LauncherItems"] = QVariant::fromValue(QList<QVariantMap>());
8393 m_properties["com.canonical.unity.AccountsService.Private"]["FailedLogins"] = 0;
8494 m_properties["com.ubuntu.touch.AccountsService.SecurityPrivacy"]["StatsWelcomeScreen"] = true;
95+ m_properties["com.ubuntu.AccountsService.Input"]["MouseCursorSpeed"] = 0.5;
96+ m_properties["com.ubuntu.AccountsService.Input"]["TouchpadCursorSpeed"] = 0.5;
8597 m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["EnableLauncherWhileLocked"] = true;
8698 m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["EnableIndicatorsWhileLocked"] = true;
8799 m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["PasswordDisplayHint"] = AccountsService::Keyboard;
tests/plugins/AccountsService/PropertiesServer.h+1
@@ -35,6 +35,7 @@ public:
3535
3636public Q_SLOTS:
3737 QDBusVariant Get(const QString &interface, const QString &property);
38+ QVariantMap GetAll(const QString &interface);
3839 void Set(const QString &interface, const QString &property, const QDBusVariant &variant);
3940
4041 // mock only.
tests/plugins/AccountsService/client.cpp+9−9
@@ -107,7 +107,7 @@ private Q_SLOTS:
107107 QCOMPARE(session.hereEnabled(), true);
108108 }
109109
110− void testAsynchornousChangeForDemoEdges()
110+ void testAsynchronousChangeForDemoEdges()
111111 {
112112 AccountsService session(this, QTest::currentTestFunction());
113113
@@ -119,7 +119,7 @@ private Q_SLOTS:
119119 QTRY_COMPARE(session.demoEdges(), true);
120120 }
121121
122− void testAsynchornousChangeForFailedLogins()
122+ void testAsynchronousChangeForFailedLogins()
123123 {
124124 AccountsService session(this, QTest::currentTestFunction());
125125
@@ -131,7 +131,7 @@ private Q_SLOTS:
131131 QTRY_COMPARE(session.failedLogins(), (uint)5);
132132 }
133133
134− void testAsynchornousChangeForStatsWelcomeScreen()
134+ void testAsynchronousChangeForStatsWelcomeScreen()
135135 {
136136 AccountsService session(this, QTest::currentTestFunction());
137137
@@ -143,7 +143,7 @@ private Q_SLOTS:
143143 QTRY_COMPARE(session.statsWelcomeScreen(), false);
144144 }
145145
146− void testAsynchornousChangeForStatsEnableLauncherWhileLocked()
146+ void testAsynchronousChangeForEnableLauncherWhileLocked()
147147 {
148148 AccountsService session(this, QTest::currentTestFunction());
149149
@@ -155,7 +155,7 @@ private Q_SLOTS:
155155 QTRY_COMPARE(session.enableLauncherWhileLocked(), false);
156156 }
157157
158− void testAsynchornousChangeForStatsEnableIndicatorsWhileLocked()
158+ void testAsynchronousChangeForEnableIndicatorsWhileLocked()
159159 {
160160 AccountsService session(this, QTest::currentTestFunction());
161161
@@ -167,7 +167,7 @@ private Q_SLOTS:
167167 QTRY_COMPARE(session.enableIndicatorsWhileLocked(), false);
168168 }
169169
170− void testAsynchornousChangeForStatsPasswordDisplayHint()
170+ void testAsynchronousChangeForPasswordDisplayHint()
171171 {
172172 AccountsService session(this, QTest::currentTestFunction());
173173
@@ -179,7 +179,7 @@ private Q_SLOTS:
179179 QTRY_COMPARE(session.passwordDisplayHint(), AccountsService::Numeric);
180180 }
181181
182− void testAsynchornousChangeForStatsLicenseAccepted()
182+ void testAsynchronousChangeForLicenseAccepted()
183183 {
184184 AccountsService session(this, QTest::currentTestFunction());
185185
@@ -191,7 +191,7 @@ private Q_SLOTS:
191191 QTRY_COMPARE(session.hereEnabled(), true);
192192 }
193193
194− void testAsynchornousChangeForLicenseBasePath()
194+ void testAsynchronousChangeForLicenseBasePath()
195195 {
196196 AccountsService session(this, QTest::currentTestFunction());
197197
@@ -203,7 +203,7 @@ private Q_SLOTS:
203203 QTRY_COMPARE(session.hereLicensePath(), QString("/"));
204204 }
205205
206− void testAsynchornousChangeForStatsBackgroundFile()
206+ void testAsynchronousChangeForBackgroundFile()
207207 {
208208 AccountsService session(this, QTest::currentTestFunction());
209209
tests/plugins/AccountsService/interfaces.xml+5
@@ -5,6 +5,11 @@
55 <arg name="property" type="s" direction="in" />
66 <arg name="value" type="v" direction="out" />
77 </method>
8+ <method name="GetAll">
9+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
10+ <arg name="interface" type="s" direction="in" />
11+ <arg name="value" type="a{sv}" direction="out" />
12+ </method>
813 <method name="Set">
914 <arg name="interface" type="s" direction="in" />
1015 <arg name="property" type="s" direction="in" />