on 3df724b help sign in
unity8/plugins/AccountsService/AccountsService.cpp
406 lines 16 kB history raw
1/*
2 * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include "AccountsService.h"
18#include "AccountsServiceDBusAdaptor.h"
20#include <QDBusInterface>
21#include <QFile>
22#include <QStringList>
23#include <QDebug>
25#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User")
26#define IFACE_LOCATION_HERE QStringLiteral("com.ubuntu.location.providers.here.AccountsService")
27#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input")
28#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy")
29#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy")
30#define IFACE_UNITY QStringLiteral("com.canonical.unity.AccountsService")
31#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private")
33#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
34#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
35#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted")
36#define PROP_EMAIL QStringLiteral("Email")
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_MOUSE_DOUBLE_CLICK_SPEED QStringLiteral("MouseDoubleClickSpeed")
44#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton")
45#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed")
46#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
47#define PROP_REAL_NAME QStringLiteral("RealName")
48#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
49#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
50#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
51#define PROP_TOUCHPAD_DISABLE_WITH_MOUSE QStringLiteral("TouchpadDisableWithMouse")
52#define PROP_TOUCHPAD_DOUBLE_CLICK_SPEED QStringLiteral("TouchpadDoubleClickSpeed")
53#define PROP_TOUCHPAD_PRIMARY_BUTTON QStringLiteral("TouchpadPrimaryButton")
54#define PROP_TOUCHPAD_SCROLL_SPEED QStringLiteral("TouchpadScrollSpeed")
55#define PROP_TOUCHPAD_TAP_TO_CLICK QStringLiteral("TouchpadTapToClick")
56#define PROP_TOUCHPAD_TWO_FINGER_SCROLL QStringLiteral("TouchpadTwoFingerScroll")
59QVariant primaryButtonConverter(const QVariant &value)
61 QString stringValue = value.toString();
62 if (stringValue == "left") {
63 return QVariant::fromValue(0);
64 } else if (stringValue == "right") {
65 return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same
66 } else {
67 return QVariant::fromValue(0); // default to left
68 }
71AccountsService::AccountsService(QObject* parent, const QString &user)
72 : QObject(parent)
73 , m_service(new AccountsServiceDBusAdaptor(this))
75 m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"),
76 QStringLiteral("/com/canonical/Unity/Input"),
77 QStringLiteral("com.canonical.Unity.Input"),
78 QDBusConnection::SM_BUSNAME(), this);
80 connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
81 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
83 registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
84 registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged"));
85 registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged"));
86 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
87 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
88 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
89 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
90 registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged"));
91 registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged"));
92 registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged"));
93 registerProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, QStringLiteral("demoEdgesCompletedChanged"));
94 registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged"));
96 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED,
97 m_unityInput, QStringLiteral("setMouseCursorSpeed"));
98 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_DOUBLE_CLICK_SPEED,
99 m_unityInput, QStringLiteral("setMouseDoubleClickSpeed"));
100 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_PRIMARY_BUTTON,
101 m_unityInput, QStringLiteral("setMousePrimaryButton"),
102 primaryButtonConverter);
103 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_SCROLL_SPEED,
104 m_unityInput, QStringLiteral("setMouseScrollSpeed"));
105 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED,
106 m_unityInput, QStringLiteral("setTouchpadCursorSpeed"));
107 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_SCROLL_SPEED,
108 m_unityInput, QStringLiteral("setTouchpadScrollSpeed"));
109 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WHILE_TYPING,
110 m_unityInput, QStringLiteral("setTouchpadDisableWhileTyping"));
111 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WITH_MOUSE,
112 m_unityInput, QStringLiteral("setTouchpadDisableWithMouse"));
113 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DOUBLE_CLICK_SPEED,
114 m_unityInput, QStringLiteral("setTouchpadDoubleClickSpeed"));
115 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_PRIMARY_BUTTON,
116 m_unityInput, QStringLiteral("setTouchpadPrimaryButton"),
117 primaryButtonConverter);
118 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TAP_TO_CLICK,
119 m_unityInput, QStringLiteral("setTouchpadTapToClick"));
120 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TWO_FINGER_SCROLL,
121 m_unityInput, QStringLiteral("setTouchpadTwoFingerScroll"));
123 setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER")));
126QString AccountsService::user() const
128 return m_user;
131void AccountsService::setUser(const QString &user)
133 if (user.isEmpty() || m_user == user)
134 return;
136 bool wasEmpty = m_user.isEmpty();
138 m_user = user;
139 Q_EMIT userChanged();
141 // Do the first update synchronously, as a cheap way to block rendering
142 // until we have the right values on bootup.
143 refresh(!wasEmpty);
146bool AccountsService::demoEdges() const
148 auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES);
149 return value.toBool();
152void AccountsService::setDemoEdges(bool demoEdges)
154 setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges);
157QStringList AccountsService::demoEdgesCompleted() const
159 auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED);
160 return value.toStringList();
163void AccountsService::markDemoEdgeCompleted(const QString &edge)
165 auto currentList = demoEdgesCompleted();
166 if (!currentList.contains(edge)) {
167 setProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, currentList << edge);
168 }
171bool AccountsService::enableLauncherWhileLocked() const
173 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED);
174 return value.toBool();
177bool AccountsService::enableIndicatorsWhileLocked() const
179 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED);
180 return value.toBool();
183QString AccountsService::backgroundFile() const
185 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE);
186 return value.toString();
189bool AccountsService::statsWelcomeScreen() const
191 auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN);
192 return value.toBool();
195AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
197 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT);
198 return (PasswordDisplayHint)value.toInt();
201bool AccountsService::hereEnabled() const
203 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
204 return value.toBool();
207void AccountsService::setHereEnabled(bool enabled)
209 setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
212QString AccountsService::hereLicensePath() const
214 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
215 QString hereLicensePath = value.toString();
216 if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
217 hereLicensePath = QStringLiteral("");
218 return hereLicensePath;
221bool AccountsService::hereLicensePathValid() const
223 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
224 return !value.toString().isNull();
227QString AccountsService::realName() const
229 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME);
230 return value.toString();
233void AccountsService::setRealName(const QString &realName)
235 setProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, realName);
238QString AccountsService::email() const
240 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL);
241 return value.toString();
244void AccountsService::setEmail(const QString &email)
246 setProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, email);
249uint AccountsService::failedLogins() const
251 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
254void AccountsService::setFailedLogins(uint failedLogins)
256 setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins);
259// ====================================================
260// Everything below this line is generic helper methods
261// ====================================================
263void AccountsService::emitChangedForProperty(const QString &interface, const QString &property)
265 QString signalName = m_properties[interface][property].signal;
266 QMetaObject::invokeMethod(this, signalName.toUtf8().data());
269QVariant AccountsService::getProperty(const QString &interface, const QString &property) const
271 return m_properties[interface][property].value;
274void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value)
276 if (m_properties[interface][property].value != value) {
277 m_properties[interface][property].value = value;
278 m_service->setUserPropertyAsync(m_user, interface, property, value);
279 emitChangedForProperty(interface, property);
280 }
283void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value)
285 PropertyInfo &info = m_properties[interface][property];
287 if (info.proxyInterface) {
288 QVariant finalValue;
289 if (info.proxyConverter) {
290 finalValue = info.proxyConverter(value);
291 } else {
292 finalValue = value;
293 }
294 info.proxyInterface->asyncCall(info.proxyMethod, finalValue);
295 return; // don't bother saving a copy
296 }
298 if (info.value != value) {
299 info.value = value;
300 emitChangedForProperty(interface, property);
301 }
304void AccountsService::updateProperty(const QString &interface, const QString &property)
306 QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
307 interface,
308 property);
309 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
311 connect(watcher, &QDBusPendingCallWatcher::finished,
312 this, [this, interface, property](QDBusPendingCallWatcher* watcher) {
314 QDBusPendingReply<QVariant> reply = *watcher;
315 watcher->deleteLater();
316 if (reply.isError()) {
317 qWarning() << "Failed to get '" << property << "' property:" << reply.error().message();
318 return;
319 }
321 updateCache(interface, property, reply.value());
322 });
325void AccountsService::updateAllProperties(const QString &interface, bool async)
327 QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user,
328 interface);
329 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
331 connect(watcher, &QDBusPendingCallWatcher::finished,
332 this, [this, interface](QDBusPendingCallWatcher* watcher) {
334 QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher;
335 watcher->deleteLater();
336 if (reply.isError()) {
337 qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message();
338 return;
339 }
341 auto valueHash = reply.value();
342 auto i = valueHash.constBegin();
343 while (i != valueHash.constEnd()) {
344 updateCache(interface, i.key(), i.value());
345 ++i;
346 }
347 });
348 if (!async) {
349 watcher->waitForFinished();
350 }
353void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter)
355 registerProperty(interface, property, nullptr);
357 m_properties[interface][property].proxyInterface = iface;
358 m_properties[interface][property].proxyMethod = method;
359 m_properties[interface][property].proxyConverter = converter;
362void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal)
364 m_properties[interface][property] = PropertyInfo();
365 m_properties[interface][property].signal = signal;
368void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
370 if (m_user != user) {
371 return;
372 }
374 auto propHash = m_properties.value(interface);
375 auto i = propHash.constBegin();
376 while (i != propHash.constEnd()) {
377 if (changed.contains(i.key())) {
378 updateProperty(interface, i.key());
379 }
380 ++i;
381 }
384void AccountsService::onMaybeChanged(const QString &user)
386 if (m_user != user) {
387 return;
388 }
390 // Any of the standard properties might have changed!
391 auto propHash = m_properties.value(IFACE_ACCOUNTS_USER);
392 auto i = propHash.constBegin();
393 while (i != propHash.constEnd()) {
394 updateProperty(IFACE_ACCOUNTS_USER, i.key());
395 ++i;
396 }
399void AccountsService::refresh(bool async)
401 auto i = m_properties.constBegin();
402 while (i != m_properties.constEnd()) {
403 updateAllProperties(i.key(), async);
404 ++i;
405 }