| 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 | |