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 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap; |
54 | typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap; |
55 | |
56 | static QLoggingCategory sensorsCategory("qt.sensors" ); |
57 | |
58 | class QSensorManagerPrivate : public QObject |
59 | { |
60 | friend class QSensorManager; |
61 | |
62 | Q_OBJECT |
63 | public: |
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 | |
139 | Q_SIGNALS: |
140 | void availableSensorsChanged(); |
141 | |
142 | public 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 | |
175 | Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate) |
176 | |
177 | static 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 | |
208 | void 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 | */ |
257 | void 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 | */ |
291 | void 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 | */ |
334 | QSensorBackend *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 | */ |
397 | bool 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 | */ |
416 | void 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 | */ |
429 | QList<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 | */ |
442 | QList<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 | */ |
468 | QByteArray 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 | |
492 | void 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 | */ |
517 | QSensorBackendFactory::~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 | |
530 | QT_END_NAMESPACE |
531 | |
532 | #include "qsensormanager.moc" |
533 | |