Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgeopositioninfosource_android.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "jnipositioning.h"
6#include <QGeoPositionInfo>
7#include <QVariantMap>
8
9using namespace Qt::StringLiterals;
10
11static constexpr int kUpdateFromColdStart = 2 * 60 * 1000;
12static constexpr int kRegularUpdatesTimerInterval = 30 * 1000;
13
14static constexpr auto kUseAltitudeConverter = "useMslAltitude"_L1;
15
17 QObject *parent) :
19{
20 androidClassKeyForUpdate = AndroidPositioning::registerPositionInfoSource(this);
21 androidClassKeyForSingleRequest = AndroidPositioning::registerPositionInfoSource(this);
22
23 parseParameters(parameters);
24
25 //by default use all methods
27
28 m_requestTimer.setSingleShot(true);
29 connect(&m_requestTimer, &QTimer::timeout, this,
30 &QGeoPositionInfoSourceAndroid::requestTimeout);
31
32 m_regularUpdatesTimer.setSingleShot(false);
33 connect(&m_regularUpdatesTimer, &QTimer::timeout, this,
34 &QGeoPositionInfoSourceAndroid::regularUpdatesTimeout);
35}
36
38{
40
41 if (m_requestTimer.isActive()) {
42 m_requestTimer.stop();
43 AndroidPositioning::stopUpdates(androidClassKeyForSingleRequest);
44 }
45
47 AndroidPositioning::unregisterPositionInfoSource(androidClassKeyForSingleRequest);
48}
49
51{
52 int previousInterval = updateInterval();
53 msec = (((msec > 0) && (msec < minimumUpdateInterval())) || msec < 0)? minimumUpdateInterval() : msec;
54
55 if (msec == previousInterval)
56 return;
57
59
60 if (updatesRunning)
61 reconfigureRunningSystem();
62}
63
64QGeoPositionInfo QGeoPositionInfoSourceAndroid::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
65{
66 return AndroidPositioning::lastKnownPosition(fromSatellitePositioningMethodsOnly,
68}
69
70QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceAndroid::supportedPositioningMethods() const
71{
73}
74
75void QGeoPositionInfoSourceAndroid::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods)
76{
77 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
79 if (previousPreferredPositioningMethods == preferredPositioningMethods())
80 return;
81
82 if (updatesRunning)
83 reconfigureRunningSystem();
84}
85
90
95
97{
98 return m_useAltitudeConverter;
99}
100
101void QGeoPositionInfoSourceAndroid::setError(Error error)
102{
103 m_error = error;
106}
107
108void QGeoPositionInfoSourceAndroid::parseParameters(const QVariantMap &parameters)
109{
110 m_useAltitudeConverter = parameters.value(kUseAltitudeConverter, false).toBool();
111}
112
114{
115 if (updatesRunning)
116 return;
117
119
120 if (preferredPositioningMethods() == 0) {
121 setError(UnknownSourceError);
122 return;
123 }
124
125 updatesRunning = true;
126 // Start calculating updates from now.
127 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
128 m_regularUpdatesErrorRaised = false;
131 updatesRunning = false;
132 setError(error);
133 } else {
134 m_regularUpdatesTimer.start(kRegularUpdatesTimerInterval);
135 }
136}
137
139{
140 if (!updatesRunning)
141 return;
142
143 updatesRunning = false;
144 m_regularUpdatesTimer.stop();
145 AndroidPositioning::stopUpdates(androidClassKeyForUpdate);
146}
147
149{
150 if (m_requestTimer.isActive())
151 return;
152
154
155 if (timeout != 0 && timeout < minimumUpdateInterval()) {
157 return;
158 }
159
160 if (timeout == 0)
162
163 m_requestTimer.start(timeout);
164
165 // if updates already running with interval equal to timeout
166 // then we wait for next update coming through
167 // assume that a single update will not be quicker than regular updates anyway
168 if (updatesRunning && updateInterval() <= timeout)
169 return;
170
172 AndroidPositioning::requestUpdate(androidClassKeyForSingleRequest, timeout);
174 m_requestTimer.stop();
175 setError(error);
176 }
177}
178
180{
181 //single update request and served as part of regular update
182 if (m_requestTimer.isActive())
183 m_requestTimer.stop();
184
185 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
186 m_regularUpdatesErrorRaised = false;
187
188 emit positionUpdated(pInfo);
189}
190
191// Might still be called multiple times (once for each provider)
193{
194 //timeout but we received a late update -> ignore
195 if (!m_requestTimer.isActive())
196 return;
197
198 queuedSingleUpdates.append(pInfo);
199 // Calculate the maximum amount of possibly received updates. It depends on
200 // preferred positioning methods. Two updates if we have both Satellite and
201 // Network, and only one otherwise.
202 const qsizetype maxPossibleUpdates =
204 ? 2 : 1;
205 // If we get the maximum number of updates, we do not need to wait for more
206 if (queuedSingleUpdates.size() == maxPossibleUpdates) {
207 m_requestTimer.stop();
208 requestTimeout();
209 }
210}
211
213{
214 if (updatesRunning && !m_regularUpdatesErrorRaised) {
215 m_regularUpdatesErrorRaised = true;
217 }
218
220}
221
226
227void QGeoPositionInfoSourceAndroid::requestTimeout()
228{
229 AndroidPositioning::stopUpdates(androidClassKeyForSingleRequest);
230 //no queued update to process -> timeout
231
232 if (queuedSingleUpdates.isEmpty()) {
234 return;
235 }
236
237 auto byAccuracy = [](const QGeoPositionInfo &info, const QGeoPositionInfo &best) {
238 //anything newer by 20s is always better
239 const qint64 timeDelta = best.timestamp().secsTo(info.timestamp());
240 if (abs(timeDelta) > 20)
241 return timeDelta > 0;
242
243 //compare accuracy
244 if (info.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) &&
245 best.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
246 {
249 }
250
251 //prefer info with accuracy information
253 return true;
254
255 return false;
256 };
257
258 QGeoPositionInfo best = *std::min_element(queuedSingleUpdates.begin(),
259 queuedSingleUpdates.end(), byAccuracy);
260 queuedSingleUpdates.clear();
261 emit positionUpdated(best);
262}
263
264void QGeoPositionInfoSourceAndroid::regularUpdatesTimeout()
265{
266 if (!m_regularUpdatesErrorRaised) {
268 if ((now - m_lastUpdateTime) > (updateInterval() + kUpdateFromColdStart)) {
269 m_regularUpdatesErrorRaised = true;
271 }
272 }
273}
274
275/*
276 Updates the system assuming that updateInterval
277 and/or preferredPositioningMethod have changed.
278 */
279void QGeoPositionInfoSourceAndroid::reconfigureRunningSystem()
280{
281 if (!updatesRunning)
282 return;
283
284 stopUpdates();
285 startUpdates();
286}
static JNINativeMethod methods[]
static qint64 currentMSecsSinceEpoch() noexcept
QGeoPositionInfoSourceAndroid(const QVariantMap &parameters, QObject *parent=0)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly=false) const override
Returns an update containing the last known position, or a null update if none is available.
void processSinglePositionUpdate(const QGeoPositionInfo &pInfo)
virtual void requestUpdate(int timeout=0) override
void processPositionUpdate(const QGeoPositionInfo &pInfo)
void setPreferredPositioningMethods(PositioningMethods methods) override
Error error() const override
Returns the type of error that last occurred.
PositioningMethods supportedPositioningMethods() const override
Returns the positioning methods available to this source.
\inmodule QtPositioning
int updateInterval
This property holds the requested interval in milliseconds between each update.
void positionUpdated(const QGeoPositionInfo &update)
If startUpdates() or requestUpdate() is called, this signal is emitted when an update becomes availab...
void errorOccurred(QGeoPositionInfoSource::Error)
This signal is emitted after an error occurred.
virtual void setPreferredPositioningMethods(PositioningMethods methods)
void supportedPositioningMethodsChanged()
This signal is emitted when the supported positioning methods changed.
Error
The Error enumeration represents the errors which can occur.
virtual void setUpdateInterval(int msec)
PositioningMethods preferredPositioningMethods
Sets the preferred positioning methods for this source.
\inmodule QtPositioning
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
iterator end()
Definition qlist.h:626
iterator begin()
Definition qlist.h:625
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void setSingleShot(bool singleShot)
Definition qtimer.cpp:552
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
Definition qtimer.cpp:167
void stop()
Stops the timer.
Definition qtimer.cpp:267
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
void unregisterPositionInfoSource(int key)
int registerPositionInfoSource(QObject *obj)
QGeoPositionInfoSource::Error requestUpdate(int androidClassKey, int timeout)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly, bool useAltitudeConverter)
QGeoPositionInfoSource::Error startUpdates(int androidClassKey)
QGeoPositionInfoSource::PositioningMethods availableProviders()
void stopUpdates(int androidClassKey)
DBusConnection const char DBusError * error
static constexpr int kUpdateFromColdStart
static constexpr int kRegularUpdatesTimerInterval
static constexpr auto kUseAltitudeConverter
GLbitfield GLuint64 timeout
[4]
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
QHostInfo info
[0]