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_cl.mm
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 <QtCore/QTimerEvent>
6#include <QtCore/QDebug>
7#include <QtCore/qdatetime.h>
8#include <QtCore/qglobal.h>
9#include <QtCore/private/qglobal_p.h>
10#include <QtCore/qtimezone.h>
11#include <QtCore/QPermission>
12#include <QtCore/QCoreApplication>
13
14
15#define MINIMUM_UPDATE_INTERVAL 1000
16
17@interface PositionLocationDelegate : NSObject <CLLocationManagerDelegate>
18@end
19
20@implementation PositionLocationDelegate
21{
22 QGeoPositionInfoSourceCL *m_positionInfoSource;
23}
24
25- (instancetype)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
26{
27 if ((self = [self init])) {
28 m_positionInfoSource = positionInfoSource;
29 }
30 return self;
31}
32
33- (void)locationManagerDidChangeAuthorization: (CLLocationManager *)manager
34{
35 // Since Qt 6.6 the application requests the desired permissions.
36 // This delegate method is invoked always upon CLLocationManager
37 // instantiation, and later if authorization status changes.
38 m_positionInfoSource->changeAuthorizationStatus([manager authorizationStatus]);
39}
40
41- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
42{
44 Q_UNUSED(oldLocation);
45
46 // Convert location timestamp to QDateTime
47 NSTimeInterval locationTimeStamp = [newLocation.timestamp timeIntervalSince1970];
48 const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(qRound64(locationTimeStamp * 1000),
50
51 // Construct position info from location data
52 QGeoPositionInfo location(QGeoCoordinate(newLocation.coordinate.latitude,
53 newLocation.coordinate.longitude,
54 newLocation.altitude),
55 timeStamp);
56 if (newLocation.horizontalAccuracy >= 0)
57 location.setAttribute(QGeoPositionInfo::HorizontalAccuracy, newLocation.horizontalAccuracy);
58 if (newLocation.verticalAccuracy >= 0)
59 location.setAttribute(QGeoPositionInfo::VerticalAccuracy, newLocation.verticalAccuracy);
60 if (newLocation.course >= 0) {
61 location.setAttribute(QGeoPositionInfo::Direction, newLocation.course);
62 if (__builtin_available(iOS 13.4, macOS 10.15.4, *)) {
63 if (newLocation.courseAccuracy >= 0) {
65 newLocation.courseAccuracy);
66 }
67 }
68 }
69 if (newLocation.speed >= 0)
70 location.setAttribute(QGeoPositionInfo::GroundSpeed, newLocation.speed);
71
72 m_positionInfoSource->locationDataAvailable(location);
73}
74
75- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
76{
78 m_positionInfoSource->setError(QGeoPositionInfoSource::AccessError);
79
80 qWarning() << QString::fromNSString([error localizedDescription]);
81
82 if ([error code] == 0
83 && QString::fromNSString([error domain]) == QStringLiteral("kCLErrorDomain"))
84 qWarning() << "(is Wi-Fi turned on?)";
85}
86@end
87
89
91 : QGeoPositionInfoSource(parent),
92 m_locationManager(0),
93 m_updatesWanted(false),
94 m_updateTimer(0),
95 m_updateTimeout(0),
96 m_positionError(QGeoPositionInfoSource::NoError)
97{
98}
99
101{
102 stopUpdates();
103 [m_locationManager release];
104}
105
107{
108 // If msec is 0 we send updates as data becomes available, otherwise we force msec to be equal
109 // to or larger than the minimum update interval.
110 if (msec != 0 && msec < minimumUpdateInterval())
111 msec = minimumUpdateInterval();
112
114
115 // Must timeout if update takes longer than specified interval
116 m_updateTimeout = msec;
117 if (m_updatesWanted)
118 setTimeoutInterval(m_updateTimeout);
119}
120
121bool QGeoPositionInfoSourceCL::enableLocationManager()
122{
123 if (!m_locationManager) {
124 m_locationManager = [[CLLocationManager alloc] init];
125
126#if defined(Q_OS_IOS)
127 NSDictionary<NSString *, id> *infoDict = [[NSBundle mainBundle] infoDictionary];
128 if (id value = [infoDict objectForKey:@"UIBackgroundModes"]) {
129 if ([value isKindOfClass:[NSArray class]]) {
130 NSArray *modes = static_cast<NSArray *>(value);
131 for (id mode in modes) {
132 if ([@"location" isEqualToString:mode]) {
133 m_locationManager.allowsBackgroundLocationUpdates = YES;
134 break;
135 }
136 }
137 }
138 }
139#endif
140
141 m_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
142 m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:this];
143 }
144
145 return qApp->checkPermission(QLocationPermission{}) == Qt::PermissionStatus::Granted;
146}
147
148void QGeoPositionInfoSourceCL::setTimeoutInterval(int msec)
149{
150 // Start timeout timer
151 if (m_updateTimer) killTimer(m_updateTimer);
152 if (msec > 0) m_updateTimer = startTimer(msec);
153 else m_updateTimer = 0;
154}
155
157{
158 m_positionError = QGeoPositionInfoSource::NoError;
159 m_updatesWanted = true;
160 if (enableLocationManager()) {
161 [m_locationManager startUpdatingLocation];
162 setTimeoutInterval(m_updateTimeout);
163 } else {
165 }
166}
167
169{
170 if (m_locationManager) {
171 [m_locationManager stopUpdatingLocation];
172 m_updatesWanted = false;
173
174 // Stop timeout timer
175 setTimeoutInterval(0);
176 } else {
178 }
179}
180
182{
183 // Get a single update within timeframe
184 m_positionError = QGeoPositionInfoSource::NoError;
185 if (timeout < minimumUpdateInterval() && timeout != 0)
187 else if (enableLocationManager()) {
188 // This will force LM to generate a new update
189 [m_locationManager stopUpdatingLocation];
190 [m_locationManager startUpdatingLocation];
191 setTimeoutInterval(timeout);
192 } else {
194 }
195}
196
198{
199#ifndef Q_OS_MACOS
200 if (status == kCLAuthorizationStatusAuthorizedAlways
201 || status == kCLAuthorizationStatusAuthorizedWhenInUse
202#else
203 if (status == kCLAuthorizationStatusAuthorized
204#endif
205 ) {
206 if (m_updatesWanted)
207 startUpdates();
208 }
209}
210
212{
213 // Update timed out?
214 if (event->timerId() == m_updateTimer) {
216
217 // Only timeout once since last data
218 setTimeoutInterval(0);
219
220 // Started for single update?
221 if (!m_updatesWanted)
222 stopUpdates();
223 }
224}
225
226QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceCL::supportedPositioningMethods() const
227{
228 // CoreLocation doesn't say which positioning method(s) it used
230}
231
236
238{
239 // Signal position data available
240 m_lastUpdate = location;
242
243 // Started for single update?
244 if (!m_updatesWanted)
245 stopUpdates();
246 // ...otherwise restart timeout timer
247 else setTimeoutInterval(m_updateTimeout);
248}
249
250QGeoPositionInfo QGeoPositionInfoSourceCL::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
251{
252 Q_UNUSED(fromSatellitePositioningMethodsOnly);
253
254 return m_lastUpdate;
255}
256
258{
259 return m_positionError;
260}
261
263{
264 m_positionError = positionError;
265 if (m_positionError != QGeoPositionInfoSource::NoError)
267}
268
270
271#include "moc_qgeopositioninfosource_cl_p.cpp"
\inmodule QtCore\reentrant
Definition qdatetime.h:283
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
\inmodule QtPositioning
QGeoPositionInfoSourceCL(QObject *parent=0)
void setUpdateInterval(int msec) override
void requestUpdate(int timeout=0) override
void locationDataAvailable(QGeoPositionInfo location)
int minimumUpdateInterval() const override
Error error() const override
Returns the type of error that last occurred.
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly=false) const override
Returns an update containing the last known position, or a null update if none is available.
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void changeAuthorizationStatus(CLAuthorizationStatus status)
PositioningMethods supportedPositioningMethods() const override
Returns the positioning methods available to this source.
void setError(QGeoPositionInfoSource::Error positionError)
\inmodule QtPositioning
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.
Error
The Error enumeration represents the errors which can occur.
virtual void setUpdateInterval(int msec)
\inmodule QtPositioning
Access the user's location.
\inmodule QtCore
Definition qobject.h:103
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1817
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1912
\inmodule QtCore
Definition qcoreevent.h:366
Combined button and popup list for selecting options.
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
qint64 qRound64(qfloat16 d) noexcept
Definition qfloat16.h:330
#define MINIMUM_UPDATE_INTERVAL
#define qWarning
Definition qlogging.h:166
GLint location
GLenum mode
GLbitfield GLuint64 timeout
[4]
struct _cl_event * event
GLuint in
#define QStringLiteral(str)
@ NoError
Definition main.cpp:34
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define emit
#define Q_UNUSED(x)
QNetworkAccessManager manager