From 0ed9f7496656fa0ea52d703c7fddff26c2192857 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Mon, 26 Aug 2013 09:35:01 +0200 Subject: Improve area monitoring API. 1.) QGeoAreaMonitor renamed to QGeoAreaMonitorSource 2.) Add new QGeoAreaMonitorInfo data type encpsulating individual areas to be monitored 3.) Port positionpoll plug-in to new features 4.) Make positionpoll monitor thread safe 4.) Extend and fix the QGeoAreaMonitor unit test 5.) Fix documentation. Task-number: QTBUG-31711 Change-Id: Icfc982de4753d2f43cb4d15c234eb7b7c039a0c4 Reviewed-by: Alex Blasche --- .../qgeopositioninfosourcefactory_geoclue.cpp | 2 +- .../qgeopositioninfosourcefactory_geoclue.h | 2 +- .../gypsy/qgeopositioninfosourcefactory_gypsy.cpp | 2 +- .../gypsy/qgeopositioninfosourcefactory_gypsy.h | 2 +- .../position/positionpoll/positionpollfactory.cpp | 5 +- .../position/positionpoll/positionpollfactory.h | 2 +- .../positionpoll/qgeoareamonitor_polling.cpp | 480 ++++++++++++-- .../positionpoll/qgeoareamonitor_polling.h | 42 +- .../qgeopositioninfosourcefactory_simulator.cpp | 2 +- .../qgeopositioninfosourcefactory_simulator.h | 2 +- src/positioning/doc/snippets/cpp/cppqml.cpp | 40 ++ src/positioning/doc/src/cpp-position.qdoc | 4 +- src/positioning/doc/src/qtpositioning-plugins.qdoc | 2 +- src/positioning/positioning.pro | 6 +- src/positioning/qgeoareamonitor.cpp | 256 ------- src/positioning/qgeoareamonitor.h | 85 --- src/positioning/qgeoareamonitorinfo.cpp | 379 +++++++++++ src/positioning/qgeoareamonitorinfo.h | 105 +++ src/positioning/qgeoareamonitorsource.cpp | 390 +++++++++++ src/positioning/qgeoareamonitorsource.h | 109 +++ src/positioning/qgeopositioninfosourcefactory.cpp | 4 +- src/positioning/qgeopositioninfosourcefactory.h | 4 +- src/positioning/qgeosatelliteinfosource.cpp | 17 + src/positioning/qgeosatelliteinfosource.h | 4 +- tests/auto/positionplugin/plugin.cpp | 4 +- .../auto/positionplugintest/tst_positionplugin.cpp | 4 +- .../auto/qgeoareamonitor/logfilepositionsource.cpp | 125 ++++ tests/auto/qgeoareamonitor/logfilepositionsource.h | 79 +++ tests/auto/qgeoareamonitor/qgeoareamonitor.pro | 7 +- tests/auto/qgeoareamonitor/simplelog.txt | 87 +++ tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp | 734 ++++++++++++++++----- 31 files changed, 2411 insertions(+), 575 deletions(-) delete mode 100644 src/positioning/qgeoareamonitor.cpp delete mode 100644 src/positioning/qgeoareamonitor.h create mode 100644 src/positioning/qgeoareamonitorinfo.cpp create mode 100644 src/positioning/qgeoareamonitorinfo.h create mode 100644 src/positioning/qgeoareamonitorsource.cpp create mode 100644 src/positioning/qgeoareamonitorsource.h create mode 100644 tests/auto/qgeoareamonitor/logfilepositionsource.cpp create mode 100644 tests/auto/qgeoareamonitor/logfilepositionsource.h create mode 100644 tests/auto/qgeoareamonitor/simplelog.txt diff --git a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp index 5f243d89..9be36053 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp +++ b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp @@ -73,7 +73,7 @@ QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryGeoclue::satelliteInfoSour #endif } -QGeoAreaMonitor *QGeoPositionInfoSourceFactoryGeoclue::areaMonitor(QObject *parent) +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryGeoclue::areaMonitor(QObject *parent) { Q_UNUSED(parent); return 0; diff --git a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h index 0fa95d72..3de93bbf 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h +++ b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h @@ -65,7 +65,7 @@ class QGeoPositionInfoSourceFactoryGeoclue : public QObject, public QGeoPosition public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitor *areaMonitor(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); }; #endif diff --git a/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.cpp b/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.cpp index dee265de..3e8b93a3 100644 --- a/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.cpp +++ b/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.cpp @@ -58,7 +58,7 @@ QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryGypsy::satelliteInfoSource return src; } -QGeoAreaMonitor *QGeoPositionInfoSourceFactoryGypsy::areaMonitor(QObject *parent) +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryGypsy::areaMonitor(QObject *parent) { Q_UNUSED(parent); return 0; diff --git a/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.h b/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.h index 6cd145ca..dab3cc71 100644 --- a/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.h +++ b/src/plugins/position/gypsy/qgeopositioninfosourcefactory_gypsy.h @@ -55,7 +55,7 @@ class QGeoPositionInfoSourceFactoryGypsy : public QObject, public QGeoPositionIn public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitor *areaMonitor(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); }; #endif diff --git a/src/plugins/position/positionpoll/positionpollfactory.cpp b/src/plugins/position/positionpoll/positionpollfactory.cpp index a3ec6527..0f02bff1 100644 --- a/src/plugins/position/positionpoll/positionpollfactory.cpp +++ b/src/plugins/position/positionpoll/positionpollfactory.cpp @@ -54,10 +54,9 @@ QGeoSatelliteInfoSource *PositionPollFactory::satelliteInfoSource(QObject *paren return 0; } -QGeoAreaMonitor *PositionPollFactory::areaMonitor(QObject *parent) +QGeoAreaMonitorSource *PositionPollFactory::areaMonitor(QObject *parent) { - QGeoAreaMonitorPolling *ret = 0; - ret = new QGeoAreaMonitorPolling(parent); + QGeoAreaMonitorPolling *ret = new QGeoAreaMonitorPolling(parent); if (ret && ret->isValid()) return ret; delete ret; diff --git a/src/plugins/position/positionpoll/positionpollfactory.h b/src/plugins/position/positionpoll/positionpollfactory.h index 73a4d60a..79ad85eb 100644 --- a/src/plugins/position/positionpoll/positionpollfactory.h +++ b/src/plugins/position/positionpoll/positionpollfactory.h @@ -54,7 +54,7 @@ class PositionPollFactory : public QObject, public QGeoPositionInfoSourceFactory public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitor *areaMonitor(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); }; #endif // POSITIONPOLLFACTORY_H diff --git a/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp b/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp index 784c9fad..55d66993 100644 --- a/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp +++ b/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp @@ -41,94 +41,476 @@ #include "qgeoareamonitor_polling.h" #include +#include +#include #include +#include +#include +#include #define UPDATE_INTERVAL_5S 5000 -QGeoAreaMonitorPolling::QGeoAreaMonitorPolling(QObject *parent) : QGeoAreaMonitor(parent) +typedef QHash MonitorTable; + + +static QMetaMethod areaEnteredSignal() { - insideArea = false; - location = QGeoPositionInfoSource::createDefaultSource(this); - if (location) { - location->setUpdateInterval(UPDATE_INTERVAL_5S); - connect(location, SIGNAL(positionUpdated(QGeoPositionInfo)), - this, SLOT(positionUpdated(QGeoPositionInfo))); - } + static QMetaMethod signal = QMetaMethod::fromSignal(&QGeoAreaMonitorPolling::areaEntered); + return signal; } -QGeoAreaMonitorPolling::~QGeoAreaMonitorPolling() +static QMetaMethod areaExitedSignal() { - if (location) - location->stopUpdates(); + static QMetaMethod signal = QMetaMethod::fromSignal(&QGeoAreaMonitorPolling::areaExited); + return signal; +} + +static QMetaMethod monitorExpiredSignal() +{ + static QMetaMethod signal = QMetaMethod::fromSignal(&QGeoAreaMonitorPolling::monitorExpired); + return signal; } -void QGeoAreaMonitorPolling::setCenter(const QGeoCoordinate &coordinate) +class QGeoAreaMonitorPollingPrivate : public QObject { - if (coordinate.isValid()) { - QGeoAreaMonitor::setCenter(coordinate); + Q_OBJECT +public: + QGeoAreaMonitorPollingPrivate() : source(0), mutex(QMutex::Recursive) + { + nextExpiryTimer = new QTimer(this); + nextExpiryTimer->setSingleShot(true); + connect(nextExpiryTimer, SIGNAL(timeout()), + this, SLOT(timeout())); + } + + void startMonitoring(const QGeoAreaMonitorInfo &monitor) + { + QMutexLocker locker(&mutex); + + activeMonitorAreas.insert(monitor.identifier(), monitor); + singleShotTrigger.remove(monitor.identifier()); + + checkStartStop(); + setupNextExpiryTimeout(); + } + + void requestUpdate(const QGeoAreaMonitorInfo &monitor, int signalId) + { + QMutexLocker locker(&mutex); + + activeMonitorAreas.insert(monitor.identifier(), monitor); + singleShotTrigger.insert(monitor.identifier(), signalId); + + checkStartStop(); + setupNextExpiryTimeout(); + } + + QGeoAreaMonitorInfo stopMonitoring(const QGeoAreaMonitorInfo &monitor) + { + QMutexLocker locker(&mutex); + + QGeoAreaMonitorInfo mon = activeMonitorAreas.take(monitor.identifier()); + checkStartStop(); + setupNextExpiryTimeout(); + + return mon; } + + void registerClient(QGeoAreaMonitorPolling *client) + { + QMutexLocker locker(&mutex); + + connect(this, SIGNAL(timeout(QGeoAreaMonitorInfo)), + client, SLOT(timeout(QGeoAreaMonitorInfo))); + + connect(this, SIGNAL(positionError(QGeoPositionInfoSource::Error)), + client, SLOT(positionError(QGeoPositionInfoSource::Error))); + + connect(this, SIGNAL(areaEventDetected(QGeoAreaMonitorInfo,QGeoPositionInfo,bool)), + client, SLOT(processAreaEvent(QGeoAreaMonitorInfo,QGeoPositionInfo,bool))); + + registeredClients.append(client); + } + + void deregisterClient(QGeoAreaMonitorPolling *client) + { + QMutexLocker locker(&mutex); + + registeredClients.removeAll(client); + if (registeredClients.isEmpty()) + checkStartStop(); + } + + void setPositionSource(QGeoPositionInfoSource *newSource) + { + QMutexLocker locker(&mutex); + + if (newSource == source) + return; + + if (source) + delete source; + + source = newSource; + + if (source) { + source->setParent(this); + source->moveToThread(this->thread()); + if (source->updateInterval() == 0) + source->setUpdateInterval(UPDATE_INTERVAL_5S); + disconnect(source, 0, 0, 0); //disconnect all + connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)), + this, SLOT(positionUpdated(QGeoPositionInfo))); + connect(source, SIGNAL(error(QGeoPositionInfoSource::Error)), + this, SIGNAL(positionError(QGeoPositionInfoSource::Error))); + checkStartStop(); + } + } + + QGeoPositionInfoSource* positionSource() const + { + QMutexLocker locker(&mutex); + return source; + } + + MonitorTable activeMonitors() const + { + QMutexLocker locker(&mutex); + + return activeMonitorAreas; + } + + void checkStartStop() + { + QMutexLocker locker(&mutex); + + bool signalsConnected = false; + foreach (const QGeoAreaMonitorPolling *client, registeredClients) { + if (client->signalsAreConnected) { + signalsConnected = true; + break; + } + } + + if (signalsConnected && !activeMonitorAreas.isEmpty()) { + if (source) + source->startUpdates(); + else + //translated to InsufficientPositionInfo + emit positionError(QGeoPositionInfoSource::ClosedError); + } else { + if (source) + source->stopUpdates(); + } + } + +private: + void setupNextExpiryTimeout() + { + nextExpiryTimer->stop(); + activeExpiry.first = QDateTime(); + activeExpiry.second = QString(); + + foreach (const QGeoAreaMonitorInfo &info, activeMonitors()) { + if (info.expiration().isValid()) { + if (!activeExpiry.first.isValid()) { + activeExpiry.first = info.expiration(); + activeExpiry.second = info.identifier(); + continue; + } + if (info.expiration() < activeExpiry.first) { + activeExpiry.first = info.expiration(); + activeExpiry.second = info.identifier(); + } + } + } + + if (activeExpiry.first.isValid()) + nextExpiryTimer->start(QDateTime::currentDateTime().msecsTo(activeExpiry.first)); + } + + + //returns true if areaEntered should be emitted + bool processInsideArea(const QString &monitorIdent) + { + if (!insideArea.contains(monitorIdent)) { + if (singleShotTrigger.value(monitorIdent, -1) == areaEnteredSignal().methodIndex()) { + //this is the finishing singleshot event + singleShotTrigger.remove(monitorIdent); + activeMonitorAreas.remove(monitorIdent); + setupNextExpiryTimeout(); + } else { + insideArea.insert(monitorIdent); + } + return true; + } + + return false; + } + + //returns true if areaExited should be emitted + bool processOutsideArea(const QString &monitorIdent) + { + if (insideArea.contains(monitorIdent)) { + if (singleShotTrigger.value(monitorIdent, -1) == areaExitedSignal().methodIndex()) { + //this is the finishing singleShot event + singleShotTrigger.remove(monitorIdent); + activeMonitorAreas.remove(monitorIdent); + setupNextExpiryTimeout(); + } else { + insideArea.remove(monitorIdent); + } + return true; + } + return false; + } + + + +Q_SIGNALS: + void timeout(const QGeoAreaMonitorInfo &info); + void positionError(const QGeoPositionInfoSource::Error error); + void areaEventDetected(const QGeoAreaMonitorInfo &minfo, + const QGeoPositionInfo &pinfo, bool isEnteredEvent); +private Q_SLOTS: + void timeout() + { + /* + * Don't block timer firing even if monitorExpiredSignal is not connected. + * This allows us to continue to remove the existing monitors as they expire. + **/ + const QGeoAreaMonitorInfo info = activeMonitorAreas.take(activeExpiry.second); + setupNextExpiryTimeout(); + emit timeout(info); + + } + + void positionUpdated(const QGeoPositionInfo &info) + { + foreach (const QGeoAreaMonitorInfo &monInfo, activeMonitors()) { + const QString identifier = monInfo.identifier(); + if (monInfo.area().contains(info.coordinate())) { + if (processInsideArea(identifier)) + emit areaEventDetected(monInfo, info, true); + } else { + if (processOutsideArea(identifier)) + emit areaEventDetected(monInfo, info, false); + } + } + } + +private: + QPair activeExpiry; + QHash singleShotTrigger; + QTimer* nextExpiryTimer; + QSet insideArea; + + MonitorTable activeMonitorAreas; + + QGeoPositionInfoSource* source; + QList registeredClients; + mutable QMutex mutex; +}; + +Q_GLOBAL_STATIC(QGeoAreaMonitorPollingPrivate, pollingPrivate) + + +QGeoAreaMonitorPolling::QGeoAreaMonitorPolling(QObject *parent) + : QGeoAreaMonitorSource(parent), signalsAreConnected(false) +{ + d = pollingPrivate(); + lastError = QGeoAreaMonitorSource::UnknownSourceError; + d->registerClient(this); + //hookup to default source if existing + if (!positionInfoSource()) + setPositionInfoSource(QGeoPositionInfoSource::createDefaultSource(this)); } -void QGeoAreaMonitorPolling::setRadius(qreal radius) +QGeoAreaMonitorPolling::~QGeoAreaMonitorPolling() { - QGeoAreaMonitor::setRadius(radius); - checkStartStop(); + d->deregisterClient(this); } -static QMetaMethod areaEnteredSignal() +QGeoPositionInfoSource* QGeoAreaMonitorPolling::positionInfoSource() const { - static QMetaMethod signal = QMetaMethod::fromSignal(&QGeoAreaMonitorPolling::areaEntered); - return signal; + return d->positionSource(); } -static QMetaMethod areaExitedSignal() +void QGeoAreaMonitorPolling::setPositionInfoSource(QGeoPositionInfoSource *source) { - static QMetaMethod signal = QMetaMethod::fromSignal(&QGeoAreaMonitorPolling::areaExited); - return signal; + d->setPositionSource(source); } -void QGeoAreaMonitorPolling::connectNotify(const QMetaMethod &signal) +QGeoAreaMonitorSource::Error QGeoAreaMonitorPolling::error() const { - if (signal == areaEnteredSignal() || - signal == areaExitedSignal()) - checkStartStop(); + return lastError; } -void QGeoAreaMonitorPolling::disconnectNotify(const QMetaMethod &signal) +bool QGeoAreaMonitorPolling::startMonitoring(const QGeoAreaMonitorInfo &monitor) { - if (signal == areaEnteredSignal() || - signal == areaExitedSignal()) - checkStartStop(); + if (!monitor.isValid()) + return false; + + //reject an expiry in the past + if (monitor.expiration().isValid() && + (monitor.expiration() < QDateTime::currentDateTime())) + return false; + + //don't accept persistent monitor since we don't support it + if (monitor.isPersistent()) + return false; + + //update or insert + d->startMonitoring(monitor); + + return true; +} + +int QGeoAreaMonitorPolling::idForSignal(const char *signal) +{ + const QByteArray sig = QMetaObject::normalizedSignature(signal + 1); + const QMetaObject * const mo = metaObject(); + + return mo->indexOfSignal(sig.constData()); +} + +bool QGeoAreaMonitorPolling::requestUpdate(const QGeoAreaMonitorInfo &monitor, const char *signal) +{ + if (!monitor.isValid()) + return false; + //reject an expiry in the past + if (monitor.expiration().isValid() && + (monitor.expiration() < QDateTime::currentDateTime())) + return false; + + //don't accept persistent monitor since we don't support it + if (monitor.isPersistent()) + return false; + + if (!signal) + return false; + + const int signalId = idForSignal(signal); + if (signalId < 0) + return false; + + //only accept area entered or exit signal + if (signalId != areaEnteredSignal().methodIndex() && + signalId != areaExitedSignal().methodIndex()) + { + return false; + } + + d->requestUpdate(monitor, signalId); + + return true; +} + +bool QGeoAreaMonitorPolling::stopMonitoring(const QGeoAreaMonitorInfo &monitor) +{ + QGeoAreaMonitorInfo info = d->stopMonitoring(monitor); + + return info.isValid(); +} + +QList QGeoAreaMonitorPolling::activeMonitors() const +{ + return d->activeMonitors().values(); +} + +QList QGeoAreaMonitorPolling::activeMonitors(const QGeoShape ®ion) const +{ + QList results; + if (region.isEmpty()) + return results; + + const MonitorTable list = d->activeMonitors(); + foreach (const QGeoAreaMonitorInfo &monitor, list) { + QGeoCoordinate center; + switch (monitor.area().type()) { + case QGeoShape::CircleType: + { + QGeoCircle circle(monitor.area()); + center = circle.center(); + break; + } + case QGeoShape::RectangleType: + { + QGeoRectangle rectangle(monitor.area()); + center = rectangle.center(); + break; + } + case QGeoShape::UnknownType: + { + break; + } + } + if (region.contains(center)) + results.append(monitor); + } + + return results; } -void QGeoAreaMonitorPolling::checkStartStop() +QGeoAreaMonitorSource::AreaMonitorFeatures QGeoAreaMonitorPolling::supportedAreaMonitorFeatures() const { - if (!location) return; + return 0; +} - if ((isSignalConnected(areaEnteredSignal()) || - isSignalConnected(areaExitedSignal())) && - QGeoAreaMonitor::center().isValid() && - QGeoAreaMonitor::radius() > qreal(0.0)) { - location->startUpdates(); - } else { - location->stopUpdates(); +void QGeoAreaMonitorPolling::connectNotify(const QMetaMethod &/*signal*/) +{ + if (!signalsAreConnected && + (isSignalConnected(areaEnteredSignal()) || + isSignalConnected(areaExitedSignal())) ) + { + signalsAreConnected = true; + d->checkStartStop(); } } -void QGeoAreaMonitorPolling::positionUpdated(const QGeoPositionInfo &info) +void QGeoAreaMonitorPolling::disconnectNotify(const QMetaMethod &/*signal*/) { - double distance = info.coordinate().distanceTo(QGeoAreaMonitor::center()); + if (!isSignalConnected(areaEnteredSignal()) && + !isSignalConnected(areaExitedSignal())) + { + signalsAreConnected = false; + d->checkStartStop(); + } +} - if (distance <= QGeoAreaMonitor::radius()) { - if (!insideArea) - emit areaEntered(info); - insideArea = true; - } else if (insideArea) { - emit areaExited(info); - insideArea = false; +void QGeoAreaMonitorPolling::positionError(const QGeoPositionInfoSource::Error error) +{ + switch (error) { + case QGeoPositionInfoSource::AccessError: + lastError = QGeoAreaMonitorSource::AccessError; + break; + case QGeoPositionInfoSource::UnknownSourceError: + lastError = QGeoAreaMonitorSource::UnknownSourceError; + break; + case QGeoPositionInfoSource::ClosedError: + lastError = QGeoAreaMonitorSource::InsufficientPositionInfo; + break; } + + emit QGeoAreaMonitorSource::error(lastError); +} + +void QGeoAreaMonitorPolling::timeout(const QGeoAreaMonitorInfo& monitor) +{ + if (isSignalConnected(monitorExpiredSignal())) + emit monitorExpired(monitor); +} + +void QGeoAreaMonitorPolling::processAreaEvent(const QGeoAreaMonitorInfo &minfo, + const QGeoPositionInfo &pinfo, bool isEnteredEvent) +{ + if (isEnteredEvent) + emit areaEntered(minfo, pinfo); + else + emit areaExited(minfo, pinfo); } +#include "qgeoareamonitor_polling.moc" #include "moc_qgeoareamonitor_polling.cpp" diff --git a/src/plugins/position/positionpoll/qgeoareamonitor_polling.h b/src/plugins/position/positionpoll/qgeoareamonitor_polling.h index a94e4e40..f25cd685 100644 --- a/src/plugins/position/positionpoll/qgeoareamonitor_polling.h +++ b/src/plugins/position/positionpoll/qgeoareamonitor_polling.h @@ -1,4 +1,4 @@ -/**************************************************************************** +/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal @@ -42,37 +42,55 @@ #ifndef QGEOAREAMONITORPOLLING_H #define QGEOAREAMONITORPOLLING_H -#include "qgeoareamonitor.h" -#include "qgeopositioninfosource.h" +#include +#include /** * QGeoAreaMonitorPolling * */ -class QGeoAreaMonitorPolling : public QGeoAreaMonitor + +class QGeoAreaMonitorPollingPrivate; +class QGeoAreaMonitorPolling : public QGeoAreaMonitorSource { Q_OBJECT - public : explicit QGeoAreaMonitorPolling(QObject *parent = 0); ~QGeoAreaMonitorPolling(); - void setCenter(const QGeoCoordinate &coordinate); - void setRadius(qreal radius); - inline bool isValid() { return location; } + void setPositionInfoSource(QGeoPositionInfoSource *source) Q_DECL_OVERRIDE; + QGeoPositionInfoSource* positionInfoSource() const Q_DECL_OVERRIDE; + + Error error() const Q_DECL_OVERRIDE; + + bool startMonitoring(const QGeoAreaMonitorInfo &monitor) Q_DECL_OVERRIDE; + bool requestUpdate(const QGeoAreaMonitorInfo &monitor, + const char *signal) Q_DECL_OVERRIDE; + bool stopMonitoring(const QGeoAreaMonitorInfo &monitor) Q_DECL_OVERRIDE; + + QList activeMonitors() const Q_DECL_OVERRIDE; + QList activeMonitors(const QGeoShape ®ion) const Q_DECL_OVERRIDE; + + QGeoAreaMonitorSource::AreaMonitorFeatures supportedAreaMonitorFeatures() const Q_DECL_OVERRIDE; + + inline bool isValid() { return positionInfoSource(); } + + bool signalsAreConnected; private Q_SLOTS: - void positionUpdated(const QGeoPositionInfo &info); + void positionError(QGeoPositionInfoSource::Error error); + void timeout(const QGeoAreaMonitorInfo &monitor); + void processAreaEvent(const QGeoAreaMonitorInfo &minfo, const QGeoPositionInfo &pinfo, bool isEnteredEvent); private: - bool insideArea; - QGeoPositionInfoSource *location; + QGeoAreaMonitorPollingPrivate* d; + QGeoAreaMonitorSource::Error lastError; void connectNotify(const QMetaMethod &signal); void disconnectNotify(const QMetaMethod &signal); - void checkStartStop(); + int idForSignal(const char *signal); }; #endif // QGEOAREAMONITORPOLLING_H diff --git a/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.cpp b/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.cpp index efdb65b4..1d737e24 100644 --- a/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.cpp +++ b/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.cpp @@ -56,7 +56,7 @@ QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactorySimulator::satelliteInfoSo return src; } -QGeoAreaMonitor *QGeoPositionInfoSourceFactorySimulator::areaMonitor(QObject *parent) +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactorySimulator::areaMonitor(QObject *parent) { Q_UNUSED(parent); return 0; diff --git a/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.h b/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.h index 42dadf77..e31a7e01 100644 --- a/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.h +++ b/src/plugins/position/simulator/qgeopositioninfosourcefactory_simulator.h @@ -57,7 +57,7 @@ class QGeoPositionInfoSourceFactorySimulator : public QObject, public QGeoPositi public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitor *areaMonitor(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); }; #endif // QGEOPOSITIONINFOSOURCEFACTORY_SIMULATOR_H diff --git a/src/positioning/doc/snippets/cpp/cppqml.cpp b/src/positioning/doc/snippets/cpp/cppqml.cpp index 5ab23513..95d34b7c 100644 --- a/src/positioning/doc/snippets/cpp/cppqml.cpp +++ b/src/positioning/doc/snippets/cpp/cppqml.cpp @@ -39,9 +39,12 @@ ****************************************************************************/ #include +#include #include #include #include +#include +#include void cppQmlInterface(QObject *qmlObject) { @@ -62,3 +65,40 @@ void cppQmlInterface(QObject *qmlObject) //! [Location set] } +class MyClass : public QObject +{ + Q_OBJECT +//! [BigBen] +public: + MyClass() : QObject() + { + QGeoAreaMonitorSource *monitor = QGeoAreaMonitorSource::createDefaultMonitorSource(this); + if (monitor) { + connect(monitor, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)), + this, SLOT(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)); + connect(monitor, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo)), + this, SLOT(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); + + QGeoAreaMonitorInfo bigBen("Big Ben"); + QGeoCoordinate position(51.50104, -0.124632); + bigBen.setMonitoredArea(QGeoCircle(position, 100)); + + monitor->startMonitoring(bigBen); + + } else { + qDebug() << "Could not create default area monitor"; + } + } + +public Q_SLOTS: + void areaEntered(const QGeoAreaMonitorInfo &mon, const QGeoPositionInfo &update) + { + qDebug() << "Now within 100 meters, current position is" << update.coordinate(); + } + + void areaExited(const QGeoAreaMonitorInfo &mon, const QGeoPositionInfo &update) + { + qDebug() << "No longer within 100 meters, current position is" << update.coordinate(); + } +//! [BigBen] +}; diff --git a/src/positioning/doc/src/cpp-position.qdoc b/src/positioning/doc/src/cpp-position.qdoc index 75c2e30e..16fceea5 100644 --- a/src/positioning/doc/src/cpp-position.qdoc +++ b/src/positioning/doc/src/cpp-position.qdoc @@ -84,10 +84,10 @@ the platform. If a problem occurs with access to the information source then an \l {QGeoPositionInfoSource::error()}{error()} signal is emitted. -The QGeoAreaMonitor class enables client applications to be notified when +The QGeoAreaMonitorSource class enables client applications to be notified when the receiving device has moved in or out of a particular area, as specified by a coordinate and radius. If the platform provides built-in support for -area monitoring, QGeoAreaMonitor::createDefaultMonitor() returns an instance of +area monitoring, QGeoAreaMonitorSource::createDefaultMonitor() returns an instance of the default area monitor. Satellite information can also be distributed through the diff --git a/src/positioning/doc/src/qtpositioning-plugins.qdoc b/src/positioning/doc/src/qtpositioning-plugins.qdoc index 1ed1be1a..5873aadd 100644 --- a/src/positioning/doc/src/qtpositioning-plugins.qdoc +++ b/src/positioning/doc/src/qtpositioning-plugins.qdoc @@ -61,7 +61,7 @@ The entries have the following meaning: \li Set to \c true if the plugin implements a \l QGeoSatelliteInfoSource. \row \li Monitor - \li Set to \c true if the plugin implements a \l QGeoAreaMonitor. + \li Set to \c true if the plugin implements a \l QGeoAreaMonitorSource. \row \li Priority \li The plugin priority. If multiple plugins have the same provider name, the plugin diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro index da1186bf..296356d0 100644 --- a/src/positioning/positioning.pro +++ b/src/positioning/positioning.pro @@ -8,7 +8,8 @@ OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator PUBLIC_HEADERS += \ qgeoaddress.h \ - qgeoareamonitor.h \ + qgeoareamonitorinfo.h \ + qgeoareamonitorsource.h \ qgeoshape.h \ qgeorectangle.h \ qgeocircle.h \ @@ -37,7 +38,8 @@ PRIVATE_HEADERS += \ SOURCES += \ qgeoaddress.cpp \ - qgeoareamonitor.cpp \ + qgeoareamonitorsource.cpp \ + qgeoareamonitorinfo.cpp \ qgeoshape.cpp \ qgeorectangle.cpp \ qgeocircle.cpp \ diff --git a/src/positioning/qgeoareamonitor.cpp b/src/positioning/qgeoareamonitor.cpp deleted file mode 100644 index 5ad69e9a..00000000 --- a/src/positioning/qgeoareamonitor.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtPositioning module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include "qgeopositioninfosourcefactory.h" -#include "qgeopositioninfosource_p.h" - -/*! - \class QGeoAreaMonitor - \inmodule QtPositioning - \ingroup QtPositioning-positioning - \since Qt Positioning 5.0 - - \brief The QGeoAreaMonitor class enables the detection of proximity - changes for a specified set of coordinates. - - A QGeoAreaMonitor emits signals when the current position is in - range, or has moved out of range, of a specified circular area. - The area is specified by a coordinate (the center point) and a - radius (in meters). - - For example: - - \code - public: - MyClass::MyClass() - { - QGeoAreaMonitor *monitor = QGeoAreaMonitor::createDefaultMonitor(); - if (monitor) { - connect(monitor, SIGNAL(areaEntered(QGeoPositionInfo)), - this, SLOT(areaEntered(QGeoPositionInfo))); - connect(monitor, SIGNAL(areaExited(QGeoPositionInfo)), - this, SLOT(areaExited(QGeoPositionInfo))); - - QGeoCoordinate bigBenLocation(51.50104, -0.124632); - monitor->setCenter(bigBenLocation); - monitor->setRadius(100); - } else { - qDebug() << "Could not create default area monitor"; - } - } - - public Q_SLOTS: - void areaEntered(const QGeoPositionInfo &update) - { - qDebug() << "Now within 100 meters, current position is" << update.coordinate(); - } - - void areaExited(const QGeoPositionInfo &update) - { - qDebug() << "No longer within 100 meters, current position is" << update.coordinate(); - } - \endcode -*/ - -QT_BEGIN_NAMESPACE - -class QGeoAreaMonitorPrivate -{ -public: - QGeoCoordinate coord; - qreal radius; -}; - - -/*! - Creates a monitor with the given \a parent. -*/ -QGeoAreaMonitor::QGeoAreaMonitor(QObject *parent) - : QObject(parent), - d(new QGeoAreaMonitorPrivate) -{ - d->radius = qreal(0.0); -} - -/*! - Destroys the monitor. -*/ -QGeoAreaMonitor::~QGeoAreaMonitor() -{ - delete d; -} - -/*! - \property QGeoAreaMonitor::center - \brief holds the center of the area to be monitored. - - When the center is set, if the radius has already been set and - the current position is within the monitored area, areaEntered() - is emitted immediately. - - By default, contains an invalid coordinate. - - Note: Subclass implementations must call the base implementation of - setCenter() so that center() returns the correct value. -*/ -void QGeoAreaMonitor::setCenter(const QGeoCoordinate &coordinate) -{ - d->coord = coordinate; -} - -QGeoCoordinate QGeoAreaMonitor::center() const -{ - return d->coord; -} - -/*! - \property QGeoAreaMonitor::radius - \brief holds the radius of the area to be monitored, in meters. - - If the specified radius is less than the minimum supported radius, the - radius is set to the minimum radius. - - When this property is set, if the center coordinate has already been set and - the current position is within the monitored area, areaEntered() - is emitted immediately. - - By default, this property is 0. - - Note: Subclass implementations must call the base implementation of - setRadius() so that radius() returns the correct value. -*/ -void QGeoAreaMonitor::setRadius(qreal radius) -{ - d->radius = radius; -} - -qreal QGeoAreaMonitor::radius() const -{ - return d->radius; -} - -/*! - Creates and returns a monitor with the given \a parent that - monitors areas using resources on the underlying system. - - Returns 0 if the system has no support for position monitoring. -*/ -QGeoAreaMonitor *QGeoAreaMonitor::createDefaultMonitor(QObject *parent) -{ - QList plugins = QGeoPositionInfoSourcePrivate::pluginsSorted(); - foreach (const QJsonObject &obj, plugins) { - if (obj.value(QStringLiteral("Monitor")).isBool() - && obj.value(QStringLiteral("Monitor")).toBool()) - { - QGeoPositionInfoSourcePrivate d; - d.metaData = obj; - d.loadPlugin(); - QGeoAreaMonitor *s = 0; - if (d.factory) - s = d.factory->areaMonitor(parent); - return s; - } - } - - return 0; -} - -/*! - Creates and returns a monitor with the given \a parent, - by loading the plugin named \a sourceName. - - Returns 0 if the plugin cannot be found. -*/ -QGeoAreaMonitor *QGeoAreaMonitor::createMonitor(const QString &sourceName, QObject *parent) -{ - QHash plugins = QGeoPositionInfoSourcePrivate::plugins(); - if (plugins.contains(sourceName)) { - QGeoPositionInfoSourcePrivate d; - d.metaData = plugins.value(sourceName); - d.loadPlugin(); - QGeoAreaMonitor *s = 0; - if (d.factory) - s = d.factory->areaMonitor(parent); - return s; - } - - return 0; -} - -/*! - Returns a list of available monitor plugins, including the default system - backend if one is available. -*/ -QStringList QGeoAreaMonitor::availableMonitors() -{ - QStringList plugins; - QHash meta = QGeoPositionInfoSourcePrivate::plugins(); - foreach (const QString &name, meta.keys()) { - if (meta.value(name).value(QStringLiteral("Monitor")).isBool() - && meta.value(name).value(QStringLiteral("Monitor")).toBool()) { - plugins << name; - } - } - - return plugins; -} - - - -/*! - \fn void QGeoAreaMonitor::areaEntered(const QGeoPositionInfo &update); - - Emitted when the current position has moved from a position outside the - monitored area to a position within the monitored area. - - The \a update holds the new position. -*/ - -/*! - \fn void QGeoAreaMonitor::areaExited(const QGeoPositionInfo &update); - - Emitted when the current position has moved from a position within the - monitored area to a position outside the monitored area. - - The \a update holds the new position. -*/ - -QT_END_NAMESPACE diff --git a/src/positioning/qgeoareamonitor.h b/src/positioning/qgeoareamonitor.h deleted file mode 100644 index 1aed8b6b..00000000 --- a/src/positioning/qgeoareamonitor.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtPositioning module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QGEOAREAMONITOR_H -#define QGEOAREAMONITOR_H - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QGeoPositionInfo; -class QGeoAreaMonitorPrivate; -class Q_POSITIONING_EXPORT QGeoAreaMonitor : public QObject -{ - Q_OBJECT - Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter) - Q_PROPERTY(qreal radius READ radius WRITE setRadius) - -public: - explicit QGeoAreaMonitor(QObject *parent); - virtual ~QGeoAreaMonitor() = 0; - - virtual void setCenter(const QGeoCoordinate &coordinate); - QGeoCoordinate center() const; - - virtual void setRadius(qreal radius); - qreal radius() const; - - static QGeoAreaMonitor *createDefaultMonitor(QObject *parent); - static QGeoAreaMonitor *createMonitor(const QString& sourceName, QObject *parent); - static QStringList availableMonitors(); - -Q_SIGNALS: - void areaEntered(const QGeoPositionInfo &update); - void areaExited(const QGeoPositionInfo &update); - -private: - Q_DISABLE_COPY(QGeoAreaMonitor) - QGeoAreaMonitorPrivate *d; -}; - - -QT_END_NAMESPACE - -#endif diff --git a/src/positioning/qgeoareamonitorinfo.cpp b/src/positioning/qgeoareamonitorinfo.cpp new file mode 100644 index 00000000..b4e0d179 --- /dev/null +++ b/src/positioning/qgeoareamonitorinfo.cpp @@ -0,0 +1,379 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#ifndef QT_NO_DEBUG_STREAM +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QGeoAreaMonitorInfo + \inmodule QtPositioning + \since Qt Positioning 5.2 + \ingroup QtPositioning-positioning + + \brief The QGeoAreaMonitorInfo class describes the parameters of an area or region + to be monitored for proximity. + + The purpose of area monitoring is to inform a user when he/she comes close to an area of + interest. In general such an area is described by a \l QGeoCircle. The circle's center + represents the place of interest and the area around it identifies the geographical region + within which notifications are sent. + + A QGeoAreaMonitorInfo object is valid if it has a non-empty name and a valid \l area(). + Such objects must be registered with a \l QGeoAreaMonitorSource to start and stop the + monitoring process. Note that extensive monitoring can be very resource consuming + because the positioning engine must remain active and has to match the current position + with each QGeoAreaMonitorInfo instance. + + To further reduce the burden on the system there are optional attributes which can + set. Each monitored area can have an expiry date which automatically removes the + to-be-monitored area from the monitoring source once the expiry date has been reached. + Another option is to adjust the persistence of a monitored area. A QGeoAreaMonitorInfo + that \l isPersistent() will remain active beyond + the current applications lifetime. If an area is entered while the monitoring + application is not running the application will be started. Note that this feature is + not available on all platforms. Its availability can be checked via + \l QGeoAreaMonitorSource::supportedAreaMonitorFeatures(). + + \sa QGeoAreaMonitorSource + + */ + +class QGeoAreaMonitorInfoPrivate : public QSharedData +{ +public: + QGeoAreaMonitorInfoPrivate() : QSharedData(), persistent(false) {} + QGeoAreaMonitorInfoPrivate(const QGeoAreaMonitorInfoPrivate &other) + : QSharedData(other) + { + uid = other.uid; + name = other.name; + shape = other.shape; + persistent = other.persistent; + notificationParameters = other.notificationParameters; + expiry = other.expiry; + } + ~QGeoAreaMonitorInfoPrivate() {} + + QUuid uid; + QString name; + QGeoShape shape; + bool persistent; + QVariantMap notificationParameters; + QDateTime expiry; +}; + +/*! + Constructs a QGeoAreaMonitorInfo object with the specified \a name. + + \sa name() + */ +QGeoAreaMonitorInfo::QGeoAreaMonitorInfo(const QString &name) +{ + d = new QGeoAreaMonitorInfoPrivate; + d->name = name; + d->uid = QUuid::createUuid(); +} + +/*! + Constructs a QGeoAreaMonitorInfo object as a copy of \a other. + */ +QGeoAreaMonitorInfo::QGeoAreaMonitorInfo(const QGeoAreaMonitorInfo &other) + : d(other.d) +{ +} + +/*! + Destructor + */ +QGeoAreaMonitorInfo::~QGeoAreaMonitorInfo() +{ +} + +/*! + Assigns \a other to this QGeoAreaMonitorInfo object and returns a reference + to this QGeoAreaMonitorInfo object. + */ +QGeoAreaMonitorInfo &QGeoAreaMonitorInfo::operator=(const QGeoAreaMonitorInfo &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if all of this object's values are the same as those of + \a other. +*/ +bool QGeoAreaMonitorInfo::operator==(const QGeoAreaMonitorInfo &other) const +{ + return (d->name == other.d->name && + d->uid == other.d->uid && + d->shape == other.d->shape && + d->persistent == other.d->persistent && + d->expiry == other.d->expiry && + d->notificationParameters == other.d->notificationParameters); +} + +/*! + Returns true if any of this object's values are not the same as those of + \a other. +*/ +bool QGeoAreaMonitorInfo::operator!=(const QGeoAreaMonitorInfo &other) const +{ + return !QGeoAreaMonitorInfo::operator ==(other); +} + +/*! + Returns the name of the QGeoAreaMonitorInfo object. The name should be used to + for user-visibility purposes. + */ +QString QGeoAreaMonitorInfo::name() const +{ + return d->name; +} + +/*! + Sets the user visibile \a name. + */ +void QGeoAreaMonitorInfo::setName(const QString &name) +{ + if (d->name != name) + d->name = name; +} + +/*! + Returns the identifier of the QGeoAreaMonitorInfo object. + The identifier is automatically generated upon construction of a new + QGeoAreaMonitorInfo object. +*/ + +QString QGeoAreaMonitorInfo::identifier() const +{ + return d->uid.toString(); +} + +/*! + Returns true, if the monitor is valid. A valid QGeoAreaMonitorInfo has a non-empty name() + and the monitored area is not \l {QGeoShape::isEmpty()}{empty()}. + Otherwise this function returns false. + */ +bool QGeoAreaMonitorInfo::isValid() const +{ + return (!d->name.isEmpty() && !d->shape.isEmpty()); +} + +/*! + Returns the boundaries of the to-be-monitored area. This area must not be empty. + + \sa setArea() + */ +QGeoShape QGeoAreaMonitorInfo::area() const +{ + return d->shape; +} + +/*! + Sets the to-be-monitored area to \a newShape. + + \sa area() + */ +void QGeoAreaMonitorInfo::setArea(const QGeoShape &newShape) +{ + d->shape = newShape; +} + +/*! + Returns the expiry date. + + After an active QGeoAreaMonitorInfo has expired the region is no longer monitored + and the QGeoAreaMonitorInfo object is removed from the list of + \l {QGeoAreaMonitorSource::activeMonitors()}{active monitors}. + + If the expiry \l QDateTime is invalid the QGeoAreaMonitorInfo object is treated as not having + an expiry date. This implies an indefinite monitoring period if the object is persistent or + until the current application closes if the object is non-persistent. + + \sa QGeoAreaMonitorSource::activeMonitors() + */ +QDateTime QGeoAreaMonitorInfo::expiration() const +{ + return d->expiry; +} + +/*! + Sets the expiry date and time to \a expiry. + */ +void QGeoAreaMonitorInfo::setExpiration(const QDateTime &expiry) +{ + d->expiry = expiry; +} + +/*! + Returns true if the QGeoAreaMonitorInfo is persistent. + The default value for this property is false. + + A non-persistent QGeoAreaMonitorInfo will be removed by the system once + the application owning the monitor object stops. Persistent objects remain + active and can be retrieved once the application restarts. + + If the system triggers an event associated to a persistent QGeoAreaMonitorInfo + the relevant application will be re-started and the appropriate signal emitted. + + \sa setPersistent() + */ +bool QGeoAreaMonitorInfo::isPersistent() const +{ + return d->persistent; +} + +/*! + Sets the QGeoAreaMonitorInfo objects persistence to \a isPersistent. + + Note that setting this flag does not imply that QGeoAreaMonitorInfoSource supports persistent + monitoring. \l QGeoAreaMonitorSource::supportedAreaMonitorFeatures() can be used to + check for this feature's availability. + + \sa isPersistent() + */ +void QGeoAreaMonitorInfo::setPersistent(bool isPersistent) +{ + d->persistent = isPersistent; +} + + +/*! + Returns the set of platform specific paraemters used by this QGeoAreaMonitorInfo. + + \sa setNotificationParameters() + */ +QVariantMap QGeoAreaMonitorInfo::notificationParameters() const +{ + return d->notificationParameters; +} + +/*! + Sets the set of platform specific \a parameters used by QGeoAreaMonitorInfo. + + \sa notificationParameters() + */ +void QGeoAreaMonitorInfo::setNotificationParameters(const QVariantMap ¶meters) +{ + d->notificationParameters = parameters; +} + +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QGeoAreaMonitorInfo &monitor) + \relates QGeoAreaMonitorInfo + + Writes the given \a monitor to the specified \a stream. + + \sa {Serializing Qt Data Types} +*/ +QDataStream &operator<<(QDataStream &ds, const QGeoAreaMonitorInfo &monitor) +{ + ds << monitor.name() << monitor.d->uid << monitor.area() + << monitor.isPersistent() << monitor.notificationParameters() << monitor.expiration(); + return ds; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QGeoAreaMonitorInfo &monitor) + \relates QGeoAreaMonitorInfo + + Reads a area monitoring data from the specified \a stream into the given + \a monitor. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &ds, QGeoAreaMonitorInfo &monitor) +{ + QString s; + ds >> s; + monitor = QGeoAreaMonitorInfo(s); + + QUuid id; + ds >> id; + monitor.d->uid = id; + + QGeoShape shape; + ds >> shape; + monitor.setArea(shape); + + bool persistent; + ds >> persistent; + monitor.setPersistent(persistent); + + QVariantMap map; + ds >> map; + monitor.setNotificationParameters(map); + + QDateTime dt; + ds >> dt; + monitor.setExpiration(dt); + + return ds; +} + +#endif + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QGeoAreaMonitorInfo &monitor) +{ + dbg.nospace() << "QGeoAreaMonitorInfo(\"" << qPrintable(monitor.name()) + << "\", " << monitor.area() + << ", persistent: " << monitor.isPersistent() + << ", expiry: " << monitor.expiration() << ")"; + return dbg.space(); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/positioning/qgeoareamonitorinfo.h b/src/positioning/qgeoareamonitorinfo.h new file mode 100644 index 00000000..938671df --- /dev/null +++ b/src/positioning/qgeoareamonitorinfo.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGEOAREAMONITORINFO_H +#define QGEOAREAMONITORINFO_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDataStream; +class QGeoAreaMonitorInfo; + +#ifndef QT_NO_DATASTREAM +Q_POSITIONING_EXPORT QDataStream &operator<<(QDataStream &, const QGeoAreaMonitorInfo &); +Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &, QGeoAreaMonitorInfo &); +#endif + +class QGeoAreaMonitorInfoPrivate; +class Q_POSITIONING_EXPORT QGeoAreaMonitorInfo +{ +public: + explicit QGeoAreaMonitorInfo(const QString &name = QString()); + QGeoAreaMonitorInfo(const QGeoAreaMonitorInfo &other); + ~QGeoAreaMonitorInfo(); + + QGeoAreaMonitorInfo &operator=(const QGeoAreaMonitorInfo &other); + + bool operator==(const QGeoAreaMonitorInfo &other) const; + bool operator!=(const QGeoAreaMonitorInfo &other) const; + + QString name() const; + void setName(const QString &name); + + QString identifier() const; + bool isValid() const; + + QGeoShape area() const; + void setArea(const QGeoShape &newShape); + + QDateTime expiration() const; + void setExpiration(const QDateTime &expiry); + + bool isPersistent() const; + void setPersistent(bool isPersistent); + + QVariantMap notificationParameters() const; + void setNotificationParameters(const QVariantMap ¶meters); +private: + QSharedDataPointer d; + +#ifndef QT_NO_DATASTREAM + friend Q_POSITIONING_EXPORT QDataStream &operator<<(QDataStream &, const QGeoAreaMonitorInfo &); + friend Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &, QGeoAreaMonitorInfo &); +#endif +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_POSITIONING_EXPORT QDebug operator<<(QDebug, const QGeoAreaMonitorInfo &); +#endif + +QT_END_NAMESPACE + +#endif // QGEOAREAMONITORINFO_H diff --git a/src/positioning/qgeoareamonitorsource.cpp b/src/positioning/qgeoareamonitorsource.cpp new file mode 100644 index 00000000..2f23d942 --- /dev/null +++ b/src/positioning/qgeoareamonitorsource.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qgeopositioninfosourcefactory.h" +#include "qgeopositioninfosource_p.h" + +/*! + \class QGeoAreaMonitorSource + \inmodule QtPositioning + \ingroup QtPositioning-positioning + \since Qt Positioning 5.0 + + \brief The QGeoAreaMonitorSource class enables the detection of proximity + changes for a specified set of coordinates. + + A QGeoAreaMonitorSource emits signals when the current position is in + range, or has moved out of range, of a specified area. + Each area is specified by a \l QGeoAreaMonitorInfo object. + For example: + + \snippet cpp/cppqml.cpp BigBen + + \c QGeoAreaMonitorSource follows a singleton pattern. Each instance of + the class with the same \l sourceName() shares the same area monitoring backend. + If a new \l QGeoAreaMonitorInfo object is added via \l startMonitoring() + or \l requestUpdate() it can be retrieved by another instance of this class + (provided that they are sourced from the same area monitor provider plug-in). + The same singleton pattern applies to the \l QGeoPositionInfoSource instance + used by this class. The following code snippet emphasizes the behavior: + + \code + QGeoAreaMonitorSource *s1 = QGeoAreaMonitorSource::createSource("blah", this); + QGeoAreaMonitorSource *s2 = QGeoAreaMonitorSource::createSource("blah", this); + QVERIFY(s1->positionInfoSource() == s2->positionInfoSource); + \endcode +*/ + +QT_BEGIN_NAMESPACE + + + +class QGeoAreaMonitorSourcePrivate +{ +public: + QGeoPositionInfoSource *source; + QString providerName; +}; + +/*! + \enum QGeoAreaMonitorSource::Error + Defines the types of positioning methods. + + The Error enumeration represents the errors which can occur. + + \value AccessError The connection setup to the remote area monitoring backend failed because the + application lacked the required privileges. + \value InsufficientPositionInfo The area monitoring source could not retrieve a location fix or + the accuracy of the fix is not high enough to provide an effective area monitoring. + \value UnknownSourceError An unidentified error occurred. +*/ + +/*! + \enum QGeoAreaMonitorSource::AreaMonitorFeature + Defines the types of area monitoring capabilities. + + \value PersistentAreaMonitorFeature QGeoAreaMonitorInfo instances can be made persistent. + A persistent monitor continues to be active even when the application managing the monitor is + not running. + \value AnyAreaMonitorFeature Matches all possible area monitoring features. +*/ + +/*! + \fn virtual AreaMonitoringFeatures QGeoAreaMonitorSource::supportedAreaMonitorFeatures() const = 0; + + Returns the area monitoring features available to this source. +*/ + +/*! + \fn virtual QGeoAreaMonitorSource::Error QGeoAreaMonitorSource::error() const + + Returns the type of error that last occurred. +*/ + +/*! + Creates a monitor with the given \a parent. +*/ +QGeoAreaMonitorSource::QGeoAreaMonitorSource(QObject *parent) + : QObject(parent), + d(new QGeoAreaMonitorSourcePrivate) +{ + d->source = 0; +} + +/*! + Destroys the monitor. +*/ +QGeoAreaMonitorSource::~QGeoAreaMonitorSource() +{ + delete d; +} + +/*! + Creates and returns a monitor with the given \a parent that + monitors areas using resources on the underlying system. + + Returns 0 if the system has no support for position monitoring. +*/ +QGeoAreaMonitorSource *QGeoAreaMonitorSource::createDefaultSource(QObject *parent) +{ + QList plugins = QGeoPositionInfoSourcePrivate::pluginsSorted(); + foreach (const QJsonObject &obj, plugins) { + if (obj.value(QStringLiteral("Monitor")).isBool() + && obj.value(QStringLiteral("Monitor")).toBool()) + { + QGeoPositionInfoSourcePrivate d; + d.metaData = obj; + d.loadPlugin(); + QGeoAreaMonitorSource *s = 0; + if (d.factory) + s = d.factory->areaMonitor(parent); + if (s) + s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); + return s; + } + } + + return 0; +} + +/*! + Creates and returns a monitor with the given \a parent, + by loading the plugin named \a sourceName. + + Returns 0 if the plugin cannot be found. +*/ +QGeoAreaMonitorSource *QGeoAreaMonitorSource::createSource(const QString &sourceName, QObject *parent) +{ + QHash plugins = QGeoPositionInfoSourcePrivate::plugins(); + if (plugins.contains(sourceName)) { + QGeoPositionInfoSourcePrivate d; + d.metaData = plugins.value(sourceName); + d.loadPlugin(); + QGeoAreaMonitorSource *s = 0; + if (d.factory) + s = d.factory->areaMonitor(parent); + if (s) + s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); + return s; + } + + return 0; +} + +/*! + Returns a list of available monitor plugins, including the default system + backend if one is available. +*/ +QStringList QGeoAreaMonitorSource::availableSources() +{ + QStringList plugins; + QHash meta = QGeoPositionInfoSourcePrivate::plugins(); + foreach (const QString &name, meta.keys()) { + if (meta.value(name).value(QStringLiteral("Monitor")).isBool() + && meta.value(name).value(QStringLiteral("Monitor")).toBool()) { + plugins << name; + } + } + + return plugins; +} + +/*! + Returns the unique name of the area monitor source implementation in use. + + This is the same name that can be passed to createSource() in order to + create a new instance of a particular area monitor source implementation. +*/ +QString QGeoAreaMonitorSource::sourceName() const +{ + return d->providerName; +} + +/*! + Returns the current QGeoPositionInfoSource used by this QGeoAreaMonitorSource + object. The function will return \l QGeoPositionInfoSource::createDefaultSource() + if no other object has been set. + + The function returns 0 if not even a default QGeoPositionInfoSource exists. + + Any usage of the returned \l QGeoPositionInfoSource instance should account + for the fact that it may reside in a different thread. + + \sa QGeoPositionInfoSource, setPositionInfoSource() +*/ +QGeoPositionInfoSource* QGeoAreaMonitorSource::positionInfoSource() const +{ + return d->source; +} + +/*! + Sets the new \l QGeoPositionInfoSource to be used by this QGeoAreaMonitorSource object. + The area monitoring backend becomes the new QObject parent for \a newSource. + The previous \l QGeoPositionInfoSource object will be deleted. All QGeoAreaMonitorSource + instances based on the same \l sourceName() share the same QGeoPositionInfoSource + instance. + + This may be useful when it is desirable to manipulate the positioning system + used by the area monitoring engine. + + Note that ownership must be taken care of by subclasses of QGeoAreaMonitorSource. + Due to the singleton pattern behind this class \a newSource may be moved to a + new thread. + + \sa positionInfoSource() + */ +void QGeoAreaMonitorSource::setPositionInfoSource(QGeoPositionInfoSource *newSource) +{ + d->source = newSource; +} + + +/*! + \fn virtual bool QGeoAreaMonitorSource::startMonitoring(const QGeoAreaMonitorInfo &monitor) + + Returns \c true if the monitoring of \a monitor could be successfully started; otherwise + returns false. A reason for not being able to start monitoring could be the unavailability + of an appropriate default position info source while no alternative QGeoPositionInfoSource + has been set via \l setPositionInfoSource(). + + If \a monitor is already active the existing monitor object will be replaced by the new \a monitor reference. + The identification of QGeoAreaMonitorInfo instances happens via \l QGeoAreaMonitorInfo::identifier(). + Therefore this function can also be used to update active monitors. + + If \a monitor has an expiry date that has been passed this function returns false. Calling + this function for an already via \l requestUpdate() registered single shot monitor + switches the monitor to a permanent monitoring mode. + + Requesting persistent monitoring on a QGeoAreaMonitorSource instance fails if the area monitoring + backend doesn't support \l QGeoAreaMonitorSource::PersistentAreaMonitorFeature. + + \sa stopMonitoring() +*/ + +/*! + \fn virtual bool QGeoAreaMonitorSource::requestUpdate(const QGeoAreaMonitorInfo &monitor, const char *signal) + + Enables single shot area monitoring. Area monitoring for \a monitor will be performed + until this QGeoAreaMonitorSource instance emits \a signal for the first time. Once + the signal was emitted, \a monitor is automatically removed from the list of \l activeMonitors(). + If \a monitor is invalid or has an expiry date that has been passed this function returns false. + + \code + QGeoAreaMonitor singleShotMonitor; + QGeoAreaMonitorSource * source = QGeoAreaMonitorSource::createDefaultSource(this); + //... + bool ret = source->requestUpdate(singleShotMonitor, + SIGNAL(areaExited(QGeoAreaMonitor,QGeoPositionInfo))); + \endcode + + The above \c singleShotMonitor object will cease to send updates once the \l areaExited() signal + was emitted for the first time. Until this point in time any other signal may be emitted + zero or more times depending on the area context. + + It is not possible to simultanously request updates for more than one signal of the same monitor object. + The last call to this function determines the signal upon which the updates cease to continue. + At this stage only the \l areaEntered() and \l areaExited() signals can be used to + terminate the monitoring process. + + Requesting persistent monitoring on a QGeoAreaMonitorSource instance fails if the area monitoring + backend doesn't support \l QGeoAreaMonitorSource::PersistentAreaMonitorFeature. + + If \a monitor was already registered via \l startMonitoring() it is converted to a single + shot behavior. + + \sa startMonitoring(), stopMonitoring() + */ + +/*! + \fn virtual bool QGeoAreaMonitorSource::stopMonitoring(const QGeoAreaMonitorInfo &monitor) + + Returns true if \a monitor was successfully removed from the list of \l activeMonitors(); + otherwise returns false. This behavior is independent on whether \a monitor was registered + via \l startMonitoring() or \l requestUpdate(). +*/ + +/*! + \fn virtual QList QGeoAreaMonitorSource::activeMonitors() const + + Returns the list of all active monitors known to the QGeoAreaMonitorSource object. + + An active monitor was started via startMonitoring() the source object will emit + the required signals such as areaEntered() or areaExited(). Multiple \l QGeoAreaMonitorSource + instances within the same application share the same active monitor objects. + + Unless an active QGeoAreaMonitorInfo \l {QGeoAreaMonitorInfo::isPersistent()}{isPersistent()} an active QGeoAreaMonitorInfo + will be stopped once the current application terminates. +*/ + +/*! + \fn virtual QList QGeoAreaMonitorSource::activeMonitors(const QGeoShape &lookupArea) const + + Returns the list of all active monitors known to the QGeoAreaMonitorSource object whose + center lies within \a lookupArea. If \a lookupArea is empty the returned list will be empty. + + An active monitor was started via startMonitoring() and the source object will emit + the required signals such as areaEntered() or areaExited(). Multiple QGeoAreaMonitorSource + instances within the same application share the same monitor objects. + + Unless an active QGeoAreaMonitorInfo \l {QGeoAreaMonitorInfo::isPersistent()}{isPersistent()} an active QGeoAreaMonitorInfo + will be stopped once the current application terminates. + + \sa QGeoShape +*/ + + +/*! + \fn void QGeoAreaMonitorSource::monitorExpired(const QGeoAreaMonitorInfo &monitor) + + Emitted when \a monitor has expired. An expired area monitor is automatically + removed from the list of \l activeMonitors(). + + \sa activeMonitors() +*/ + +/*! + \fn void QGeoAreaMonitorSource::areaEntered(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update) + + Emitted when the current position has moved from a position outside of the active \a monitor + to a position within the monitored area. + + The \a update holds the new position. +*/ + +/*! + \fn void QGeoAreaMonitorSource::areaExited(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update) + + Emitted when the current position has moved from a position within the active \a monitor + to a position outside the monitored area. + + The \a update holds the new position. +*/ + +/*! + \fn void QGeoAreaMonitorSource::error(QGeoAreaMonitorSource::Error areaMonitoringError) + + This signal is emitted after an error occurred. The \a areaMonitoringError + parameter describes the type of error that occurred. + +*/ + +QT_END_NAMESPACE diff --git a/src/positioning/qgeoareamonitorsource.h b/src/positioning/qgeoareamonitorsource.h new file mode 100644 index 00000000..03c98874 --- /dev/null +++ b/src/positioning/qgeoareamonitorsource.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QGEOAREAMONITORSOURCE_H +#define QGEOAREAMONITORSOURCE_H + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QGeoPositionInfo; +class QGeoAreaMonitorSourcePrivate; +class Q_POSITIONING_EXPORT QGeoAreaMonitorSource : public QObject +{ + Q_OBJECT + +public: + enum Error { + AccessError = 0, + InsufficientPositionInfo, + UnknownSourceError + }; + Q_ENUMS(Error) + + enum AreaMonitorFeature { + PersistentAreaMonitorFeature = 0x00000001, + AnyAreaMonitorFeature = 0xffffffff + }; + Q_DECLARE_FLAGS(AreaMonitorFeatures, AreaMonitorFeature) + + explicit QGeoAreaMonitorSource(QObject *parent); + virtual ~QGeoAreaMonitorSource(); + + static QGeoAreaMonitorSource *createDefaultSource(QObject *parent); + static QGeoAreaMonitorSource *createSource(const QString& sourceName, QObject *parent); + static QStringList availableSources(); + + virtual void setPositionInfoSource(QGeoPositionInfoSource *source); + virtual QGeoPositionInfoSource* positionInfoSource() const; + + QString sourceName() const; + + virtual Error error() const = 0; + virtual AreaMonitorFeatures supportedAreaMonitorFeatures() const = 0; + + virtual bool startMonitoring(const QGeoAreaMonitorInfo &monitor) = 0; + virtual bool stopMonitoring(const QGeoAreaMonitorInfo &monitor) = 0; + virtual bool requestUpdate(const QGeoAreaMonitorInfo &monitor, const char *signal) = 0; + + virtual QList activeMonitors() const = 0; + virtual QList activeMonitors(const QGeoShape &lookupArea) const = 0; + +Q_SIGNALS: + void areaEntered(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update); + void areaExited(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update); + void monitorExpired(const QGeoAreaMonitorInfo &monitor); + void error(QGeoAreaMonitorSource::Error error); + +private: + Q_DISABLE_COPY(QGeoAreaMonitorSource) + QGeoAreaMonitorSourcePrivate *d; +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/positioning/qgeopositioninfosourcefactory.cpp b/src/positioning/qgeopositioninfosourcefactory.cpp index a113a4aa..bebbe20e 100644 --- a/src/positioning/qgeopositioninfosourcefactory.cpp +++ b/src/positioning/qgeopositioninfosourcefactory.cpp @@ -73,9 +73,9 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QGeoAreaMonitor *QGeoPositionInfoSourceFactory::areaMonitor(QObject *parent); + \fn QGeoAreaMonitorSource *QGeoPositionInfoSourceFactory::areaMonitor(QObject *parent); - Returns a new QGeoAreaMonitor associated with this plugin with parent \a parent. + Returns a new QGeoAreaMonitorSource associated with this plugin with parent \a parent. Can also return 0, in which case the plugin loader will use the factory with the next highest priority. */ diff --git a/src/positioning/qgeopositioninfosourcefactory.h b/src/positioning/qgeopositioninfosourcefactory.h index 32e0bc00..5704c2dc 100644 --- a/src/positioning/qgeopositioninfosourcefactory.h +++ b/src/positioning/qgeopositioninfosourcefactory.h @@ -44,7 +44,7 @@ #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -56,7 +56,7 @@ public: virtual QGeoPositionInfoSource *positionInfoSource(QObject *parent) = 0; virtual QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent) = 0; - virtual QGeoAreaMonitor *areaMonitor(QObject *parent) = 0; + virtual QGeoAreaMonitorSource *areaMonitor(QObject *parent) = 0; }; #define QT_POSITION_SOURCE_INTERFACE diff --git a/src/positioning/qgeosatelliteinfosource.cpp b/src/positioning/qgeosatelliteinfosource.cpp index faf8dad8..ee1b316a 100644 --- a/src/positioning/qgeosatelliteinfosource.cpp +++ b/src/positioning/qgeosatelliteinfosource.cpp @@ -93,6 +93,7 @@ class QGeoSatelliteInfoSourcePrivate { public: int interval; + QString providerName; }; /*! @@ -113,6 +114,18 @@ QGeoSatelliteInfoSource::~QGeoSatelliteInfoSource() delete d; } +/*! + Returns the unique name of the satellite source implementation in use. + + This is the same name that can be passed to createSource() in order to + create a new instance of a particular satellite source implementation. +*/ +QString QGeoSatelliteInfoSource::sourceName() const +{ + return d->providerName; +} + + /*! \property QGeoSatelliteInfoSource::updateInterval \brief This property holds the requested interval in milliseconds between each update. @@ -168,6 +181,8 @@ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *p QGeoSatelliteInfoSource *s = 0; if (d.factory) s = d.factory->satelliteInfoSource(parent); + if (s) + s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); return s; } } @@ -191,6 +206,8 @@ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &so QGeoSatelliteInfoSource *src = 0; if (d.factory) src = d.factory->satelliteInfoSource(parent); + if (src) + src->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); return src; } diff --git a/src/positioning/qgeosatelliteinfosource.h b/src/positioning/qgeosatelliteinfosource.h index 35aa2b33..2b25aec7 100644 --- a/src/positioning/qgeosatelliteinfosource.h +++ b/src/positioning/qgeosatelliteinfosource.h @@ -57,7 +57,7 @@ class Q_POSITIONING_EXPORT QGeoSatelliteInfoSource : public QObject public: enum Error { - AccessError, + AccessError = 0, ClosedError, /* 1 */ UnknownSourceError = -1 }; @@ -70,6 +70,8 @@ public: static QGeoSatelliteInfoSource *createSource(const QString &sourceName, QObject *parent); static QStringList availableSources(); + QString sourceName() const; + virtual void setUpdateInterval(int msec); int updateInterval() const; virtual int minimumUpdateInterval() const = 0; diff --git a/tests/auto/positionplugin/plugin.cpp b/tests/auto/positionplugin/plugin.cpp index 26f8ed34..bfc4880b 100644 --- a/tests/auto/positionplugin/plugin.cpp +++ b/tests/auto/positionplugin/plugin.cpp @@ -190,7 +190,7 @@ class QGeoPositionInfoSourceFactoryTest : public QObject, public QGeoPositionInf public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitor *areaMonitor(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); }; QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryTest::positionInfoSource(QObject *parent) @@ -205,7 +205,7 @@ QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryTest::satelliteInfoSource( return 0; } -QGeoAreaMonitor *QGeoPositionInfoSourceFactoryTest::areaMonitor(QObject* parent) +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryTest::areaMonitor(QObject* parent) { Q_UNUSED(parent) return 0; diff --git a/tests/auto/positionplugintest/tst_positionplugin.cpp b/tests/auto/positionplugintest/tst_positionplugin.cpp index 384f7a80..f152e762 100644 --- a/tests/auto/positionplugintest/tst_positionplugin.cpp +++ b/tests/auto/positionplugintest/tst_positionplugin.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include QT_USE_NAMESPACE @@ -78,7 +78,7 @@ void tst_PositionPlugin::availableSources() { QVERIFY(QGeoPositionInfoSource::availableSources().contains("test.source")); QVERIFY(!QGeoSatelliteInfoSource::availableSources().contains("test.source")); - QVERIFY(!QGeoAreaMonitor::availableMonitors().contains("test.source")); + QVERIFY(!QGeoAreaMonitorSource::availableSources().contains("test.source")); } void tst_PositionPlugin::create() diff --git a/tests/auto/qgeoareamonitor/logfilepositionsource.cpp b/tests/auto/qgeoareamonitor/logfilepositionsource.cpp new file mode 100644 index 00000000..fcfb7e0d --- /dev/null +++ b/tests/auto/qgeoareamonitor/logfilepositionsource.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "logfilepositionsource.h" + +LogFilePositionSource::LogFilePositionSource(QObject *parent) + : QGeoPositionInfoSource(parent), + logFile(new QFile(this)), + timer(new QTimer(this)) +{ + connect(timer, SIGNAL(timeout()), this, SLOT(readNextPosition())); + + logFile->setFileName(QFINDTESTDATA("simplelog.txt")); + if (!logFile->open(QIODevice::ReadOnly)) + qWarning() << "Error: cannot open source file" << logFile->fileName(); +} + +QGeoPositionInfo LogFilePositionSource::lastKnownPosition(bool /*fromSatellitePositioningMethodsOnly*/) const +{ + return lastPosition; +} + +LogFilePositionSource::PositioningMethods LogFilePositionSource::supportedPositioningMethods() const +{ + return AllPositioningMethods; +} + +int LogFilePositionSource::minimumUpdateInterval() const +{ + return 200; +} + +void LogFilePositionSource::startUpdates() +{ + int interval = updateInterval(); + if (interval < minimumUpdateInterval()) + interval = minimumUpdateInterval(); + + timer->start(interval); +} + +void LogFilePositionSource::stopUpdates() +{ + timer->stop(); +} + +void LogFilePositionSource::requestUpdate(int /*timeout*/) +{ + // For simplicity, ignore timeout - assume that if data is not available + // now, no data will be added to the file later + if (logFile->canReadLine()) + readNextPosition(); + else + emit updateTimeout(); +} + +void LogFilePositionSource::readNextPosition() +{ + QByteArray line = logFile->readLine().trimmed(); + if (!line.isEmpty()) { + QList data = line.split(' '); + double latitude; + double longitude; + bool hasLatitude = false; + bool hasLongitude = false; + QDateTime timestamp = QDateTime::fromString(QString(data.value(0)), Qt::ISODate); + latitude = data.value(1).toDouble(&hasLatitude); + longitude = data.value(2).toDouble(&hasLongitude); + + if (hasLatitude && hasLongitude && timestamp.isValid()) { + QGeoCoordinate coordinate(latitude, longitude); + QGeoPositionInfo info(coordinate, timestamp); + if (info.isValid()) { + lastPosition = info; + emit positionUpdated(info); + } + } + } +} + +QGeoPositionInfoSource::Error LogFilePositionSource::error() const +{ + return QGeoPositionInfoSource::UnknownSourceError; +} diff --git a/tests/auto/qgeoareamonitor/logfilepositionsource.h b/tests/auto/qgeoareamonitor/logfilepositionsource.h new file mode 100644 index 00000000..966b2540 --- /dev/null +++ b/tests/auto/qgeoareamonitor/logfilepositionsource.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOGFILEPOSITIONSOURCE_H +#define LOGFILEPOSITIONSOURCE_H + +#include + +QT_BEGIN_NAMESPACE +class QFile; +class QTimer; +QT_END_NAMESPACE + +class LogFilePositionSource : public QGeoPositionInfoSource +{ + Q_OBJECT +public: + LogFilePositionSource(QObject *parent = 0); + + QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const; + + PositioningMethods supportedPositioningMethods() const; + int minimumUpdateInterval() const; + Error error() const; + +public slots: + virtual void startUpdates(); + virtual void stopUpdates(); + + virtual void requestUpdate(int timeout = 5000); + +private slots: + void readNextPosition(); + +private: + QFile *logFile; + QTimer *timer; + QGeoPositionInfo lastPosition; +}; + +#endif diff --git a/tests/auto/qgeoareamonitor/qgeoareamonitor.pro b/tests/auto/qgeoareamonitor/qgeoareamonitor.pro index 05cc5ef5..35581bca 100644 --- a/tests/auto/qgeoareamonitor/qgeoareamonitor.pro +++ b/tests/auto/qgeoareamonitor/qgeoareamonitor.pro @@ -2,7 +2,12 @@ TEMPLATE = app CONFIG+=testcase TARGET=tst_qgeoareamonitor -SOURCES += tst_qgeoareamonitor.cpp +SOURCES += tst_qgeoareamonitor.cpp \ + logfilepositionsource.cpp + +HEADERS += logfilepositionsource.h + +OTHER_FILES += *.txt QT += positioning testlib DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qgeoareamonitor/simplelog.txt b/tests/auto/qgeoareamonitor/simplelog.txt new file mode 100644 index 00000000..5a14fb80 --- /dev/null +++ b/tests/auto/qgeoareamonitor/simplelog.txt @@ -0,0 +1,87 @@ +2009-08-24T22:24:34 -27.54 153.090718 +2009-08-24T22:24:35 -27.55 153.090718 +2009-08-24T22:24:36 -27.56 153.090718 +2009-08-24T22:24:37 -27.57 153.090718 +2009-08-24T22:24:38 -27.58 153.090783 +2009-08-24T22:24:39 -27.59 153.090845 +2009-08-24T22:24:40 -27.60 153.090908 +2009-08-24T22:24:41 -27.61 153.090971 +2009-08-24T22:24:42 -27.62 153.091036 +2009-08-24T22:24:43 -27.63 153.091102 +2009-08-24T22:24:44 -27.64 153.091167 +2009-08-24T22:24:45 -27.65 153.091232 +2009-08-24T22:24:46 -27.65 153.091298 +2009-08-24T22:24:47 -27.65 153.091366 +2009-08-24T22:24:48 -27.65 153.091435 +2009-08-24T22:24:49 -27.66 153.091507 +2009-08-24T22:24:50 -27.67 153.091581 +2009-08-24T22:24:51 -27.68 153.091654 +2009-08-24T22:24:52 -27.69 153.091729 +2009-08-24T22:24:53 -27.70 153.091800 +2009-08-24T22:24:54 -27.71 153.091870 +2009-08-24T22:24:55 -27.72 153.091940 +2009-08-24T22:24:56 -27.73 153.092010 +2009-08-24T22:24:57 -27.74 153.092078 +2009-08-24T22:24:58 -27.75 153.092144 +2009-08-24T22:24:59 -27.78 153.092218 +2009-08-24T22:25:00 -27.79 153.092308 +2009-08-24T22:25:01 -27.80 153.092415 +2009-08-24T22:25:02 -27.81 153.092530 +2009-08-24T22:25:03 -27.82 153.092648 +2009-08-24T22:25:04 -27.83 153.092763 +2009-08-24T22:25:05 -27.84 153.092879 +2009-08-24T22:25:06 -27.85 153.092990 +2009-08-24T22:25:07 -27.84 153.093099 +2009-08-24T22:25:08 -27.83 153.093204 +2009-08-24T22:25:09 -27.82 153.093303 +2009-08-24T22:25:10 -27.81 153.093396 +2009-08-24T22:25:11 -27.80 153.093484 +2009-08-24T22:25:12 -27.79 153.093568 +2009-08-24T22:25:13 -27.78 153.093647 +2009-08-24T22:25:14 -27.77 153.093727 +2009-08-24T22:25:15 -27.76 153.093810 +2009-08-24T22:25:16 -27.75 153.093896 +2009-08-24T22:25:17 -27.74 153.093984 +2009-08-24T22:25:18 -27.72 153.094074 +2009-08-24T22:25:19 -27.70 153.094168 +2009-08-24T22:25:20 -27.71 153.094267 +2009-08-24T22:25:21 -27.69 153.094370 +2009-08-24T22:25:22 -27.68 153.094474 +2009-08-24T22:25:23 -27.67 153.094581 +2009-08-24T22:25:24 -27.66 153.094688 +2009-08-24T22:25:25 -27.65 153.094796 +2009-08-24T22:25:26 -27.64 153.094905 +2009-08-24T22:25:27 -27.63 153.095012 +2009-08-24T22:25:28 -27.62 153.095121 +2009-08-24T22:25:29 -27.61 153.095231 +2009-08-24T22:25:30 -27.60 153.095340 +2009-08-24T22:25:31 -27.59 153.095449 +2009-08-24T22:25:32 -27.58 153.095558 +2009-08-24T22:25:33 -27.57 153.095667 +2009-08-24T22:25:34 -27.56 153.095776 +2009-08-24T22:25:35 -27.55 153.095885 +2009-08-24T22:25:36 -27.54 153.095995 +2009-08-24T22:25:37 -27.53 153.096109 +2009-08-24T22:25:38 -27.52 153.096226 +2009-08-24T22:25:39 -27.51 153.096337 +2009-08-24T22:25:40 -27.50 153.096441 +2009-08-24T22:25:41 -27.49 153.096537 +2009-08-24T22:25:42 -27.48 153.096628 +2009-08-24T22:25:43 -27.47 153.096714 +2009-08-24T22:25:44 -27.46 153.096795 +2009-08-24T22:25:45 -27.45 153.096847 +2009-08-24T22:25:46 -27.44 153.096855 +2009-08-24T22:25:47 -27.43 153.096873 +2009-08-24T22:25:48 -27.42 153.096875 +2009-08-24T22:25:49 -27.41 153.096878 +2009-08-24T22:25:50 -27.40 153.096880 +2009-08-24T22:25:51 -27.39 153.096880 +2009-08-24T22:25:52 -27.38 153.096881 +2009-08-24T22:25:53 -27.37 153.096882 +2009-08-24T22:25:54 -27.36 153.096883 +2009-08-24T22:25:55 -27.35 153.096883 +2009-08-24T22:25:56 -27.34 153.096883 +2009-08-24T22:25:57 -27.33 153.096890 +2009-08-24T22:25:58 -27.32 153.096919 +2009-08-24T22:25:59 -27.31 153.096985 +2009-08-24T22:26:00 -27.30 153.097060 diff --git a/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp b/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp index 347fca19..cd9894e5 100644 --- a/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp +++ b/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp @@ -48,41 +48,30 @@ #include #include -#include +#include +#include + +#include +#include #include #include +#include +#include +#include + +#include "logfilepositionsource.h" QT_USE_NAMESPACE -#define MINIMUM_TIMEOUT 5000 +#define UPDATE_INTERVAL 200 Q_DECLARE_METATYPE(QGeoPositionInfo) +Q_DECLARE_METATYPE(QGeoAreaMonitorInfo) - -class MyPositionAreaMonitor : public QGeoAreaMonitor -{ - Q_OBJECT -public: - MyPositionAreaMonitor(QObject* parent = 0) : QGeoAreaMonitor(parent) {} - ~MyPositionAreaMonitor() {} -}; - - -static qreal tst_qgeoareamonitor_minimumRadius() -{ - // tests should not be run with minimum radius in this case - return 0; -} - - -class tst_QGeoAreaMonitor : public QObject +class tst_QGeoAreaMonitorSource : public QObject { Q_OBJECT -private: - QGeoAreaMonitor* monitor; - - private slots: void initTestCase() { @@ -92,179 +81,628 @@ private slots: QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() + QStringLiteral("/../../../plugins")); qRegisterMetaType(); + qRegisterMetaType(); } void init() { - monitor = 0; } void cleanup() { - delete monitor; - monitor = 0; + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + + QList list = obj->activeMonitors(); + if (list.count() > 0) { + //cleanup installed monitors + foreach (const QGeoAreaMonitorInfo& info, list) { + QVERIFY(obj->stopMonitoring(info)); + } + } + QVERIFY(obj->activeMonitors().count() == 0); } void cleanupTestCase() { } - void coordinate() + void tst_monitor() { - MyPositionAreaMonitor mon; - QCOMPARE(mon.center(), QGeoCoordinate()); + QGeoAreaMonitorInfo defaultMonitor; + QVERIFY(defaultMonitor.name().isEmpty()); + QVERIFY(!defaultMonitor.identifier().isEmpty()); + QCOMPARE(defaultMonitor.isPersistent(), false); + QVERIFY(!defaultMonitor.area().isValid()); + QVERIFY(!defaultMonitor.isValid()); + QCOMPARE(defaultMonitor.expiration(), QDateTime()); + QCOMPARE(defaultMonitor.notificationParameters(), QVariantMap()); + + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + QVERIFY(!obj->startMonitoring(defaultMonitor)); + QCOMPARE(obj->activeMonitors().count(), 0); + QVERIFY(!obj->requestUpdate(defaultMonitor, + SIGNAL(areaEntered(QGeoMonitorInfo,QGeoAreaPositionInfo)))); + delete obj; + + //copy constructor based + QGeoAreaMonitorInfo copy(defaultMonitor); + QVERIFY(copy.name().isEmpty()); + QCOMPARE(copy.identifier(), defaultMonitor.identifier()); + QVERIFY(copy == defaultMonitor); + QVERIFY(!(copy != defaultMonitor)); + QCOMPARE(copy.isPersistent(), false); + + copy.setName(QString("my name")); + QCOMPARE(copy.name(), QString("my name")); + + + QDateTime now = QDateTime::currentDateTime().addSecs(1000); //little bit in the future + copy.setExpiration(now); + QVERIFY(copy != defaultMonitor); + QCOMPARE(copy.expiration(), now); + + QCOMPARE(copy.isPersistent(), defaultMonitor.isPersistent()); + copy.setPersistent(true); + QCOMPARE(copy.isPersistent(), true); + QCOMPARE(defaultMonitor.isPersistent(), false); + copy.setPersistent(false); + + QVERIFY(copy.area() == defaultMonitor.area()); + QVERIFY(!copy.area().isValid()); + copy.setArea(QGeoCircle(QGeoCoordinate(1, 2), 4)); + QVERIFY(copy.area().isValid()); + QVERIFY(copy.area() != defaultMonitor.area()); + QVERIFY(copy.area().contains(QGeoCoordinate(1, 2))); + + QVERIFY(copy.notificationParameters().isEmpty()); + QVariantMap map; + map.insert(QString("MyKey"), QVariant(123)); + copy.setNotificationParameters(map); + QVERIFY(!copy.notificationParameters().isEmpty()); + QCOMPARE(copy.notificationParameters().value(QString("MyKey")).toInt(), 123); + QCOMPARE(defaultMonitor.notificationParameters().value(QString("MyKey")).toInt(), 0); + + QCOMPARE(defaultMonitor.identifier(), copy.identifier()); + + //assignment operator based + QGeoAreaMonitorInfo assignmentCopy; + assignmentCopy = copy; + QVERIFY(copy == assignmentCopy); + QVERIFY(assignmentCopy != defaultMonitor); + + QVERIFY(assignmentCopy.area().contains(QGeoCoordinate(1, 2))); + QCOMPARE(assignmentCopy.expiration(), now); + QCOMPARE(assignmentCopy.isPersistent(), false); + QCOMPARE(assignmentCopy.notificationParameters().value(QString("MyKey")).toInt(), 123); + QCOMPARE(defaultMonitor.identifier(), assignmentCopy.identifier()); + QCOMPARE(assignmentCopy.name(), QString("my name")); + + //validity checks for requestUpdate() + obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + QCOMPARE(obj->activeMonitors().count(), 0); + //reference -> should work + QVERIFY(obj->requestUpdate(copy, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + QCOMPARE(obj->activeMonitors().count(), 1); + //replaces areaEntered single shot + QVERIFY(obj->requestUpdate(copy, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + QCOMPARE(obj->activeMonitors().count(), 1); + //replaces areaExited single shot + QVERIFY(obj->startMonitoring(copy)); + QCOMPARE(obj->activeMonitors().count(), 1); + + + //invalid signal + QVERIFY(!obj->requestUpdate(copy, 0)); + QCOMPARE(obj->activeMonitors().count(), 1); + + //signal that doesn't exist + QVERIFY(!obj->requestUpdate(copy, SIGNAL(areaEntered(QGeoMonitor)))); + QCOMPARE(obj->activeMonitors().count(), 1); + + QVERIFY(!obj->requestUpdate(copy, "SIGNAL(areaEntered(QGeoMonitor))")); + QCOMPARE(obj->activeMonitors().count(), 1); + + //ensure that we cannot add a persistent monitor to a source + //that doesn't support persistence + QGeoAreaMonitorInfo persistenceMonitor(copy); + persistenceMonitor.setPersistent(obj->supportedAreaMonitorFeatures() & QGeoAreaMonitorSource::PersistentAreaMonitorFeature); + persistenceMonitor.setPersistent(!persistenceMonitor.isPersistent()); + + QVERIFY(!obj->requestUpdate(persistenceMonitor, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + QCOMPARE(obj->activeMonitors().count(), 1); + QVERIFY(!obj->startMonitoring(persistenceMonitor)); + QCOMPARE(obj->activeMonitors().count(), 1); + + //ensure that persistence was only reason for rejection + persistenceMonitor.setPersistent(!persistenceMonitor.isPersistent()); + QVERIFY(obj->startMonitoring(persistenceMonitor)); + //persistenceMonitor is copy of already added monitor + //the last call was an update + QCOMPARE(obj->activeMonitors().count(), 1); + + delete obj; } - void radius() + void tst_monitorValid() { - MyPositionAreaMonitor mon; - qFuzzyCompare(mon.radius(), qreal(0.0)); + QGeoAreaMonitorInfo mon; + QVERIFY(!mon.isValid()); + QCOMPARE(mon.name(), QString()); + QCOMPARE(mon.area().isValid(), false); + + QGeoAreaMonitorInfo mon2 = mon; + QVERIFY(!mon2.isValid()); + + QGeoShape invalidShape; + QGeoCircle emptyCircle(QGeoCoordinate(0,1), 0); + QGeoCircle validCircle(QGeoCoordinate(0,1), 1); + + //all invalid since no name set yet + mon2.setArea(invalidShape); + QVERIFY(mon2.area() == invalidShape); + QVERIFY(!mon2.isValid()); + + mon2.setArea(emptyCircle); + QVERIFY(mon2.area() == emptyCircle); + QVERIFY(!mon2.isValid()); + + mon2.setArea(validCircle); + QVERIFY(mon2.area() == validCircle); + QVERIFY(!mon2.isValid()); + + //valid since name and non-empy shape has been set + QGeoAreaMonitorInfo validMonitor("TestMonitor"); + QVERIFY(validMonitor.name() == QString("TestMonitor")); + QVERIFY(!validMonitor.isValid()); + + validMonitor.setArea(invalidShape); + QVERIFY(validMonitor.area() == invalidShape); + QVERIFY(!validMonitor.isValid()); + + validMonitor.setArea(emptyCircle); + QVERIFY(validMonitor.area() == emptyCircle); + QVERIFY(!validMonitor.isValid()); + + validMonitor.setArea(validCircle); + QVERIFY(validCircle == validMonitor.area()); + QVERIFY(validMonitor.isValid()); } - void constructor_withoutParent() + void tst_monitorStreaming() { - MyPositionAreaMonitor *myMonitor = new MyPositionAreaMonitor(); - delete myMonitor; - } + QByteArray container; + QDataStream stream(&container, QIODevice::ReadWrite); - void constructor_withParent() - { - QObject* parent = new QObject; - new MyPositionAreaMonitor(parent); - delete parent; + QGeoAreaMonitorInfo monitor("someName"); + monitor.setArea(QGeoCircle(QGeoCoordinate(1,3), 5.4)); + QVERIFY(monitor.isValid()); + QCOMPARE(monitor.name(), QString("someName")); + + QGeoAreaMonitorInfo target; + QVERIFY(!target.isValid()); + QVERIFY(target.name().isEmpty()); + + QVERIFY(target != monitor); + + stream << monitor; + stream.device()->seek(0); + stream >> target; + + QVERIFY(target == monitor); + QVERIFY(target.isValid()); + QCOMPARE(target.name(), QString("someName")); + QVERIFY(target.area() == QGeoCircle(QGeoCoordinate(1,3), 5.4)); } - void createDefaultMonitor() + void tst_createDefaultSource() { QObject* parent = new QObject; - QGeoAreaMonitor* obj = QGeoAreaMonitor::createDefaultMonitor(parent); + QGeoAreaMonitorSource* obj = QGeoAreaMonitorSource::createDefaultSource(parent); QVERIFY(obj != 0); - delete parent; + QVERIFY(obj->parent() == parent); + delete obj; - const QStringList monitors = QGeoAreaMonitor::availableMonitors(); + const QStringList monitors = QGeoAreaMonitorSource::availableSources(); QVERIFY(!monitors.isEmpty()); QVERIFY(monitors.contains(QStringLiteral("positionpoll"))); - parent = new QObject; - obj = QGeoAreaMonitor::createMonitor(QStringLiteral("positionpoll"), parent); + obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), parent); QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); delete parent; - obj = QGeoAreaMonitor::createMonitor(QStringLiteral("randomNonExistingName"), 0); + obj = QGeoAreaMonitorSource::createSource(QStringLiteral("randomNonExistingName"), 0); QVERIFY(obj == 0); } - //TC_ID_4_x_1 - void center_createDefaultMonitor() + void tst_activeMonitors() { - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - QVERIFY(monitor->center().isValid() == false); - } - - //TC_ID_4_x_1 - void radius_createDefaultMonitor() - { - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - qFuzzyCompare(monitor->radius(), qreal(0.0)); - } - - void setCenter() - { - QFETCH(QGeoCoordinate, coord); - QFETCH(bool, validity); - - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - - monitor->setCenter(coord); - QCOMPARE(monitor->center().isValid(), validity); - if (validity) - QCOMPARE(monitor->center(), coord); - } - - void setCenter_data() - { - QTest::addColumn("coord"); - QTest::addColumn("validity"); - - QTest::newRow("valid coordinate") << QGeoCoordinate(34.56, -12.4, 56) << true; //TC_ID_4_x_1 - QTest::newRow("invalid coordinate") << QGeoCoordinate(173.2, -195.8) << false; //TC_ID_4_x_2 - QTest::newRow("uninitialised coordinate") << QGeoCoordinate() << false; //TC_ID_4_x_3 - } - - void setCenter_twice() - { - QFETCH(QGeoCoordinate, first_coord); - QFETCH(QGeoCoordinate, second_coord); - QFETCH(QGeoCoordinate, expected_coord); - - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - - monitor->setCenter(first_coord); - monitor->setCenter(second_coord); - QCOMPARE(monitor->center(), expected_coord); - } - - void setCenter_twice_data() - { - QTest::addColumn("first_coord"); - QTest::addColumn("second_coord"); - QTest::addColumn("expected_coord"); - - //TC_ID_4_x_4 - QTest::newRow("setting first valid then invalid coordinate") - << QGeoCoordinate(34.56, -12.4, 56) << QGeoCoordinate(173.2, -195.8) - << QGeoCoordinate(34.56, -12.4, 56); - //TC_ID_4_x_5 - QTest::newRow("setting first invalid then valid coordinate") - << QGeoCoordinate(173.2, -195.8) << QGeoCoordinate(34.56, -12.4, 56) - << QGeoCoordinate(34.56, -12.4, 56); - //TC_ID_4_x_6 - QTest::newRow("setting first valid then valid coordinate") - << QGeoCoordinate(-12.56, 101.4, 56) << QGeoCoordinate(34.56, -12.4, 56) - << QGeoCoordinate(34.56, -12.4, 56); + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + + LogFilePositionSource *source = new LogFilePositionSource(this); + source->setUpdateInterval(UPDATE_INTERVAL); + obj->setPositionInfoSource(source); + QCOMPARE(obj->positionInfoSource(), source); + + + QVERIFY(obj->activeMonitors().isEmpty()); + + QGeoAreaMonitorInfo mon("Monitor_Circle"); + mon.setArea(QGeoCircle(QGeoCoordinate(1,1), 1000)); + QVERIFY(obj->startMonitoring(mon)); + + QGeoAreaMonitorInfo mon2("Monitor_rectangle_below"); + QGeoRectangle r_below(QGeoCoordinate(1,1),2,2); + mon2.setArea(r_below); + QVERIFY(obj->startMonitoring(mon2)); + + QGeoAreaMonitorInfo mon3("Monitor_rectangle_above"); + QGeoRectangle r_above(QGeoCoordinate(2,1),2,2); + mon3.setArea(r_above); + QVERIFY(obj->startMonitoring(mon3)); + + QList results = obj->activeMonitors(); + QCOMPARE(results.count(), 3); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2 || info == mon3); + } + + results = obj->activeMonitors(QGeoShape()); + QCOMPARE(results.count(), 0); + + results = obj->activeMonitors(QGeoRectangle(QGeoCoordinate(1,1),0.2, 0.2)); + QCOMPARE(results.count(), 2); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2); + } + + results = obj->activeMonitors(QGeoCircle(QGeoCoordinate(1,1),1000)); + QCOMPARE(results.count(), 2); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2); + } + + results = obj->activeMonitors(QGeoCircle(QGeoCoordinate(2,1),1000)); + QCOMPARE(results.count(), 1); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon3); + } + + //same as above except that we use a different monitor source object instance + //all monitor objects of same type share same active monitors + QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(secondObj != 0); + QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll")); + + results = secondObj->activeMonitors(); + QCOMPARE(results.count(), 3); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2 || info == mon3); + } + + results = secondObj->activeMonitors(QGeoShape()); + QCOMPARE(results.count(), 0); + + results = secondObj->activeMonitors(QGeoRectangle(QGeoCoordinate(1,1),0.2, 0.2)); + QCOMPARE(results.count(), 2); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2); + } + + results = secondObj->activeMonitors(QGeoCircle(QGeoCoordinate(1,1),1000)); + QCOMPARE(results.count(), 2); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon || info == mon2); + } + + results = secondObj->activeMonitors(QGeoCircle(QGeoCoordinate(2,1),1000)); + QCOMPARE(results.count(), 1); + foreach (const QGeoAreaMonitorInfo& info, results) { + QVERIFY(info == mon3); + } + + delete obj; + delete secondObj; } - void setRadius() + void tst_testExpiryTimeout() { - QFETCH(qreal, radius); - QFETCH(qreal, expected_radius); - - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - - monitor->setRadius(radius); - qFuzzyCompare(monitor->radius(), expected_radius); + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + + QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(secondObj != 0); + QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll")); + + LogFilePositionSource *source = new LogFilePositionSource(this); + source->setUpdateInterval(UPDATE_INTERVAL); + obj->setPositionInfoSource(source); + + //Singleton pattern behind QGeoAreaMonitorSource ensures same position info source + QCOMPARE(obj->positionInfoSource(), source); + QCOMPARE(secondObj->positionInfoSource(), source); + + QSignalSpy expirySpy(obj, SIGNAL(monitorExpired(QGeoAreaMonitorInfo))); + QSignalSpy expirySpy2(secondObj, SIGNAL(monitorExpired(QGeoAreaMonitorInfo))); + + QDateTime now = QDateTime::currentDateTime(); + + const int monitorCount = 4; + for (int i = 1; i <= monitorCount; i++) { + QGeoAreaMonitorInfo mon(QString::number(i)); + mon.setArea(QGeoRectangle(QGeoCoordinate(i,i), i, i)); + mon.setExpiration(now.addSecs(i*5)); + QVERIFY(mon.isValid()); + QVERIFY(obj->startMonitoring(mon)); + } + + + + QCOMPARE(obj->activeMonitors().count(), monitorCount); + QCOMPARE(secondObj->activeMonitors().count(), monitorCount); + + QGeoAreaMonitorInfo info("InvalidExpiry"); + info.setArea(QGeoRectangle(QGeoCoordinate(10,10), 1, 1 )); + QVERIFY(info.isValid()); + info.setExpiration(now.addSecs(-1000)); + QVERIFY(info.expiration() < now); + QVERIFY(!obj->startMonitoring(info)); + QCOMPARE(obj->activeMonitors().count(), monitorCount); + QVERIFY(!obj->requestUpdate(info, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + QCOMPARE(obj->activeMonitors().count(), monitorCount); + + for (int i = 1; i <= monitorCount; i++) { + QTRY_VERIFY_WITH_TIMEOUT(expirySpy.count() == 1, 7000); //each expiry within 5 s + QGeoAreaMonitorInfo mon = expirySpy.takeFirst().at(0).value(); + QCOMPARE(obj->activeMonitors().count(), monitorCount-i); + QCOMPARE(mon.name(), QString::number(i)); + } + + QCOMPARE(expirySpy2.count(), monitorCount); + QCOMPARE(secondObj->activeMonitors().count(), 0); //all monitors expired + for (int i = 1; i <= monitorCount; i++) { + QGeoAreaMonitorInfo mon = expirySpy2.takeFirst().at(0).value(); + QCOMPARE(mon.name(), QString::number(i)); + } + + delete obj; + delete secondObj; } - void setRadius_data() + void tst_enteredExitedSignal() { - QTest::addColumn("radius"); - QTest::addColumn("expected_radius"); - - QTest::newRow("zero radius") << qreal(0.0) << tst_qgeoareamonitor_minimumRadius(); //TC_ID_4_x_1 - QTest::newRow("radius ok") << qreal(1000.58) << qreal(1000.58); //TC_ID_4_x_2 - QTest::newRow("negative radius") << qreal(-876.58) << tst_qgeoareamonitor_minimumRadius(); //TC_ID_4_x_3 - QTest::newRow("float min") << qreal(FLT_MIN) << tst_qgeoareamonitor_minimumRadius(); //TC_ID_4 - QTest::newRow("float max") << qreal(FLT_MAX) << qreal(FLT_MAX); //TC_ID_4_x_4_x_5 + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + obj->setObjectName("firstObject"); + QSignalSpy enteredSpy(obj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); + QSignalSpy exitedSpy(obj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); + + LogFilePositionSource *source = new LogFilePositionSource(this); + source->setUpdateInterval(UPDATE_INTERVAL); + obj->setPositionInfoSource(source); + QCOMPARE(obj->positionInfoSource(), source); + + QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(secondObj != 0); + QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll")); + QSignalSpy enteredSpy2(secondObj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); + QSignalSpy exitedSpy2(secondObj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); + secondObj->setObjectName("secondObject"); + + QGeoAreaMonitorInfo infoRectangle("Rectangle"); + infoRectangle.setArea(QGeoRectangle(QGeoCoordinate(-27.65, 153.093), 0.2, 0.2)); + QVERIFY(infoRectangle.isValid()); + QVERIFY(obj->startMonitoring(infoRectangle)); + + QGeoAreaMonitorInfo infoCircle("Circle"); + infoCircle.setArea(QGeoCircle(QGeoCoordinate(-27.70, 153.093),10000)); + QVERIFY(infoCircle.isValid()); + QVERIFY(obj->startMonitoring(infoCircle)); + + QGeoAreaMonitorInfo singleShot_enter("SingleShot_on_Entered"); + singleShot_enter.setArea(QGeoRectangle(QGeoCoordinate(-27.67, 153.093), 0.2, 0.2)); + QVERIFY(singleShot_enter.isValid()); + QVERIFY(obj->requestUpdate(singleShot_enter, + SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + + QGeoAreaMonitorInfo singleShot_exit("SingleShot_on_Exited"); + singleShot_exit.setArea(QGeoRectangle(QGeoCoordinate(-27.70, 153.093), 0.2, 0.2)); + QVERIFY(singleShot_exit.isValid()); + QVERIFY(obj->requestUpdate(singleShot_exit, + SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo)))); + + QVERIFY(obj->activeMonitors().count() == 4); //all monitors active + QVERIFY(secondObj->activeMonitors().count() == 4); //all monitors active + + static const int Number_Of_Entered_Events = 6; + static const int Number_Of_Exited_Events = 5; + //takes 87 (lines)*200(timeout)/1000 seconds to finish + QTRY_VERIFY_WITH_TIMEOUT(enteredSpy.count() == Number_Of_Entered_Events, 20000); + QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == Number_Of_Exited_Events, 20000); + QCOMPARE(enteredSpy.count(), Number_Of_Entered_Events); + QCOMPARE(exitedSpy.count(), Number_Of_Exited_Events); + + QList monitorsInExpectedEnteredEventOrder; + monitorsInExpectedEnteredEventOrder << infoRectangle << singleShot_enter << singleShot_exit + << infoCircle << infoCircle << infoRectangle; + + QList monitorsInExpectedExitedEventOrder; + monitorsInExpectedExitedEventOrder << infoRectangle << infoCircle + << singleShot_exit << infoCircle << infoRectangle; + + QList enteredEventCoordinateOrder; + enteredEventCoordinateOrder << QGeoCoordinate(-27.55, 153.090718) //infoRectangle + << QGeoCoordinate(-27.57, 153.090718) //singleshot_enter + << QGeoCoordinate(-27.60, 153.090908) //singleshot_exit + << QGeoCoordinate(-27.62, 153.091036) //infoCircle + << QGeoCoordinate(-27.78, 153.093647) //infoCircle + << QGeoCoordinate(-27.75, 153.093896);//infoRectangle + QCOMPARE(enteredEventCoordinateOrder.count(), Number_Of_Entered_Events); + QCOMPARE(monitorsInExpectedEnteredEventOrder.count(), Number_Of_Entered_Events); + + QList exitedEventCoordinateOrder; + exitedEventCoordinateOrder << QGeoCoordinate(-27.78, 153.092218) //infoRectangle + << QGeoCoordinate(-27.79, 153.092308) //infoCircle + << QGeoCoordinate(-27.81, 153.092530) //singleshot_exit + << QGeoCoordinate(-27.61, 153.095231) //infoCircle + << QGeoCoordinate(-27.54, 153.095995);//infoCircle + QCOMPARE(exitedEventCoordinateOrder.count(), Number_Of_Exited_Events); + QCOMPARE(monitorsInExpectedExitedEventOrder.count(), Number_Of_Exited_Events); + + //verify that both sources got the same signals + for (int i = 0; i < Number_Of_Entered_Events; i++) { + //first source + QGeoAreaMonitorInfo monInfo = enteredSpy.first().at(0).value(); + QGeoPositionInfo posInfo = enteredSpy.takeFirst().at(1).value(); + QVERIFY2(monInfo == monitorsInExpectedEnteredEventOrder.at(i), + qPrintable(QString::number(i) + ": " + monInfo.name())); + QVERIFY2(posInfo.coordinate() == enteredEventCoordinateOrder.at(i), + qPrintable(QString::number(i) + ". posInfo")); + + //reset info objects to avoid comparing the same + monInfo = QGeoAreaMonitorInfo(); + posInfo = QGeoPositionInfo(); + + //second source + monInfo = enteredSpy2.first().at(0).value(); + posInfo = enteredSpy2.takeFirst().at(1).value(); + QVERIFY2(monInfo == monitorsInExpectedEnteredEventOrder.at(i), + qPrintable(QString::number(i) + ": " + monInfo.name())); + QVERIFY2(posInfo.coordinate() == enteredEventCoordinateOrder.at(i), + qPrintable(QString::number(i) + ". posInfo")); + } + + for (int i = 0; i < Number_Of_Exited_Events; i++) { + //first source + QGeoAreaMonitorInfo monInfo = exitedSpy.first().at(0).value(); + QGeoPositionInfo posInfo = exitedSpy.takeFirst().at(1).value(); + QVERIFY2(monInfo == monitorsInExpectedExitedEventOrder.at(i), + qPrintable(QString::number(i) + ": " + monInfo.name())); + QVERIFY2(posInfo.coordinate() == exitedEventCoordinateOrder.at(i), + qPrintable(QString::number(i) + ". posInfo")); + + //reset info objects to avoid comparing the same + monInfo = QGeoAreaMonitorInfo(); + posInfo = QGeoPositionInfo(); + + //second source + monInfo = exitedSpy2.first().at(0).value(); + posInfo = exitedSpy2.takeFirst().at(1).value(); + QVERIFY2(monInfo == monitorsInExpectedExitedEventOrder.at(i), + qPrintable(QString::number(i) + ": " + monInfo.name())); + QVERIFY2(posInfo.coordinate() == exitedEventCoordinateOrder.at(i), + qPrintable(QString::number(i) + ". posInfo")); + } + + QCOMPARE(obj->activeMonitors().count(), 2); //single shot monitors have been removed + QCOMPARE(secondObj->activeMonitors().count(), 2); + + delete obj; + delete secondObj; } - //TC_ID_4_x_6 - void setRadius_twice() + void tst_swapOfPositionSource() { - monitor = QGeoAreaMonitor::createDefaultMonitor(0); - QVERIFY(monitor != 0); - - monitor->setRadius(qreal(1235.985)); - monitor->setRadius(qreal(6754.075)); - - qFuzzyCompare(monitor->radius(), qreal(6754.075f)); + QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj != 0); + QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll")); + obj->setObjectName("firstObject"); + QSignalSpy enteredSpy(obj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); + QSignalSpy exitedSpy(obj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); + + QGeoAreaMonitorSource *obj2 = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0); + QVERIFY(obj2 != 0); + QCOMPARE(obj2->sourceName(), QStringLiteral("positionpoll")); + obj2->setObjectName("secondObject"); + QSignalSpy enteredSpy2(obj2, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); + QSignalSpy exitedSpy2(obj2, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); + + LogFilePositionSource *source = new LogFilePositionSource(this); + source->setUpdateInterval(UPDATE_INTERVAL); + source->setObjectName("FirstLogFileSource"); + + LogFilePositionSource *source2 = new LogFilePositionSource(this); + source2->setUpdateInterval(UPDATE_INTERVAL); + source2->setObjectName("SecondLogFileSource"); + + obj->setPositionInfoSource(source); + QCOMPARE(obj->positionInfoSource(), obj2->positionInfoSource()); + QCOMPARE(obj2->positionInfoSource(), source); + + QGeoAreaMonitorInfo infoRectangle("Rectangle"); + infoRectangle.setArea(QGeoRectangle(QGeoCoordinate(-27.70, 153.092), 0.2, 0.2)); + QVERIFY(infoRectangle.isValid()); + QVERIFY(obj->startMonitoring(infoRectangle)); + + QCOMPARE(obj->activeMonitors().count(), 1); + QCOMPARE(obj2->activeMonitors().count(), 1); + + QGeoCoordinate firstBorder(-27.6, 153.090908); + QGeoCoordinate secondBorder(-27.81, 153.092530); + + /***********************************/ + //1. trigger events on source (until areaExit + QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == 1, 20000); + QCOMPARE(enteredSpy.count(), enteredSpy2.count()); + QCOMPARE(exitedSpy.count(), exitedSpy2.count()); + + //compare entered event + QVERIFY(enteredSpy.first().at(0).value() == + enteredSpy2.first().at(0).value()); + QGeoPositionInfo info = enteredSpy.takeFirst().at(1).value(); + QVERIFY(info == enteredSpy2.takeFirst().at(1).value()); + QVERIFY(info.coordinate() == firstBorder); + //compare exit event + QVERIFY(exitedSpy.first().at(0).value() == + exitedSpy2.first().at(0).value()); + info = exitedSpy.takeFirst().at(1).value(); + QVERIFY(info == exitedSpy2.takeFirst().at(1).value()); + QVERIFY(info.coordinate() == secondBorder); + + QCOMPARE(exitedSpy.count(), 0); + QCOMPARE(enteredSpy.count(), 0); + QCOMPARE(exitedSpy2.count(), 0); + QCOMPARE(enteredSpy2.count(), 0); + + /***********************************/ + //2. change position source -> which restarts at beginning again + obj2->setPositionInfoSource(source2); + QCOMPARE(obj->positionInfoSource(), obj2->positionInfoSource()); + QCOMPARE(obj2->positionInfoSource(), source2); + + QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == 1, 20000); + QCOMPARE(enteredSpy.count(), enteredSpy2.count()); + QCOMPARE(exitedSpy.count(), exitedSpy2.count()); + + //compare entered event + QVERIFY(enteredSpy.first().at(0).value() == + enteredSpy2.first().at(0).value()); + info = enteredSpy.takeFirst().at(1).value(); + QVERIFY(info == enteredSpy2.takeFirst().at(1).value()); + QVERIFY(info.coordinate() == firstBorder); + //compare exit event + QVERIFY(exitedSpy.first().at(0).value() == + exitedSpy2.first().at(0).value()); + info = exitedSpy.takeFirst().at(1).value(); + QVERIFY(info == exitedSpy2.takeFirst().at(1).value()); + QVERIFY(info.coordinate() == secondBorder); + + + //obj was deleted when setting new source + delete obj2; } }; -QTEST_GUILESS_MAIN(tst_QGeoAreaMonitor) +QTEST_GUILESS_MAIN(tst_QGeoAreaMonitorSource) #include "tst_qgeoareamonitor.moc" -- cgit v1.2.3