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>
53 return "DAILY_LIFE_SERVICE";
56 qOhosReportFatalErrorAndAbort(
57 "%s received invalid UserActivityScenario: %d", Q_FUNC_INFO, scenario);
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";
75 qOhosReportFatalErrorAndAbort(
76 "%s received invalid LocationError: %d", Q_FUNC_INFO, locationError);
80 QGeoPositionInfoSource::PositioningMethods positioningMethods)
82 qOhosPrintfDebug(
"%s: %d", Q_FUNC_INFO,
static_cast<
int>(positioningMethods));
84 if (positioningMethods.testFlag(QGeoPositionInfoSource::SatellitePositioningMethods))
87 if (positioningMethods.testFlag(QGeoPositionInfoSource::NonSatellitePositioningMethods))
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"));
102 QGeoPositionInfo positionInfo(coordinate, dateTime);
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"));
114 positionInfo.setAttribute(
115 QGeoPositionInfo::GroundSpeed, locationObject.get<QNapi::Number>(
"speed"));
121 QObject *contextObject,
long intervalSec,
123 QOhosConsumer<
const QGeoPositionInfo &> positionInfoUpdateConsumer)
125 auto sharedPositionInfoUpdateConsumer = QtOhos::moveToSharedPtr(std::move(positionInfoUpdateConsumer));
127 auto weakPositionInfoUpdateConsumer = QtOhos::makeWeakPtr(sharedPositionInfoUpdateConsumer);
128 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
130 auto registrationHandle = QOhosJsThreadGateway::eval(
131 [&](QOhosJsState &jsState) {
132 qOhosPrintfWarning(
"%s Interval in Seconds: %li", Q_FUNC_INFO, intervalSec);
133 auto continuousLocationRequest = QNapi::makeObject(
136 {
"interval", intervalSec},
137 {
"locationScenario", jsState.mapOhosEnumToJs(userActivityScenario)},
141 "%s registering callback with scenario: %s",
142 Q_FUNC_INFO, toStaticString(userActivityScenario));
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);
150 contextObjectRef.visitInQtThreadIfAlive(
151 [weakPositionInfoUpdateConsumer, positionInfo](
auto &) {
152 auto sharedPositionInfoUpdateConsumer = weakPositionInfoUpdateConsumer.lock();
153 if (sharedPositionInfoUpdateConsumer)
154 (*sharedPositionInfoUpdateConsumer)(positionInfo);
158 .extraOnArg = std::make_optional<QNapi::ValueWrapper>(continuousLocationRequest),
162 return QtOhos::moveToSharedPtr(
163 std::make_pair(sharedPositionInfoUpdateConsumer, registrationHandle));
167 QObject *contextObject,
int intervalMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
168 QOhosConsumer<
const QGeoPositionInfo &, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
170 auto userActivityScenario =
171 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
172 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
173 auto intervalSec =
std::lround(
static_cast<
double>(intervalMs) / 1000.0);
175 return registerLocationChangeUpdateHandler(
176 contextObject, intervalSec, userActivityScenario,
177 [positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer), positioningMethods](
const QGeoPositionInfo &positionInfo) {
178 positionInfoUpdateConsumer(positionInfo, positioningMethods);
183 QObject *contextObject,
int timeoutMs, QGeoPositionInfoSource::PositioningMethods positioningMethods,
184 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer)
186 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject << timeoutMs;
190 QOhosConsumer<std::optional<QGeoPositionInfo>, QGeoPositionInfoSource::PositioningMethods> positionInfoUpdateConsumer;
191 QtOhos::QThreadSafeRef<QObject> contextObjectRef;
194 auto sharedContext = QtOhos::moveToSharedPtr(Context{
195 .positionInfoUpdateConsumer = std::move(positionInfoUpdateConsumer),
196 .contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject)
199 auto weakContext = QtOhos::makeWeakPtr(sharedContext);
200 auto positionInfoUpdateConsumerJsProxy =
201 [weakContext, positioningMethods](std::optional<QGeoPositionInfo> optPositionInfo) {
202 auto sharedContext = weakContext.lock();
204 sharedContext->contextObjectRef.visitInQtThreadIfAlive(
205 [weakContext, optPositionInfo, positioningMethods](
auto &) {
206 auto sharedContext = weakContext.lock();
208 sharedContext->positionInfoUpdateConsumer(optPositionInfo, positioningMethods);
213 QOhosJsThreadGateway::runAndWait(
214 [&](QOhosJsState &jsState) {
215 auto userActivityScenario =
216 tryMapPositioningMethodsToUserActivityScenario(positioningMethods)
217 .value_or(UserActivityScenario::DAILY_LIFE_SERVICE);
218 auto currentLocationRequest = QNapi::makeObject(
221 {
"scenario", jsState.mapOhosEnumToJs(userActivityScenario)},
222 {
"timeoutMs", timeoutMs},
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));
232 .onCatchWithContext([](
const QOhosCallbackInfo &cbInfo,
auto &positionInfoUpdateConsumerJsProxy) {
233 QtOhos::logJsCallbackError(cbInfo,
"getCurrentLocation() failed");
234 positionInfoUpdateConsumerJsProxy(std::nullopt);
238 return sharedContext;
242 QObject *contextObject, QOhosConsumer<LocationError> errorConsumer)
244 qOhosDebug(QtForOhos) << Q_FUNC_INFO << contextObject;
246 auto sharedErrorConsumer = QtOhos::moveToSharedPtr(std::move(errorConsumer));
248 auto contextObjectRef = QtOhos::makeQThreadSafeRef(contextObject);
249 auto weakErrorConsumer = QtOhos::makeWeakPtr(sharedErrorConsumer);
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);
267 return QtOhos::makeSharedPtrWithAttachedExtraData(registrationHandle, sharedErrorConsumer);
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;
283 qOhosPrintfWarning(
"%s received unknown error: %d", Q_FUNC_INFO,
static_cast<
int>(error));
284 return QGeoPositionInfoSource::UnknownSourceError;
311 void setErrorHelper(QGeoPositionInfoSource::Error error);
312 void continuousUpdateTimeout();
314 void updatePositionInfo(
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods);
317 QGeoPositionInfo m_lastUpdatedPositionInfo;
318 QGeoPositionInfo m_lastUpdatedPositionInfoFromSatelliteSource;
320 std::shared_ptr<
void> m_locationErrorHandle;
322 std::shared_ptr<
void> m_continuousLocationUpdatesHandle;
323 QTimer m_continuousUpdateTimeoutTimer;
324 qint64 m_lastUpdateTime = 0;
325 bool m_continuousUpdateTimeoutErrorRaised =
false;
327 std::shared_ptr<
void> m_singlePositionUpdateHandle;
328 std::unique_ptr<QTimer> m_singleUpdateTimeoutTimer;
334 qOhosDebug(QtForOhos)
336 <<
"Location permission isn't granted. Can't create QOhosGeoPositionInfoSource";
346 qOhosDebug(QtForOhos) << Q_FUNC_INFO << parent;
348 m_locationErrorHandle = registerLocationErrorHandler(
350 [
this](LocationError error) {
351 qOhosWarning(QtForOhos)
352 << Q_FUNC_INFO <<
"Received error from callback:" << toStaticString(error);
353 setErrorHelper(convertLocationErrorToQtError(error));
356 m_continuousUpdateTimeoutTimer.setSingleShot(
false);
357 m_continuousUpdateTimeoutTimer.setInterval(continuousUpdateTimerIntervalMs);
358 QObject::connect(&m_continuousUpdateTimeoutTimer, &QTimer::timeout,
359 this, [
this]() { continuousUpdateTimeout(); });
366 qOhosDebug(QtForOhos) << Q_FUNC_INFO << msec;
368 QGeoPositionInfoSource::setUpdateInterval(msec);
370 if (m_continuousLocationUpdatesHandle) {
378 qOhosDebug(QtForOhos) << Q_FUNC_INFO << fromSatellitePositioningMethodsOnly;
380 return fromSatellitePositioningMethodsOnly
381 ? m_lastUpdatedPositionInfoFromSatelliteSource
382 : m_lastUpdatedPositionInfo;
387 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
389 return QGeoPositionInfoSource::AllPositioningMethods;
394 qOhosDebug(QtForOhos) << Q_FUNC_INFO << methods;
396 QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
401 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
408 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
415 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
417 if (m_continuousLocationUpdatesHandle) {
418 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Continuous updates already running. Ignoring";
424 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
425 m_continuousUpdateTimeoutErrorRaised =
false;
427 m_continuousLocationUpdatesHandle =
428 makeContinuousPositionInfoUpdateProducer(
430 preferredPositioningMethods(),
431 [
this](
const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods) {
432 updatePositionInfo(positionInfo, positioningMethods);
435 m_continuousUpdateTimeoutTimer.start();
437 setErrorHelper(QGeoPositionInfoSource::NoError);
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);
453 qOhosDebug(QtForOhos) << Q_FUNC_INFO;
455 m_continuousLocationUpdatesHandle.reset();
456 m_continuousUpdateTimeoutTimer.stop();
461 qOhosDebug(QtForOhos) << Q_FUNC_INFO << timeoutMs;
463 if (m_singlePositionUpdateHandle) {
464 qOhosDebug(QtForOhos) << Q_FUNC_INFO <<
"Update already in progress. Ignoring this one";
469 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
475 m_singlePositionUpdateHandle = makeSinglePositionInfoUpdateProducer(
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);
485 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
487 if (!m_singlePositionUpdateHandle) {
488 qOhosWarning(QtForOhos) << Q_FUNC_INFO <<
"Failed to make single position info update producer";
489 setErrorHelper(QGeoPositionInfoSource::UnknownSourceError);
493 m_singleUpdateTimeoutTimer =
494 makeSingleShotUpdateTimeoutTimer(timeout, [
this]() {
495 m_singlePositionUpdateHandle.reset();
496 setErrorHelper(QGeoPositionInfoSource::UpdateTimeoutError);
499 setErrorHelper(QGeoPositionInfoSource::NoError);
504 qOhosDebug(QtForOhos) << Q_FUNC_INFO << newError;
506 if (m_error == newError)
511 if (newError != QGeoPositionInfoSource::NoError)
512 Q_EMIT QGeoPositionInfoSource::errorOccurred(m_error);
516 const QGeoPositionInfo &positionInfo, PositioningMethods positioningMethods)
518 qOhosDebug(QtForOhos) << Q_FUNC_INFO << positionInfo;
520 m_lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
521 m_continuousUpdateTimeoutErrorRaised =
false;
522 setErrorHelper(QGeoPositionInfoSource::NoError);
524 if (positioningMethods.testFlag(PositioningMethod::SatellitePositioningMethods))
525 m_lastUpdatedPositionInfoFromSatelliteSource = positionInfo;
526 m_lastUpdatedPositionInfo = positionInfo;
527 Q_EMIT positionUpdated(m_lastUpdatedPositionInfo);
534 return QOhosGeoPositionInfoSource::tryMakeInstance(parent);
542 static constexpr const char *
fullTypeName =
"@ohos.geoLocationManager.UserActivityScenario";
554 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)
constexpr int continuousUpdateTimerIntervalMs
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)
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()