summaryrefslogtreecommitdiffstats
path: root/src/sensors/qsensormanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sensors/qsensormanager.cpp')
-rw-r--r--src/sensors/qsensormanager.cpp498
1 files changed, 498 insertions, 0 deletions
diff --git a/src/sensors/qsensormanager.cpp b/src/sensors/qsensormanager.cpp
new file mode 100644
index 00000000..c8cc1ce6
--- /dev/null
+++ b/src/sensors/qsensormanager.cpp
@@ -0,0 +1,498 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsensormanager.h"
+#include <QDebug>
+#include "qsensorpluginloader_p.h"
+#include "qsensorplugin.h"
+#include <QSettings>
+#include "sensorlog_p.h"
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QSensorPluginLoader, pluginLoader)
+
+typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap;
+typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap;
+
+class QSensorManagerPrivate : public QObject
+{
+ friend class QSensorManager;
+
+ Q_OBJECT
+public:
+ enum PluginLoadingState {
+ NotLoaded,
+ Loading,
+ Loaded
+ };
+ QSensorManagerPrivate()
+ : pluginLoadingState(NotLoaded)
+ , sensorsChanged(false)
+ {
+ }
+
+ PluginLoadingState pluginLoadingState;
+ void loadPlugins();
+
+ QList<CreatePluginFunc> staticRegistrations;
+
+ // Holds a mapping from type to available identifiers (and from there to the factory)
+ BackendIdentifiersForTypeMap backendsByType;
+
+ // Holds the first identifier for each type
+ QHash<QByteArray, QByteArray> firstIdentifierForType;
+
+ bool sensorsChanged;
+ QList<QSensorChangesInterface*> changeListeners;
+
+Q_SIGNALS:
+ void availableSensorsChanged();
+
+public Q_SLOTS:
+ void emitSensorsChanged()
+ {
+ static bool alreadyRunning = false;
+ if (pluginLoadingState != QSensorManagerPrivate::Loaded || alreadyRunning) {
+ // We're busy.
+ // Just note that a registration changed and exit.
+ // Someone up the call stack will deal with this.
+ sensorsChanged = true;
+ return;
+ }
+
+ // Set a flag so any recursive calls doesn't cause a loop.
+ alreadyRunning = true;
+
+ // Since one [un]registration may cause other [un]registrations and since
+ // the order in which we do things matters we just do a cascading update
+ // until things stop changing.
+ do {
+ sensorsChanged = false;
+ Q_FOREACH (QSensorChangesInterface *changes, changeListeners) {
+ changes->sensorsChanged();
+ }
+ } while (sensorsChanged);
+
+ // We're going away now so clear the flag
+ alreadyRunning = false;
+
+ // Notify the client of the changes
+ Q_EMIT availableSensorsChanged();
+ }
+};
+
+Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate)
+
+// The unit test needs to change the behaviour of the library. It does this
+// through an exported but undocumented function.
+static void initPlugin(QObject *plugin);
+static QSettings::Scope settings_scope = QSettings::SystemScope;
+static bool load_external_plugins = true;
+Q_SENSORS_EXPORT void sensors_unit_test_hook(int index)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+
+ switch (index) {
+ case 0:
+ Q_ASSERT(d->pluginLoadingState == QSensorManagerPrivate::NotLoaded);
+ settings_scope = QSettings::UserScope;
+ load_external_plugins = false;
+ break;
+ case 1:
+ Q_ASSERT(load_external_plugins == false);
+ Q_ASSERT(d->pluginLoadingState == QSensorManagerPrivate::Loaded);
+ SENSORLOG() << "initializing plugins";
+ Q_FOREACH (QObject *plugin, pluginLoader()->plugins()) {
+ initPlugin(plugin);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void initPlugin(QObject *o)
+{
+ if (!o) return;
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+
+ QSensorChangesInterface *changes = qobject_cast<QSensorChangesInterface*>(o);
+ if (changes)
+ d->changeListeners << changes;
+
+ QSensorPluginInterface *plugin = qobject_cast<QSensorPluginInterface*>(o);
+ if (plugin)
+ plugin->registerSensors();
+}
+
+void QSensorManagerPrivate::loadPlugins()
+{
+ QSensorManagerPrivate *d = this;
+ if (d->pluginLoadingState != QSensorManagerPrivate::NotLoaded) return;
+ d->pluginLoadingState = QSensorManagerPrivate::Loading;
+
+ SENSORLOG() << "initializing legacy static plugins";
+ // Legacy static plugins
+ Q_FOREACH (CreatePluginFunc func, d->staticRegistrations) {
+ QSensorPluginInterface *plugin = func();
+ plugin->registerSensors();
+ }
+
+ SENSORLOG() << "initializing static plugins";
+ // Qt-style static plugins
+ Q_FOREACH (QObject *plugin, QPluginLoader::staticInstances()) {
+ initPlugin(plugin);
+ }
+
+ if (load_external_plugins) {
+ SENSORLOG() << "initializing plugins";
+ Q_FOREACH (QObject *plugin, pluginLoader()->plugins()) {
+ initPlugin(plugin);
+ }
+ }
+
+ d->pluginLoadingState = QSensorManagerPrivate::Loaded;
+
+ if (d->sensorsChanged) {
+ // Notify the app that the available sensor list has changed.
+ // This may cause recursive calls!
+ d->emitSensorsChanged();
+ }
+}
+
+// =====================================================================
+
+/*!
+ \class QSensorManager
+ \ingroup sensors_backend
+ \inmodule QtSensors
+ \since 1.0
+
+ \brief The QSensorManager class handles registration and creation of sensor backends.
+
+ Sensor plugins register backends using the registerBackend() function.
+
+ When QSensor::connectToBackend() is called, the createBackend() function will be called.
+*/
+
+/*!
+ Register a sensor for \a type. The \a identifier must be unique.
+
+ The \a factory will be asked to create instances of the backend.
+*/
+void QSensorManager::registerBackend(const QByteArray &type, const QByteArray &identifier, QSensorBackendFactory *factory)
+{
+ Q_ASSERT(type.count());
+ Q_ASSERT(identifier.count());
+ Q_ASSERT(factory);
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ if (!d->backendsByType.contains(type)) {
+ (void)d->backendsByType[type];
+ d->firstIdentifierForType[type] = identifier;
+ } else if (d->firstIdentifierForType[type].startsWith("generic.")) {
+ // Don't let a generic backend be the default when some other backend exists!
+ d->firstIdentifierForType[type] = identifier;
+ }
+ FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
+ if (factoryByIdentifier.contains(identifier)) {
+ qWarning() << "A backend with type" << type << "and identifier" << identifier << "has already been registered!";
+ return;
+ }
+ SENSORLOG() << "registering backend for type" << type << "identifier" << identifier;// << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
+ factoryByIdentifier[identifier] = factory;
+
+ // Notify the app that the available sensor list has changed.
+ // This may cause recursive calls!
+ d->emitSensorsChanged();
+}
+
+/*!
+ Unregister the backend for \a type with \a identifier.
+
+ Note that this only prevents new instance of the backend from being created. It does not
+ invalidate the existing instances of the backend. The backend code should handle the
+ disappearance of the underlying hardware itself.
+*/
+void QSensorManager::unregisterBackend(const QByteArray &type, const QByteArray &identifier)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ if (!d->backendsByType.contains(type)) {
+ qWarning() << "No backends of type" << type << "are registered";
+ return;
+ }
+ FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
+ if (!factoryByIdentifier.contains(identifier)) {
+ qWarning() << "Identifier" << identifier << "is not registered";
+ return;
+ }
+
+ (void)factoryByIdentifier.take(identifier); // we don't own this pointer anyway
+ if (d->firstIdentifierForType[type] == identifier) {
+ if (factoryByIdentifier.count()) {
+ d->firstIdentifierForType[type] = factoryByIdentifier.begin().key();
+ if (d->firstIdentifierForType[type].startsWith("generic.")) {
+ // Don't let a generic backend be the default when some other backend exists!
+ for (FactoryForIdentifierMap::const_iterator it = factoryByIdentifier.begin()++; it != factoryByIdentifier.end(); it++) {
+ const QByteArray &identifier(it.key());
+ if (!identifier.startsWith("generic.")) {
+ d->firstIdentifierForType[type] = identifier;
+ break;
+ }
+ }
+ }
+ } else {
+ (void)d->firstIdentifierForType.take(type);
+ }
+ }
+ if (!factoryByIdentifier.count())
+ (void)d->backendsByType.take(type);
+
+ // Notify the app that the available sensor list has changed.
+ // This may cause recursive calls!
+ d->emitSensorsChanged();
+}
+
+/*!
+ \internal
+*/
+void QSensorManager::registerStaticPlugin(CreatePluginFunc func)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->staticRegistrations.append(func);
+}
+
+/*!
+ Create a backend for \a sensor. Returns null if no suitable backend exists.
+*/
+QSensorBackend *QSensorManager::createBackend(QSensor *sensor)
+{
+ Q_ASSERT(sensor);
+
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->loadPlugins();
+
+ SENSORLOG() << "QSensorManager::createBackend" << "type" << sensor->type() << "identifier" << sensor->identifier();
+
+ if (!d->backendsByType.contains(sensor->type())) {
+ SENSORLOG() << "no backends of type" << sensor->type() << "have been registered.";
+ return 0;
+ }
+
+ const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[sensor->type()];
+ QSensorBackendFactory *factory;
+ QSensorBackend *backend;
+
+ if (sensor->identifier().isEmpty()) {
+ QByteArray defaultIdentifier = QSensor::defaultSensorForType(sensor->type());
+ SENSORLOG() << "Trying the default" << defaultIdentifier;
+ // No identifier set, try the default
+ factory = factoryByIdentifier[defaultIdentifier];
+ //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
+ sensor->setIdentifier(defaultIdentifier); // the factory requires this
+ backend = factory->createBackend(sensor);
+ if (backend) return backend; // Got it!
+
+ // The default failed to instantiate so try any other registered sensors for this type
+ Q_FOREACH (const QByteArray &identifier, factoryByIdentifier.keys()) {
+ SENSORLOG() << "Trying" << identifier;
+ if (identifier == defaultIdentifier) continue; // Don't do the default one again
+ factory = factoryByIdentifier[identifier];
+ //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
+ sensor->setIdentifier(identifier); // the factory requires this
+ backend = factory->createBackend(sensor);
+ if (backend) return backend; // Got it!
+ }
+ SENSORLOG() << "FAILED";
+ sensor->setIdentifier(QByteArray()); // clear the identifier
+ } else {
+ if (!factoryByIdentifier.contains(sensor->identifier())) {
+ SENSORLOG() << "no backend with identifier" << sensor->identifier() << "for type" << sensor->type();
+ return 0;
+ }
+
+ // We were given an explicit identifier so don't substitute other backends if it fails to instantiate
+ factory = factoryByIdentifier[sensor->identifier()];
+ //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
+ backend = factory->createBackend(sensor);
+ if (backend) return backend; // Got it!
+ }
+
+ SENSORLOG() << "no suitable backend found for requested identifier" << sensor->identifier() << "and type" << sensor->type();
+ return 0;
+}
+
+/*!
+ Returns true if the backend identified by \a type and \a identifier is registered.
+
+ This is a convenience method that helps out plugins doing dynamic registration.
+*/
+bool QSensorManager::isBackendRegistered(const QByteArray &type, const QByteArray &identifier)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->loadPlugins();
+
+ if (!d->backendsByType.contains(type))
+ return false;
+
+ const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
+ if (!factoryByIdentifier.contains(identifier))
+ return false;
+
+ return true;
+}
+
+// =====================================================================
+
+/*!
+ Returns a list of all sensor types.
+*/
+QList<QByteArray> QSensor::sensorTypes()
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->loadPlugins();
+
+ return d->backendsByType.keys();
+}
+
+/*!
+ Returns a list of ids for each of the sensors for \a type.
+ If there are no sensors of that type available the list will be empty.
+*/
+QList<QByteArray> QSensor::sensorsForType(const QByteArray &type)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->loadPlugins();
+
+ // no sensors of that type exist
+ if (!d->backendsByType.contains(type))
+ return QList<QByteArray>();
+
+ return d->backendsByType[type].keys();
+}
+
+/*!
+ Returns the default sensor identifier for \a type.
+ This is set in a config file and can be overridden if required.
+ If no default is available the system will return the first registered
+ sensor for \a type.
+
+ Note that there is special case logic to prevent the generic plugin's backends from becoming the
+ default when another backend is registered for the same type. This logic means that a backend
+ identifier starting with \c{generic.} will only be the default if no other backends have been
+ registered for that type or if it is specified in \c{Sensors.conf}.
+
+ \sa {Determining the default sensor for a type}
+*/
+QByteArray QSensor::defaultSensorForType(const QByteArray &type)
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ d->loadPlugins();
+
+ // no sensors of that type exist
+ if (!d->backendsByType.contains(type))
+ return QByteArray();
+
+ // The unit test needs to modify Sensors.conf but it can't access the system directory
+ QSettings settings(settings_scope, QLatin1String("Nokia"), QLatin1String("Sensors"));
+ QVariant value = settings.value(QString(QLatin1String("Default/%1")).arg(QString::fromLatin1(type)));
+ if (!value.isNull()) {
+ QByteArray defaultIdentifier = value.toByteArray();
+ if (d->backendsByType[type].contains(defaultIdentifier)) // Don't return a value that we can't use!
+ return defaultIdentifier;
+ }
+
+ // This is our fallback
+ return d->firstIdentifierForType[type];
+}
+
+void QSensor::registerInstance()
+{
+ QSensorManagerPrivate *d = sensorManagerPrivate();
+ connect(d, SIGNAL(availableSensorsChanged()), this, SIGNAL(availableSensorsChanged()));
+}
+
+// =====================================================================
+
+/*!
+ \class QSensorBackendFactory
+ \ingroup sensors_backend
+ \inmodule QtSensors
+
+ \brief The QSensorBackendFactory class instantiates instances of
+ QSensorBackend.
+
+ This interface must be implemented in order to register a sensor backend.
+
+ \sa {Creating a sensor plugin}
+*/
+
+/*!
+ \fn QSensorBackendFactory::~QSensorBackendFactory()
+ \internal
+*/
+
+/*!
+ \fn QSensorBackendFactory::createBackend(QSensor *sensor)
+
+ Instantiate a backend. If the factory handles multiple identifiers
+ it should check with the \a sensor to see which one is requested.
+
+ If the factory cannot create a backend it should return 0.
+*/
+
+/*!
+ \macro REGISTER_STATIC_PLUGIN(pluginname)
+ \relates QSensorManager
+
+ Registers a static plugin, \a pluginname.
+
+ Note that this macro relies on static initialization so it may not be appropriate
+ for use in a library and may not work on all platforms.
+
+ \sa {Creating a sensor plugin}
+*/
+
+#include "qsensormanager.moc"
+
+QT_END_NAMESPACE
+