diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-26 14:25:06 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-26 14:25:06 +0100 |
commit | c6a28570a7300788127117378eb7cd36dcd0953f (patch) | |
tree | b8e56b1bd18fb4438de171004d588d12dbf7abec /src/plugins/position | |
parent | e9ead74ec4169d483de0b711986b5b560bbb730a (diff) | |
parent | 24e50e40caaa2f2e057180b8ed8179795e605e2a (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Change-Id: I23c874c5dcd0452142c3cf8abff65415ad31a1e7
Diffstat (limited to 'src/plugins/position')
7 files changed, 322 insertions, 166 deletions
diff --git a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java index 4723a805..43767f0e 100644 --- a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java +++ b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java @@ -179,6 +179,58 @@ public class QtPositioning implements LocationListener return false; } + + static private void addActiveListener(QtPositioning listener, String provider) + { + int androidClassKey = listener.nativeClassReference; + //start update thread + listener.setActiveLooper(true); + + if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { + removeActiveListener(androidClassKey); + } + + locationManager.requestSingleUpdate(provider, + listener, + listener.looper()); + + runningListeners.put(androidClassKey, listener); + } + + + static private void addActiveListener(QtPositioning listener, String provider, long minTime, float minDistance) + { + int androidClassKey = listener.nativeClassReference; + //start update thread + listener.setActiveLooper(true); + + if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { + removeActiveListener(androidClassKey); + } + + locationManager.requestLocationUpdates(provider, + minTime, minDistance, + listener, + listener.looper()); + + runningListeners.put(androidClassKey, listener); + } + + + static private void removeActiveListener(QtPositioning listener) + { + removeActiveListener(listener.nativeClassReference); + } + + + static private void removeActiveListener(int androidClassKey) + { + QtPositioning listener = runningListeners.remove(androidClassKey); + locationManager.removeUpdates(listener); + listener.setActiveLooper(false); + } + + static public int startUpdates(int androidClassKey, int locationProvider, int updateInterval) { synchronized (m_syncObject) { @@ -188,8 +240,6 @@ public class QtPositioning implements LocationListener positioningListener.nativeClassReference = androidClassKey; positioningListener.expectedProviders = locationProvider; positioningListener.isSatelliteUpdate = false; - //start update thread - positioningListener.setActiveLooper(true); if (updateInterval == 0) updateInterval = 1000; //don't update more often than once per second @@ -198,10 +248,9 @@ public class QtPositioning implements LocationListener if ((locationProvider & QT_GPS_PROVIDER) > 0) { Log.d(TAG, "Regular updates using GPS " + updateInterval); try { - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, - updateInterval, 0, - positioningListener, - positioningListener.looper()); + addActiveListener(positioningListener, + LocationManager.GPS_PROVIDER, + updateInterval, 0); } catch (SecurityException se) { se.printStackTrace(); exceptionOccurred = true; @@ -211,18 +260,16 @@ public class QtPositioning implements LocationListener if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { Log.d(TAG, "Regular updates using network " + updateInterval); try { - locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - updateInterval, 0, - positioningListener, - positioningListener.looper()); + addActiveListener(positioningListener, + LocationManager.NETWORK_PROVIDER, + updateInterval, 0); } catch (SecurityException se) { se.printStackTrace(); exceptionOccurred = true; } } if (exceptionOccurred) { - positioningListener.setActiveLooper(false); - locationManager.removeUpdates(positioningListener); + removeActiveListener(positioningListener); return QT_ACCESS_ERROR; } @@ -231,7 +278,6 @@ public class QtPositioning implements LocationListener return QT_CLOSED_ERROR; } - runningListeners.put(androidClassKey, positioningListener); } catch(Exception e) { e.printStackTrace(); return QT_POSITION_UNKNOWN_SOURCE_ERROR; @@ -246,9 +292,7 @@ public class QtPositioning implements LocationListener synchronized (m_syncObject) { try { Log.d(TAG, "Stopping updates"); - QtPositioning listener = runningListeners.remove(androidClassKey); - locationManager.removeUpdates(listener); - listener.setActiveLooper(false); + removeActiveListener(androidClassKey); } catch(Exception e) { e.printStackTrace(); return; @@ -266,15 +310,11 @@ public class QtPositioning implements LocationListener positioningListener.isSingleUpdate = true; positioningListener.expectedProviders = locationProvider; positioningListener.isSatelliteUpdate = false; - //start update thread - positioningListener.setActiveLooper(true); if ((locationProvider & QT_GPS_PROVIDER) > 0) { Log.d(TAG, "Single update using GPS"); try { - locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, - positioningListener, - positioningListener.looper()); + addActiveListener(positioningListener, LocationManager.GPS_PROVIDER); } catch (SecurityException se) { se.printStackTrace(); exceptionOccurred = true; @@ -284,17 +324,14 @@ public class QtPositioning implements LocationListener if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { Log.d(TAG, "Single update using network"); try { - locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, - positioningListener, - positioningListener.looper()); + addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER); } catch (SecurityException se) { se.printStackTrace(); exceptionOccurred = true; } } if (exceptionOccurred) { - positioningListener.setActiveLooper(false); - locationManager.removeUpdates(positioningListener); + removeActiveListener(positioningListener); return QT_ACCESS_ERROR; } @@ -304,7 +341,6 @@ public class QtPositioning implements LocationListener return QT_CLOSED_ERROR; } - runningListeners.put(androidClassKey, positioningListener); } catch(Exception e) { e.printStackTrace(); return QT_POSITION_UNKNOWN_SOURCE_ERROR; @@ -324,8 +360,6 @@ public class QtPositioning implements LocationListener positioningListener.nativeClassReference = androidClassKey; positioningListener.expectedProviders = 1; //always satellite provider positioningListener.isSingleUpdate = isSingleRequest; - //start update thread - positioningListener.setActiveLooper(true); if (updateInterval == 0) updateInterval = 1000; //don't update more often than once per second @@ -335,18 +369,15 @@ public class QtPositioning implements LocationListener else Log.d(TAG, "Regular updates for Satellites " + updateInterval); try { - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, - updateInterval, 0, - positioningListener, - positioningListener.looper()); + addActiveListener(positioningListener, LocationManager.GPS_PROVIDER, + updateInterval, 0); } catch (SecurityException se) { se.printStackTrace(); exceptionOccurred = true; } if (exceptionOccurred) { - positioningListener.setActiveLooper(false); - locationManager.removeUpdates(positioningListener); + removeActiveListener(positioningListener); return QT_ACCESS_ERROR; } @@ -356,7 +387,6 @@ public class QtPositioning implements LocationListener return QT_CLOSED_ERROR; } - runningListeners.put(androidClassKey, positioningListener); } catch(Exception e) { e.printStackTrace(); return QT_SATELLITE_UNKNOWN_SOURCE_ERROR; diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp index c9b209e8..1d1a6f4f 100644 --- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp +++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp @@ -42,6 +42,7 @@ #include <QtSerialPort/qserialport.h> #include <QtSerialPort/qserialportinfo.h> #include <QtCore/qloggingcategory.h> +#include <QSet> Q_LOGGING_CATEGORY(lcSerial, "qt.positioning.serialnmea") @@ -70,16 +71,13 @@ NmeaSource::NmeaSource(QObject *parent) } // Try to find a well-known device. + QSet<int> supportedDevices; + supportedDevices << 0x67b; // GlobalSat (BU-353S4 and probably others) + supportedDevices << 0xe8d; // Qstarz MTK II QString portName; - for (int i = 0; i < ports.count(); ++i) { - const QString candidatePortName = ports[i].portName(); - bool acceptThis = false; - - // GlobalSat (BU-353S4 and probably others) - acceptThis |= ports[i].hasVendorIdentifier() && ports[i].vendorIdentifier() == 0x67b; - - if (acceptThis) { - portName = candidatePortName; + foreach (const QSerialPortInfo& port, ports) { + if (port.hasVendorIdentifier() && supportedDevices.contains(port.vendorIdentifier())) { + portName = port.portName(); break; } } diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp index 4e70cc07..5dbbacb5 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp @@ -37,75 +37,119 @@ #include "qgeopositioninfosource_winrt_p.h" #include <QCoreApplication> +#include <QMutex> +#include <qfunctions_winrt.h> +#include <private/qeventdispatcher_winrt_p.h> +#include <functional> #include <windows.system.h> #include <windows.devices.geolocation.h> +#include <windows.foundation.h> #include <windows.foundation.collections.h> using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Devices::Geolocation; using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::System; +using namespace ABI::Windows::Foundation::Collections; typedef ITypedEventHandler<Geolocator *, PositionChangedEventArgs *> GeoLocatorPositionHandler; typedef ITypedEventHandler<Geolocator *, StatusChangedEventArgs *> GeoLocatorStatusHandler; +typedef IAsyncOperationCompletedHandler<Geoposition*> PositionHandler; +#if _MSC_VER >= 1900 +typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler; +#endif QT_BEGIN_NAMESPACE -QGeoPositionInfoSourceWinrt::QGeoPositionInfoSourceWinrt(QObject *parent) +Q_DECLARE_METATYPE(QGeoPositionInfo) + +class QGeoPositionInfoSourceWinRTPrivate { +public: + ComPtr<IGeolocator> locator; + QTimer periodicTimer; + QTimer singleUpdateTimer; + QGeoPositionInfo lastPosition; + QGeoPositionInfoSource::Error positionError; + EventRegistrationToken statusToken; + EventRegistrationToken positionToken; + QMutex mutex; + bool updatesOngoing; +}; + + +QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent) : QGeoPositionInfoSource(parent) - , m_positionError(QGeoPositionInfoSource::NoError) - , m_updatesOngoing(false) + , d_ptr(new QGeoPositionInfoSourceWinRTPrivate) { - HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(), - &m_locator); + Q_D(QGeoPositionInfoSourceWinRT); + d->positionError = QGeoPositionInfoSource::NoError; + d->updatesOngoing = false; + + qRegisterMetaType<QGeoPositionInfo>(); + + requestAccess(); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(), + &d->locator); + RETURN_HR_IF_FAILED("Could not initialize native location services."); + + // StatusChanged throws an exception on Windows 8.1 +#if _MSC_VER >= 1900 + hr = d->locator->add_StatusChanged(Callback<GeoLocatorStatusHandler>(this, + &QGeoPositionInfoSourceWinRT::onStatusChanged).Get(), + &d->statusToken); + RETURN_HR_IF_FAILED("Could not add status callback."); +#endif - if (FAILED(hr)) { - setError(QGeoPositionInfoSource::UnknownSourceError); - qErrnoWarning(hr, "Could not initialize native location services"); - return; - } + hr = d->locator->put_ReportInterval(1000); + RETURN_HR_IF_FAILED("Could not initialize report interval."); - hr = m_locator->put_ReportInterval(minimumUpdateInterval()); - if (FAILED(hr)) { - setError(QGeoPositionInfoSource::UnknownSourceError); - qErrnoWarning(hr, "Could not initialize report interval"); - return; - } - hr = m_locator->put_DesiredAccuracy(PositionAccuracy::PositionAccuracy_High); + return hr; + }); + Q_ASSERT_SUCCEEDED(hr); + + hr = d->locator->put_DesiredAccuracy(PositionAccuracy::PositionAccuracy_Default); if (FAILED(hr)) { setError(QGeoPositionInfoSource::UnknownSourceError); - qErrnoWarning(hr, "Could not initialize desired accuracy"); + qErrnoWarning(hr, "Could not initialize desired accuracy."); return; } - m_positionToken.value = 0; + d->positionToken.value = 0; - m_periodicTimer.setSingleShot(true); - m_periodicTimer.setInterval(minimumUpdateInterval()); - connect(&m_periodicTimer, SIGNAL(timeout()), this, SLOT(virtualPositionUpdate())); + d->periodicTimer.setSingleShot(true); + d->periodicTimer.setInterval(minimumUpdateInterval()); + connect(&d->periodicTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::virtualPositionUpdate); - m_singleUpdateTimer.setSingleShot(true); - connect(&m_singleUpdateTimer, SIGNAL(timeout()), this, SLOT(singleUpdateTimeOut())); + d->singleUpdateTimer.setSingleShot(true); + connect(&d->singleUpdateTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::singleUpdateTimeOut); setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods); + + connect(this, &QGeoPositionInfoSourceWinRT::nativePositionUpdate, this, &QGeoPositionInfoSourceWinRT::updateSynchronized); } -QGeoPositionInfoSourceWinrt::~QGeoPositionInfoSourceWinrt() +QGeoPositionInfoSourceWinRT::~QGeoPositionInfoSourceWinRT() { } -QGeoPositionInfo QGeoPositionInfoSourceWinrt::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const +QGeoPositionInfo QGeoPositionInfoSourceWinRT::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const { + Q_D(const QGeoPositionInfoSourceWinRT); Q_UNUSED(fromSatellitePositioningMethodsOnly) - return m_lastPosition; + return d->lastPosition; } -QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinrt::supportedPositioningMethods() const +QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supportedPositioningMethods() const { + Q_D(const QGeoPositionInfoSourceWinRT); + PositionStatus status; - HRESULT hr = m_locator->get_LocationStatus(&status); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, &status]() { + HRESULT hr = d->locator->get_LocationStatus(&status); + return hr; + }); if (FAILED(hr)) return QGeoPositionInfoSource::NoPositioningMethods; @@ -119,88 +163,94 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinrt::supporte return QGeoPositionInfoSource::AllPositioningMethods; } -void QGeoPositionInfoSourceWinrt::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods) +void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods) { + Q_D(QGeoPositionInfoSourceWinRT); + PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods(); QGeoPositionInfoSource::setPreferredPositioningMethods(methods); if (previousPreferredPositioningMethods == preferredPositioningMethods()) return; - bool needsRestart = m_positionToken.value != 0; + bool needsRestart = d->positionToken.value != 0; if (needsRestart) stopHandler(); - HRESULT hr; - if (methods & PositioningMethod::SatellitePositioningMethods) - hr = m_locator->put_DesiredAccuracy(PositionAccuracy::PositionAccuracy_High); - else - hr = m_locator->put_DesiredAccuracy(PositionAccuracy::PositionAccuracy_Default); - - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not set positioning accuracy"); - return; - } + PositionAccuracy acc = methods & PositioningMethod::SatellitePositioningMethods ? + PositionAccuracy::PositionAccuracy_High : + PositionAccuracy::PositionAccuracy_Default; + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, acc]() { + HRESULT hr = d->locator->put_DesiredAccuracy(acc); + return hr; + }); + RETURN_VOID_IF_FAILED("Could not set positioning accuracy."); if (needsRestart) startHandler(); } -void QGeoPositionInfoSourceWinrt::setUpdateInterval(int msec) +void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec) { - // Windows Phone does not support 0 interval -#ifdef Q_OS_WINPHONE + Q_D(QGeoPositionInfoSourceWinRT); + // Windows Phone 8.1 and Windows 10 do not support 0 interval +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) if (msec == 0) msec = minimumUpdateInterval(); #endif + // If msec is 0 we send updates as data becomes available, otherwise we force msec to be equal // to or larger than the minimum update interval. if (msec != 0 && msec < minimumUpdateInterval()) msec = minimumUpdateInterval(); - HRESULT hr = m_locator->put_ReportInterval(msec); + HRESULT hr = d->locator->put_ReportInterval(msec); if (FAILED(hr)) { setError(QGeoPositionInfoSource::UnknownSourceError); qErrnoWarning(hr, "Failed to set update interval"); return; } - if (msec != 0) - m_periodicTimer.setInterval(msec); - else - m_periodicTimer.setInterval(minimumUpdateInterval()); + + d->periodicTimer.setInterval(qMax(msec, minimumUpdateInterval())); QGeoPositionInfoSource::setUpdateInterval(msec); } -int QGeoPositionInfoSourceWinrt::minimumUpdateInterval() const +int QGeoPositionInfoSourceWinRT::minimumUpdateInterval() const { // We use one second to reduce potential timer events // in case the platform itself stops reporting return 1000; } -void QGeoPositionInfoSourceWinrt::startUpdates() +void QGeoPositionInfoSourceWinRT::startUpdates() { - if (m_updatesOngoing) + Q_D(QGeoPositionInfoSourceWinRT); + + if (d->updatesOngoing) return; if (!startHandler()) return; - m_updatesOngoing = true; - m_periodicTimer.start(); + d->updatesOngoing = true; + d->periodicTimer.start(); } -void QGeoPositionInfoSourceWinrt::stopUpdates() +void QGeoPositionInfoSourceWinRT::stopUpdates() { + Q_D(QGeoPositionInfoSourceWinRT); + stopHandler(); - m_updatesOngoing = false; - m_periodicTimer.stop(); + d->updatesOngoing = false; + d->periodicTimer.stop(); } -bool QGeoPositionInfoSourceWinrt::startHandler() +bool QGeoPositionInfoSourceWinRT::startHandler() { + Q_D(QGeoPositionInfoSourceWinRT); + // Check if already attached - if (m_positionToken.value != 0) + if (d->positionToken.value != 0) return true; if (preferredPositioningMethods() == QGeoPositionInfoSource::NoPositioningMethods) { @@ -208,31 +258,49 @@ bool QGeoPositionInfoSourceWinrt::startHandler() return false; } - if (!checkNativeState()) + if (!requestAccess() || !checkNativeState()) return false; - HRESULT hr = m_locator->add_PositionChanged(Callback<GeoLocatorPositionHandler>(this, - &QGeoPositionInfoSourceWinrt::onPositionChanged).Get(), - &m_positionToken); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + // We need to call this at least once on Windows 10 Mobile. + // Unfortunately this operation does not have a completion handler + // registered. That could have helped in the single update case + ComPtr<IAsyncOperation<Geoposition*>> op; + hr = d->locator->GetGeopositionAsync(&op); + + hr = d->locator->add_PositionChanged(Callback<GeoLocatorPositionHandler>(this, + &QGeoPositionInfoSourceWinRT::onPositionChanged).Get(), + &d->positionToken); + return hr; + }); if (FAILED(hr)) { setError(QGeoPositionInfoSource::UnknownSourceError); qErrnoWarning(hr, "Could not add position handler"); return false; } + return true; } -void QGeoPositionInfoSourceWinrt::stopHandler() +void QGeoPositionInfoSourceWinRT::stopHandler() { - if (!m_positionToken.value) + Q_D(QGeoPositionInfoSourceWinRT); + + if (!d->positionToken.value) return; - m_locator->remove_PositionChanged(m_positionToken); - m_positionToken.value = 0; + QEventDispatcherWinRT::runOnXamlThread([d]() { + d->locator->remove_PositionChanged(d->positionToken); + return S_OK; + }); + d->positionToken.value = 0; } -void QGeoPositionInfoSourceWinrt::requestUpdate(int timeout) +void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout) { + Q_D(QGeoPositionInfoSourceWinRT); + if (timeout != 0 && timeout < minimumUpdateInterval()) { emit updateTimeout(); return; @@ -242,11 +310,14 @@ void QGeoPositionInfoSourceWinrt::requestUpdate(int timeout) timeout = 2*60*1000; // Maximum time for cold start (see Android) startHandler(); - m_singleUpdateTimer.start(timeout); + d->singleUpdateTimer.start(timeout); } -void QGeoPositionInfoSourceWinrt::virtualPositionUpdate() +void QGeoPositionInfoSourceWinRT::virtualPositionUpdate() { + Q_D(QGeoPositionInfoSourceWinRT); + QMutexLocker locker(&d->mutex); + // Need to check if services are still running and ok if (!checkNativeState()) { stopUpdates(); @@ -258,39 +329,69 @@ void QGeoPositionInfoSourceWinrt::virtualPositionUpdate() // between backends. // This only applies to the periodic timer, not for single requests // We can only do this if we received a valid position before - if (m_lastPosition.isValid()) { - QGeoPositionInfo sent = m_lastPosition; + if (d->lastPosition.isValid()) { + QGeoPositionInfo sent = d->lastPosition; sent.setTimestamp(QDateTime::currentDateTime()); - m_lastPosition = sent; + d->lastPosition = sent; emit positionUpdated(sent); } - m_periodicTimer.start(); + d->periodicTimer.start(); } -void QGeoPositionInfoSourceWinrt::singleUpdateTimeOut() +void QGeoPositionInfoSourceWinRT::singleUpdateTimeOut() { - emit updateTimeout(); - if (!m_updatesOngoing) + Q_D(QGeoPositionInfoSourceWinRT); + QMutexLocker locker(&d->mutex); + + if (d->singleUpdateTimer.isActive()) { + emit updateTimeout(); + if (!d->updatesOngoing) + stopHandler(); + } +} + +void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInfo) +{ + Q_D(QGeoPositionInfoSourceWinRT); + QMutexLocker locker(&d->mutex); + + d->periodicTimer.stop(); + d->lastPosition = currentInfo; + + if (d->updatesOngoing) + d->periodicTimer.start(); + + if (d->singleUpdateTimer.isActive()) { + d->singleUpdateTimer.stop(); + if (!d->updatesOngoing) stopHandler(); + } + + emit positionUpdated(currentInfo); } -QGeoPositionInfoSource::Error QGeoPositionInfoSourceWinrt::error() const +QGeoPositionInfoSource::Error QGeoPositionInfoSourceWinRT::error() const { - return m_positionError; + Q_D(const QGeoPositionInfoSourceWinRT); + return d->positionError; } -void QGeoPositionInfoSourceWinrt::setError(QGeoPositionInfoSource::Error positionError) +void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positionError) { - if (positionError == m_positionError) + Q_D(QGeoPositionInfoSourceWinRT); + + if (positionError == d->positionError) return; - m_positionError = positionError; + d->positionError = positionError; emit QGeoPositionInfoSource::error(positionError); } -bool QGeoPositionInfoSourceWinrt::checkNativeState() +bool QGeoPositionInfoSourceWinRT::checkNativeState() { + Q_D(QGeoPositionInfoSourceWinRT); + PositionStatus status; - HRESULT hr = m_locator->get_LocationStatus(&status); + HRESULT hr = d->locator->get_LocationStatus(&status); if (FAILED(hr)) { setError(QGeoPositionInfoSource::UnknownSourceError); qErrnoWarning(hr, "Could not query status"); @@ -314,17 +415,14 @@ bool QGeoPositionInfoSourceWinrt::checkNativeState() return result; } -HRESULT QGeoPositionInfoSourceWinrt::onPositionChanged(IGeolocator *locator, IPositionChangedEventArgs *args) +HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPositionChangedEventArgs *args) { Q_UNUSED(locator); - m_periodicTimer.stop(); - HRESULT hr; ComPtr<IGeoposition> pos; hr = args->get_Position(&pos); - if (FAILED(hr)) - qErrnoWarning(hr, "Could not access position object"); + RETURN_HR_IF_FAILED("Could not access position object."); QGeoPositionInfo currentInfo; @@ -378,19 +476,48 @@ HRESULT QGeoPositionInfoSourceWinrt::onPositionChanged(IGeolocator *locator, IPo currentInfo.setTimestamp(QDateTime::currentDateTime()); - m_lastPosition = currentInfo; + emit nativePositionUpdate(currentInfo); - if (m_updatesOngoing) - m_periodicTimer.start(); - - if (m_singleUpdateTimer.isActive()) { - m_singleUpdateTimer.stop(); - if (!m_updatesOngoing) - stopHandler(); - } + return S_OK; +} - emit positionUpdated(currentInfo); +HRESULT QGeoPositionInfoSourceWinRT::onStatusChanged(IGeolocator*, IStatusChangedEventArgs *args) +{ + PositionStatus st; + args->get_Status(&st); return S_OK; } +bool QGeoPositionInfoSourceWinRT::requestAccess() const +{ +#if _MSC_VER >= 1900 + static GeolocationAccessStatus accessStatus = GeolocationAccessStatus_Unspecified; + static ComPtr<IGeolocatorStatics> statics; + + if (accessStatus == GeolocationAccessStatus_Allowed) + return true; + else if (accessStatus == GeolocationAccessStatus_Denied) + return false; + + ComPtr<IAsyncOperation<GeolocationAccessStatus>> op; + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([&op]() { + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(), + IID_PPV_ARGS(&statics)); + RETURN_HR_IF_FAILED("Could not access Geolocation Statics."); + + hr = statics->RequestAccessAsync(&op); + return hr; + }); + Q_ASSERT_SUCCEEDED(hr); + + // We cannot wait inside the XamlThread as that would deadlock + QWinRTFunctions::await(op, &accessStatus); + return accessStatus == GeolocationAccessStatus_Allowed; +#else // _MSC_VER < 1900 + return true; +#endif // _MSC_VER < 1900 +} + QT_END_NAMESPACE diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h index 45c22847..b8820dd2 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h @@ -70,12 +70,14 @@ namespace ABI { QT_BEGIN_NAMESPACE -class QGeoPositionInfoSourceWinrt : public QGeoPositionInfoSource +class QGeoPositionInfoSourceWinRTPrivate; + +class QGeoPositionInfoSourceWinRT : public QGeoPositionInfoSource { Q_OBJECT public: - QGeoPositionInfoSourceWinrt(QObject *parent = 0); - ~QGeoPositionInfoSourceWinrt(); + QGeoPositionInfoSourceWinRT(QObject *parent = 0); + ~QGeoPositionInfoSourceWinRT(); QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const; PositioningMethods supportedPositioningMethods() const; @@ -89,6 +91,12 @@ public: HRESULT onPositionChanged(ABI::Windows::Devices::Geolocation::IGeolocator *locator, ABI::Windows::Devices::Geolocation::IPositionChangedEventArgs *args); + HRESULT onStatusChanged(ABI::Windows::Devices::Geolocation::IGeolocator*, + ABI::Windows::Devices::Geolocation::IStatusChangedEventArgs *args); + + bool requestAccess() const; +Q_SIGNALS: + void nativePositionUpdate(const QGeoPositionInfo); public slots: void startUpdates(); void stopUpdates(); @@ -99,23 +107,16 @@ private slots: void stopHandler(); void virtualPositionUpdate(); void singleUpdateTimeOut(); + void updateSynchronized(const QGeoPositionInfo info); private: bool startHandler(); - Q_DISABLE_COPY(QGeoPositionInfoSourceWinrt) + Q_DISABLE_COPY(QGeoPositionInfoSourceWinRT) void setError(QGeoPositionInfoSource::Error positionError); bool checkNativeState(); - Microsoft::WRL::ComPtr<ABI::Windows::Devices::Geolocation::IGeolocator> m_locator; - EventRegistrationToken m_positionToken; - - QGeoPositionInfo m_lastPosition; - QGeoPositionInfoSource::Error m_positionError; - - //EventRegistrationToken m_StatusToken; - QTimer m_periodicTimer; - QTimer m_singleUpdateTimer; - bool m_updatesOngoing; + QScopedPointer<QGeoPositionInfoSourceWinRTPrivate> d_ptr; + Q_DECLARE_PRIVATE(QGeoPositionInfoSourceWinRT) }; QT_END_NAMESPACE diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp index 0f9a21f2..81656c21 100644 --- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp @@ -37,18 +37,18 @@ #include "qgeopositioninfosourcefactory_winrt.h" #include "qgeopositioninfosource_winrt_p.h" -QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryWinrt::positionInfoSource(QObject *parent) +QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryWinRT::positionInfoSource(QObject *parent) { - return new QGeoPositionInfoSourceWinrt(parent); + return new QGeoPositionInfoSourceWinRT(parent); } -QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryWinrt::satelliteInfoSource(QObject *parent) +QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryWinRT::satelliteInfoSource(QObject *parent) { Q_UNUSED(parent); return 0; } -QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryWinrt::areaMonitor(QObject *parent) +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryWinRT::areaMonitor(QObject *parent) { Q_UNUSED(parent); return 0; diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h index 0627abc4..46cd3853 100644 --- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h +++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE -class QGeoPositionInfoSourceFactoryWinrt : public QObject, public QGeoPositionInfoSourceFactory +class QGeoPositionInfoSourceFactoryWinRT : public QObject, public QGeoPositionInfoSourceFactory { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0" diff --git a/src/plugins/position/winrt/winrt.pro b/src/plugins/position/winrt/winrt.pro index 228a9e78..c58c6c18 100644 --- a/src/plugins/position/winrt/winrt.pro +++ b/src/plugins/position/winrt/winrt.pro @@ -1,8 +1,8 @@ TARGET = qtposition_winrt -QT = core positioning +QT = core core-private positioning PLUGIN_TYPE = position -PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryWinrt +PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryWinRT load(qt_plugin) SOURCES += qgeopositioninfosource_winrt.cpp \ |