1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtPositioning module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <QGeoAreaMonitorSource>
41 #include "qgeopositioninfosourcefactory.h"
42 #include "qgeopositioninfosource_p.h"
43 
44 /*!
45     \class QGeoAreaMonitorSource
46     \inmodule QtPositioning
47     \ingroup QtPositioning-positioning
48     \since 5.2
49 
50     \brief The QGeoAreaMonitorSource class enables the detection of proximity
51     changes for a specified set of coordinates.
52 
53     A QGeoAreaMonitorSource emits signals when the current position is in
54     range, or has moved out of range, of a specified area.
55     Each area is specified by a \l QGeoAreaMonitorInfo object.
56     For example:
57 
58     \snippet cpp/cppqml.cpp BigBen
59 
60     \c QGeoAreaMonitorSource follows a singleton pattern. Each instance of
61     the class with the same \l sourceName() shares the same area monitoring backend.
62     If a new \l QGeoAreaMonitorInfo object is added via \l startMonitoring()
63     or \l requestUpdate() it can be retrieved by another instance of this class
64     (provided that they are sourced from the same area monitor provider plug-in).
65     The same singleton pattern applies to the \l QGeoPositionInfoSource instance
66     used by this class. The following code snippet emphasizes the behavior:
67 
68     \code
69         QGeoAreaMonitorSource *s1 = QGeoAreaMonitorSource::createSource("blah", this);
70         QGeoAreaMonitorSource *s2 = QGeoAreaMonitorSource::createSource("blah", this);
71         QVERIFY(s1->positionInfoSource() == s2->positionInfoSource);
72     \endcode
73 */
74 
75 QT_BEGIN_NAMESPACE
76 
77 
78 
79 class QGeoAreaMonitorSourcePrivate
80 {
81 public:
82     QGeoPositionInfoSource *source;
83     QString providerName;
84 };
85 
86 /*!
87     \enum QGeoAreaMonitorSource::Error
88     Defines the types of positioning methods.
89 
90     The Error enumeration represents the errors which can occur.
91 
92     \value AccessError The connection setup to the remote area monitoring backend failed because the
93         application lacked the required privileges.
94     \value InsufficientPositionInfo The area monitoring source could not retrieve a location fix or
95         the accuracy of the fix is not high enough to provide an effective area monitoring.
96     \value NoError No error has occurred.
97     \value UnknownSourceError An unidentified error occurred.
98 */
99 
100 /*!
101     \enum QGeoAreaMonitorSource::AreaMonitorFeature
102     Defines the types of area monitoring capabilities.
103 
104     \value PersistentAreaMonitorFeature QGeoAreaMonitorInfo instances can be made persistent.
105     A persistent monitor continues to be active even when the application managing the monitor is
106     not running.
107     \value AnyAreaMonitorFeature Matches all possible area monitoring features.
108 */
109 
110 /*!
111     \fn virtual AreaMonitoringFeatures QGeoAreaMonitorSource::supportedAreaMonitorFeatures() const = 0;
112 
113     Returns the area monitoring features available to this source.
114 */
115 
116 /*!
117      \fn virtual QGeoAreaMonitorSource::Error QGeoAreaMonitorSource::error() const
118 
119      Returns the type of error that last occurred.
120 */
121 
122 /*!
123     Creates a monitor with the given \a parent.
124 */
QGeoAreaMonitorSource(QObject * parent)125 QGeoAreaMonitorSource::QGeoAreaMonitorSource(QObject *parent)
126         : QObject(parent),
127         d(new QGeoAreaMonitorSourcePrivate)
128 {
129     d->source = 0;
130 }
131 
132 /*!
133     Destroys the monitor.
134 */
~QGeoAreaMonitorSource()135 QGeoAreaMonitorSource::~QGeoAreaMonitorSource()
136 {
137     delete d;
138 }
139 
140 /*!
141     Creates and returns a monitor with the given \a parent that
142     monitors areas using resources on the underlying system.
143 
144     Returns 0 if the system has no support for position monitoring.
145 */
createDefaultSource(QObject * parent)146 QGeoAreaMonitorSource *QGeoAreaMonitorSource::createDefaultSource(QObject *parent)
147 {
148     QList<QJsonObject> plugins = QGeoPositionInfoSourcePrivate::pluginsSorted();
149     foreach (const QJsonObject &obj, plugins) {
150         if (obj.value(QStringLiteral("Monitor")).isBool()
151                 && obj.value(QStringLiteral("Monitor")).toBool())
152         {
153             QGeoPositionInfoSourcePrivate d;
154             d.metaData = obj;
155             d.loadPlugin();
156             QGeoAreaMonitorSource *s = 0;
157             if (d.factory)
158                 s = d.factory->areaMonitor(parent);
159             if (s)
160                 s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString();
161             return s;
162         }
163     }
164 
165     return 0;
166 }
167 
168 /*!
169     Creates and returns a monitor with the given \a parent,
170     by loading the plugin named \a sourceName.
171 
172     Returns 0 if the plugin cannot be found.
173 */
createSource(const QString & sourceName,QObject * parent)174 QGeoAreaMonitorSource *QGeoAreaMonitorSource::createSource(const QString &sourceName, QObject *parent)
175 {
176     QHash<QString, QJsonObject> plugins = QGeoPositionInfoSourcePrivate::plugins();
177     if (plugins.contains(sourceName)) {
178         QGeoPositionInfoSourcePrivate d;
179         d.metaData = plugins.value(sourceName);
180         d.loadPlugin();
181         QGeoAreaMonitorSource *s = 0;
182         if (d.factory)
183             s = d.factory->areaMonitor(parent);
184         if (s)
185             s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString();
186         return s;
187     }
188 
189     return 0;
190 }
191 
192 /*!
193     Returns a list of available monitor plugins, including the default system
194     backend if one is available.
195 */
availableSources()196 QStringList QGeoAreaMonitorSource::availableSources()
197 {
198     QStringList plugins;
199     const QHash<QString, QJsonObject> meta = QGeoPositionInfoSourcePrivate::plugins();
200     for (auto it = meta.cbegin(), end = meta.cend(); it != end; ++it) {
201         if (it.value().value(QStringLiteral("Monitor")).isBool()
202                 && it.value().value(QStringLiteral("Monitor")).toBool()) {
203             plugins << it.key();
204         }
205     }
206 
207     return plugins;
208 }
209 
210 /*!
211     Returns the unique name of the area monitor source implementation in use.
212 
213     This is the same name that can be passed to createSource() in order to
214     create a new instance of a particular area monitor source implementation.
215 */
sourceName() const216 QString QGeoAreaMonitorSource::sourceName() const
217 {
218     return d->providerName;
219 }
220 
221 /*!
222     Returns the current QGeoPositionInfoSource used by this QGeoAreaMonitorSource
223     object. The function will return \l QGeoPositionInfoSource::createDefaultSource()
224     if no other object has been set.
225 
226     The function returns 0 if not even a default QGeoPositionInfoSource exists.
227 
228     Any usage of the returned \l QGeoPositionInfoSource instance should account
229     for the fact that it may reside in a different thread.
230 
231     \sa QGeoPositionInfoSource, setPositionInfoSource()
232 */
positionInfoSource() const233 QGeoPositionInfoSource* QGeoAreaMonitorSource::positionInfoSource() const
234 {
235     return d->source;
236 }
237 
238 /*!
239     Sets the new \l QGeoPositionInfoSource to be used by this QGeoAreaMonitorSource object.
240     The area monitoring backend becomes the new QObject parent for \a newSource.
241     The previous \l QGeoPositionInfoSource object will be deleted. All QGeoAreaMonitorSource
242     instances based on the same \l sourceName() share the same QGeoPositionInfoSource
243     instance.
244 
245     This may be useful when it is desirable to manipulate the positioning system
246     used by the area monitoring engine.
247 
248     Note that ownership must be taken care of by subclasses of QGeoAreaMonitorSource.
249     Due to the singleton pattern behind this class \a newSource may be moved to a
250     new thread.
251 
252     \sa positionInfoSource()
253  */
setPositionInfoSource(QGeoPositionInfoSource * newSource)254 void QGeoAreaMonitorSource::setPositionInfoSource(QGeoPositionInfoSource *newSource)
255 {
256     d->source = newSource;
257 }
258 
259 
260 /*!
261     \fn virtual bool QGeoAreaMonitorSource::startMonitoring(const QGeoAreaMonitorInfo &monitor)
262 
263     Returns \c true if the monitoring of \a monitor could be successfully started; otherwise
264     returns false. A reason for not being able to start monitoring could be the unavailability
265     of an appropriate default position info source while no alternative QGeoPositionInfoSource
266     has been set via \l setPositionInfoSource().
267 
268     If \a monitor is already active the existing monitor object will be replaced by the new \a monitor reference.
269     The identification of QGeoAreaMonitorInfo instances happens via \l QGeoAreaMonitorInfo::identifier().
270     Therefore this function can also be used to update active monitors.
271 
272     If \a monitor has an expiry date that has been passed this function returns false. Calling
273     this function for an already via \l requestUpdate() registered single shot monitor
274     switches the monitor to a permanent monitoring mode.
275 
276     Requesting persistent monitoring on a QGeoAreaMonitorSource instance fails if the area monitoring
277     backend doesn't support \l QGeoAreaMonitorSource::PersistentAreaMonitorFeature.
278 
279     \sa stopMonitoring()
280 */
281 
282 /*!
283     \fn virtual bool QGeoAreaMonitorSource::requestUpdate(const QGeoAreaMonitorInfo &monitor, const char *signal)
284 
285     Enables single shot area monitoring. Area monitoring for \a monitor will be performed
286     until this QGeoAreaMonitorSource instance emits \a signal for the first time. Once
287     the signal was emitted, \a monitor is automatically removed from the list of \l activeMonitors().
288     If \a monitor is invalid or has an expiry date that has been passed this function returns false.
289 
290     \code
291         QGeoAreaMonitor singleShotMonitor;
292         QGeoAreaMonitorSource * source = QGeoAreaMonitorSource::createDefaultSource(this);
293         //...
294         bool ret = source->requestUpdate(singleShotMonitor,
295                               SIGNAL(areaExited(QGeoAreaMonitor,QGeoPositionInfo)));
296     \endcode
297 
298     The above \c singleShotMonitor object will cease to send updates once the \l areaExited() signal
299     was emitted for the first time. Until this point in time any other signal may be emitted
300     zero or more times depending on the area context.
301 
302     It is not possible to simultanously request updates for more than one signal of the same monitor object.
303     The last call to this function determines the signal upon which the updates cease to continue.
304     At this stage only the \l areaEntered() and \l areaExited() signals can be used to
305     terminate the monitoring process.
306 
307     Requesting persistent monitoring on a QGeoAreaMonitorSource instance fails if the area monitoring
308     backend doesn't support \l QGeoAreaMonitorSource::PersistentAreaMonitorFeature.
309 
310     If \a monitor was already registered via \l startMonitoring() it is converted to a single
311     shot behavior.
312 
313     \sa startMonitoring(), stopMonitoring()
314  */
315 
316 /*!
317     \fn virtual bool QGeoAreaMonitorSource::stopMonitoring(const QGeoAreaMonitorInfo &monitor)
318 
319     Returns true if \a monitor was successfully removed from the list of \l activeMonitors();
320     otherwise returns false. This behavior is independent on whether \a monitor was registered
321     via \l startMonitoring() or \l requestUpdate().
322 */
323 
324 /*!
325     \fn virtual QList<QGeoAreaMonitorInfo> QGeoAreaMonitorSource::activeMonitors() const
326 
327     Returns the list of all active monitors known to the QGeoAreaMonitorSource object.
328 
329     An active monitor was started via startMonitoring() the source object will emit
330     the required signals such as areaEntered() or areaExited(). Multiple \l QGeoAreaMonitorSource
331     instances within the same application share the same active monitor objects.
332 
333     Unless an active QGeoAreaMonitorInfo \l {QGeoAreaMonitorInfo::isPersistent()}{isPersistent()} an active QGeoAreaMonitorInfo
334     will be stopped once the current application terminates.
335 */
336 
337 /*!
338     \fn virtual QList<QGeoAreaMonitorInfo> QGeoAreaMonitorSource::activeMonitors(const QGeoShape &lookupArea) const
339 
340     Returns the list of all active monitors known to the QGeoAreaMonitorSource object whose
341     center lies within \a lookupArea. If \a lookupArea is empty the returned list will be empty.
342 
343     An active monitor was started via startMonitoring() and the source object will emit
344     the required signals such as areaEntered() or areaExited(). Multiple QGeoAreaMonitorSource
345     instances within the same application share the same monitor objects.
346 
347     Unless an active QGeoAreaMonitorInfo \l {QGeoAreaMonitorInfo::isPersistent()}{isPersistent()} an active QGeoAreaMonitorInfo
348     will be stopped once the current application terminates.
349 
350     \sa QGeoShape
351 */
352 
353 
354 /*!
355     \fn void QGeoAreaMonitorSource::monitorExpired(const QGeoAreaMonitorInfo &monitor)
356 
357     Emitted when \a monitor has expired. An expired area monitor is automatically
358     removed from the list of \l activeMonitors().
359 
360     \sa activeMonitors()
361 */
362 
363 /*!
364     \fn void QGeoAreaMonitorSource::areaEntered(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update)
365 
366     Emitted when the current position has moved from a position outside of the active \a monitor
367     to a position within the monitored area.
368 
369     The \a update holds the new position.
370 */
371 
372 /*!
373     \fn void QGeoAreaMonitorSource::areaExited(const QGeoAreaMonitorInfo &monitor, const QGeoPositionInfo &update)
374 
375     Emitted when the current position has moved from a position within the active \a monitor
376     to a position outside the monitored area.
377 
378     The \a update holds the new position.
379 */
380 
381 /*!
382     \fn void QGeoAreaMonitorSource::error(QGeoAreaMonitorSource::Error areaMonitoringError)
383 
384     This signal is emitted after an error occurred. The \a areaMonitoringError
385     parameter describes the type of error that occurred.
386 
387 */
388 
389 QT_END_NAMESPACE
390