Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qgeopositioninfosource.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
// Qt-Security score:significant reason:default
4
#
include
<
qgeopositioninfosource
.
h
>
5
#
include
"qgeopositioninfosource_p.h"
6
#
include
"qgeopositioninfosourcefactory.h"
7
8
#
include
<
QFile
>
9
#
include
<
QPluginLoader
>
10
#
include
<
QStringList
>
11
#
include
<
QCryptographicHash
>
12
#
include
<
QtCore
/
private
/
qfactoryloader_p
.
h
>
13
#
include
<
QtCore
/
private
/
qthread_p
.
h
>
14
15
#
include
<
algorithm
>
16
17
QT_BEGIN_NAMESPACE
18
19
Q_GLOBAL_STATIC_WITH_ARGS
(QFactoryLoader, loader,
20
(
"org.qt-project.qt.position.sourcefactory/6.0"
,
21
QLatin1String(
"/position"
)))
22
23
/*!
24
\class QGeoPositionInfoSource
25
\inmodule QtPositioning
26
\ingroup QtPositioning-positioning
27
\since 5.2
28
29
\brief The QGeoPositionInfoSource class is an abstract base class for the distribution of positional updates.
30
31
The static function QGeoPositionInfoSource::createDefaultSource() creates a default
32
position source that is appropriate for the platform, if one is available.
33
Otherwise, QGeoPositionInfoSource will check for available plugins that
34
implement the QGeoPositionInfoSourceFactory interface.
35
36
Users of a QGeoPositionInfoSource subclass can request the current position using
37
requestUpdate(), or start and stop regular position updates using
38
startUpdates() and stopUpdates(). When an update is available,
39
positionUpdated() is emitted. The last known position can be accessed with
40
lastKnownPosition().
41
42
If regular position updates are required, setUpdateInterval() can be used
43
to specify how often these updates should be emitted. If no interval is
44
specified, updates are simply provided whenever they are available.
45
For example:
46
47
\code
48
// Emit updates every 10 seconds if available
49
QGeoPositionInfoSource *source = QGeoPositionInfoSource::createDefaultSource(0);
50
if (source)
51
source->setUpdateInterval(10000);
52
\endcode
53
54
To remove an update interval that was previously set, call
55
setUpdateInterval() with a value of 0.
56
57
\note The position source may have a minimum value requirement for
58
update intervals, as returned by minimumUpdateInterval().
59
60
\note To use this class from Android service, see
61
\l {Qt Positioning on Android}.
62
*/
63
64
/*!
65
\enum QGeoPositionInfoSource::PositioningMethod
66
Defines the types of positioning methods.
67
68
\value NoPositioningMethods None of the positioning methods.
69
\value SatellitePositioningMethods Satellite-based positioning methods such as GPS or GLONASS.
70
\value NonSatellitePositioningMethods Other positioning methods such as 3GPP cell identifier or WiFi based positioning.
71
\value AllPositioningMethods Satellite-based positioning methods as soon as available. Otherwise non-satellite based methods.
72
*/
73
74
QGeoPositionInfoSourcePrivate::~QGeoPositionInfoSourcePrivate()
75
{
76
77
}
78
79
QGeoPositionInfoSourceFactory *QGeoPositionInfoSourcePrivate::loadFactory(
const
QCborMap &meta)
80
{
81
const
int
idx =
static_cast
<
int
>(meta.value(QStringLiteral(
"index"
)).toDouble());
82
if
(idx < 0)
83
return
nullptr
;
84
QObject *instance = loader()->instance(idx);
85
if
(!instance)
86
return
nullptr
;
87
return
qobject_cast<QGeoPositionInfoSourceFactory *>(instance);
88
}
89
90
QMultiHash<QString, QCborMap> QGeoPositionInfoSourcePrivate::plugins(
bool
reload)
91
{
92
static
QMultiHash<QString, QCborMap> plugins;
93
static
bool
alreadyDiscovered =
false
;
94
95
if
(reload ==
true
)
96
alreadyDiscovered =
false
;
97
98
if
(!alreadyDiscovered) {
99
loadPluginMetadata(plugins);
100
alreadyDiscovered =
true
;
101
}
102
return
plugins;
103
}
104
105
static
bool
pluginComparator
(
const
QCborMap &p1,
const
QCborMap &p2)
106
{
107
const
QString prio = QStringLiteral(
"Priority"
);
108
if
(p1.contains(prio) && !p2.contains(prio))
109
return
true
;
110
if
(!p1.contains(prio) && p2.contains(prio))
111
return
false
;
112
if
(p1.value(prio).isDouble() && !p2.value(prio).isDouble())
113
return
true
;
114
if
(!p1.value(prio).isDouble() && p2.value(prio).isDouble())
115
return
false
;
116
return
(p1.value(prio).toDouble() > p2.value(prio).toDouble());
117
}
118
119
QList<QCborMap> QGeoPositionInfoSourcePrivate::pluginsSorted()
120
{
121
QList<QCborMap> list = plugins().values();
122
std::stable_sort(list.begin(), list.end(), pluginComparator);
123
return
list;
124
}
125
126
void
QGeoPositionInfoSourcePrivate::loadPluginMetadata(QMultiHash<QString, QCborMap> &plugins)
127
{
128
QFactoryLoader *l = loader();
129
QList<QPluginParsedMetaData> meta = l->metaData();
130
for
(qsizetype i = 0; i < meta.size(); ++i) {
131
QCborMap obj = meta.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
132
const
QLatin1String testableKey(
"Testable"
);
133
if
(!obj.value(testableKey).toBool(
true
)) {
134
static
bool
inTest = qEnvironmentVariableIsSet(
"QT_QTESTLIB_RUNNING"
);
135
if
(inTest)
136
continue
;
137
}
138
obj.insert(QLatin1String(
"index"
),
static_cast
<qint64>(i));
139
plugins.insert(obj.value(QStringLiteral(
"Provider"
)).toString(), obj);
140
}
141
}
142
143
/*!
144
Creates a position source with the specified \a parent.
145
*/
146
147
QGeoPositionInfoSource::QGeoPositionInfoSource(QObject *parent)
148
: QObject(*
new
QGeoPositionInfoSourcePrivate, parent)
149
{
150
qRegisterMetaType<QGeoPositionInfo>();
151
}
152
153
/*!
154
Destroys the position source.
155
*/
156
QGeoPositionInfoSource::~QGeoPositionInfoSource()
157
{
158
}
159
160
/*!
161
\property QGeoPositionInfoSource::sourceName
162
\brief This property holds the unique name of the position source
163
implementation in use.
164
165
This is the same name that can be passed to createSource() in order to
166
create a new instance of a particular position source implementation.
167
*/
168
QString QGeoPositionInfoSource::sourceName()
const
169
{
170
Q_D(
const
QGeoPositionInfoSource);
171
return
d->sourceName;
172
}
173
174
/*!
175
Sets the backend-specific property named \a name to \a value.
176
Returns \c true on success, \c false otherwise.
177
Backend-specific properties can be used to configure the positioning subsystem behavior
178
at runtime.
179
Supported backend-specific properties are listed and described in
180
\l {Qt Positioning plugins#Default plugins}.
181
182
\sa backendProperty
183
\since Qt 5.14
184
*/
185
bool
QGeoPositionInfoSource::setBackendProperty(
const
QString &name,
const
QVariant &value)
186
{
187
Q_UNUSED(name)
188
Q_UNUSED(value)
189
return
false
;
190
}
191
192
/*!
193
Returns the value of the backend-specific property named \a name, if present.
194
Otherwise, the returned value will be invalid.
195
Supported backend-specific properties are listed and described in
196
\l {Qt Positioning plugins#Default plugins}.
197
198
\sa setBackendProperty
199
\since Qt 5.14
200
*/
201
QVariant QGeoPositionInfoSource::backendProperty(
const
QString &name)
const
202
{
203
Q_UNUSED(name)
204
return
QVariant();
205
}
206
207
/*!
208
\property QGeoPositionInfoSource::updateInterval
209
\brief This property holds the requested interval in milliseconds between each update.
210
211
If the update interval is not set (or is set to 0) the
212
source will provide updates as often as necessary.
213
214
If the update interval is set, the source will provide updates at an
215
interval as close to the requested interval as possible. If the requested
216
interval is less than the minimumUpdateInterval(),
217
the minimum interval is used instead.
218
219
Changes to the update interval will happen as soon as is practical, however the
220
time the change takes may vary between implementations. Whether or not the elapsed
221
time from the previous interval is counted as part of the new interval is also
222
implementation dependent.
223
224
The default value for this property is 0.
225
226
\note Subclass implementations must call the base implementation of
227
\c {setUpdateInterval()} so that \c {updateInterval()} returns the correct
228
value.
229
230
\note This property can't be used to tune update frequency on iOS and macOS,
231
because their APIs do not provide such possibility. On these systems this
232
parameter is only used to set \l UpdateTimeoutError and trigger an
233
\l errorOccurred signal if the update is not received within the desired
234
interval.
235
*/
236
void
QGeoPositionInfoSource::setUpdateInterval(
int
msec)
237
{
238
Q_D(QGeoPositionInfoSource);
239
d->interval = msec;
240
}
241
242
int
QGeoPositionInfoSource::updateInterval()
const
243
{
244
Q_D(
const
QGeoPositionInfoSource);
245
return
d->interval.value();
246
}
247
248
QBindable<
int
> QGeoPositionInfoSource::bindableUpdateInterval()
249
{
250
Q_D(QGeoPositionInfoSource);
251
return
QBindable<
int
>(&d->interval);
252
}
253
254
/*!
255
\property QGeoPositionInfoSource::preferredPositioningMethods
256
257
\brief Sets the preferred positioning methods for this source.
258
259
If new methods include a method that is not supported by the source, the
260
unsupported method will be ignored.
261
262
If new methods do not include a single method available/supported by the
263
source, the preferred methods will be set to the set of methods which the
264
source has available. If the source has no method availabe (e.g. because its
265
Location service is turned off or it does not offer a Location service),
266
the passed methods are accepted as they are.
267
268
The default value for this property is \l {QGeoPositionInfoSource::}
269
{NoPositioningMethods}.
270
271
\note Subclass implementations must call the base implementation of
272
\c {setPreferredPositioningMethods()} to ensure
273
\c {preferredPositioningMethods()} returns the correct value.
274
275
\sa supportedPositioningMethods()
276
*/
277
void
QGeoPositionInfoSource::setPreferredPositioningMethods(PositioningMethods methods)
278
{
279
Q_D(QGeoPositionInfoSource);
280
d->methods.removeBindingUnlessInWrapper();
281
// The supported positioning methods can change during the calls to this
282
// method, so we can't have a simple check like:
283
// if (currentMethods == methods) return;
284
// Instead we need to save the current value and compare it afterwards
285
const
auto
prevMethods = d->methods.valueBypassingBindings();
286
287
if
(supportedPositioningMethods() != QGeoPositionInfoSource::NoPositioningMethods) {
288
d->methods.setValueBypassingBindings(methods & supportedPositioningMethods());
289
if
(d->methods.valueBypassingBindings() == 0) {
290
d->methods.setValueBypassingBindings(supportedPositioningMethods());
291
}
292
}
else
{
// avoid that turned of Location service blocks any changes to d->methods
293
d->methods.setValueBypassingBindings(methods);
294
}
295
if
(prevMethods != d->methods.valueBypassingBindings())
296
d->methods.notify();
297
}
298
299
QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSource::preferredPositioningMethods()
const
300
{
301
Q_D(
const
QGeoPositionInfoSource);
302
return
d->methods.value();
303
}
304
305
QBindable<QGeoPositionInfoSource::PositioningMethods>
306
QGeoPositionInfoSource::bindablePreferredPositioningMethods()
307
{
308
Q_D(QGeoPositionInfoSource);
309
return
QBindable<PositioningMethods>(&d->methods);
310
}
311
312
/*!
313
\class QGeoPositionInfoSourcePrivate
314
\inmodule QtPositioning
315
\internal
316
*/
317
QGeoPositionInfoSource *QGeoPositionInfoSourcePrivate::createSourceReal(
const
QCborMap &meta,
const
QVariantMap ¶meters, QObject *parent)
318
{
319
QGeoPositionInfoSource *s =
nullptr
;
320
auto
factory = QGeoPositionInfoSourcePrivate::loadFactory(meta);
321
if
(factory)
322
s = factory->positionInfoSource(parent, parameters);
323
if
(s)
324
s->d_func()->sourceName = meta.value(QStringLiteral(
"Provider"
)).toString();
325
326
return
s;
327
}
328
329
/*!
330
Creates and returns a position source with the given \a parent that
331
reads from the system's default sources of location data, or the plugin
332
with the highest available priority.
333
334
Returns \c nullptr if the system has no default position source, no valid
335
plugins could be found or the user does not have the permission to access
336
the current position.
337
*/
338
QGeoPositionInfoSource *QGeoPositionInfoSource::createDefaultSource(QObject *parent)
339
{
340
return
createDefaultSource(QVariantMap(), parent);
341
}
342
343
/*!
344
Creates and returns a position source with the given \a parent that
345
reads from the system's default sources of location data, or the plugin
346
with the highest available priority.
347
348
Returns \c nullptr if the system has no default position source, no valid plugins
349
could be found or the user does not have the permission to access the current position.
350
351
This method passes \a parameters to the factory to configure the source.
352
353
\since Qt 5.14
354
*/
355
QGeoPositionInfoSource *QGeoPositionInfoSource::createDefaultSource(
const
QVariantMap ¶meters, QObject *parent)
356
{
357
const
QList<QCborMap> plugins = QGeoPositionInfoSourcePrivate::pluginsSorted();
358
for
(
const
QCborMap &obj : plugins) {
359
if
(obj.value(QStringLiteral(
"Position"
)).isBool()
360
&& obj.value(QStringLiteral(
"Position"
)).toBool()) {
361
QGeoPositionInfoSource *source = QGeoPositionInfoSourcePrivate::createSourceReal(obj, parameters, parent);
362
if
(source)
363
return
source;
364
}
365
}
366
return
nullptr
;
367
}
368
369
/*!
370
Creates and returns a position source with the given \a parent,
371
by loading the plugin named \a sourceName.
372
373
Returns \c nullptr if the plugin cannot be found.
374
*/
375
QGeoPositionInfoSource *QGeoPositionInfoSource::createSource(
const
QString &sourceName, QObject *parent)
376
{
377
return
createSource(sourceName, QVariantMap(), parent);
378
}
379
380
/*!
381
Creates and returns a position source with the given \a parent,
382
by loading the plugin named \a sourceName.
383
384
Returns \c nullptr if the plugin cannot be found.
385
386
This method passes \a parameters to the factory to configure the source.
387
388
\since Qt 5.14
389
*/
390
QGeoPositionInfoSource *QGeoPositionInfoSource::createSource(
const
QString &sourceName,
const
QVariantMap ¶meters, QObject *parent)
391
{
392
auto
plugins = QGeoPositionInfoSourcePrivate::plugins();
393
if
(plugins.contains(sourceName))
394
return
QGeoPositionInfoSourcePrivate::createSourceReal(plugins.value(sourceName), parameters, parent);
395
return
nullptr
;
396
}
397
398
/*!
399
Returns a list of available source plugins. This includes any default backend
400
plugin for the current platform.
401
*/
402
QStringList QGeoPositionInfoSource::availableSources()
403
{
404
QStringList plugins;
405
const
auto
meta = QGeoPositionInfoSourcePrivate::plugins();
406
for
(
auto
it = meta.cbegin(), end = meta.cend(); it != end; ++it) {
407
if
(it.value().value(QStringLiteral(
"Position"
)).isBool()
408
&& it.value().value(QStringLiteral(
"Position"
)).toBool()) {
409
plugins << it.key();
410
}
411
}
412
413
return
plugins;
414
}
415
416
QGeoPositionInfoSource::QGeoPositionInfoSource(QGeoPositionInfoSourcePrivate &dd, QObject *parent)
417
: QObject(dd, parent)
418
{
419
qRegisterMetaType<QGeoPositionInfo>();
420
Q_D(QGeoPositionInfoSource);
421
d->interval.setValueBypassingBindings(0);
422
d->methods.setValueBypassingBindings(NoPositioningMethods);
423
}
424
425
/*!
426
\fn QGeoPositionInfo QGeoPositionInfoSource::lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const = 0;
427
428
Returns an update containing the last known position, or a null update
429
if none is available.
430
431
If \a fromSatellitePositioningMethodsOnly is true, this returns the last
432
known position received from a satellite positioning method; if none
433
is available, a null update is returned.
434
*/
435
436
/*!
437
\fn virtual PositioningMethods QGeoPositionInfoSource::supportedPositioningMethods() const = 0;
438
439
Returns the positioning methods available to this source. Availability is defined as being usable
440
at the time of calling this function. Therefore user settings like turned off location service or
441
limitations to Satellite-based position providers are reflected by this function. Runtime notifications
442
when the status changes can be obtained via \l supportedPositioningMethodsChanged().
443
444
Not all platforms distinguish the different positioning methods or communicate the current user
445
configuration of the device. The following table provides an overview of the current platform situation:
446
447
\table
448
\header
449
\li Platform
450
\li Brief Description
451
\row
452
\li Android
453
\li Individual provider status and general Location service state are known and communicated
454
when location service is active.
455
\row
456
\li GeoClue
457
\li Hardcoced to always return AllPositioningMethods.
458
\row
459
\li GeoClue2
460
\li Individual providers are not distinguishable but disabled Location services reflected.
461
\row
462
\li iOS
463
\li Hardcoced to always return AllPositioningMethods.
464
\row
465
\li macOS
466
\li Hardcoced to always return AllPositioningMethods.
467
\row
468
\li Windows (UWP)
469
\li Individual providers are not distinguishable but disabled Location services reflected.
470
\endtable
471
472
\sa supportedPositioningMethodsChanged(), setPreferredPositioningMethods()
473
*/
474
475
476
/*!
477
\property QGeoPositionInfoSource::minimumUpdateInterval
478
\brief This property holds the minimum time (in milliseconds) required to retrieve a position update.
479
480
This is the minimum value accepted by setUpdateInterval() and
481
requestUpdate().
482
*/
483
484
485
/*!
486
\fn virtual void QGeoPositionInfoSource::startUpdates() = 0;
487
488
Starts emitting updates at regular intervals as specified by setUpdateInterval().
489
490
If setUpdateInterval() has not been called, the source will emit updates
491
as soon as they become available.
492
493
An errorOccurred() signal with the \l {QGeoPositionInfoSource::}
494
{UpdateTimeoutError} will be emitted if this QGeoPositionInfoSource subclass
495
determines that it will not be able to provide regular updates. This could
496
happen if a satellite fix is lost or if a hardware error is detected.
497
Position updates will recommence if the data becomes available later on.
498
The \l {QGeoPositionInfoSource::}{UpdateTimeoutError} error will not
499
be emitted again until after the periodic updates resume.
500
501
\note Since Qt6 this method always resets the last error to
502
\l {QGeoPositionInfoSource::}{NoError} before starting the updates.
503
504
\note To understand how to use this method from an Android service, see
505
\l {Qt Positioning on Android}.
506
507
On iOS, starting from version 8, Core Location framework requires additional
508
entries in the application's Info.plist with keys NSLocationAlwaysUsageDescription or
509
NSLocationWhenInUseUsageDescription and a string to be displayed in the authorization prompt.
510
The key NSLocationWhenInUseUsageDescription is used when requesting permission
511
to use location services while the app is in the foreground.
512
The key NSLocationAlwaysUsageDescription is used when requesting permission
513
to use location services whenever the app is running (both the foreground and the background).
514
If both entries are defined, NSLocationWhenInUseUsageDescription has a priority in the
515
foreground mode.
516
*/
517
518
/*!
519
\fn virtual void QGeoPositionInfoSource::stopUpdates() = 0;
520
521
Stops emitting updates at regular intervals.
522
*/
523
524
/*!
525
\fn virtual void QGeoPositionInfoSource::requestUpdate(int timeout = 0);
526
527
Attempts to get the current position and emit positionUpdated() with
528
this information. If the current position cannot be found within the given \a timeout
529
(in milliseconds) or if \a timeout is less than the value returned by
530
minimumUpdateInterval(), an errorOccurred() signal with the
531
\l {QGeoPositionInfoSource::}{UpdateTimeoutError} is emitted.
532
533
If the timeout is zero, the timeout defaults to a reasonable timeout
534
period as appropriate for the source.
535
536
This does nothing if another update request is in progress. However
537
it can be called even if startUpdates() has already been called and
538
regular updates are in progress.
539
540
If the source uses multiple positioning methods, it tries to get the
541
current position from the most accurate positioning method within the
542
given timeout.
543
544
\note Since Qt6 this method always resets the last error to
545
\l {QGeoPositionInfoSource::}{NoError} before requesting
546
the position.
547
548
\note To understand how to use this method from an Android service, see
549
\l {Qt Positioning on Android}.
550
*/
551
552
/*!
553
\fn virtual QGeoPositionInfoSource::Error QGeoPositionInfoSource::error() const;
554
555
Returns the type of error that last occurred.
556
557
\note Since Qt6 the last error is always reset when calling startUpdates()
558
or requestUpdate().
559
*/
560
561
/*!
562
\fn void QGeoPositionInfoSource::positionUpdated(const QGeoPositionInfo &update);
563
564
If startUpdates() or requestUpdate() is called, this signal is emitted
565
when an update becomes available.
566
567
The \a update value holds the value of the new update.
568
*/
569
570
/*!
571
\fn void QGeoPositionInfoSource::errorOccurred(QGeoPositionInfoSource::Error positioningError)
572
573
This signal is emitted after an error occurred. The \a positioningError
574
parameter describes the type of error that occurred.
575
*/
576
577
/*!
578
\enum QGeoPositionInfoSource::Error
579
580
The Error enumeration represents the errors which can occur.
581
582
\value AccessError The connection setup to the remote positioning backend failed because the
583
application lacked the required privileges.
584
\value ClosedError The remote positioning backend closed the connection, which happens for example in case
585
the user is switching location services to off. As soon as the location service is re-enabled
586
regular updates will resume.
587
\value NoError No error has occurred.
588
\value UnknownSourceError An unidentified error occurred.
589
\value [since 6.2] UpdateTimeoutError If requestUpdate() was called, this
590
error indicates that the current position could not be retrieved within
591
the specified timeout. If startUpdates() was called, this error
592
indicates that this QGeoPositionInfoSource subclass determined that it
593
will not be able to provide further regular updates. In the latter case
594
the error would not be emitted again until after the regular updates
595
resume.
596
*/
597
598
/*!
599
\fn void QGeoPositionInfoSource::supportedPositioningMethodsChanged()
600
601
This signal is emitted when the supported positioning methods changed. The cause for a change could be
602
a user turning Location services on/off or restricting Location services to certain types (e.g. GPS only).
603
Note that changes to the supported positioning methods cannot be detected on all platforms.
604
\l supportedPositioningMethods() provides an overview of the current platform support.
605
606
\since Qt 5.12
607
*/
608
609
QT_END_NAMESPACE
610
611
#
include
"moc_qgeopositioninfosource.cpp"
pluginComparator
static bool pluginComparator(const QCborMap &p1, const QCborMap &p2)
Definition
qgeopositioninfosource.cpp:105
Q_GLOBAL_STATIC_WITH_ARGS
Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash,({ { qMetaTypeId< QCameraPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QMicrophonePermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QBluetoothPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QContactsPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QCalendarPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QLocationPermission >(), Qt::PermissionStatus::Undetermined } }))
qtpositioning
src
positioning
qgeopositioninfosource.cpp
Generated on
for Qt by
1.18.0