Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosgeopositioninfosource.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qohosjsutils.h"
7#include <QtCore/private/qcore_ohos_p.h>
8#include <QtCore/private/qohoscommon_p.h>
9#include <QtCore/private/qohoslogger_p.h>
10#include <QtCore/qtimer.h>
11#include <algorithm>
12#include <cmath>
13#include <cstdlib>
14#include <functional>
15#include <memory>
16#include <optional>
17#include <utility>
18
19QT_BEGIN_NAMESPACE
20
21namespace {
22
30
39
40constexpr int coldStartMarginMs = 2 * 60 * 1000;
41constexpr int continuousUpdateTimerIntervalMs = 30 * 1000;
42
44{
45 switch (scenario) {
47 return "NAVIGATION";
49 return "SPORT";
51 return "TRANSPORT";
53 return "DAILY_LIFE_SERVICE";
54 }
55
56 qOhosReportFatalErrorAndAbort(
57 "%s received invalid UserActivityScenario: %d", Q_FUNC_INFO, scenario);
58}
59
60const char *toStaticString(LocationError locationError)
61{
62 switch (locationError) {
64 return "LOCATING_FAILED_DEFAULT";
66 return "LOCATING_FAILED_LOCATION_PERMISSION_DENIED";
68 return "LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED";
70 return "LOCATING_FAILED_LOCATION_SWITCH_OFF";
72 return "LOCATING_FAILED_INTERNET_ACCESS_FAILURE";
73 }
74
75 qOhosReportFatalErrorAndAbort(
76 "%s received invalid LocationError: %d", Q_FUNC_INFO, locationError);
77}
78
80 QGeoPositionInfoSource::PositioningMethods positioningMethods)
81{
82 qOhosPrintfDebug("%s: %d", Q_FUNC_INFO, static_cast<int>(positioningMethods));
83
84 if (positioningMethods.testFlag(QGeoPositionInfoSource::SatellitePositioningMethods))
86
87 if (positioningMethods.testFlag(QGeoPositionInfoSource::NonSatellitePositioningMethods))
89
90 return std::nullopt;
91}
92
93QGeoPositionInfo convertLocationObjectToPositionInfo(const QNapi::Object &locationObject)
94{
95 auto dateTime = QDateTime::fromMSecsSinceEpoch(
96 locationObject.get<QNapi::Number>("timeStamp").Int64Value());
97 QGeoCoordinate coordinate(
98 locationObject.get<QNapi::Number>("latitude"),
99 locationObject.get<QNapi::Number>("longitude"),
100 locationObject.get<QNapi::Number>("altitude"));
101
102 QGeoPositionInfo positionInfo(coordinate, dateTime);
103
104 positionInfo.setAttribute(
105 QGeoPositionInfo::Direction, locationObject.get<QNapi::Number>("direction"));
106 positionInfo.setAttribute(
107 QGeoPositionInfo::HorizontalAccuracy, locationObject.get<QNapi::Number>("accuracy"));
108 positionInfo.setAttribute(
109 QGeoPositionInfo::VerticalAccuracy, locationObject.get<QNapi::Number>("altitudeAccuracy"));
110 // NOTE: QGeoPositionInfo distinguishes GroundSpeed and VerticalSpeed, while OHOS provides only
111 // Location_BasicInfo::speed. Here, we assume, that since Location_BasicInfo::accuracy relates
112 // to HorizontalAccuracy, the Location_BasicInfo::speed relates to GroundSpeed (although, there
113 // is no information about that anywhere in the documentation).
114 positionInfo.setAttribute(
115 QGeoPositionInfo::GroundSpeed, locationObject.get<QNapi::Number>("speed"));
116
117 return positionInfo;
118}
119
121 QObject *contextObject, long intervalSec,
122 UserActivityScenario userActivityScenario,
123 QOhosConsumer<const QGeoPositionInfo &> positionInfoUpdateConsumer)
124{
125 auto sharedPositionInfoUpdateConsumer = QtOhos::moveToSharedPtr(std::move(positionInfoUpdateConsumer));
126
127 auto weakPositionInfoUpdateConsumer = QtOhos::makeWeakPtr(sharedPositionInfoUpdateConsumer);
128 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
129
130 auto registrationHandle = QOhosJsThreadGateway::eval(
131 [&](QOhosJsState &jsState) {
132 qOhosPrintfWarning("%s Interval in Seconds: %li", Q_FUNC_INFO, intervalSec);
133 auto continuousLocationRequest = QNapi::makeObject(
134 jsState.env(),
135 {
136 {"interval", intervalSec},
137 {"locationScenario", jsState.mapOhosEnumToJs(userActivityScenario)},
138 });
139
140 qOhosPrintfDebug(
141 "%s registering callback with scenario: %s",
142 Q_FUNC_INFO, toStaticString(userActivityScenario));
143
144 return QtOhos::registerOnOffMethodsBasedEventHandler(
145 getGeoLocationManagerObject(jsState), "locationChange",
146 [contextObjectRef, weakPositionInfoUpdateConsumer](const QOhosCallbackInfo &cbInfo) {
147 auto location = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
148 auto positionInfo = convertLocationObjectToPositionInfo(location);
149
150 contextObjectRef.visitInQtThreadIfAlive(
151 [weakPositionInfoUpdateConsumer, positionInfo](auto &) {
152 auto sharedPositionInfoUpdateConsumer = weakPositionInfoUpdateConsumer.lock();
153 if (sharedPositionInfoUpdateConsumer)
154 (*sharedPositionInfoUpdateConsumer)(positionInfo);
155 });
156 },
157 {
158 .extraOnArg = std::make_optional<QNapi::ValueWrapper>(continuousLocationRequest),
159 });
160 });
161
162 return QtOhos::moveToSharedPtr(
163 std::make_pair(sharedPositionInfoUpdateConsumer, registrationHandle));
164}
165
167 QObject *contextObject, int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
168 QOhosConsumer<const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
169{
170 auto userActivityScenario =
171 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
172 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
173 auto intervalSec = std::lround(static_cast<double>(intervalMs) / 1000.0);
174
175 return registerLocationChangeUpdateHandler(
176 contextObject, intervalSec, userActivityScenario,
177 [positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer), positioningMethods](const QGeoPositionInfo &positionInfo) {
178 positionInfoUpdateConsumer(positionInfo, positioningMethods);
179 });
180}
181
183 QObject *contextObject, int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
184 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
185{
186 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject << timeoutMs;
187
188 struct Context
189 {
190 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer;
191 QtOhos::QThreadSafeRef<QObject> contextObjectRef;
192 };
193
194 auto sharedContext = QtOhos::moveToSharedPtr(Context{
195 .positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer),
196 .contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject)
197 });
198
199 auto weakContext = QtOhos::makeWeakPtr(sharedContext);
200 auto positionInfoUpdateConsumerJsProxy =
201 [weakContext, positioningMethods](std::optional<QGeoPositionInfo> optPositionInfo) {
202 auto sharedContext = weakContext.lock();
203 if (sharedContext) {
204 sharedContext->contextObjectRef.visitInQtThreadIfAlive(
205 [weakContext, optPositionInfo, positioningMethods](auto &) {
206 auto sharedContext = weakContext.lock();
207 if (sharedContext)
208 sharedContext->positionInfoUpdateConsumer(optPositionInfo, positioningMethods);
209 });
210 }
211 };
212
213 QOhosJsThreadGateway::runAndWait(
214 [&](QOhosJsState &jsState) {
215 auto userActivityScenario =
216 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
217 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
218 auto currentLocationRequest = QNapi::makeObject(
219 jsState.env(),
220 {
221 {"scenario", jsState.mapOhosEnumToJs(userActivityScenario)},
222 {"timeoutMs", timeoutMs},
223 });
224
225 getGeoLocationManagerObject(jsState)
226 .evalToPromiseOrRejectOnThrow("getCurrentLocation(*)", {currentLocationRequest})
227 .withContext(std::move(positionInfoUpdateConsumerJsProxy))
228 .onThenWithContext([](const QOhosCallbackInfo &cbInfo, auto &positionInfoUpdateConsumerJsProxy) {
229 auto location = cbInfo.getFirstArg<QNapi::Object>("getCurrentLocation");
230 positionInfoUpdateConsumerJsProxy(convertLocationObjectToPositionInfo(location));
231 })
232 .onCatchWithContext([](const QOhosCallbackInfo &cbInfo, auto &positionInfoUpdateConsumerJsProxy) {
233 QtOhos::logJsCallbackError(cbInfo, "getCurrentLocation() failed");
234 positionInfoUpdateConsumerJsProxy(std::nullopt);
235 });
236 });
237
238 return sharedContext;
239}
240
242 QObject *contextObject, QOhosConsumer<LocationError> errorConsumer)
243{
244 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject;
245
246 auto sharedErrorConsumer = QtOhos::moveToSharedPtr(std::move(errorConsumer));
247
248 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
249 auto weakErrorConsumer = QtOhos::makeWeakPtr(sharedErrorConsumer);
250
251 auto registrationHandle = QOhosJsThreadGateway::eval(
252 [&](QOhosJsState &jsState) {
253 return QtOhos::registerOnOffMethodsBasedEventHandler(
254 getGeoLocationManagerObject(jsState), "locationError",
255 [contextObjectRef, weakErrorConsumer](const QOhosCallbackInfo &cbInfo) {
256 auto jsLocationError = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
257 auto locationError = cbInfo.jsState().mapOhosEnumFromJs<LocationError>(jsLocationError);
258 contextObjectRef.visitInQtThreadIfAlive(
259 [weakErrorConsumer, locationError](auto &) {
260 auto sharedErrorConsumer = weakErrorConsumer.lock();
261 if (sharedErrorConsumer)
262 (*sharedErrorConsumer)(locationError);
263 });
264 });
265 });
266
267 return QtOhos::makeSharedPtrWithAttachedExtraData(registrationHandle, sharedErrorConsumer);
268}
269
271{
272 switch (error) {
273 case LocationError::LOCATING_FAILED_DEFAULT:
274 return QGeoPositionInfoSource::UnknownSourceError;
275 case LocationError::LOCATING_FAILED_LOCATION_SWITCH_OFF:
276 return QGeoPositionInfoSource::ClosedError;
277 case LocationError::LOCATING_FAILED_LOCATION_PERMISSION_DENIED:
278 case LocationError::LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED:
279 case LocationError::LOCATING_FAILED_INTERNET_ACCESS_FAILURE:
280 return QGeoPositionInfoSource::AccessError;
281 }
282
283 qOhosPrintfWarning("%s received unknown error: %d", Q_FUNC_INFO, static_cast<int>(error));
284 return QGeoPositionInfoSource::UnknownSourceError;
285}
286
288{
289public:
291
293
295 QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const override;
297 void setPreferredPositioningMethods(PositioningMethods methods) override;
299 Error error() const override;
300
301public:
304
305 void requestUpdate(int timeout) override;
306
307protected:
309
310private:
311 void setErrorHelper(QGeoPositionInfoSource::Error error);
312 void continuousUpdateTimeout();
313
314 void updatePositionInfo(const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods);
315
317 QGeoPositionInfo m_lastUpdatedPositionInfo;
318 QGeoPositionInfo m_lastUpdatedPositionInfoFromSatelliteSource;
319
320 std::shared_ptr<void> m_locationErrorHandle;
321
322 std::shared_ptr<void> m_continuousLocationUpdatesHandle;
323 QTimer m_continuousUpdateTimeoutTimer;
324 qint64 m_lastUpdateTime = 0;
325 bool m_continuousUpdateTimeoutErrorRaised = false;
326
327 std::shared_ptr<void> m_singlePositionUpdateHandle;
328 std::unique_ptr<QTimer> m_singleUpdateTimeoutTimer;
329};
330
332{
334 qOhosDebug(QtForOhos)
335 << Q_FUNC_INFO
336 << "Location permission isn't granted. Can't create QOhosGeoPositionInfoSource";
337 return nullptr;
338 }
339
340 return new QOhosGeoPositionInfoSource(parent);
341}
342
345{
346 qOhosDebug(QtForOhos) << Q_FUNC_INFO << parent;
347
348 m_locationErrorHandle = registerLocationErrorHandler(
349 this,
350 [this](LocationError error) {
351 qOhosWarning(QtForOhos)
352 << Q_FUNC_INFO << "Received error from callback:" << toStaticString(error);
353 setErrorHelper(convertLocationErrorToQtError(error));
354 });
355
356 m_continuousUpdateTimeoutTimer.setSingleShot(false);
357 m_continuousUpdateTimeoutTimer.setInterval(continuousUpdateTimerIntervalMs);
358 QObject::connect(&m_continuousUpdateTimeoutTimer, &QTimer::timeout,
359 this, [this]() { continuousUpdateTimeout(); });
360}
361
363
365{
366 qOhosDebug(QtForOhos) << Q_FUNC_INFO << msec;
367
368 QGeoPositionInfoSource::setUpdateInterval(msec);
369
370 if (m_continuousLocationUpdatesHandle) {
373 }
374}
375
376QGeoPositionInfo QOhosGeoPositionInfoSource::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
377{
378 qOhosDebug(QtForOhos) << Q_FUNC_INFO << fromSatellitePositioningMethodsOnly;
379
380 return fromSatellitePositioningMethodsOnly
381 ? m_lastUpdatedPositionInfoFromSatelliteSource
382 : m_lastUpdatedPositionInfo;
383}
384
386{
387 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
388
389 return QGeoPositionInfoSource::AllPositioningMethods;
390}
391
393{
394 qOhosDebug(QtForOhos) << Q_FUNC_INFO << methods;
395
396 QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
397}
398
400{
401 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
402
403 return 1000;
404}
405
407{
408 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
409
410 return m_error;
411}
412
414{
415 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
416
417 if (m_continuousLocationUpdatesHandle) {
418 qOhosDebug(QtForOhos) << Q_FUNC_INFO << "Continuous updates already running. Ignoring";
419 return;
420 }
421
422 auto intervalMs = std::max(updateInterval(), minimumUpdateInterval());
423
424 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
425 m_continuousUpdateTimeoutErrorRaised = false;
426
427 m_continuousLocationUpdatesHandle =
428 makeContinuousPositionInfoUpdateProducer(
429 this, intervalMs,
430 preferredPositioningMethods(),
431 [this](const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods) {
432 updatePositionInfo(positionInfo, positioningMethods);
433 });
434
435 m_continuousUpdateTimeoutTimer.start();
436
437 setErrorHelper(QGeoPositionInfoSource::NoError);
438}
439
440void QOhosGeoPositionInfoSource::continuousUpdateTimeout()
441{
442 if (!m_continuousUpdateTimeoutErrorRaised) {
443 const auto now = QDateTime::currentMSecsSinceEpoch();
444 if ((now - m_lastUpdateTime) > (updateInterval() + coldStartMarginMs)) {
445 m_continuousUpdateTimeoutErrorRaised = true;
446 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
447 }
448 }
449}
450
452{
453 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
454
455 m_continuousLocationUpdatesHandle.reset();
456 m_continuousUpdateTimeoutTimer.stop();
457}
458
460{
461 qOhosDebug(QtForOhos) << Q_FUNC_INFO << timeoutMs;
462
463 if (m_singlePositionUpdateHandle) {
464 qOhosDebug(QtForOhos) << Q_FUNC_INFO << "Update already in progress. Ignoring this one";
465 return;
466 }
467
468 if (timeoutMs != 0 && timeoutMs < minimumUpdateInterval()) {
469 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
470 return;
471 }
472
473 auto timeout = timeoutMs != 0 ? timeoutMs : coldStartMarginMs;
474
475 m_singlePositionUpdateHandle = makeSinglePositionInfoUpdateProducer(
476 this,
477 updateInterval() >= minimumUpdateInterval() ? updateInterval() : minimumUpdateInterval(),
478 preferredPositioningMethods(),
479 [this](std::optional<QGeoPositionInfo> optPositionInfo, PositioningMethods positioningMethods) {
480 m_singlePositionUpdateHandle.reset();
481 m_singleUpdateTimeoutTimer.reset();
482 if (optPositionInfo.has_value())
483 updatePositionInfo(optPositionInfo.value(), positioningMethods);
484 else
485 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
486 });
487 if (!m_singlePositionUpdateHandle) {
488 qOhosWarning(QtForOhos) << Q_FUNC_INFO << "Failed to make single position info update producer";
489 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
490 return;
491 }
492
493 m_singleUpdateTimeoutTimer =
494 makeSingleShotUpdateTimeoutTimer(timeout, [this]() {
495 m_singlePositionUpdateHandle.reset();
496 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
497 });
498
499 setErrorHelper(QGeoPositionInfoSource::NoError);
500}
501
502void QOhosGeoPositionInfoSource::setErrorHelper(QGeoPositionInfoSource::Error newError)
503{
504 qOhosDebug(QtForOhos) << Q_FUNC_INFO << newError;
505
506 if (m_error == newError)
507 return;
508
509 m_error = newError;
510
511 if (newError != QGeoPositionInfoSource::NoError)
512 Q_EMIT QGeoPositionInfoSource::errorOccurred(m_error);
513}
514
515void QOhosGeoPositionInfoSource::updatePositionInfo(
516 const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods)
517{
518 qOhosDebug(QtForOhos) << Q_FUNC_INFO << positionInfo;
519
520 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
521 m_continuousUpdateTimeoutErrorRaised = false;
522 setErrorHelper(QGeoPositionInfoSource::NoError);
523
524 if (positioningMethods.testFlag(PositioningMethod::SatellitePositioningMethods))
525 m_lastUpdatedPositionInfoFromSatelliteSource = positionInfo;
526 m_lastUpdatedPositionInfo = positionInfo;
527 Q_EMIT positionUpdated(m_lastUpdatedPositionInfo);
528}
529
530}
531
533{
534 return QOhosGeoPositionInfoSource::tryMakeInstance(parent);
535}
536
537namespace QtOhos {
538
539template<>
541{
542 static constexpr const char *fullTypeName = "@ohos.geoLocationManager.UserActivityScenario";
543 static constexpr std::array<std::pair<UserActivityScenario, const char *>, 4> enumeratorsNames = {{
544 {UserActivityScenario::NAVIGATION, "NAVIGATION"},
546 {UserActivityScenario::TRANSPORT, "TRANSPORT"},
547 {UserActivityScenario::DAILY_LIFE_SERVICE, "DAILY_LIFE_SERVICE"},
548 }};
549};
550
551template<>
553{
554 static constexpr const char *fullTypeName = "@ohos.geoLocationManager.LocationError";
555 static constexpr std::array<std::pair<LocationError, const char *>, 5> enumeratorsNames = {{
556 {LocationError::LOCATING_FAILED_DEFAULT, "LOCATING_FAILED_DEFAULT"},
557 {LocationError::LOCATING_FAILED_LOCATION_PERMISSION_DENIED, "LOCATING_FAILED_LOCATION_PERMISSION_DENIED"},
558 {LocationError::LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED, "LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED"},
559 {LocationError::LOCATING_FAILED_LOCATION_SWITCH_OFF, "LOCATING_FAILED_LOCATION_SWITCH_OFF"},
560 {LocationError::LOCATING_FAILED_INTERNET_ACCESS_FAILURE, "LOCATING_FAILED_INTERNET_ACCESS_FAILURE"},
561 }};
562};
563
564}
565
566QT_END_NAMESPACE
void setPreferredPositioningMethods(PositioningMethods methods) override
void startUpdates() override
Starts emitting updates at regular intervals as specified by setUpdateInterval().
PositioningMethods supportedPositioningMethods() const override
Returns the positioning methods available to this source.
void requestUpdate(int timeout) override
Attempts to get the current position and emit positionUpdated() with this information.
static QOhosGeoPositionInfoSource * tryMakeInstance(QObject *parent)
Error error() const override
Returns the type of error that last occurred.
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const override
Returns an update containing the last known position, or a null update if none is available.
void stopUpdates() override
Stops emitting updates at regular intervals.
std::shared_ptr< void > registerLocationChangeUpdateHandler(QObject *contextObject, long intervalSec, UserActivityScenario userActivityScenario, QOhosConsumer< const QGeoPositionInfo & > positionInfoUpdateConsumer)
std::shared_ptr< void > registerLocationErrorHandler(QObject *contextObject, QOhosConsumer< LocationError > errorConsumer)
std::optional< UserActivityScenario > tryMapPositioningMethodsToUserActivityScenario(QGeoPositionInfoSource::PositioningMethods positioningMethods)
const char * toStaticString(UserActivityScenario scenario)
QGeoPositionInfo convertLocationObjectToPositionInfo(const QNapi::Object &locationObject)
QGeoPositionInfoSource::Error convertLocationErrorToQtError(LocationError error)
constexpr int continuousUpdateTimerIntervalMs
const char * toStaticString(LocationError locationError)
std::shared_ptr< void > makeContinuousPositionInfoUpdateProducer(QObject *contextObject, int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods, QOhosConsumer< const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods > positionInfoUpdateConsumer)
std::shared_ptr< void > makeSinglePositionInfoUpdateProducer(QObject *contextObject, int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods, QOhosConsumer< std::optional< QGeoPositionInfo >, QGeoPositionInfoSource::PositioningMethods > positionInfoUpdateConsumer)
QGeoPositionInfoSource * tryMakeQOhosGeoPositionInfoSource(QObject *parent)
bool checkLocationOrApproximatelyLocationPermissionGranted()
static constexpr std::array< std::pair< UserActivityScenario, const char * >, 4 > enumeratorsNames