7#include <QtCore/private/qcore_ohos_p.h>
8#include <QtCore/private/qohoscommon_p.h>
9#include <QtCore/private/qohosjstools_p.h>
10#include <QtCore/private/qohoslogger_p.h>
11#include <QtCore/qtimer.h>
40 return "DAILY_LIFE_SERVICE";
43 qOhosReportFatalErrorAndAbort(
44 "%s received invalid UserActivityScenario: %d", Q_FUNC_INFO, scenario);
49 switch (locationError) {
51 return "LOCATING_FAILED_DEFAULT";
53 return "LOCATING_FAILED_LOCATION_PERMISSION_DENIED";
55 return "LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED";
57 return "LOCATING_FAILED_LOCATION_SWITCH_OFF";
59 return "LOCATING_FAILED_INTERNET_ACCESS_FAILURE";
62 qOhosReportFatalErrorAndAbort(
63 "%s received invalid LocationError: %d", Q_FUNC_INFO, locationError);
67 QGeoPositionInfoSource::PositioningMethods positioningMethods)
69 qOhosPrintfDebug(
"%s: %d", Q_FUNC_INFO,
static_cast<
int>(positioningMethods));
71 if (positioningMethods.testFlag(QGeoPositionInfoSource::SatellitePositioningMethods))
74 if (positioningMethods.testFlag(QGeoPositionInfoSource::NonSatellitePositioningMethods))
82 auto dateTime = QDateTime::fromMSecsSinceEpoch(
83 locationObject.get<QNapi::Number>(
"timeStamp").Int64Value());
84 QGeoCoordinate coordinate(
85 locationObject.get<QNapi::Number>(
"latitude"),
86 locationObject.get<QNapi::Number>(
"longitude"),
87 locationObject.get<QNapi::Number>(
"altitude"));
89 QGeoPositionInfo positionInfo(coordinate, dateTime);
91 positionInfo.setAttribute(
92 QGeoPositionInfo::Direction, locationObject.get<QNapi::Number>(
"direction"));
93 positionInfo.setAttribute(
94 QGeoPositionInfo::HorizontalAccuracy, locationObject.get<QNapi::Number>(
"accuracy"));
95 positionInfo.setAttribute(
96 QGeoPositionInfo::VerticalAccuracy, locationObject.get<QNapi::Number>(
"altitudeAccuracy"));
101 positionInfo.setAttribute(
102 QGeoPositionInfo::GroundSpeed, locationObject.get<QNapi::Number>(
"speed"));
108 QObject *contextObject,
long intervalSec,
110 QOhosConsumer<
const QGeoPositionInfo &> positionInfoUpdateConsumer)
112 auto sharedPositionInfoUpdateConsumer = QtOhos::moveToSharedPtr(std::move(positionInfoUpdateConsumer));
114 auto weakPositionInfoUpdateConsumer = QtOhos::makeWeakPtr(sharedPositionInfoUpdateConsumer);
115 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
117 auto registrationHandle = QOhosJsThreadGateway::eval(
118 [&](QOhosJsState &jsState) {
119 qOhosPrintfWarning(
"%s Interval in Seconds: %li", Q_FUNC_INFO, intervalSec);
120 auto continuousLocationRequest = QNapi::makeObject(
123 {
"interval", intervalSec},
124 {
"locationScenario", jsState.mapOhosEnumToJs(userActivityScenario)},
128 "%s registering callback with scenario: %s",
129 Q_FUNC_INFO, toStaticString(userActivityScenario));
131 return QtOhos::makeProxyWithJsThreadDeleter(
132 registerQOhosOnOffMethodsBasedEventHandler(
133 getGeoLocationManagerObject(jsState),
"locationChange",
134 [contextObjectRef, weakPositionInfoUpdateConsumer](
const QOhosCallbackInfo &cbInfo) {
135 auto location = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
136 auto positionInfo = convertLocationObjectToPositionInfo(location);
138 contextObjectRef.visitInQtThreadIfAlive(
139 [weakPositionInfoUpdateConsumer, positionInfo](
auto &) {
140 auto sharedPositionInfoUpdateConsumer = weakPositionInfoUpdateConsumer.lock();
141 if (sharedPositionInfoUpdateConsumer)
142 (*sharedPositionInfoUpdateConsumer)(positionInfo);
146 .optEventSourceAliveCheckFunc = {},
147 .extraOnArg = std::make_optional<QNapi::ValueWrapper>(continuousLocationRequest),
149 .optOnCallExceptionHandler = {},
153 return QtOhos::moveToSharedPtr(
154 std::make_pair(sharedPositionInfoUpdateConsumer, registrationHandle));
158 QObject *contextObject,
int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
159 QOhosConsumer<
const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
161 auto userActivityScenario =
162 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
163 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
164 auto intervalSec =
std::lround(
static_cast<
double>(intervalMs) / 1000.0);
166 return registerLocationChangeUpdateHandler(
167 contextObject, intervalSec, userActivityScenario,
168 [positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer), positioningMethods](
const QGeoPositionInfo &positionInfo) {
169 positionInfoUpdateConsumer(positionInfo, positioningMethods);
174 QObject *contextObject,
int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
175 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
177 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject << timeoutMs;
181 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer;
182 QtOhos::QThreadSafeRef<QObject> contextObjectRef;
185 auto sharedContext = QtOhos::moveToSharedPtr(Context{
186 .positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer),
187 .contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject)
190 auto weakContext = QtOhos::makeWeakPtr(sharedContext);
191 auto sharedPositionInfoUpdateProxy = QtOhos::moveToSharedPtr(
192 [weakContext, positioningMethods](std::optional<QGeoPositionInfo> optPositionInfo) {
193 auto sharedContext = weakContext.lock();
195 sharedContext->contextObjectRef.visitInQtThreadIfAlive(
196 [weakContext, optPositionInfo, positioningMethods](
auto &) {
197 auto sharedContext = weakContext.lock();
199 sharedContext->positionInfoUpdateConsumer(optPositionInfo, positioningMethods);
204 QOhosJsThreadGateway::runAndWait(
205 [&](QOhosJsState &jsState) {
206 auto userActivityScenario =
207 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
208 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
209 auto currentLocationRequest = QNapi::makeObject(
212 {
"scenario", jsState.mapOhosEnumToJs(userActivityScenario)},
213 {
"timeoutMs", timeoutMs},
216 getGeoLocationManagerObject(jsState)
217 .evalToPromiseOrRejectOnThrow(
"getCurrentLocation(*)", {currentLocationRequest})
218 .onThen([sharedPositionInfoUpdateProxy](
const QOhosCallbackInfo &cbInfo) {
219 auto location = cbInfo.getFirstArg<QNapi::Object>(
"getCurrentLocation");
220 (*sharedPositionInfoUpdateProxy)(convertLocationObjectToPositionInfo(location));
222 .onCatch([sharedPositionInfoUpdateProxy](
const QOhosCallbackInfo &cbInfo) {
223 QtOhos::logJsCallbackError(cbInfo,
"getCurrentLocation() failed");
224 (*sharedPositionInfoUpdateProxy)(std::nullopt);
228 return sharedContext;
232 QObject *contextObject, QOhosConsumer<LocationError> errorConsumer)
234 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject;
236 auto sharedErrorConsumer = QtOhos::moveToSharedPtr(std::move(errorConsumer));
238 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
239 auto weakErrorConsumer = QtOhos::makeWeakPtr(sharedErrorConsumer);
241 auto registrationHandle = QOhosJsThreadGateway::eval(
242 [&](QOhosJsState &jsState) {
243 return QtOhos::makeProxyWithJsThreadDeleter(
244 registerQOhosOnOffMethodsBasedEventHandler(
245 getGeoLocationManagerObject(jsState),
"locationError",
246 [contextObjectRef, weakErrorConsumer](
const QOhosCallbackInfo &cbInfo) {
247 auto jsLocationError = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
248 auto locationError = cbInfo.jsState().mapOhosEnumFromJs<LocationError>(jsLocationError);
249 contextObjectRef.visitInQtThreadIfAlive(
250 [weakErrorConsumer, locationError](
auto &) {
251 auto sharedErrorConsumer = weakErrorConsumer.lock();
252 if (sharedErrorConsumer)
253 (*sharedErrorConsumer)(locationError);
258 return QtOhos::makeSharedPtrWithAttachedExtraData(registrationHandle, sharedErrorConsumer);
264 case LocationError::LOCATING_FAILED_DEFAULT:
265 return QGeoPositionInfoSource::UnknownSourceError;
266 case LocationError::LOCATING_FAILED_LOCATION_SWITCH_OFF:
267 return QGeoPositionInfoSource::ClosedError;
268 case LocationError::LOCATING_FAILED_LOCATION_PERMISSION_DENIED:
269 case LocationError::LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED:
270 case LocationError::LOCATING_FAILED_INTERNET_ACCESS_FAILURE:
271 return QGeoPositionInfoSource::AccessError;
274 qOhosPrintfWarning(
"%s received unknown error: %d", Q_FUNC_INFO,
static_cast<
int>(error));
275 return QGeoPositionInfoSource::UnknownSourceError;
302 void setErrorHelper(QGeoPositionInfoSource::Error error);
303 void continuousUpdateTimeout();
305 void updatePositionInfo(
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods);
308 QGeoPositionInfo m_lastUpdatedPositionInfo;
309 QGeoPositionInfo m_lastUpdatedPositionInfoFromSatelliteSource;
311 std::shared_ptr<
void> m_locationErrorHandle;
313 std::shared_ptr<
void> m_continuousLocationUpdatesHandle;
314 QTimer m_continuousUpdateTimeoutTimer;
315 qint64 m_lastUpdateTime = 0;
316 bool m_continuousUpdateTimeoutErrorRaised =
false;
318 std::shared_ptr<
void> m_singlePositionUpdateHandle;
319 std::unique_ptr<QTimer> m_singleUpdateTimeoutTimer;
325 qOhosDebug(QtForOhos)
327 <<
"Location permission isn't granted. Can't create QOhosGeoPositionInfoSource";
337 qOhosDebug(QtForOhos) << Q_FUNC_INFO << parent;
339 m_locationErrorHandle = registerLocationErrorHandler(
341 [
this](LocationError error) {
342 qOhosWarning(QtForOhos)
343 << Q_FUNC_INFO <<
"Received error from callback:" << toStaticString(error);
344 setErrorHelper(convertLocationErrorToQtError(error));
347 m_continuousUpdateTimeoutTimer.setSingleShot(
false);
348 m_continuousUpdateTimeoutTimer.setInterval(continuousUpdateTimerIntervalMs);
349 QObject::connect(&m_continuousUpdateTimeoutTimer, &QTimer::timeout,
350 this, [
this]() { continuousUpdateTimeout(); });
357 qOhosDebug(QtForOhos) << Q_FUNC_INFO << msec;
359 QGeoPositionInfoSource::setUpdateInterval(msec);
361 if (m_continuousLocationUpdatesHandle) {
369 qOhosDebug(QtForOhos) << Q_FUNC_INFO << fromSatellitePositioningMethodsOnly;
371 return fromSatellitePositioningMethodsOnly
372 ? m_lastUpdatedPositionInfoFromSatelliteSource
373 : m_lastUpdatedPositionInfo;
378 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
380 return QGeoPositionInfoSource::AllPositioningMethods;
385 qOhosDebug(QtForOhos) << Q_FUNC_INFO << methods;
387 QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
392 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
399 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
406 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
408 if (m_continuousLocationUpdatesHandle) {
409 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Continuous updates already running. Ignoring";
415 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
416 m_continuousUpdateTimeoutErrorRaised =
false;
418 m_continuousLocationUpdatesHandle =
419 makeContinuousPositionInfoUpdateProducer(
421 preferredPositioningMethods(),
422 [
this](
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods) {
423 updatePositionInfo(positionInfo, positioningMethods);
426 m_continuousUpdateTimeoutTimer.start();
428 setErrorHelper(QGeoPositionInfoSource::NoError);
433 if (!m_continuousUpdateTimeoutErrorRaised) {
434 const auto now = QDateTime::currentMSecsSinceEpoch();
435 if ((now - m_lastUpdateTime) > (updateInterval() + coldStartMarginMs)) {
436 m_continuousUpdateTimeoutErrorRaised =
true;
437 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
444 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
446 m_continuousLocationUpdatesHandle.reset();
447 m_continuousUpdateTimeoutTimer.stop();
452 qOhosDebug(QtForOhos) << Q_FUNC_INFO << timeoutMs;
454 if (m_singlePositionUpdateHandle) {
455 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Update already in progress. Ignoring this one";
460 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
466 m_singlePositionUpdateHandle = makeSinglePositionInfoUpdateProducer(
468 updateInterval() >= minimumUpdateInterval() ? updateInterval() : minimumUpdateInterval(),
469 preferredPositioningMethods(),
470 [
this](std::optional<QGeoPositionInfo> optPositionInfo, PositioningMethods positioningMethods) {
471 m_singlePositionUpdateHandle.reset();
472 m_singleUpdateTimeoutTimer.reset();
473 if (optPositionInfo.has_value())
474 updatePositionInfo(optPositionInfo.value(), positioningMethods);
476 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
478 if (!m_singlePositionUpdateHandle) {
479 qOhosWarning(QtForOhos) << Q_FUNC_INFO <<
"Failed to make single position info update producer";
480 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
484 m_singleUpdateTimeoutTimer =
485 makeSingleShotUpdateTimeoutTimer(timeout, [
this]() {
486 m_singlePositionUpdateHandle.reset();
487 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
490 setErrorHelper(QGeoPositionInfoSource::NoError);
495 qOhosDebug(QtForOhos) << Q_FUNC_INFO << newError;
497 if (m_error == newError)
502 if (newError != QGeoPositionInfoSource::NoError)
503 Q_EMIT QGeoPositionInfoSource::errorOccurred(m_error);
507 const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods)
509 qOhosDebug(QtForOhos) << Q_FUNC_INFO << positionInfo;
511 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
512 m_continuousUpdateTimeoutErrorRaised =
false;
513 setErrorHelper(QGeoPositionInfoSource::NoError);
515 if (positioningMethods.testFlag(PositioningMethod::SatellitePositioningMethods))
516 m_lastUpdatedPositionInfoFromSatelliteSource = positionInfo;
517 m_lastUpdatedPositionInfo = positionInfo;
518 Q_EMIT positionUpdated(m_lastUpdatedPositionInfo);
525 return QOhosGeoPositionInfoSource::tryMakeInstance(parent);
void setPreferredPositioningMethods(PositioningMethods methods) override
~QOhosGeoPositionInfoSource() 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 setUpdateInterval(int msec) override
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.
QOhosGeoPositionInfoSource(QObject *parent)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const override
Returns an update containing the last known position, or a null update if none is available.
int minimumUpdateInterval() const override
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
QtOhosPositioning::enums::ohos::geoLocationManager::UserActivityScenario UserActivityScenario
constexpr int coldStartMarginMs
const char * toStaticString(LocationError locationError)
std::shared_ptr< void > makeContinuousPositionInfoUpdateProducer(QObject *contextObject, int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods, QOhosConsumer< const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods > positionInfoUpdateConsumer)
QtOhosPositioning::enums::ohos::geoLocationManager::LocationError LocationError
std::shared_ptr< void > makeSinglePositionInfoUpdateProducer(QObject *contextObject, int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods, QOhosConsumer< std::optional< QGeoPositionInfo >, QGeoPositionInfoSource::PositioningMethods > positionInfoUpdateConsumer)
@ LOCATING_FAILED_DEFAULT
@ LOCATING_FAILED_INTERNET_ACCESS_FAILURE
@ LOCATING_FAILED_LOCATION_SWITCH_OFF
@ LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED
@ LOCATING_FAILED_LOCATION_PERMISSION_DENIED
QGeoPositionInfoSource * tryMakeQOhosGeoPositionInfoSource(QObject *parent)
bool checkLocationOrApproximatelyLocationPermissionGranted()