6#include <QtCore/QTimerEvent>
7#include <QtCore/QDebug>
8#include <QtCore/qdatetime.h>
9#include <QtCore/qglobal.h>
10#include <QtCore/private/qglobal_p.h>
11#include <QtCore/qtimezone.h>
12#include <QtCore/QPermission>
13#include <QtCore/QCoreApplication>
16#define MINIMUM_UPDATE_INTERVAL 1000
18@interface PositionLocationDelegate : NSObject <CLLocationManagerDelegate>
21@implementation PositionLocationDelegate
23 QGeoPositionInfoSourceCL *m_positionInfoSource;
26- (instancetype)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
28 if ((self = [self init])) {
29 m_positionInfoSource = positionInfoSource;
34- (
void)locationManagerDidChangeAuthorization: (CLLocationManager *)manager
39 m_positionInfoSource->changeAuthorizationStatus([manager authorizationStatus]);
42- (
void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
45 Q_UNUSED(oldLocation);
48 NSTimeInterval locationTimeStamp = [newLocation.timestamp timeIntervalSince1970];
49 const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(qRound64(locationTimeStamp * 1000),
53 QGeoPositionInfo location(QGeoCoordinate(newLocation.coordinate.latitude,
54 newLocation.coordinate.longitude,
55 newLocation.altitude),
57 if (newLocation.horizontalAccuracy >= 0)
58 location.setAttribute(QGeoPositionInfo::HorizontalAccuracy, newLocation.horizontalAccuracy);
59 if (newLocation.verticalAccuracy >= 0)
60 location.setAttribute(QGeoPositionInfo::VerticalAccuracy, newLocation.verticalAccuracy);
61 if (newLocation.course >= 0) {
62 location.setAttribute(QGeoPositionInfo::Direction, newLocation.course);
63 if (
__builtin_available(iOS 13.4, macOS 10.15.4, *)) {
64 if (newLocation.courseAccuracy >= 0) {
65 location.setAttribute(QGeoPositionInfo::DirectionAccuracy,
66 newLocation.courseAccuracy);
70 if (newLocation.speed >= 0)
71 location.setAttribute(QGeoPositionInfo::GroundSpeed, newLocation.speed);
73 m_positionInfoSource->locationDataAvailable(location);
76- (
void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
79 m_positionInfoSource->setError(QGeoPositionInfoSource::AccessError);
81 qWarning() << QString::fromNSString([error localizedDescription]);
84 && QString::fromNSString([error domain]) == QStringLiteral(
"kCLErrorDomain"))
85 qWarning() <<
"(is Wi-Fi turned on?)";
91QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(QObject *parent)
92 : QGeoPositionInfoSource(parent),
94 m_updatesWanted(
false),
97 m_positionError(QGeoPositionInfoSource::NoError)
101QGeoPositionInfoSourceCL::~QGeoPositionInfoSourceCL()
104 [m_locationManager release];
107void QGeoPositionInfoSourceCL::setUpdateInterval(
int msec)
111 if (msec != 0 && msec < minimumUpdateInterval())
112 msec = minimumUpdateInterval();
114 QGeoPositionInfoSource::setUpdateInterval(msec);
117 m_updateTimeout = msec;
119 setTimeoutInterval(m_updateTimeout);
122bool QGeoPositionInfoSourceCL::enableLocationManager()
124 if (!m_locationManager) {
125 m_locationManager = [[CLLocationManager alloc] init];
128 NSDictionary<NSString *, id> *infoDict = [[NSBundle mainBundle] infoDictionary];
129 if (id value = [infoDict objectForKey:@
"UIBackgroundModes"]) {
130 if ([value isKindOfClass:[NSArray
class]]) {
131 NSArray *modes =
static_cast<NSArray *>(value);
132 for (id mode in modes) {
133 if ([@
"location" isEqualToString:mode]) {
134 m_locationManager.allowsBackgroundLocationUpdates = YES;
142 m_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
143 m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:
this];
146 return qApp->checkPermission(QLocationPermission{}) == Qt::PermissionStatus::Granted;
149void QGeoPositionInfoSourceCL::setTimeoutInterval(
int msec)
152 if (m_updateTimer) killTimer(m_updateTimer);
153 if (msec > 0) m_updateTimer = startTimer(msec);
154 else m_updateTimer = 0;
157void QGeoPositionInfoSourceCL::startUpdates()
159 m_positionError = QGeoPositionInfoSource::NoError;
160 m_updatesWanted =
true;
161 if (enableLocationManager()) {
162 [m_locationManager startUpdatingLocation];
163 setTimeoutInterval(m_updateTimeout);
165 setError(QGeoPositionInfoSource::AccessError);
169void QGeoPositionInfoSourceCL::stopUpdates()
171 if (m_locationManager) {
172 [m_locationManager stopUpdatingLocation];
173 m_updatesWanted =
false;
176 setTimeoutInterval(0);
178 setError(QGeoPositionInfoSource::AccessError);
182void QGeoPositionInfoSourceCL::requestUpdate(
int timeout)
185 m_positionError = QGeoPositionInfoSource::NoError;
186 if (timeout < minimumUpdateInterval() && timeout != 0)
187 setError(QGeoPositionInfoSource::UpdateTimeoutError);
188 else if (enableLocationManager()) {
190 [m_locationManager stopUpdatingLocation];
191 [m_locationManager startUpdatingLocation];
192 setTimeoutInterval(timeout);
194 setError(QGeoPositionInfoSource::AccessError);
198void QGeoPositionInfoSourceCL::changeAuthorizationStatus(CLAuthorizationStatus status)
201 if (status == kCLAuthorizationStatusAuthorizedAlways
202 || status == kCLAuthorizationStatusAuthorizedWhenInUse
204 if (status == kCLAuthorizationStatusAuthorized
212void QGeoPositionInfoSourceCL::timerEvent( QTimerEvent * event )
215 if (event->timerId() == m_updateTimer) {
216 setError(QGeoPositionInfoSource::UpdateTimeoutError);
219 setTimeoutInterval(0);
222 if (!m_updatesWanted)
227QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceCL::supportedPositioningMethods()
const
230 return QGeoPositionInfoSource::AllPositioningMethods;
233int QGeoPositionInfoSourceCL::minimumUpdateInterval()
const
238void QGeoPositionInfoSourceCL::locationDataAvailable(QGeoPositionInfo location)
241 m_lastUpdate = location;
242 emit positionUpdated(location);
245 if (!m_updatesWanted)
248 else setTimeoutInterval(m_updateTimeout);
251QGeoPositionInfo QGeoPositionInfoSourceCL::lastKnownPosition(
bool fromSatellitePositioningMethodsOnly)
const
253 Q_UNUSED(fromSatellitePositioningMethodsOnly);
258QGeoPositionInfoSource::Error QGeoPositionInfoSourceCL::error()
const
260 return m_positionError;
263void QGeoPositionInfoSourceCL::setError(QGeoPositionInfoSource::Error positionError)
265 m_positionError = positionError;
266 if (m_positionError != QGeoPositionInfoSource::NoError)
267 emit QGeoPositionInfoSource::errorOccurred(positionError);
272#include "moc_qgeopositioninfosource_cl_p.cpp"
#define MINIMUM_UPDATE_INTERVAL