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>
50 return "DAILY_LIFE_SERVICE";
53 qOhosReportFatalErrorAndAbort(
54 "%s received invalid UserActivityScenario: %d", Q_FUNC_INFO, scenario);
59 switch (locationError) {
61 return "LOCATING_FAILED_DEFAULT";
63 return "LOCATING_FAILED_LOCATION_PERMISSION_DENIED";
65 return "LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED";
67 return "LOCATING_FAILED_LOCATION_SWITCH_OFF";
69 return "LOCATING_FAILED_INTERNET_ACCESS_FAILURE";
72 qOhosReportFatalErrorAndAbort(
73 "%s received invalid LocationError: %d", Q_FUNC_INFO, locationError);
77 QGeoPositionInfoSource::PositioningMethods positioningMethods)
79 qOhosPrintfDebug(
"%s: %d", Q_FUNC_INFO,
static_cast<
int>(positioningMethods));
81 if (positioningMethods.testFlag(QGeoPositionInfoSource::SatellitePositioningMethods))
84 if (positioningMethods.testFlag(QGeoPositionInfoSource::NonSatellitePositioningMethods))
92 auto dateTime = QDateTime::fromMSecsSinceEpoch(
93 locationObject.get<QNapi::Number>(
"timeStamp").Int64Value());
94 QGeoCoordinate coordinate(
95 locationObject.get<QNapi::Number>(
"latitude"),
96 locationObject.get<QNapi::Number>(
"longitude"),
97 locationObject.get<QNapi::Number>(
"altitude"));
99 QGeoPositionInfo positionInfo(coordinate, dateTime);
101 positionInfo.setAttribute(
102 QGeoPositionInfo::Direction, locationObject.get<QNapi::Number>(
"direction"));
103 positionInfo.setAttribute(
104 QGeoPositionInfo::HorizontalAccuracy, locationObject.get<QNapi::Number>(
"accuracy"));
105 positionInfo.setAttribute(
106 QGeoPositionInfo::VerticalAccuracy, locationObject.get<QNapi::Number>(
"altitudeAccuracy"));
111 positionInfo.setAttribute(
112 QGeoPositionInfo::GroundSpeed, locationObject.get<QNapi::Number>(
"speed"));
118 QObject *contextObject,
long intervalSec,
120 QOhosConsumer<
const QGeoPositionInfo &> positionInfoUpdateConsumer)
122 auto sharedPositionInfoUpdateConsumer = QtOhos::moveToSharedPtr(std::move(positionInfoUpdateConsumer));
124 auto weakPositionInfoUpdateConsumer = QtOhos::makeWeakPtr(sharedPositionInfoUpdateConsumer);
125 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
127 auto registrationHandle = QOhosJsThreadGateway::eval(
128 [&](QOhosJsState &jsState) {
129 qOhosPrintfWarning(
"%s Interval in Seconds: %li", Q_FUNC_INFO, intervalSec);
130 auto continuousLocationRequest = QNapi::makeObject(
133 {
"interval", intervalSec},
134 {
"locationScenario", jsState.mapOhosEnumToJs(userActivityScenario)},
138 "%s registering callback with scenario: %s",
139 Q_FUNC_INFO, toStaticString(userActivityScenario));
141 return QtOhos::registerOnOffMethodsBasedEventHandler(
142 getGeoLocationManagerObject(jsState),
"locationChange",
143 [contextObjectRef, weakPositionInfoUpdateConsumer](
const QOhosCallbackInfo &cbInfo) {
144 auto location = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
145 auto positionInfo = convertLocationObjectToPositionInfo(location);
147 contextObjectRef.visitInQtThreadIfAlive(
148 [weakPositionInfoUpdateConsumer, positionInfo](
auto &) {
149 auto sharedPositionInfoUpdateConsumer = weakPositionInfoUpdateConsumer.lock();
150 if (sharedPositionInfoUpdateConsumer)
151 (*sharedPositionInfoUpdateConsumer)(positionInfo);
155 .extraOnArg = std::make_optional<QNapi::ValueWrapper>(continuousLocationRequest),
159 return QtOhos::moveToSharedPtr(
160 std::make_pair(sharedPositionInfoUpdateConsumer, registrationHandle));
164 QObject *contextObject,
int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
165 QOhosConsumer<
const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
167 auto userActivityScenario =
168 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
169 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
170 auto intervalSec =
std::lround(
static_cast<
double>(intervalMs) / 1000.0);
172 return registerLocationChangeUpdateHandler(
173 contextObject, intervalSec, userActivityScenario,
174 [positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer), positioningMethods](
const QGeoPositionInfo &positionInfo) {
175 positionInfoUpdateConsumer(positionInfo, positioningMethods);
180 QObject *contextObject,
int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
181 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
183 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject << timeoutMs;
187 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer;
188 QtOhos::QThreadSafeRef<QObject> contextObjectRef;
191 auto sharedContext = QtOhos::moveToSharedPtr(Context{
192 .positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer),
193 .contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject)
196 auto weakContext = QtOhos::makeWeakPtr(sharedContext);
197 auto positionInfoUpdateConsumerJsProxy =
198 [weakContext, positioningMethods](std::optional<QGeoPositionInfo> optPositionInfo) {
199 auto sharedContext = weakContext.lock();
201 sharedContext->contextObjectRef.visitInQtThreadIfAlive(
202 [weakContext, optPositionInfo, positioningMethods](
auto &) {
203 auto sharedContext = weakContext.lock();
205 sharedContext->positionInfoUpdateConsumer(optPositionInfo, positioningMethods);
210 QOhosJsThreadGateway::runAndWait(
211 [&](QOhosJsState &jsState) {
212 auto userActivityScenario =
213 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
214 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
215 auto currentLocationRequest = QNapi::makeObject(
218 {
"scenario", jsState.mapOhosEnumToJs(userActivityScenario)},
219 {
"timeoutMs", timeoutMs},
222 getGeoLocationManagerObject(jsState)
223 .evalToPromiseOrRejectOnThrow(
"getCurrentLocation(*)", {currentLocationRequest})
224 .withContext(std::move(positionInfoUpdateConsumerJsProxy))
225 .onThenWithContext([](
const QOhosCallbackInfo &cbInfo,
auto &positionInfoUpdateConsumerJsProxy) {
226 auto location = cbInfo.getFirstArg<QNapi::Object>(
"getCurrentLocation");
227 positionInfoUpdateConsumerJsProxy(convertLocationObjectToPositionInfo(location));
229 .onCatchWithContext([](
const QOhosCallbackInfo &cbInfo,
auto &positionInfoUpdateConsumerJsProxy) {
230 QtOhos::logJsCallbackError(cbInfo,
"getCurrentLocation() failed");
231 positionInfoUpdateConsumerJsProxy(std::nullopt);
235 return sharedContext;
239 QObject *contextObject, QOhosConsumer<LocationError> errorConsumer)
241 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject;
243 auto sharedErrorConsumer = QtOhos::moveToSharedPtr(std::move(errorConsumer));
245 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
246 auto weakErrorConsumer = QtOhos::makeWeakPtr(sharedErrorConsumer);
248 auto registrationHandle = QOhosJsThreadGateway::eval(
249 [&](QOhosJsState &jsState) {
250 return QtOhos::registerOnOffMethodsBasedEventHandler(
251 getGeoLocationManagerObject(jsState),
"locationError",
252 [contextObjectRef, weakErrorConsumer](
const QOhosCallbackInfo &cbInfo) {
253 auto jsLocationError = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
254 auto locationError = cbInfo.jsState().mapOhosEnumFromJs<LocationError>(jsLocationError);
255 contextObjectRef.visitInQtThreadIfAlive(
256 [weakErrorConsumer, locationError](
auto &) {
257 auto sharedErrorConsumer = weakErrorConsumer.lock();
258 if (sharedErrorConsumer)
259 (*sharedErrorConsumer)(locationError);
264 return QtOhos::makeSharedPtrWithAttachedExtraData(registrationHandle, sharedErrorConsumer);
270 case LocationError::LOCATING_FAILED_DEFAULT:
271 return QGeoPositionInfoSource::UnknownSourceError;
272 case LocationError::LOCATING_FAILED_LOCATION_SWITCH_OFF:
273 return QGeoPositionInfoSource::ClosedError;
274 case LocationError::LOCATING_FAILED_LOCATION_PERMISSION_DENIED:
275 case LocationError::LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED:
276 case LocationError::LOCATING_FAILED_INTERNET_ACCESS_FAILURE:
277 return QGeoPositionInfoSource::AccessError;
280 qOhosPrintfWarning(
"%s received unknown error: %d", Q_FUNC_INFO,
static_cast<
int>(error));
281 return QGeoPositionInfoSource::UnknownSourceError;
308 void setErrorHelper(QGeoPositionInfoSource::Error error);
310 void updatePositionInfo(
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods);
313 QGeoPositionInfo m_lastUpdatedPositionInfo;
314 QGeoPositionInfo m_lastUpdatedPositionInfoFromSatelliteSource;
316 std::shared_ptr<
void> m_locationErrorHandle;
318 std::shared_ptr<
void> m_continuousLocationUpdatesHandle;
319 std::unique_ptr<QTimer> m_continuousUpdateTimeoutTimer;
321 std::shared_ptr<
void> m_singlePositionUpdateHandle;
322 std::unique_ptr<QTimer> m_singleUpdateTimeoutTimer;
328 qOhosDebug(QtForOhos)
330 <<
"Location permission isn't granted. Can't create QOhosGeoPositionInfoSource";
340 qOhosDebug(QtForOhos) << Q_FUNC_INFO << parent;
342 m_locationErrorHandle = registerLocationErrorHandler(
344 [
this](LocationError error) {
345 qOhosWarning(QtForOhos)
346 << Q_FUNC_INFO <<
"Received error from callback:" << toStaticString(error);
347 setErrorHelper(convertLocationErrorToQtError(error));
355 qOhosDebug(QtForOhos) << Q_FUNC_INFO << msec;
357 QGeoPositionInfoSource::setUpdateInterval(msec);
359 if (m_continuousLocationUpdatesHandle)
365 qOhosDebug(QtForOhos) << Q_FUNC_INFO << fromSatellitePositioningMethodsOnly;
367 return fromSatellitePositioningMethodsOnly
368 ? m_lastUpdatedPositionInfoFromSatelliteSource
369 : m_lastUpdatedPositionInfo;
374 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
376 return QGeoPositionInfoSource::AllPositioningMethods;
381 qOhosDebug(QtForOhos) << Q_FUNC_INFO << methods;
383 QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
388 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
395 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
402 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
404 constexpr int allowedTimeoutDelayMs = 1000;
408 m_continuousLocationUpdatesHandle =
409 makeContinuousPositionInfoUpdateProducer(
411 preferredPositioningMethods(),
412 [
this, intervalMs](
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods) {
413 updatePositionInfo(positionInfo, positioningMethods);
415 m_continuousUpdateTimeoutTimer =
416 makeSingleShotUpdateTimeoutTimer(
417 intervalMs + allowedTimeoutDelayMs, [
this]() {
418 Q_EMIT errorOccurred(QGeoPositionInfoSource::UpdateTimeoutError);
422 m_continuousUpdateTimeoutTimer =
423 makeSingleShotUpdateTimeoutTimer(
424 intervalMs + allowedTimeoutDelayMs, [
this]() {
425 Q_EMIT errorOccurred(QGeoPositionInfoSource::UpdateTimeoutError);
428 setErrorHelper(QGeoPositionInfoSource::NoError);
433 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
435 m_continuousLocationUpdatesHandle.reset();
440 qOhosDebug(QtForOhos) << Q_FUNC_INFO << timeoutMs;
442 constexpr int defaultTimeoutMs = 3000;
444 if (m_singlePositionUpdateHandle) {
445 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Update already in progress. Ignoring this one";
450 Q_EMIT errorOccurred(QGeoPositionInfoSource::UpdateTimeoutError);
454 auto timeout = timeoutMs != 0 ? timeoutMs : defaultTimeoutMs;
456 m_singlePositionUpdateHandle = makeSinglePositionInfoUpdateProducer(
458 updateInterval() >= minimumUpdateInterval() ? updateInterval() : minimumUpdateInterval(),
459 preferredPositioningMethods(),
460 [
this](std::optional<QGeoPositionInfo> optPositionInfo, PositioningMethods positioningMethods) {
461 m_singlePositionUpdateHandle.reset();
462 m_singleUpdateTimeoutTimer.reset();
463 if (optPositionInfo.has_value()) {
464 updatePositionInfo(optPositionInfo.value(), positioningMethods);
466 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
467 Q_EMIT errorOccurred(QGeoPositionInfoSource::UpdateTimeoutError);
470 if (!m_singlePositionUpdateHandle) {
471 qOhosWarning(QtForOhos) << Q_FUNC_INFO <<
"Failed to make single position info update producer";
472 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
476 m_singleUpdateTimeoutTimer =
477 makeSingleShotUpdateTimeoutTimer(timeout, [
this]() {
478 m_singlePositionUpdateHandle.reset();
479 Q_EMIT errorOccurred(QGeoPositionInfoSource::UpdateTimeoutError);
482 setErrorHelper(QGeoPositionInfoSource::NoError);
487 qOhosDebug(QtForOhos) << Q_FUNC_INFO << newError;
489 if (m_error == newError)
494 if (newError != QGeoPositionInfoSource::NoError)
495 Q_EMIT QGeoPositionInfoSource::errorOccurred(m_error);
499 const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods)
501 qOhosDebug(QtForOhos) << Q_FUNC_INFO << positionInfo;
503 if (positioningMethods.testFlag(PositioningMethod::SatellitePositioningMethods))
504 m_lastUpdatedPositionInfoFromSatelliteSource = positionInfo;
505 m_lastUpdatedPositionInfo = positionInfo;
506 Q_EMIT positionUpdated(m_lastUpdatedPositionInfo);
513 return QOhosGeoPositionInfoSource::tryMakeInstance(parent);
521 static constexpr const char *
fullTypeName =
"@ohos.geoLocationManager.UserActivityScenario";
533 static constexpr const char *
fullTypeName =
"@ohos.geoLocationManager.LocationError";
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)
@ LOCATING_FAILED_DEFAULT
@ LOCATING_FAILED_INTERNET_ACCESS_FAILURE
@ LOCATING_FAILED_LOCATION_SWITCH_OFF
@ LOCATING_FAILED_BACKGROUND_PERMISSION_DENIED
@ LOCATING_FAILED_LOCATION_PERMISSION_DENIED
QGeoPositionInfo convertLocationObjectToPositionInfo(const QNapi::Object &locationObject)
QGeoPositionInfoSource::Error convertLocationErrorToQtError(LocationError error)
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()