Revision control
++ // Copyright (C) 2015 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qgeopositioninfosource_winrt_p.h"
++
++ #include <QtCore/qcoreapplication.h>
++ #include <QtCore/qdatetime.h>
++ #include <QtCore/private/qfunctions_winrt_p.h>
++ #include <QtCore/qloggingcategory.h>
++ #include <QtCore/qmutex.h>
++ #include <QtCore/qtimezone.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::Foundation::Collections;
++
++ typedef ITypedEventHandler<Geolocator *, PositionChangedEventArgs *> GeoLocatorPositionHandler;
++ typedef ITypedEventHandler<Geolocator *, StatusChangedEventArgs *> GeoLocatorStatusHandler;
++ typedef IAsyncOperationCompletedHandler<Geoposition*> PositionHandler;
++ typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler;
++
++ Q_DECLARE_LOGGING_CATEGORY(lcPositioningWinRT)
++
++ QT_BEGIN_NAMESPACE
++
++ static inline HRESULT await(const ComPtr<IAsyncOperation<GeolocationAccessStatus>> &asyncOp,
++ GeolocationAccessStatus *result)
++ {
++ ComPtr<IAsyncInfo> asyncInfo;
++ HRESULT hr = asyncOp.As(&asyncInfo);
++ if (FAILED(hr))
++ return hr;
++
++ AsyncStatus status;
++ while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started)
++ QThread::yieldCurrentThread();
++
++ if (FAILED(hr) || status != AsyncStatus::Completed) {
++ HRESULT ec;
++ hr = asyncInfo->get_ErrorCode(&ec);
++ if (FAILED(hr))
++ return hr;
++ hr = asyncInfo->Close();
++ if (FAILED(hr))
++ return hr;
++ return ec;
++ }
++
++ if (FAILED(hr))
++ return hr;
++
++ return asyncOp->GetResults(result);
++ }
++
++ enum class InitializationState {
++ Uninitialized,
++ Initializing,
++ Initialized
++ };
++
++ class QGeoPositionInfoSourceWinRTPrivate {
++ public:
++ ComPtr<IGeolocator> locator;
++ mutable ComPtr<IGeolocatorStatics> statics;
++ QTimer periodicTimer;
++ QTimer singleUpdateTimer;
++ QGeoPositionInfo lastPosition;
++ QGeoPositionInfoSource::Error positionError = QGeoPositionInfoSource::NoError;
++ EventRegistrationToken statusToken;
++ EventRegistrationToken positionToken;
++ QMutex mutex;
++ bool updatesOngoing = false;
++ int minimumUpdateInterval = -1;
++ int updateInterval = -1;
++ InitializationState initState = InitializationState::Uninitialized;
++
++ PositionStatus positionStatus = PositionStatus_NotInitialized;
++ };
++
++ QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent)
++ : QGeoPositionInfoSource(parent)
++ , d_ptr(new QGeoPositionInfoSourceWinRTPrivate)
++ {
++ qRegisterMetaType<QGeoPositionInfoSource::Error>();
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
++ Q_D(QGeoPositionInfoSourceWinRT);
++ d->positionError = QGeoPositionInfoSource::NoError;
++ d->updatesOngoing = false;
++ d->positionToken.value = 0;
++ d->statusToken.value = 0;
++ }
++
++ QGeoPositionInfoSourceWinRT::~QGeoPositionInfoSourceWinRT()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ CoUninitialize();
++ }
++
++ int QGeoPositionInfoSourceWinRT::init()
++ {
++ Q_D(QGeoPositionInfoSourceWinRT);
++ Q_ASSERT(d->initState != InitializationState::Initializing);
++ if (d->initState == InitializationState::Initialized)
++ return 0;
++
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ d->initState = InitializationState::Initializing;
++ if (!requestAccess()) {
++ d->initState = InitializationState::Uninitialized;
++ setError(QGeoPositionInfoSource::AccessError);
++ qWarning ("Location access failed.");
++ return -1;
++ }
++ HRESULT hr = [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.");
++
++ if (d->minimumUpdateInterval == -1) {
++ UINT32 interval;
++ hr = d->locator->get_ReportInterval(&interval);
++ RETURN_HR_IF_FAILED("Could not retrieve report interval.");
++ d->minimumUpdateInterval = static_cast<int>(interval);
++ }
++ if (d->updateInterval == -1)
++ d->updateInterval = d->minimumUpdateInterval;
++ setUpdateInterval(d->updateInterval);
++
++ return hr;
++ }();
++ if (FAILED(hr)) {
++ d->initState = InitializationState::Uninitialized;
++ setError(QGeoPositionInfoSource::UnknownSourceError);
++ return -1;
++ }
++
++ d->periodicTimer.setSingleShot(true);
++ connect(&d->periodicTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::virtualPositionUpdate);
++
++ d->singleUpdateTimer.setSingleShot(true);
++ connect(&d->singleUpdateTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::singleUpdateTimeOut);
++
++ QGeoPositionInfoSource::PositioningMethods preferredMethods = preferredPositioningMethods();
++ if (preferredMethods == QGeoPositionInfoSource::NoPositioningMethods)
++ preferredMethods = QGeoPositionInfoSource::AllPositioningMethods;
++ setPreferredPositioningMethods(preferredMethods);
++
++ connect(this, &QGeoPositionInfoSourceWinRT::nativePositionUpdate, this, &QGeoPositionInfoSourceWinRT::updateSynchronized);
++ d->initState = InitializationState::Initialized;
++ return 0;
++ }
++
++ QGeoPositionInfo QGeoPositionInfoSourceWinRT::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(const QGeoPositionInfoSourceWinRT);
++ Q_UNUSED(fromSatellitePositioningMethodsOnly);
++ return d->lastPosition;
++ }
++
++ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supportedPositioningMethods() const
++ {
++ return requestAccess() ? QGeoPositionInfoSource::AllPositioningMethods
++ : QGeoPositionInfoSource::NoPositioningMethods;
++ }
++
++ void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods)
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << methods;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
++ QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
++ if (previousPreferredPositioningMethods == preferredPositioningMethods()
++ || d->initState == InitializationState::Uninitialized) {
++ return;
++ }
++
++ const bool needsRestart = d->positionToken.value != 0 || d->statusToken.value != 0;
++
++ if (needsRestart)
++ stopHandler();
++
++ PositionAccuracy acc = methods & PositioningMethod::SatellitePositioningMethods ?
++ PositionAccuracy::PositionAccuracy_High :
++ PositionAccuracy::PositionAccuracy_Default;
++ HRESULT hr = [d, acc]() {
++ return d->locator->put_DesiredAccuracy(acc);
++ }();
++ RETURN_VOID_IF_FAILED("Could not set positioning accuracy.");
++
++ if (needsRestart)
++ startHandler();
++ }
++
++ void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec)
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << msec;
++ Q_D(QGeoPositionInfoSourceWinRT);
++ if (d->initState == InitializationState::Uninitialized) {
++ d->updateInterval = msec;
++ return;
++ }
++
++ // minimumUpdateInterval is initialized to the lowest possible update interval in init().
++ // Passing 0 will cause an error on Windows 10.
++ // See https://docs.microsoft.com/en-us/uwp/api/windows.devices.geolocation.geolocator.reportinterval
++ if (msec < minimumUpdateInterval())
++ msec = minimumUpdateInterval();
++
++ const bool needsRestart = d->positionToken.value != 0 || d->statusToken.value != 0;
++
++ if (needsRestart)
++ stopHandler();
++
++ HRESULT hr = d->locator->put_ReportInterval(static_cast<UINT32>(msec));
++ if (FAILED(hr)) {
++ setError(QGeoPositionInfoSource::UnknownSourceError);
++ qErrnoWarning(hr, "Failed to set update interval");
++ return;
++ }
++
++ d->updateInterval = msec;
++ d->periodicTimer.setInterval(d->updateInterval);
++
++ QGeoPositionInfoSource::setUpdateInterval(d->updateInterval);
++
++ if (needsRestart)
++ startHandler();
++ }
++
++ int QGeoPositionInfoSourceWinRT::minimumUpdateInterval() const
++ {
++ Q_D(const QGeoPositionInfoSourceWinRT);
++ return d->minimumUpdateInterval == -1 ? 1000 : d->minimumUpdateInterval;
++ }
++
++ void QGeoPositionInfoSourceWinRT::startUpdates()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ setError(QGeoPositionInfoSource::NoError);
++ if (init() < 0)
++ return;
++
++ if (d->updatesOngoing)
++ return;
++
++ if (!startHandler())
++ return;
++ d->updatesOngoing = true;
++ d->periodicTimer.start();
++ }
++
++ void QGeoPositionInfoSourceWinRT::stopUpdates()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ if (init() < 0)
++ return;
++
++ stopHandler();
++ d->updatesOngoing = false;
++ d->periodicTimer.stop();
++ }
++
++ bool QGeoPositionInfoSourceWinRT::startHandler()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ // Check if already attached
++ if (d->positionToken.value != 0)
++ return true;
++
++ if (preferredPositioningMethods() == QGeoPositionInfoSource::NoPositioningMethods) {
++ setError(QGeoPositionInfoSource::UnknownSourceError);
++ return false;
++ }
++
++ if (!requestAccess()) {
++ setError(QGeoPositionInfoSource::AccessError);
++ return false;
++ }
++
++ HRESULT hr = [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);
++ RETURN_HR_IF_FAILED("Could not start position operation");
++
++ hr = d->locator->add_PositionChanged(Callback<GeoLocatorPositionHandler>(this,
++ &QGeoPositionInfoSourceWinRT::onPositionChanged).Get(),
++ &d->positionToken);
++ RETURN_HR_IF_FAILED("Could not add position handler");
++
++ hr = d->locator->add_StatusChanged(Callback<GeoLocatorStatusHandler>(this,
++ &QGeoPositionInfoSourceWinRT::onStatusChanged).Get(),
++ &d->statusToken);
++ RETURN_HR_IF_FAILED("Could not add status handler");
++ return hr;
++ }();
++ if (FAILED(hr)) {
++ setError(QGeoPositionInfoSource::UnknownSourceError);
++ return false;
++ }
++
++ return true;
++ }
++
++ void QGeoPositionInfoSourceWinRT::stopHandler()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ if (!d->positionToken.value)
++ return;
++ d->locator->remove_PositionChanged(d->positionToken);
++ d->locator->remove_StatusChanged(d->statusToken);
++ d->positionToken.value = 0;
++ d->statusToken.value = 0;
++ }
++
++ void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout)
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << timeout;
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ if (init() < 0)
++ return;
++
++ setError(QGeoPositionInfoSource::NoError);
++ if (timeout != 0 && timeout < minimumUpdateInterval()) {
++ d->positionError = QGeoPositionInfoSource::UpdateTimeoutError;
++ emit QGeoPositionInfoSource::errorOccurred(d->positionError);
++ return;
++ }
++
++ if (timeout == 0)
++ timeout = 2*60*1000; // Maximum time for cold start (see Android)
++
++ if (startHandler())
++ d->singleUpdateTimer.start(timeout);
++ }
++
++ void QGeoPositionInfoSourceWinRT::virtualPositionUpdate()
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_D(QGeoPositionInfoSourceWinRT);
++ QMutexLocker locker(&d->mutex);
++
++ // The operating system did not provide information in time
++ // Hence we send a virtual position update to keep same behavior
++ // 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 (d->lastPosition.isValid()) {
++ QGeoPositionInfo sent = d->lastPosition;
++ sent.setTimestamp(sent.timestamp().addMSecs(updateInterval()));
++ d->lastPosition = sent;
++ emit positionUpdated(sent);
++ }
++ d->periodicTimer.start();
++ }
++
++ void QGeoPositionInfoSourceWinRT::singleUpdateTimeOut()
++ {
++ Q_D(QGeoPositionInfoSourceWinRT);
++ QMutexLocker locker(&d->mutex);
++
++ if (d->singleUpdateTimer.isActive()) {
++ d->positionError = QGeoPositionInfoSource::UpdateTimeoutError;
++ emit QGeoPositionInfoSource::errorOccurred(d->positionError);
++ if (!d->updatesOngoing)
++ stopHandler();
++ }
++ }
++
++ void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInfo)
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << 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
++ {
++ Q_D(const QGeoPositionInfoSourceWinRT);
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << d->positionError;
++
++ // If the last encountered error was "Access denied", it is possible that the location service
++ // has been enabled by now so that we are clear again.
++ if ((d->positionError == QGeoPositionInfoSource::AccessError
++ || d->positionError == QGeoPositionInfoSource::UnknownSourceError) && requestAccess())
++ return QGeoPositionInfoSource::NoError;
++
++ return d->positionError;
++ }
++
++ void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positionError)
++ {
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ if (positionError == d->positionError)
++ return;
++
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << positionError;
++ d->positionError = positionError;
++ if (positionError != QGeoPositionInfoSource::NoError)
++ emit QGeoPositionInfoSource::errorOccurred(positionError);
++ }
++
++ void QGeoPositionInfoSourceWinRT::reactOnError(QGeoPositionInfoSource::Error positionError)
++ {
++ setError(positionError);
++ stopUpdates();
++ }
++
++ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPositionChangedEventArgs *args)
++ {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ Q_UNUSED(locator);
++
++ HRESULT hr;
++ ComPtr<IGeoposition> position;
++ hr = args->get_Position(&position);
++ RETURN_HR_IF_FAILED("Could not access position object.");
++
++ QGeoPositionInfo currentInfo;
++
++ ComPtr<IGeocoordinate> coord;
++ hr = position->get_Coordinate(&coord);
++ if (FAILED(hr))
++ qErrnoWarning(hr, "Could not access coordinate");
++
++ ComPtr<IGeocoordinateWithPoint> pointCoordinate;
++ hr = coord.As(&pointCoordinate);
++ if (FAILED(hr))
++ qErrnoWarning(hr, "Could not cast coordinate.");
++
++ ComPtr<IGeopoint> point;
++ hr = pointCoordinate->get_Point(&point);
++ if (FAILED(hr))
++ qErrnoWarning(hr, "Could not obtain coordinate's point.");
++
++ BasicGeoposition pos;
++ hr = point->get_Position(&pos);
++ if (FAILED(hr))
++ qErrnoWarning(hr, "Could not obtain point's position.");
++
++ DOUBLE lat = pos.Latitude;
++ DOUBLE lon = pos.Longitude;
++ DOUBLE alt = pos.Altitude;
++
++ bool altitudeAvailable = false;
++ ComPtr<IGeoshape> shape;
++ hr = point.As(&shape);
++ if (SUCCEEDED(hr) && shape) {
++ AltitudeReferenceSystem altitudeSystem;
++ hr = shape->get_AltitudeReferenceSystem(&altitudeSystem);
++ if (SUCCEEDED(hr) && altitudeSystem == AltitudeReferenceSystem_Geoid)
++ altitudeAvailable = true;
++ }
++ if (altitudeAvailable)
++ currentInfo.setCoordinate(QGeoCoordinate(lat, lon, alt));
++ else
++ currentInfo.setCoordinate(QGeoCoordinate(lat, lon));
++
++ DOUBLE accuracy;
++ hr = coord->get_Accuracy(&accuracy);
++ if (SUCCEEDED(hr))
++ currentInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy, accuracy);
++
++ IReference<double> *altAccuracy;
++ hr = coord->get_AltitudeAccuracy(&altAccuracy);
++ if (SUCCEEDED(hr) && altAccuracy) {
++ double value;
++ hr = altAccuracy->get_Value(&value);
++ currentInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy, value);
++ }
++
++ IReference<double> *speed;
++ hr = coord->get_Speed(&speed);
++ if (SUCCEEDED(hr) && speed) {
++ double value;
++ hr = speed->get_Value(&value);
++ currentInfo.setAttribute(QGeoPositionInfo::GroundSpeed, value);
++ }
++
++ IReference<double> *heading;
++ hr = coord->get_Heading(&heading);
++ if (SUCCEEDED(hr) && heading) {
++ double value;
++ hr = heading->get_Value(&value);
++ double mod = 0;
++ value = modf(value, &mod);
++ value += static_cast<int>(mod) % 360;
++ if (value >=0 && value <= 359) // get_Value might return nan/-nan
++ currentInfo.setAttribute(QGeoPositionInfo::Direction, value);
++ }
++
++ DateTime dateTime;
++ hr = coord->get_Timestamp(&dateTime);
++
++ if (dateTime.UniversalTime > 0) {
++ ULARGE_INTEGER uLarge;
++ uLarge.QuadPart = dateTime.UniversalTime;
++ FILETIME fileTime;
++ fileTime.dwHighDateTime = uLarge.HighPart;
++ fileTime.dwLowDateTime = uLarge.LowPart;
++ SYSTEMTIME systemTime;
++ if (FileTimeToSystemTime(&fileTime, &systemTime)) {
++ currentInfo.setTimestamp(QDateTime(QDate(systemTime.wYear, systemTime.wMonth,
++ systemTime.wDay),
++ QTime(systemTime.wHour, systemTime.wMinute,
++ systemTime.wSecond, systemTime.wMilliseconds),
++ QTimeZone::UTC));
++ }
++ }
++
++ emit nativePositionUpdate(currentInfo);
++
++ return S_OK;
++ }
++
++ static inline bool isDisabledStatus(PositionStatus status)
++ {
++ return status == PositionStatus_NoData || status == PositionStatus_Disabled
++ || status == PositionStatus_NotAvailable;
++ }
++
++ HRESULT QGeoPositionInfoSourceWinRT::onStatusChanged(IGeolocator *, IStatusChangedEventArgs *args)
++ {
++ Q_D(QGeoPositionInfoSourceWinRT);
++
++ const PositionStatus oldStatus = d->positionStatus;
++ HRESULT hr = args->get_Status(&d->positionStatus);
++ RETURN_HR_IF_FAILED("Could not obtain position status");
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << d->positionStatus;
++ QGeoPositionInfoSource::Error error = QGeoPositionInfoSource::NoError;
++ switch (d->positionStatus) {
++ case PositionStatus::PositionStatus_NotAvailable:
++ error = QGeoPositionInfoSource::UnknownSourceError;
++ break;
++ case PositionStatus::PositionStatus_Disabled:
++ error = QGeoPositionInfoSource::AccessError;
++ break;
++ case PositionStatus::PositionStatus_NoData:
++ error = QGeoPositionInfoSource::ClosedError;
++ break;
++ }
++ if (error != QGeoPositionInfoSource::NoError) {
++ QMetaObject::invokeMethod(this, "reactOnError", Qt::QueuedConnection,
++ Q_ARG(QGeoPositionInfoSource::Error,
++ QGeoPositionInfoSource::UnknownSourceError));
++ }
++
++ if (isDisabledStatus(oldStatus) != isDisabledStatus(d->positionStatus))
++ emit supportedPositioningMethodsChanged();
++
++ return S_OK;
++ }
++
++ bool QGeoPositionInfoSourceWinRT::requestAccess() const
++ {
++ Q_D(const QGeoPositionInfoSourceWinRT);
++ qCDebug(lcPositioningWinRT) << __FUNCTION__;
++ GeolocationAccessStatus accessStatus;
++
++ ComPtr<IAsyncOperation<GeolocationAccessStatus>> op;
++ HRESULT hr = [&op, d]() {
++ HRESULT hr;
++ if (!d->statics) {
++ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(),
++ IID_PPV_ARGS(&d->statics));
++ RETURN_HR_IF_FAILED("Could not access Geolocation Statics.");
++ }
++
++ hr = d->statics->RequestAccessAsync(&op);
++ return hr;
++ }();
++ if (FAILED(hr)) {
++ qCDebug(lcPositioningWinRT) << __FUNCTION__ << "Requesting access from Xaml thread failed";
++ return false;
++ }
++
++ await(op, &accessStatus);
++ return accessStatus == GeolocationAccessStatus_Allowed;
++ }
++
++ QT_END_NAMESPACE