1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtSensors module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsensormanager.h"
41#include <QDebug>
42#include <private/qfactoryloader_p.h>
43#include <QPluginLoader>
44#include "qsensorplugin.h"
45#include <QStandardPaths>
46#include "sensorlog_p.h"
47#include <QTimer>
48#include <QFile>
49#include <QLoggingCategory>
50
51QT_BEGIN_NAMESPACE
52
53typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap;
54typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap;
55
56static QLoggingCategory sensorsCategory("qt.sensors");
57
58class QSensorManagerPrivate : public QObject
59{
60 friend class QSensorManager;
61
62 Q_OBJECT
63public:
64 enum PluginLoadingState {
65 NotLoaded,
66 Loading,
67 Loaded
68 };
69 QSensorManagerPrivate()
70 : loadExternalPlugins(true)
71 , pluginLoadingState(NotLoaded)
72 , loader(new QFactoryLoader("com.qt-project.Qt.QSensorPluginInterface/1.0", QLatin1String("/sensors")))
73 , defaultIdentifierForTypeLoaded(false)
74 , sensorsChanged(false)
75 {
76 QByteArray env = qgetenv(varName: "QT_SENSORS_LOAD_PLUGINS");
77 if (env == "0") {
78 loadExternalPlugins = false;
79 }
80 }
81 bool loadExternalPlugins;
82 PluginLoadingState pluginLoadingState;
83 QFactoryLoader *loader;
84 void loadPlugins();
85
86 // Holds a mapping from type to available identifiers (and from there to the factory)
87 BackendIdentifiersForTypeMap backendsByType;
88
89 // Holds the default identifier
90 QHash<QByteArray, QByteArray> defaultIdentifierForType;
91 bool defaultIdentifierForTypeLoaded;
92 void readConfigFile()
93 {
94 defaultIdentifierForTypeLoaded = true;
95#ifdef QTSENSORS_CONFIG_PATH
96 QString config = QString::fromLocal8Bit(QTSENSORS_CONFIG_PATH);
97#else
98 QStringList configs = QStandardPaths::standardLocations(type: QStandardPaths::ConfigLocation);
99 if (configs.count() == 0) return; // QStandardPaths is broken?
100 QString config = configs.at(i: configs.count()-1);
101 if (config.isEmpty()) return; // QStandardPaths is broken?
102 config += QLatin1String("/QtProject/Sensors.conf");
103#endif
104 qCDebug(sensorsCategory) << "Loading config from" << config;
105 if (!QFile::exists(fileName: config)) {
106 qCDebug(sensorsCategory) << "There is no config file" << config;
107 return;
108 }
109 QFile cfgfile(config);
110 if (!cfgfile.open(flags: QFile::ReadOnly)) {
111 qCWarning(sensorsCategory) << "Can't open config file" << config;
112 return;
113 }
114
115 QTextStream stream(&cfgfile);
116 QString line;
117 bool isconfig = false;
118 while (!stream.atEnd()) {
119 line = stream.readLine();
120 if (!isconfig && line == QLatin1String("[Default]"))
121 isconfig = true;
122 else if (isconfig) {
123 //read out setting line
124 line.remove(c: ' ');
125 QStringList pair = line.split(sep: '=');
126 if (pair.count() == 2)
127 defaultIdentifierForType.insert(akey: pair[0].toLatin1(), avalue: pair[1].toLatin1());
128 }
129 }
130 }
131
132 // Holds the first identifier for each type
133 QHash<QByteArray, QByteArray> firstIdentifierForType;
134
135 bool sensorsChanged;
136 QList<QSensorChangesInterface*> changeListeners;
137 QSet <QObject *> seenPlugins;
138
139Q_SIGNALS:
140 void availableSensorsChanged();
141
142public Q_SLOTS:
143 void emitSensorsChanged()
144 {
145 static bool alreadyRunning = false;
146 if (pluginLoadingState != QSensorManagerPrivate::Loaded || alreadyRunning) {
147 // We're busy.
148 // Just note that a registration changed and exit.
149 // Someone up the call stack will deal with this.
150 sensorsChanged = true;
151 return;
152 }
153
154 // Set a flag so any recursive calls doesn't cause a loop.
155 alreadyRunning = true;
156
157 // Since one [un]registration may cause other [un]registrations and since
158 // the order in which we do things matters we just do a cascading update
159 // until things stop changing.
160 do {
161 sensorsChanged = false;
162 Q_FOREACH (QSensorChangesInterface *changes, changeListeners) {
163 changes->sensorsChanged();
164 }
165 } while (sensorsChanged);
166
167 // We're going away now so clear the flag
168 alreadyRunning = false;
169
170 // Notify the client of the changes
171 Q_EMIT availableSensorsChanged();
172 }
173};
174
175Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate)
176
177static void initPlugin(QObject *o, bool warnOnFail = true)
178{
179 qCDebug(sensorsCategory) << "Init plugin" << o;
180 if (!o) {
181 qCWarning(sensorsCategory) << "Null plugin" << o;
182 return;
183 }
184
185 QSensorManagerPrivate *d = sensorManagerPrivate();
186 if (!d) return; // hardly likely but just in case...
187
188 if (d->seenPlugins.contains(value: o)) {
189 qCDebug(sensorsCategory) << "Plugin is seen" << o;
190 return;
191 }
192
193 QSensorChangesInterface *changes = qobject_cast<QSensorChangesInterface*>(object: o);
194 if (changes)
195 d->changeListeners << changes;
196
197 QSensorPluginInterface *plugin = qobject_cast<QSensorPluginInterface*>(object: o);
198
199 if (plugin) {
200 qCDebug(sensorsCategory) << "Register sensors for " << plugin;
201 d->seenPlugins.insert(value: o);
202 plugin->registerSensors();
203 } else if (warnOnFail) {
204 qCWarning(sensorsCategory) << "Can't cast to plugin" << o;
205 }
206}
207
208void QSensorManagerPrivate::loadPlugins()
209{
210 QSensorManagerPrivate *d = this;
211 if (d->pluginLoadingState != QSensorManagerPrivate::NotLoaded) return;
212 d->pluginLoadingState = QSensorManagerPrivate::Loading;
213
214 SENSORLOG() << "initializing static plugins";
215 // Qt-style static plugins
216 Q_FOREACH (QObject *plugin, QPluginLoader::staticInstances()) {
217 initPlugin(o: plugin, warnOnFail: false/*do not warn on fail*/);
218 }
219
220 if (d->loadExternalPlugins) {
221 SENSORLOG() << "initializing plugins";
222 QList<QJsonObject> meta = d->loader->metaData();
223 for (int i = 0; i < meta.count(); i++) {
224 QObject *plugin = d->loader->instance(index: i);
225 initPlugin(o: plugin);
226 }
227 }
228
229 d->pluginLoadingState = QSensorManagerPrivate::Loaded;
230
231 if (d->sensorsChanged) {
232 // Notify the app that the available sensor list has changed.
233 // This may cause recursive calls!
234 d->emitSensorsChanged();
235 }
236}
237
238// =====================================================================
239
240/*!
241 \class QSensorManager
242 \ingroup sensors_backend
243 \inmodule QtSensors
244
245 \brief The QSensorManager class handles registration and creation of sensor backends.
246
247 Sensor plugins register backends using the registerBackend() function.
248
249 When QSensor::connectToBackend() is called, the createBackend() function will be called.
250*/
251
252/*!
253 Register a sensor for \a type. The \a identifier must be unique.
254
255 The \a factory will be asked to create instances of the backend.
256*/
257void QSensorManager::registerBackend(const QByteArray &type, const QByteArray &identifier, QSensorBackendFactory *factory)
258{
259 Q_ASSERT(type.count());
260 Q_ASSERT(identifier.count());
261 Q_ASSERT(factory);
262 QSensorManagerPrivate *d = sensorManagerPrivate();
263 if (!d) return; // hardly likely but just in case...
264 if (!d->backendsByType.contains(akey: type)) {
265 (void)d->backendsByType[type];
266 d->firstIdentifierForType[type] = identifier;
267 } else if (d->firstIdentifierForType[type].startsWith(c: "generic.")) {
268 // Don't let a generic backend be the default when some other backend exists!
269 d->firstIdentifierForType[type] = identifier;
270 }
271 FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
272 if (factoryByIdentifier.contains(akey: identifier)) {
273 qWarning() << "A backend with type" << type << "and identifier" << identifier << "has already been registered!";
274 return;
275 }
276 SENSORLOG() << "registering backend for type" << type << "identifier" << identifier;// << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
277 factoryByIdentifier[identifier] = factory;
278
279 // Notify the app that the available sensor list has changed.
280 // This may cause recursive calls!
281 d->emitSensorsChanged();
282}
283
284/*!
285 Unregister the backend for \a type with \a identifier.
286
287 Note that this only prevents new instance of the backend from being created. It does not
288 invalidate the existing instances of the backend. The backend code should handle the
289 disappearance of the underlying hardware itself.
290*/
291void QSensorManager::unregisterBackend(const QByteArray &type, const QByteArray &identifier)
292{
293 QSensorManagerPrivate *d = sensorManagerPrivate();
294 if (!d) return; // hardly likely but just in case...
295 if (!d->backendsByType.contains(akey: type)) {
296 qWarning() << "No backends of type" << type << "are registered";
297 return;
298 }
299 FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
300 if (!factoryByIdentifier.contains(akey: identifier)) {
301 qWarning() << "Identifier" << identifier << "is not registered";
302 return;
303 }
304
305 (void)factoryByIdentifier.take(akey: identifier); // we don't own this pointer anyway
306 if (d->firstIdentifierForType[type] == identifier) {
307 if (factoryByIdentifier.count()) {
308 d->firstIdentifierForType[type] = factoryByIdentifier.begin().key();
309 if (d->firstIdentifierForType[type].startsWith(c: "generic.")) {
310 // Don't let a generic backend be the default when some other backend exists!
311 for (FactoryForIdentifierMap::const_iterator it = factoryByIdentifier.begin()++; it != factoryByIdentifier.end(); ++it) {
312 const QByteArray &identifier(it.key());
313 if (!identifier.startsWith(c: "generic.")) {
314 d->firstIdentifierForType[type] = identifier;
315 break;
316 }
317 }
318 }
319 } else {
320 (void)d->firstIdentifierForType.take(akey: type);
321 }
322 }
323 if (!factoryByIdentifier.count())
324 (void)d->backendsByType.take(akey: type);
325
326 // Notify the app that the available sensor list has changed.
327 // This may cause recursive calls!
328 d->emitSensorsChanged();
329}
330
331/*!
332 Create a backend for \a sensor. Returns null if no suitable backend exists.
333*/
334QSensorBackend *QSensorManager::createBackend(QSensor *sensor)
335{
336 Q_ASSERT(sensor);
337
338 QSensorManagerPrivate *d = sensorManagerPrivate();
339 if (!d) return 0; // hardly likely but just in case...
340 d->loadPlugins();
341
342 SENSORLOG() << "QSensorManager::createBackend" << "type" << sensor->type() << "identifier" << sensor->identifier();
343
344 if (!d->backendsByType.contains(akey: sensor->type())) {
345 SENSORLOG() << "no backends of type" << sensor->type() << "have been registered.";
346 return 0;
347 }
348
349 const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[sensor->type()];
350 QSensorBackendFactory *factory;
351 QSensorBackend *backend;
352
353 if (sensor->identifier().isEmpty()) {
354 QByteArray defaultIdentifier = QSensor::defaultSensorForType(type: sensor->type());
355 SENSORLOG() << "Trying the default" << defaultIdentifier;
356 // No identifier set, try the default
357 factory = factoryByIdentifier[defaultIdentifier];
358 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
359 sensor->setIdentifier(defaultIdentifier); // the factory requires this
360 backend = factory->createBackend(sensor);
361 if (backend) return backend; // Got it!
362
363 // The default failed to instantiate so try any other registered sensors for this type
364 Q_FOREACH (const QByteArray &identifier, factoryByIdentifier.keys()) {
365 SENSORLOG() << "Trying" << identifier;
366 if (identifier == defaultIdentifier) continue; // Don't do the default one again
367 factory = factoryByIdentifier[identifier];
368 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
369 sensor->setIdentifier(identifier); // the factory requires this
370 backend = factory->createBackend(sensor);
371 if (backend) return backend; // Got it!
372 }
373 SENSORLOG() << "FAILED";
374 sensor->setIdentifier(QByteArray()); // clear the identifier
375 } else {
376 if (!factoryByIdentifier.contains(akey: sensor->identifier())) {
377 SENSORLOG() << "no backend with identifier" << sensor->identifier() << "for type" << sensor->type();
378 return 0;
379 }
380
381 // We were given an explicit identifier so don't substitute other backends if it fails to instantiate
382 factory = factoryByIdentifier[sensor->identifier()];
383 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
384 backend = factory->createBackend(sensor);
385 if (backend) return backend; // Got it!
386 }
387
388 SENSORLOG() << "no suitable backend found for requested identifier" << sensor->identifier() << "and type" << sensor->type();
389 return 0;
390}
391
392/*!
393 Returns true if the backend identified by \a type and \a identifier is registered.
394
395 This is a convenience method that helps out plugins doing dynamic registration.
396*/
397bool QSensorManager::isBackendRegistered(const QByteArray &type, const QByteArray &identifier)
398{
399 QSensorManagerPrivate *d = sensorManagerPrivate();
400 if (!d) return false; // hardly likely but just in case...
401 d->loadPlugins();
402
403 if (!d->backendsByType.contains(akey: type))
404 return false;
405
406 const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
407 if (!factoryByIdentifier.contains(akey: identifier))
408 return false;
409
410 return true;
411}
412
413/*!
414 Sets or overwrite the sensor \a type with the backend \a identifier.
415*/
416void QSensorManager::setDefaultBackend(const QByteArray &type, const QByteArray &identifier)
417{
418 QSensorManagerPrivate *d = sensorManagerPrivate();
419 if (!d) return; // hardly likely but just in case...
420 d->defaultIdentifierForType.insert(akey: type, avalue: identifier);
421}
422
423
424// =====================================================================
425
426/*!
427 Returns a list of all sensor types.
428*/
429QList<QByteArray> QSensor::sensorTypes()
430{
431 QSensorManagerPrivate *d = sensorManagerPrivate();
432 if (!d) return QList<QByteArray>(); // hardly likely but just in case...
433 d->loadPlugins();
434
435 return d->backendsByType.keys();
436}
437
438/*!
439 Returns a list of ids for each of the sensors for \a type.
440 If there are no sensors of that type available the list will be empty.
441*/
442QList<QByteArray> QSensor::sensorsForType(const QByteArray &type)
443{
444 QSensorManagerPrivate *d = sensorManagerPrivate();
445 if (!d) return QList<QByteArray>(); // hardly likely but just in case...
446 d->loadPlugins();
447
448 // no sensors of that type exist
449 if (!d->backendsByType.contains(akey: type))
450 return QList<QByteArray>();
451
452 return d->backendsByType[type].keys();
453}
454
455/*!
456 Returns the default sensor identifier for \a type.
457 This is set in a config file and can be overridden if required.
458 If no default is available the system will return the first registered
459 sensor for \a type.
460
461 Note that there is special case logic to prevent the generic plugin's backends from becoming the
462 default when another backend is registered for the same type. This logic means that a backend
463 identifier starting with \c{generic.} will only be the default if no other backends have been
464 registered for that type or if it is specified in \c{Sensors.conf}.
465
466 \sa {Determining the default sensor for a type}
467*/
468QByteArray QSensor::defaultSensorForType(const QByteArray &type)
469{
470 QSensorManagerPrivate *d = sensorManagerPrivate();
471 if (!d) return QByteArray(); // hardly likely but just in case...
472 d->loadPlugins();
473
474 // no sensors of that type exist
475 if (!d->backendsByType.contains(akey: type))
476 return QByteArray();
477
478 //check if we need to read the config setting file
479 if (!d->defaultIdentifierForTypeLoaded)
480 d->readConfigFile();
481
482 QHash<QByteArray, QByteArray>::const_iterator i = d->defaultIdentifierForType.find(akey: type);
483 if (i != d->defaultIdentifierForType.end() && i.key() == type) {
484 if (d->backendsByType[type].contains(akey: i.value())) // Don't return a value that we can't use!
485 return i.value();
486 }
487
488 // This is our fallback
489 return d->firstIdentifierForType[type];
490}
491
492void QSensor::registerInstance()
493{
494 QSensorManagerPrivate *d = sensorManagerPrivate();
495 if (!d) return; // hardly likely but just in case...
496 connect(sender: d, SIGNAL(availableSensorsChanged()), receiver: this, SIGNAL(availableSensorsChanged()));
497}
498
499// =====================================================================
500
501/*!
502 \class QSensorBackendFactory
503 \ingroup sensors_backend
504 \inmodule QtSensors
505
506 \brief The QSensorBackendFactory class instantiates instances of
507 QSensorBackend.
508
509 This interface must be implemented in order to register a sensor backend.
510
511 \sa {Creating a sensor plugin}
512*/
513
514/*!
515 \internal
516*/
517QSensorBackendFactory::~QSensorBackendFactory()
518{
519}
520
521/*!
522 \fn QSensorBackendFactory::createBackend(QSensor *sensor)
523
524 Instantiate a backend. If the factory handles multiple identifiers
525 it should check with the \a sensor to see which one is requested.
526
527 If the factory cannot create a backend it should return 0.
528*/
529
530QT_END_NAMESPACE
531
532#include "qsensormanager.moc"
533

source code of qtsensors/src/sensors/qsensormanager.cpp