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>
14#include <QtCore/QVariantMap>
16using namespace Qt::Literals::StringLiterals;
20#define MINIMUM_UPDATE_INTERVAL 1000
22@interface PositionLocationDelegate : NSObject <CLLocationManagerDelegate>
25@implementation PositionLocationDelegate
27 QGeoPositionInfoSourceCL *m_positionInfoSource;
30- (instancetype)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
32 if ((self = [self init])) {
33 m_positionInfoSource = positionInfoSource;
38- (
void)locationManagerDidChangeAuthorization: (CLLocationManager *)manager
43 m_positionInfoSource->changeAuthorizationStatus([manager authorizationStatus]);
46- (
void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
49 Q_UNUSED(oldLocation);
52 NSTimeInterval locationTimeStamp = [newLocation.timestamp timeIntervalSince1970];
53 const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(qRound64(locationTimeStamp * 1000),
57 QGeoPositionInfo location(QGeoCoordinate(newLocation.coordinate.latitude,
58 newLocation.coordinate.longitude,
59 newLocation.altitude),
61 if (newLocation.horizontalAccuracy >= 0)
62 location.setAttribute(QGeoPositionInfo::HorizontalAccuracy, newLocation.horizontalAccuracy);
63 if (newLocation.verticalAccuracy >= 0)
64 location.setAttribute(QGeoPositionInfo::VerticalAccuracy, newLocation.verticalAccuracy);
65 if (newLocation.course >= 0) {
66 location.setAttribute(QGeoPositionInfo::Direction, newLocation.course);
67 if (
__builtin_available(iOS 13.4, macOS 10.15.4, *)) {
68 if (newLocation.courseAccuracy >= 0) {
69 location.setAttribute(QGeoPositionInfo::DirectionAccuracy,
70 newLocation.courseAccuracy);
74 if (newLocation.speed >= 0)
75 location.setAttribute(QGeoPositionInfo::GroundSpeed, newLocation.speed);
77 m_positionInfoSource->locationDataAvailable(location);
80- (
void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
83 m_positionInfoSource->setError(QGeoPositionInfoSource::AccessError);
85 qWarning() << QString::fromNSString([error localizedDescription]);
88 && QString::fromNSString([error domain]) == QStringLiteral(
"kCLErrorDomain"))
89 qWarning() <<
"(is Wi-Fi turned on?)";
95QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(
const QVariantMap ¶meters, QObject *parent)
96 : QGeoPositionInfoSource(parent),
98 m_updatesWanted(
false),
101 m_positionError(QGeoPositionInfoSource::NoError)
103 parseParameters(parameters);
106QGeoPositionInfoSourceCL::~QGeoPositionInfoSourceCL()
109 [m_locationManager release];
112void QGeoPositionInfoSourceCL::setUpdateInterval(
int msec)
116 if (msec != 0 && msec < minimumUpdateInterval())
117 msec = minimumUpdateInterval();
119 QGeoPositionInfoSource::setUpdateInterval(msec);
122 m_updateTimeout = msec;
124 setTimeoutInterval(m_updateTimeout);
127bool QGeoPositionInfoSourceCL::enableLocationManager()
129 if (!m_locationManager) {
130 m_locationManager = [[CLLocationManager alloc] init];
133 NSDictionary<NSString *, id> *infoDict = [[NSBundle mainBundle] infoDictionary];
134 if (id value = [infoDict objectForKey:@
"UIBackgroundModes"]) {
135 if ([value isKindOfClass:[NSArray
class]]) {
136 NSArray *modes =
static_cast<NSArray *>(value);
137 for (id mode in modes) {
138 if ([@
"location" isEqualToString:mode]) {
139 m_locationManager.allowsBackgroundLocationUpdates = YES;
140 m_locationManager.pausesLocationUpdatesAutomatically =
141 m_allowAutoPause ? YES : NO;
149 m_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
150 m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:
this];
153 return qApp->checkPermission(QLocationPermission{}) == Qt::PermissionStatus::Granted;
156void QGeoPositionInfoSourceCL::setTimeoutInterval(
int msec)
159 if (m_updateTimer) killTimer(m_updateTimer);
160 if (msec > 0) m_updateTimer = startTimer(msec);
161 else m_updateTimer = 0;
164void QGeoPositionInfoSourceCL::parseParameters(
const QVariantMap ¶meters)
166 m_allowAutoPause = parameters.value(kAllowAutoPause,
true).toBool();
169void QGeoPositionInfoSourceCL::startUpdates()
171 m_positionError = QGeoPositionInfoSource::NoError;
172 m_updatesWanted =
true;
173 if (enableLocationManager()) {
174 [m_locationManager startUpdatingLocation];
175 setTimeoutInterval(m_updateTimeout);
177 setError(QGeoPositionInfoSource::AccessError);
181void QGeoPositionInfoSourceCL::stopUpdates()
183 if (m_locationManager) {
184 [m_locationManager stopUpdatingLocation];
185 m_updatesWanted =
false;
188 setTimeoutInterval(0);
190 setError(QGeoPositionInfoSource::AccessError);
194void QGeoPositionInfoSourceCL::requestUpdate(
int timeout)
197 m_positionError = QGeoPositionInfoSource::NoError;
198 if (timeout < minimumUpdateInterval() && timeout != 0)
199 setError(QGeoPositionInfoSource::UpdateTimeoutError);
200 else if (enableLocationManager()) {
202 [m_locationManager stopUpdatingLocation];
203 [m_locationManager startUpdatingLocation];
204 setTimeoutInterval(timeout);
206 setError(QGeoPositionInfoSource::AccessError);
210void QGeoPositionInfoSourceCL::changeAuthorizationStatus(CLAuthorizationStatus status)
213 if (status == kCLAuthorizationStatusAuthorizedAlways
214 || status == kCLAuthorizationStatusAuthorizedWhenInUse
216 if (status == kCLAuthorizationStatusAuthorized
224void QGeoPositionInfoSourceCL::timerEvent( QTimerEvent * event )
227 if (event->timerId() == m_updateTimer) {
228 setError(QGeoPositionInfoSource::UpdateTimeoutError);
231 setTimeoutInterval(0);
234 if (!m_updatesWanted)
239QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceCL::supportedPositioningMethods()
const
242 return QGeoPositionInfoSource::AllPositioningMethods;
245int QGeoPositionInfoSourceCL::minimumUpdateInterval()
const
250void QGeoPositionInfoSourceCL::locationDataAvailable(QGeoPositionInfo location)
253 m_lastUpdate = location;
254 emit positionUpdated(location);
257 if (!m_updatesWanted)
260 else setTimeoutInterval(m_updateTimeout);
263QGeoPositionInfo QGeoPositionInfoSourceCL::lastKnownPosition(
bool fromSatellitePositioningMethodsOnly)
const
265 Q_UNUSED(fromSatellitePositioningMethodsOnly);
270QGeoPositionInfoSource::Error QGeoPositionInfoSourceCL::error()
const
272 return m_positionError;
275void QGeoPositionInfoSourceCL::setError(QGeoPositionInfoSource::Error positionError)
277 m_positionError = positionError;
278 if (m_positionError != QGeoPositionInfoSource::NoError)
279 emit QGeoPositionInfoSource::errorOccurred(positionError);
284#include "moc_qgeopositioninfosource_cl_p.cpp"
#define MINIMUM_UPDATE_INTERVAL
static constexpr auto kAllowAutoPause