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 .extraOnArg = std::make_optional<QNapi::ValueWrapper>(continuousLocationRequest),
150 return QtOhos::moveToSharedPtr(
151 std::make_pair(sharedPositionInfoUpdateConsumer, registrationHandle));
155 QObject *contextObject,
int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
156 QOhosConsumer<
const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
158 auto userActivityScenario =
159 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
160 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
161 auto intervalSec =
std::lround(
static_cast<
double>(intervalMs) / 1000.0);
163 return registerLocationChangeUpdateHandler(
164 contextObject, intervalSec, userActivityScenario,
165 [positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer), positioningMethods](
const QGeoPositionInfo &positionInfo) {
166 positionInfoUpdateConsumer(positionInfo, positioningMethods);
171 QObject *contextObject,
int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
172 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
174 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject << timeoutMs;
178 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer;
179 QtOhos::QThreadSafeRef<QObject> contextObjectRef;
182 auto sharedContext = QtOhos::moveToSharedPtr(Context{
183 .positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer),
184 .contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject)
187 auto weakContext = QtOhos::makeWeakPtr(sharedContext);
188 auto positionInfoUpdateConsumerJsProxy =
189 [weakContext, positioningMethods](std::optional<QGeoPositionInfo> optPositionInfo) {
190 auto sharedContext = weakContext.lock();
192 sharedContext->contextObjectRef.visitInQtThreadIfAlive(
193 [weakContext, optPositionInfo, positioningMethods](
auto &) {
194 auto sharedContext = weakContext.lock();
196 sharedContext->positionInfoUpdateConsumer(optPositionInfo, positioningMethods);
201 QOhosJsThreadGateway::runAndWait(
202 [&](QOhosJsState &jsState) {
203 auto userActivityScenario =
204 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
205 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
206 auto currentLocationRequest = QNapi::makeObject(
209 {
"scenario", jsState.mapOhosEnumToJs(userActivityScenario)},
210 {
"timeoutMs", timeoutMs},
213 getGeoLocationManagerObject(jsState)
214 .evalToPromiseOrRejectOnThrow(
"getCurrentLocation(*)", {currentLocationRequest})
215 .withContext(std::move(positionInfoUpdateConsumerJsProxy))
216 .onThenWithContext([](
const QOhosCallbackInfo &cbInfo,
auto &positionInfoUpdateConsumerJsProxy) {
217 auto location = cbInfo.getFirstArg<QNapi::Object>(
"getCurrentLocation");
218 positionInfoUpdateConsumerJsProxy(convertLocationObjectToPositionInfo(location));
220 .onCatchWithContext([](
const QOhosCallbackInfo &cbInfo,
auto &positionInfoUpdateConsumerJsProxy) {
221 QtOhos::logJsCallbackError(cbInfo,
"getCurrentLocation() failed");
222 positionInfoUpdateConsumerJsProxy(std::nullopt);
226 return sharedContext;
230 QObject *contextObject, QOhosConsumer<LocationError> errorConsumer)
232 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject;
234 auto sharedErrorConsumer = QtOhos::moveToSharedPtr(std::move(errorConsumer));
236 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
237 auto weakErrorConsumer = QtOhos::makeWeakPtr(sharedErrorConsumer);
239 auto registrationHandle = QOhosJsThreadGateway::eval(
240 [&](QOhosJsState &jsState) {
241 return QtOhos::makeProxyWithJsThreadDeleter(
242 registerQOhosOnOffMethodsBasedEventHandler(
243 getGeoLocationManagerObject(jsState),
"locationError",
244 [contextObjectRef, weakErrorConsumer](
const QOhosCallbackInfo &cbInfo) {
245 auto jsLocationError = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
246 auto locationError = cbInfo.jsState().mapOhosEnumFromJs<LocationError>(jsLocationError);
247 contextObjectRef.visitInQtThreadIfAlive(
248 [weakErrorConsumer, locationError](
auto &) {
249 auto sharedErrorConsumer = weakErrorConsumer.lock();
250 if (sharedErrorConsumer)
251 (*sharedErrorConsumer)(locationError);
256 return QtOhos::makeSharedPtrWithAttachedExtraData(registrationHandle, sharedErrorConsumer);
262 case LocationError::LOCATING_FAILED_DEFAULT:
263 return QGeoPositionInfoSource::UnknownSourceError;
264 case LocationError::LOCATING_FAILED_LOCATION_SWITCH_OFF:
265 return QGeoPositionInfoSource::ClosedError;
266 case LocationError::LOCATING_FAILED_LOCATION_PERMISSION_DENIED:
267 case LocationError::LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED:
268 case LocationError::LOCATING_FAILED_INTERNET_ACCESS_FAILURE:
269 return QGeoPositionInfoSource::AccessError;
272 qOhosPrintfWarning(
"%s received unknown error: %d", Q_FUNC_INFO,
static_cast<
int>(error));
273 return QGeoPositionInfoSource::UnknownSourceError;
300 void setErrorHelper(QGeoPositionInfoSource::Error error);
301 void continuousUpdateTimeout();
303 void updatePositionInfo(
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods);
306 QGeoPositionInfo m_lastUpdatedPositionInfo;
307 QGeoPositionInfo m_lastUpdatedPositionInfoFromSatelliteSource;
309 std::shared_ptr<
void> m_locationErrorHandle;
311 std::shared_ptr<
void> m_continuousLocationUpdatesHandle;
312 QTimer m_continuousUpdateTimeoutTimer;
313 qint64 m_lastUpdateTime = 0;
314 bool m_continuousUpdateTimeoutErrorRaised =
false;
316 std::shared_ptr<
void> m_singlePositionUpdateHandle;
317 std::unique_ptr<QTimer> m_singleUpdateTimeoutTimer;
323 qOhosDebug(QtForOhos)
325 <<
"Location permission isn't granted. Can't create QOhosGeoPositionInfoSource";
335 qOhosDebug(QtForOhos) << Q_FUNC_INFO << parent;
337 m_locationErrorHandle = registerLocationErrorHandler(
339 [
this](LocationError error) {
340 qOhosWarning(QtForOhos)
341 << Q_FUNC_INFO <<
"Received error from callback:" << toStaticString(error);
342 setErrorHelper(convertLocationErrorToQtError(error));
345 m_continuousUpdateTimeoutTimer.setSingleShot(
false);
346 m_continuousUpdateTimeoutTimer.setInterval(continuousUpdateTimerIntervalMs);
347 QObject::connect(&m_continuousUpdateTimeoutTimer, &QTimer::timeout,
348 this, [
this]() { continuousUpdateTimeout(); });
355 qOhosDebug(QtForOhos) << Q_FUNC_INFO << msec;
357 QGeoPositionInfoSource::setUpdateInterval(msec);
359 if (m_continuousLocationUpdatesHandle) {
367 qOhosDebug(QtForOhos) << Q_FUNC_INFO << fromSatellitePositioningMethodsOnly;
369 return fromSatellitePositioningMethodsOnly
370 ? m_lastUpdatedPositionInfoFromSatelliteSource
371 : m_lastUpdatedPositionInfo;
376 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
378 return QGeoPositionInfoSource::AllPositioningMethods;
383 qOhosDebug(QtForOhos) << Q_FUNC_INFO << methods;
385 QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
390 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
397 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
404 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
406 if (m_continuousLocationUpdatesHandle) {
407 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Continuous updates already running. Ignoring";
413 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
414 m_continuousUpdateTimeoutErrorRaised =
false;
416 m_continuousLocationUpdatesHandle =
417 makeContinuousPositionInfoUpdateProducer(
419 preferredPositioningMethods(),
420 [
this](
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods) {
421 updatePositionInfo(positionInfo, positioningMethods);
424 m_continuousUpdateTimeoutTimer.start();
426 setErrorHelper(QGeoPositionInfoSource::NoError);
431 if (!m_continuousUpdateTimeoutErrorRaised) {
432 const auto now = QDateTime::currentMSecsSinceEpoch();
433 if ((now - m_lastUpdateTime) > (updateInterval() + coldStartMarginMs)) {
434 m_continuousUpdateTimeoutErrorRaised =
true;
435 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
442 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
444 m_continuousLocationUpdatesHandle.reset();
445 m_continuousUpdateTimeoutTimer.stop();
450 qOhosDebug(QtForOhos) << Q_FUNC_INFO << timeoutMs;
452 if (m_singlePositionUpdateHandle) {
453 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Update already in progress. Ignoring this one";
458 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
464 m_singlePositionUpdateHandle = makeSinglePositionInfoUpdateProducer(
466 updateInterval() >= minimumUpdateInterval() ? updateInterval() : minimumUpdateInterval(),
467 preferredPositioningMethods(),
468 [
this](std::optional<QGeoPositionInfo> optPositionInfo, PositioningMethods positioningMethods) {
469 m_singlePositionUpdateHandle.reset();
470 m_singleUpdateTimeoutTimer.reset();
471 if (optPositionInfo.has_value())
472 updatePositionInfo(optPositionInfo.value(), positioningMethods);
474 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
476 if (!m_singlePositionUpdateHandle) {
477 qOhosWarning(QtForOhos) << Q_FUNC_INFO <<
"Failed to make single position info update producer";
478 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
482 m_singleUpdateTimeoutTimer =
483 makeSingleShotUpdateTimeoutTimer(timeout, [
this]() {
484 m_singlePositionUpdateHandle.reset();
485 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
488 setErrorHelper(QGeoPositionInfoSource::NoError);
493 qOhosDebug(QtForOhos) << Q_FUNC_INFO << newError;
495 if (m_error == newError)
500 if (newError != QGeoPositionInfoSource::NoError)
501 Q_EMIT QGeoPositionInfoSource::errorOccurred(m_error);
505 const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods)
507 qOhosDebug(QtForOhos) << Q_FUNC_INFO << positionInfo;
509 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
510 m_continuousUpdateTimeoutErrorRaised =
false;
511 setErrorHelper(QGeoPositionInfoSource::NoError);
513 if (positioningMethods.testFlag(PositioningMethod::SatellitePositioningMethods))
514 m_lastUpdatedPositionInfoFromSatelliteSource = positionInfo;
515 m_lastUpdatedPositionInfo = positionInfo;
516 Q_EMIT positionUpdated(m_lastUpdatedPositionInfo);
523 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
constexpr int coldStartMarginMs
QtOhos::enums::ohos::geoLocationManager::LocationError LocationError
const char * toStaticString(LocationError locationError)
std::shared_ptr< void > makeContinuousPositionInfoUpdateProducer(QObject *contextObject, int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods, QOhosConsumer< const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods > positionInfoUpdateConsumer)
QtOhos::enums::ohos::geoLocationManager::UserActivityScenario UserActivityScenario
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()