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>
15#define MINIMUM_UPDATE_INTERVAL 1000
17@interface PositionLocationDelegate : NSObject <CLLocationManagerDelegate>
20@implementation PositionLocationDelegate
22 QGeoPositionInfoSourceCL *m_positionInfoSource;
25- (instancetype)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
27 if ((self = [self init])) {
28 m_positionInfoSource = positionInfoSource;
33- (
void)locationManagerDidChangeAuthorization: (CLLocationManager *)manager
38 m_positionInfoSource->changeAuthorizationStatus([manager authorizationStatus]);
41- (
void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
44 Q_UNUSED(oldLocation);
47 NSTimeInterval locationTimeStamp = [newLocation.timestamp timeIntervalSince1970];
48 const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(qRound64(locationTimeStamp * 1000),
52 QGeoPositionInfo location(QGeoCoordinate(newLocation.coordinate.latitude,
53 newLocation.coordinate.longitude,
54 newLocation.altitude),
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) {
64 location.setAttribute(QGeoPositionInfo::DirectionAccuracy,
65 newLocation.courseAccuracy);
69 if (newLocation.speed >= 0)
70 location.setAttribute(QGeoPositionInfo::GroundSpeed, newLocation.speed);
72 m_positionInfoSource->locationDataAvailable(location);
75- (
void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
78 m_positionInfoSource->setError(QGeoPositionInfoSource::AccessError);
80 qWarning() << QString::fromNSString([error localizedDescription]);
83 && QString::fromNSString([error domain]) == QStringLiteral(
"kCLErrorDomain"))
84 qWarning() <<
"(is Wi-Fi turned on?)";
90QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(QObject *parent)
91 : QGeoPositionInfoSource(parent),
93 m_updatesWanted(
false),
96 m_positionError(QGeoPositionInfoSource::NoError)
100QGeoPositionInfoSourceCL::~QGeoPositionInfoSourceCL()
103 [m_locationManager release];
106void QGeoPositionInfoSourceCL::setUpdateInterval(
int msec)
110 if (msec != 0 && msec < minimumUpdateInterval())
111 msec = minimumUpdateInterval();
113 QGeoPositionInfoSource::setUpdateInterval(msec);
116 m_updateTimeout = msec;
118 setTimeoutInterval(m_updateTimeout);
121bool QGeoPositionInfoSourceCL::enableLocationManager()
123 if (!m_locationManager) {
124 m_locationManager = [[CLLocationManager alloc] init];
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;
141 m_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
142 m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:
this];
145 return qApp->checkPermission(QLocationPermission{}) == Qt::PermissionStatus::Granted;
148void QGeoPositionInfoSourceCL::setTimeoutInterval(
int msec)
151 if (m_updateTimer) killTimer(m_updateTimer);
152 if (msec > 0) m_updateTimer = startTimer(msec);
153 else m_updateTimer = 0;
156void QGeoPositionInfoSourceCL::startUpdates()
158 m_positionError = QGeoPositionInfoSource::NoError;
159 m_updatesWanted =
true;
160 if (enableLocationManager()) {
161 [m_locationManager startUpdatingLocation];
162 setTimeoutInterval(m_updateTimeout);
164 setError(QGeoPositionInfoSource::AccessError);
168void QGeoPositionInfoSourceCL::stopUpdates()
170 if (m_locationManager) {
171 [m_locationManager stopUpdatingLocation];
172 m_updatesWanted =
false;
175 setTimeoutInterval(0);
177 setError(QGeoPositionInfoSource::AccessError);
181void QGeoPositionInfoSourceCL::requestUpdate(
int timeout)
184 m_positionError = QGeoPositionInfoSource::NoError;
185 if (timeout < minimumUpdateInterval() && timeout != 0)
186 setError(QGeoPositionInfoSource::UpdateTimeoutError);
187 else if (enableLocationManager()) {
189 [m_locationManager stopUpdatingLocation];
190 [m_locationManager startUpdatingLocation];
191 setTimeoutInterval(timeout);
193 setError(QGeoPositionInfoSource::AccessError);
197void QGeoPositionInfoSourceCL::changeAuthorizationStatus(CLAuthorizationStatus status)
200 if (status == kCLAuthorizationStatusAuthorizedAlways
201 || status == kCLAuthorizationStatusAuthorizedWhenInUse
203 if (status == kCLAuthorizationStatusAuthorized
211void QGeoPositionInfoSourceCL::timerEvent( QTimerEvent * event )
214 if (event->timerId() == m_updateTimer) {
215 setError(QGeoPositionInfoSource::UpdateTimeoutError);
218 setTimeoutInterval(0);
221 if (!m_updatesWanted)
226QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceCL::supportedPositioningMethods()
const
229 return QGeoPositionInfoSource::AllPositioningMethods;
232int QGeoPositionInfoSourceCL::minimumUpdateInterval()
const
237void QGeoPositionInfoSourceCL::locationDataAvailable(QGeoPositionInfo location)
240 m_lastUpdate = location;
241 emit positionUpdated(location);
244 if (!m_updatesWanted)
247 else setTimeoutInterval(m_updateTimeout);
250QGeoPositionInfo QGeoPositionInfoSourceCL::lastKnownPosition(
bool fromSatellitePositioningMethodsOnly)
const
252 Q_UNUSED(fromSatellitePositioningMethodsOnly);
257QGeoPositionInfoSource::Error QGeoPositionInfoSourceCL::error()
const
259 return m_positionError;
262void QGeoPositionInfoSourceCL::setError(QGeoPositionInfoSource::Error positionError)
264 m_positionError = positionError;
265 if (m_positionError != QGeoPositionInfoSource::NoError)
266 emit QGeoPositionInfoSource::errorOccurred(positionError);
271#include "moc_qgeopositioninfosource_cl_p.cpp"
#define MINIMUM_UPDATE_INTERVAL