on ee69752 help sign in
unity8/plugins/AccountsService/AccountsService.cpp
442 lines 18 kB history raw
1/*
2 * Copyright (C) 2013-2016 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#include <glib.h>
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")
35#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
36#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
37#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted")
38#define PROP_EMAIL QStringLiteral("Email")
39#define PROP_ENABLE_FINGERPRINT_IDENTIFICATION QStringLiteral("EnableFingerprintIdentification")
40#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked")
41#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked")
42#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins")
43#define PROP_INPUT_SOURCES QStringLiteral("InputSources")
44#define PROP_LICENSE_ACCEPTED QStringLiteral("LicenseAccepted")
45#define PROP_LICENSE_BASE_PATH QStringLiteral("LicenseBasePath")
46#define PROP_MOUSE_CURSOR_SPEED QStringLiteral("MouseCursorSpeed")
47#define PROP_MOUSE_DOUBLE_CLICK_SPEED QStringLiteral("MouseDoubleClickSpeed")
48#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton")
49#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed")
50#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
51#define PROP_REAL_NAME QStringLiteral("RealName")
52#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
53#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
54#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
55#define PROP_TOUCHPAD_DISABLE_WITH_MOUSE QStringLiteral("TouchpadDisableWithMouse")
56#define PROP_TOUCHPAD_DOUBLE_CLICK_SPEED QStringLiteral("TouchpadDoubleClickSpeed")
57#define PROP_TOUCHPAD_PRIMARY_BUTTON QStringLiteral("TouchpadPrimaryButton")
58#define PROP_TOUCHPAD_SCROLL_SPEED QStringLiteral("TouchpadScrollSpeed")
59#define PROP_TOUCHPAD_TAP_TO_CLICK QStringLiteral("TouchpadTapToClick")
60#define PROP_TOUCHPAD_TWO_FINGER_SCROLL QStringLiteral("TouchpadTwoFingerScroll")
62using StringMap = QMap<QString,QString>;
63using StringMapList = QList<StringMap>;
64Q_DECLARE_METATYPE(StringMapList)
67QVariant primaryButtonConverter(const QVariant &value)
69 QString stringValue = value.toString();
70 if (stringValue == "left") {
71 return QVariant::fromValue(0);
72 } else if (stringValue == "right") {
73 return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same
74 } else {
75 return QVariant::fromValue(0); // default to left
76 }
79AccountsService::AccountsService(QObject* parent, const QString &user)
80 : QObject(parent)
81 , m_service(new AccountsServiceDBusAdaptor(this))
83 m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"),
84 QStringLiteral("/com/canonical/Unity/Input"),
85 QStringLiteral("com.canonical.Unity.Input"),
86 QDBusConnection::SM_BUSNAME(), this);
88 connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
89 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
91 registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
92 registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged"));
93 registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged"));
94 registerProperty(IFACE_ACCOUNTS_USER, PROP_INPUT_SOURCES, QStringLiteral("keymapsChanged"));
95 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
96 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
97 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_FINGERPRINT_IDENTIFICATION, QStringLiteral("enableFingerprintIdentificationChanged"));
98 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
99 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
100 registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged"));
101 registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged"));
102 registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged"));
103 registerProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, QStringLiteral("demoEdgesCompletedChanged"));
104 registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged"));
106 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED,
107 m_unityInput, QStringLiteral("setMouseCursorSpeed"));
108 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_DOUBLE_CLICK_SPEED,
109 m_unityInput, QStringLiteral("setMouseDoubleClickSpeed"));
110 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_PRIMARY_BUTTON,
111 m_unityInput, QStringLiteral("setMousePrimaryButton"),
112 primaryButtonConverter);
113 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_SCROLL_SPEED,
114 m_unityInput, QStringLiteral("setMouseScrollSpeed"));
115 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED,
116 m_unityInput, QStringLiteral("setTouchpadCursorSpeed"));
117 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_SCROLL_SPEED,
118 m_unityInput, QStringLiteral("setTouchpadScrollSpeed"));
119 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WHILE_TYPING,
120 m_unityInput, QStringLiteral("setTouchpadDisableWhileTyping"));
121 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WITH_MOUSE,
122 m_unityInput, QStringLiteral("setTouchpadDisableWithMouse"));
123 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DOUBLE_CLICK_SPEED,
124 m_unityInput, QStringLiteral("setTouchpadDoubleClickSpeed"));
125 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_PRIMARY_BUTTON,
126 m_unityInput, QStringLiteral("setTouchpadPrimaryButton"),
127 primaryButtonConverter);
128 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TAP_TO_CLICK,
129 m_unityInput, QStringLiteral("setTouchpadTapToClick"));
130 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TWO_FINGER_SCROLL,
131 m_unityInput, QStringLiteral("setTouchpadTwoFingerScroll"));
133 setUser(!user.isEmpty() ? user : QString::fromUtf8(g_get_user_name()));
136QString AccountsService::user() const
138 return m_user;
141void AccountsService::setUser(const QString &user)
143 if (user.isEmpty() || m_user == user)
144 return;
146 bool wasEmpty = m_user.isEmpty();
148 m_user = user;
149 Q_EMIT userChanged();
151 // Do the first update synchronously, as a cheap way to block rendering
152 // until we have the right values on bootup.
153 refresh(!wasEmpty);
156bool AccountsService::demoEdges() const
158 auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES);
159 return value.toBool();
162void AccountsService::setDemoEdges(bool demoEdges)
164 setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges);
167QStringList AccountsService::demoEdgesCompleted() const
169 auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED);
170 return value.toStringList();
173void AccountsService::markDemoEdgeCompleted(const QString &edge)
175 auto currentList = demoEdgesCompleted();
176 if (!currentList.contains(edge)) {
177 setProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, currentList << edge);
178 }
181bool AccountsService::enableFingerprintIdentification() const
183 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_FINGERPRINT_IDENTIFICATION);
184 return value.toBool();
187bool AccountsService::enableLauncherWhileLocked() const
189 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED);
190 return value.toBool();
193bool AccountsService::enableIndicatorsWhileLocked() const
195 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED);
196 return value.toBool();
199QString AccountsService::backgroundFile() const
201 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE);
202 return value.toString();
205bool AccountsService::statsWelcomeScreen() const
207 auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN);
208 return value.toBool();
211AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
213 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT);
214 return (PasswordDisplayHint)value.toInt();
217bool AccountsService::hereEnabled() const
219 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
220 return value.toBool();
223void AccountsService::setHereEnabled(bool enabled)
225 setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
228QString AccountsService::hereLicensePath() const
230 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
231 QString hereLicensePath = value.toString();
232 if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
233 hereLicensePath = QStringLiteral("");
234 return hereLicensePath;
237bool AccountsService::hereLicensePathValid() const
239 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
240 return !value.toString().isNull();
243QString AccountsService::realName() const
245 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME);
246 return value.toString();
249void AccountsService::setRealName(const QString &realName)
251 setProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, realName);
254QString AccountsService::email() const
256 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL);
257 return value.toString();
260void AccountsService::setEmail(const QString &email)
262 setProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, email);
265QStringList AccountsService::keymaps() const
267 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_INPUT_SOURCES);
268 QDBusArgument arg = value.value<QDBusArgument>();
269 StringMapList maps = qdbus_cast<StringMapList>(arg);
270 QStringList simplifiedMaps;
272 Q_FOREACH(const StringMap &map, maps) {
273 Q_FOREACH(const QString &entry, map) {
274 simplifiedMaps.append(entry);
275 }
276 }
278 if (!simplifiedMaps.isEmpty()) {
279 return simplifiedMaps;
280 }
282 return {QStringLiteral("us")};
285uint AccountsService::failedLogins() const
287 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
290void AccountsService::setFailedLogins(uint failedLogins)
292 setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins);
295// ====================================================
296// Everything below this line is generic helper methods
297// ====================================================
299void AccountsService::emitChangedForProperty(const QString &interface, const QString &property)
301 QString signalName = m_properties[interface][property].signal;
302 QMetaObject::invokeMethod(this, signalName.toUtf8().data());
305QVariant AccountsService::getProperty(const QString &interface, const QString &property) const
307 return m_properties[interface][property].value;
310void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value)
312 if (m_properties[interface][property].value != value) {
313 m_properties[interface][property].value = value;
314 m_service->setUserPropertyAsync(m_user, interface, property, value);
315 emitChangedForProperty(interface, property);
316 }
319void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value)
321 PropertyInfo &info = m_properties[interface][property];
323 if (info.proxyInterface) {
324 QVariant finalValue;
325 if (info.proxyConverter) {
326 finalValue = info.proxyConverter(value);
327 } else {
328 finalValue = value;
329 }
330 info.proxyInterface->asyncCall(info.proxyMethod, finalValue);
331 return; // don't bother saving a copy
332 }
334 if (info.value != value) {
335 info.value = value;
336 emitChangedForProperty(interface, property);
337 }
340void AccountsService::updateProperty(const QString &interface, const QString &property)
342 QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
343 interface,
344 property);
345 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
347 connect(watcher, &QDBusPendingCallWatcher::finished,
348 this, [this, interface, property](QDBusPendingCallWatcher* watcher) {
350 QDBusPendingReply<QVariant> reply = *watcher;
351 watcher->deleteLater();
352 if (reply.isError()) {
353 qWarning() << "Failed to get '" << property << "' property:" << reply.error().message();
354 return;
355 }
357 updateCache(interface, property, reply.value());
358 });
361void AccountsService::updateAllProperties(const QString &interface, bool async)
363 QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user,
364 interface);
365 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
367 connect(watcher, &QDBusPendingCallWatcher::finished,
368 this, [this, interface](QDBusPendingCallWatcher* watcher) {
370 QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher;
371 watcher->deleteLater();
372 if (reply.isError()) {
373 qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message();
374 return;
375 }
377 auto valueHash = reply.value();
378 auto i = valueHash.constBegin();
379 while (i != valueHash.constEnd()) {
380 updateCache(interface, i.key(), i.value());
381 ++i;
382 }
383 });
384 if (!async) {
385 watcher->waitForFinished();
386 }
389void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter)
391 registerProperty(interface, property, nullptr);
393 m_properties[interface][property].proxyInterface = iface;
394 m_properties[interface][property].proxyMethod = method;
395 m_properties[interface][property].proxyConverter = converter;
398void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal)
400 m_properties[interface][property] = PropertyInfo();
401 m_properties[interface][property].signal = signal;
404void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
406 if (m_user != user) {
407 return;
408 }
410 auto propHash = m_properties.value(interface);
411 auto i = propHash.constBegin();
412 while (i != propHash.constEnd()) {
413 if (changed.contains(i.key())) {
414 updateProperty(interface, i.key());
415 }
416 ++i;
417 }
420void AccountsService::onMaybeChanged(const QString &user)
422 if (m_user != user) {
423 return;
424 }
426 // Any of the standard properties might have changed!
427 auto propHash = m_properties.value(IFACE_ACCOUNTS_USER);
428 auto i = propHash.constBegin();
429 while (i != propHash.constEnd()) {
430 updateProperty(IFACE_ACCOUNTS_USER, i.key());
431 ++i;
432 }
435void AccountsService::refresh(bool async)
437 auto i = m_properties.constBegin();
438 while (i != m_properties.constEnd()) {
439 updateAllProperties(i.key(), async);
440 ++i;
441 }