on 59bb048 help sign in
unity8/plugins/AccountsService/AccountsService.cpp
366 lines 15 kB history raw
1/*
2 * Copyright (C) 2013 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 *
16 * Author: Michael Terry <michael.terry@canonical.com>
17 */
19#include "AccountsService.h"
20#include "AccountsServiceDBusAdaptor.h"
22#include <QDBusInterface>
23#include <QFile>
24#include <QStringList>
25#include <QDebug>
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_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_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
48#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
49#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
50#define PROP_TOUCHPAD_DISABLE_WITH_MOUSE QStringLiteral("TouchpadDisableWithMouse")
51#define PROP_TOUCHPAD_DOUBLE_CLICK_SPEED QStringLiteral("TouchpadDoubleClickSpeed")
52#define PROP_TOUCHPAD_PRIMARY_BUTTON QStringLiteral("TouchpadPrimaryButton")
53#define PROP_TOUCHPAD_SCROLL_SPEED QStringLiteral("TouchpadScrollSpeed")
54#define PROP_TOUCHPAD_TAP_TO_CLICK QStringLiteral("TouchpadTapToClick")
55#define PROP_TOUCHPAD_TWO_FINGER_SCROLL QStringLiteral("TouchpadTwoFingerScroll")
58QVariant primaryButtonConverter(const QVariant &value)
60 QString stringValue = value.toString();
61 if (stringValue == "left") {
62 return QVariant::fromValue(0);
63 } else if (stringValue == "right") {
64 return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same
65 } else {
66 return QVariant::fromValue(0); // default to left
67 }
70AccountsService::AccountsService(QObject* parent, const QString &user)
71 : QObject(parent)
72 , m_service(new AccountsServiceDBusAdaptor(this))
74 m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"),
75 QStringLiteral("/com/canonical/Unity/Input"),
76 QStringLiteral("com.canonical.Unity.Input"),
77 QDBusConnection::SM_BUSNAME(), this);
79 connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
80 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
82 registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
83 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
84 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
85 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
86 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
87 registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged"));
88 registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged"));
89 registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged"));
90 registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged"));
92 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED,
93 m_unityInput, QStringLiteral("setMouseCursorSpeed"));
94 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_DOUBLE_CLICK_SPEED,
95 m_unityInput, QStringLiteral("setMouseDoubleClickSpeed"));
96 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_PRIMARY_BUTTON,
97 m_unityInput, QStringLiteral("setMousePrimaryButton"),
98 primaryButtonConverter);
99 registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_SCROLL_SPEED,
100 m_unityInput, QStringLiteral("setMouseScrollSpeed"));
101 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED,
102 m_unityInput, QStringLiteral("setTouchpadCursorSpeed"));
103 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_SCROLL_SPEED,
104 m_unityInput, QStringLiteral("setTouchpadScrollSpeed"));
105 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WHILE_TYPING,
106 m_unityInput, QStringLiteral("setTouchpadDisableWhileTyping"));
107 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WITH_MOUSE,
108 m_unityInput, QStringLiteral("setTouchpadDisableWithMouse"));
109 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DOUBLE_CLICK_SPEED,
110 m_unityInput, QStringLiteral("setTouchpadDoubleClickSpeed"));
111 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_PRIMARY_BUTTON,
112 m_unityInput, QStringLiteral("setTouchpadPrimaryButton"),
113 primaryButtonConverter);
114 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TAP_TO_CLICK,
115 m_unityInput, QStringLiteral("setTouchpadTapToClick"));
116 registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TWO_FINGER_SCROLL,
117 m_unityInput, QStringLiteral("setTouchpadTwoFingerScroll"));
119 setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER")));
122QString AccountsService::user() const
124 return m_user;
127void AccountsService::setUser(const QString &user)
129 if (user.isEmpty() || m_user == user)
130 return;
132 bool wasEmpty = m_user.isEmpty();
134 m_user = user;
135 Q_EMIT userChanged();
137 // Do the first update synchronously, as a cheap way to block rendering
138 // until we have the right values on bootup.
139 refresh(!wasEmpty);
142bool AccountsService::demoEdges() const
144 auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES);
145 return value.toBool();
148void AccountsService::setDemoEdges(bool demoEdges)
150 setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges);
153bool AccountsService::enableLauncherWhileLocked() const
155 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED);
156 return value.toBool();
159bool AccountsService::enableIndicatorsWhileLocked() const
161 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED);
162 return value.toBool();
165QString AccountsService::backgroundFile() const
167 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE);
168 return value.toString();
171bool AccountsService::statsWelcomeScreen() const
173 auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN);
174 return value.toBool();
177AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
179 auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT);
180 return (PasswordDisplayHint)value.toInt();
183bool AccountsService::hereEnabled() const
185 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
186 return value.toBool();
189void AccountsService::setHereEnabled(bool enabled)
191 setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
194QString AccountsService::hereLicensePath() const
196 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
197 QString hereLicensePath = value.toString();
198 if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
199 hereLicensePath = QStringLiteral("");
200 return hereLicensePath;
203bool AccountsService::hereLicensePathValid() const
205 auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
206 return !value.toString().isNull();
209uint AccountsService::failedLogins() const
211 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
214void AccountsService::setFailedLogins(uint failedLogins)
216 setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins);
219// ====================================================
220// Everything below this line is generic helper methods
221// ====================================================
223void AccountsService::emitChangedForProperty(const QString &interface, const QString &property)
225 QString signalName = m_properties[interface][property].signal;
226 QMetaObject::invokeMethod(this, signalName.toUtf8().data());
229QVariant AccountsService::getProperty(const QString &interface, const QString &property) const
231 return m_properties[interface][property].value;
234void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value)
236 if (m_properties[interface][property].value != value) {
237 m_properties[interface][property].value = value;
238 m_service->setUserPropertyAsync(m_user, interface, property, value);
239 emitChangedForProperty(interface, property);
240 }
243void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value)
245 PropertyInfo &info = m_properties[interface][property];
247 if (info.proxyInterface) {
248 QVariant finalValue;
249 if (info.proxyConverter) {
250 finalValue = info.proxyConverter(value);
251 } else {
252 finalValue = value;
253 }
254 info.proxyInterface->asyncCall(info.proxyMethod, finalValue);
255 return; // don't bother saving a copy
256 }
258 if (info.value != value) {
259 info.value = value;
260 emitChangedForProperty(interface, property);
261 }
264void AccountsService::updateProperty(const QString &interface, const QString &property)
266 QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
267 interface,
268 property);
269 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
271 connect(watcher, &QDBusPendingCallWatcher::finished,
272 this, [this, interface, property](QDBusPendingCallWatcher* watcher) {
274 QDBusPendingReply<QVariant> reply = *watcher;
275 watcher->deleteLater();
276 if (reply.isError()) {
277 qWarning() << "Failed to get '" << property << "' property:" << reply.error().message();
278 return;
279 }
281 updateCache(interface, property, reply.value());
282 });
285void AccountsService::updateAllProperties(const QString &interface, bool async)
287 QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user,
288 interface);
289 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
291 connect(watcher, &QDBusPendingCallWatcher::finished,
292 this, [this, interface](QDBusPendingCallWatcher* watcher) {
294 QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher;
295 watcher->deleteLater();
296 if (reply.isError()) {
297 qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message();
298 return;
299 }
301 auto valueHash = reply.value();
302 auto i = valueHash.constBegin();
303 while (i != valueHash.constEnd()) {
304 updateCache(interface, i.key(), i.value());
305 ++i;
306 }
307 });
308 if (!async) {
309 watcher->waitForFinished();
310 }
313void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter)
315 registerProperty(interface, property, nullptr);
317 m_properties[interface][property].proxyInterface = iface;
318 m_properties[interface][property].proxyMethod = method;
319 m_properties[interface][property].proxyConverter = converter;
322void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal)
324 m_properties[interface][property] = PropertyInfo();
325 m_properties[interface][property].signal = signal;
328void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
330 if (m_user != user) {
331 return;
332 }
334 auto propHash = m_properties.value(interface);
335 auto i = propHash.constBegin();
336 while (i != propHash.constEnd()) {
337 if (changed.contains(i.key())) {
338 updateProperty(interface, i.key());
339 }
340 ++i;
341 }
344void AccountsService::onMaybeChanged(const QString &user)
346 if (m_user != user) {
347 return;
348 }
350 // Any of the standard properties might have changed!
351 auto propHash = m_properties.value(IFACE_ACCOUNTS_USER);
352 auto i = propHash.constBegin();
353 while (i != propHash.constEnd()) {
354 updateProperty(IFACE_ACCOUNTS_USER, i.key());
355 ++i;
356 }
359void AccountsService::refresh(bool async)
361 auto i = m_properties.constBegin();
362 while (i != m_properties.constEnd()) {
363 updateAllProperties(i.key(), async);
364 ++i;
365 }