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
jnipositioning.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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// Qt-Security score:significant reason:default
4
8#include <QtPositioning/QGeoPositionInfo>
9#include <QtCore/QDateTime>
10#include <QtCore/QMap>
11#include <QtCore/QRandomGenerator>
12#include <QtCore/QJniEnvironment>
13#include <QtCore/QJniObject>
14#include <QtCore/QLoggingCategory>
15#include <QtCore/QPermission>
16#include <QtCore/QCoreApplication>
17#include <QtCore/QTimeZone>
18#include <QtCore/QSet>
19#include <android/log.h>
20
21Q_DECLARE_JNI_CLASS(QtPositioning, "org/qtproject/qt/android/positioning/QtPositioning")
22Q_DECLARE_JNI_CLASS(GnssStatus, "android/location/GnssStatus")
23Q_DECLARE_JNI_CLASS(Location, "android/location/Location")
24
25using namespace Qt::StringLiterals;
26
27template<typename T>
29{
30public:
33 {
34 if (m_classRef) {
35 QJniEnvironment env;
36 if (env.jniEnv())
37 env->DeleteGlobalRef(m_classRef);
38 }
39 }
40
41 bool init()
42 {
43 QJniEnvironment env;
44 if (env.jniEnv()) {
45 if (m_classRef) {
46 env->DeleteGlobalRef(m_classRef);
47 m_classRef = nullptr;
48 }
49
50 m_classRef = env.findClass<T>(); // it returns global ref!
51 }
52 return m_classRef != nullptr;
53 }
54
55 jclass operator()() { return m_classRef; }
56
57private:
58 jclass m_classRef = nullptr;
59};
60
62
69
70static const char logTag[] = "qt.positioning.android";
71static const char methodErrorMsg[] = "Can't find method \"%s%s\"";
72
73Q_LOGGING_CATEGORY(lcPositioning, logTag)
74
75namespace {
76
77/*!
78 \internal
79 This class encapsulates satellite system types, as defined by Android
80 GnssStatus API. Initialize during JNI_OnLoad() by the init() method, from
81 the Java side, rather than hard-coding.
82*/
83class ConstellationMapper
84{
85public:
86 static bool init()
87 {
88 m_gnssStatusObject = QJniEnvironment().findClass<QtJniTypes::GnssStatus>();
89 if (!m_gnssStatusObject)
90 return false;
91
92 const auto sdkVersion = QNativeInterface::QAndroidApplication::sdkVersion();
93 if (sdkVersion >= 29) {
94 m_irnssTypeId = QJniObject::getStaticField<jint>(m_gnssStatusObject,
95 "CONSTELLATION_IRNSS");
96 }
97 return true;
98 }
99
100 static QGeoSatelliteInfo::SatelliteSystem toSatelliteSystem(int constellationType)
101 {
102 if (!m_gnssStatusObject)
103 return QGeoSatelliteInfo::Undefined;
104
105 static const int gps =
106 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GPS");
107 static const int glonass =
108 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GLONASS");
109 static const int galileo =
110 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GALILEO");
111 static const int beidou =
112 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_BEIDOU");
113 static const int qzss =
114 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_QZSS");
115 static const int sbas =
116 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_SBAS");
117
118 if (constellationType == gps) {
119 return QGeoSatelliteInfo::GPS;
120 } else if (constellationType == glonass) {
121 return QGeoSatelliteInfo::GLONASS;
122 } else if (constellationType == galileo) {
123 return QGeoSatelliteInfo::GALILEO;
124 } else if (constellationType == beidou) {
125 return QGeoSatelliteInfo::BEIDOU;
126 } else if (constellationType == qzss){
127 return QGeoSatelliteInfo::QZSS;
128 } else if (constellationType == sbas) {
129 return QGeoSatelliteInfo::SBAS;
130 } else if (m_irnssTypeId > 0 && constellationType == m_irnssTypeId) {
131 return QGeoSatelliteInfo::IRNSS;
132 } else {
133 qCWarning(lcPositioning) << "Unknown satellite system" << constellationType;
134 return QGeoSatelliteInfo::Undefined;
135 }
136 }
137
138private:
139 static jclass m_gnssStatusObject;
140 static int m_irnssTypeId; // API level >= 29!
141};
142
143jclass ConstellationMapper::m_gnssStatusObject = nullptr;
144int ConstellationMapper::m_irnssTypeId = 0;
145
146} // anonymous namespace
147
151
153
155
157 {
158 int key = -1;
159 if (obj->inherits("QGeoPositionInfoSource")) {
161 Q_ASSERT(src);
162 do {
164 } while (idToPosSource()->contains(key));
165
167 } else if (obj->inherits("QGeoSatelliteInfoSource")) {
169 Q_ASSERT(src);
170 do {
172 } while (idToSatSource()->contains(key));
173
175 }
176
177 return key;
178 }
179
188
195
196
198 {
199 QGeoPositionInfoSource::PositioningMethods ret = QGeoPositionInfoSource::NoPositioningMethods;
200 QJniEnvironment env;
201 if (!env.jniEnv())
202 return ret;
203 QJniObject jniProvidersObj =
204 QJniObject::callStaticMethod<jobject>(positioningClass(), providerListMethodId);
205 jintArray jProviders = jniProvidersObj.object<jintArray>();
206 if (!jProviders) {
207 // Work-around for QTBUG-116645
208 __android_log_print(ANDROID_LOG_INFO, logTag, "Got null providers array!");
209 return ret;
210 }
211 jint *providers = env->GetIntArrayElements(jProviders, nullptr);
212 const int size = env->GetArrayLength(jProviders);
213 for (int i = 0; i < size; i++) {
214 switch (providers[i]) {
215 case PROVIDER_GPS:
216 ret |= QGeoPositionInfoSource::SatellitePositioningMethods;
217 break;
218 case PROVIDER_NETWORK:
219 ret |= QGeoPositionInfoSource::NonSatellitePositioningMethods;
220 break;
221 case PROVIDER_PASSIVE:
222 //we ignore as Qt doesn't have interface for it right now
223 break;
224 default:
225 __android_log_print(ANDROID_LOG_INFO, logTag, "Unknown positioningMethod");
226 }
227 }
228
229 env->ReleaseIntArrayElements(jProviders, providers, 0);
230
231 return ret;
232 }
233
234 QGeoPositionInfo positionInfoFromJavaLocation(const jobject &location, bool useAltConverter)
235 {
236 QGeoPositionInfo info;
237
238 QJniObject jniObject(location);
239 if (!jniObject.isValid())
240 return QGeoPositionInfo();
241
242 const jdouble latitude = jniObject.callMethod<jdouble>("getLatitude");
243 const jdouble longitude = jniObject.callMethod<jdouble>("getLongitude");
244
245 QGeoCoordinate coordinate(latitude, longitude);
246
247 // altitude
248 jboolean attributeExists = jniObject.callMethod<jboolean>("hasAltitude");
249 if (attributeExists) {
250 const jdouble value = jniObject.callMethod<jdouble>("getAltitude");
251 if (!qFuzzyIsNull(value))
252 coordinate.setAltitude(value);
253 }
254 // MSL altitude, available in API Level 34+.
255 // In API Level 34 it was available only if we manually added it.
256 // In API Level 35 (and potentially later), it's automatically added
257 // to the location object, so we need to use it *only* when the user
258 // set the relevant plugin parameter.
259 if (useAltConverter && QNativeInterface::QAndroidApplication::sdkVersion() >= 34) {
260 attributeExists = jniObject.callMethod<jboolean>("hasMslAltitude");
261 if (attributeExists) {
262 const jdouble value = jniObject.callMethod<jdouble>("getMslAltitudeMeters");
263 if (!qFuzzyIsNull(value))
264 coordinate.setAltitude(value);
265 }
266 }
267
268 info.setCoordinate(coordinate);
269
270 // time stamp
271 const jlong timestamp = jniObject.callMethod<jlong>("getTime");
272 info.setTimestamp(QDateTime::fromMSecsSinceEpoch(timestamp, QTimeZone::UTC));
273
274 // horizontal accuracy
275 attributeExists = jniObject.callMethod<jboolean>("hasAccuracy");
276 if (attributeExists) {
277 const jfloat accuracy = jniObject.callMethod<jfloat>("getAccuracy");
278 if (!qFuzzyIsNull(accuracy))
279 info.setAttribute(QGeoPositionInfo::HorizontalAccuracy, qreal(accuracy));
280 }
281
282 // vertical accuracy (available in API Level 26+)
283 attributeExists = jniObject.callMethod<jboolean>("hasVerticalAccuracy");
284 if (attributeExists) {
285 const jfloat accuracy = jniObject.callMethod<jfloat>("getVerticalAccuracyMeters");
286 if (!qFuzzyIsNull(accuracy))
287 info.setAttribute(QGeoPositionInfo::VerticalAccuracy, qreal(accuracy));
288 }
289
290 // ground speed
291 attributeExists = jniObject.callMethod<jboolean>("hasSpeed");
292 if (attributeExists) {
293 const jfloat speed = jniObject.callMethod<jfloat>("getSpeed");
294 if (!qFuzzyIsNull(speed))
295 info.setAttribute(QGeoPositionInfo::GroundSpeed, qreal(speed));
296 }
297
298 // bearing
299 attributeExists = jniObject.callMethod<jboolean>("hasBearing");
300 if (attributeExists) {
301 const jfloat bearing = jniObject.callMethod<jfloat>("getBearing");
302 if (!qFuzzyIsNull(bearing))
303 info.setAttribute(QGeoPositionInfo::Direction, qreal(bearing));
304
305 // bearingAccuracy is available in API Level 26+
306 const jfloat bearingAccuracy =
307 jniObject.callMethod<jfloat>("getBearingAccuracyDegrees");
308 if (!qFuzzyIsNull(bearingAccuracy))
309 info.setAttribute(QGeoPositionInfo::DirectionAccuracy, qreal(bearingAccuracy));
310 }
311
312 return info;
313 }
314
315 using UniqueId = std::pair<int, int>;
316 static UniqueId getUid(const QGeoSatelliteInfo &info)
317 {
318 return std::make_pair(static_cast<int>(info.satelliteSystem()),
319 info.satelliteIdentifier());
320 }
321
323 QList<QGeoSatelliteInfo>* usedInFix)
324 {
325 QJniObject jniStatus(gnssStatus);
326 QList<QGeoSatelliteInfo> sats;
327 QSet<UniqueId> uids;
328
329 const int satellitesCount = jniStatus.callMethod<jint>("getSatelliteCount");
330 for (int i = 0; i < satellitesCount; ++i) {
331 QGeoSatelliteInfo info;
332
333 // signal strength - this is actually a carrier-to-noise density,
334 // but the values are very close to what was previously returned by
335 // getSnr() method of the GpsSatellite API.
336 const jfloat cn0 = jniStatus.callMethod<jfloat>("getCn0DbHz", i);
337 info.setSignalStrength(static_cast<int>(cn0));
338
339 // satellite system
340 const jint constellationType =
341 jniStatus.callMethod<jint>("getConstellationType", i);
342 info.setSatelliteSystem(ConstellationMapper::toSatelliteSystem(constellationType));
343
344 // satellite identifier
345 const jint svId = jniStatus.callMethod<jint>("getSvid", i);
346 info.setSatelliteIdentifier(svId);
347
348 // azimuth
349 const jfloat azimuth = jniStatus.callMethod<jfloat>("getAzimuthDegrees", i);
350 info.setAttribute(QGeoSatelliteInfo::Azimuth, static_cast<qreal>(azimuth));
351
352 // elevation
353 const jfloat elevation = jniStatus.callMethod<jfloat>("getElevationDegrees", i);
354 info.setAttribute(QGeoSatelliteInfo::Elevation, static_cast<qreal>(elevation));
355
356 // Used in fix - true if this satellite is actually used in
357 // determining the position.
358 const jboolean inFix = jniStatus.callMethod<jboolean>("usedInFix", i);
359
360 const UniqueId id = getUid(info);
361 if (uids.contains(id))
362 continue;
363
364 sats.append(info);
365 uids.insert(id);
366
367 if (inFix)
368 usedInFix->append(info);
369 }
370
371 return sats;
372 }
373
374 QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly,
375 bool useAltitudeConverter)
376 {
377 QJniEnvironment env;
378 if (!env.jniEnv())
379 return QGeoPositionInfo();
380
381 const auto accuracy = fromSatellitePositioningMethodsOnly
384
385 if (!hasPositioningPermissions(accuracy))
386 return {};
387
388 QJniObject locationObj = QJniObject::callStaticMethod<jobject>(
389 positioningClass(), lastKnownPositionMethodId, fromSatellitePositioningMethodsOnly,
390 useAltitudeConverter);
391 jobject location = locationObj.object();
392 if (location == nullptr)
393 return QGeoPositionInfo();
394
395 const QGeoPositionInfo info = positionInfoFromJavaLocation(location, useAltitudeConverter);
396
397 return info;
398 }
399
400 inline int positioningMethodToInt(QGeoPositionInfoSource::PositioningMethods m)
401 {
402 int providerSelection = 0;
403 if (m & QGeoPositionInfoSource::SatellitePositioningMethods)
404 providerSelection |= 1;
405 if (m & QGeoPositionInfoSource::NonSatellitePositioningMethods)
406 providerSelection |= 2;
407
408 return providerSelection;
409 }
410
411 static AccuracyTypes
412 accuracyFromPositioningMethods(QGeoPositionInfoSource::PositioningMethods m)
413 {
414 AccuracyTypes types = AccuracyType::None;
415 if (m & QGeoPositionInfoSource::NonSatellitePositioningMethods)
417 if (m & QGeoPositionInfoSource::SatellitePositioningMethods)
418 types |= AccuracyType::Precise;
419 return types;
420 }
421
423 {
424 QJniEnvironment env;
425 if (!env.jniEnv())
426 return QGeoPositionInfoSource::UnknownSourceError;
427
428 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
429
430 if (source) {
431 const auto preferredMethods = source->preferredPositioningMethods();
432 const auto accuracy = accuracyFromPositioningMethods(preferredMethods);
433 if (!hasPositioningPermissions(accuracy))
434 return QGeoPositionInfoSource::AccessError;
435
436 int errorCode = QJniObject::callStaticMethod<jint>(
437 positioningClass(), startUpdatesMethodId, androidClassKey,
438 positioningMethodToInt(preferredMethods),
439 source->updateInterval(), source->useAltitudeConverter());
440 switch (errorCode) {
441 case 0:
442 case 1:
443 case 2:
444 case 3:
445 return static_cast<QGeoPositionInfoSource::Error>(errorCode);
446 default:
447 break;
448 }
449 }
450
451 return QGeoPositionInfoSource::UnknownSourceError;
452 }
453
454 //used for stopping regular and single updates
455 void stopUpdates(int androidClassKey)
456 {
457 QJniObject::callStaticMethod<void>(positioningClass(), stopUpdatesMethodId,
458 androidClassKey);
459 }
460
461 QGeoPositionInfoSource::Error requestUpdate(int androidClassKey, int timeout)
462 {
463 QJniEnvironment env;
464 if (!env.jniEnv())
465 return QGeoPositionInfoSource::UnknownSourceError;
466
467 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
468
469 if (source) {
470 const auto preferredMethods = source->preferredPositioningMethods();
471 const auto accuracy = accuracyFromPositioningMethods(preferredMethods);
472 if (!hasPositioningPermissions(accuracy))
473 return QGeoPositionInfoSource::AccessError;
474
475 int errorCode = QJniObject::callStaticMethod<jint>(
476 positioningClass(), requestUpdateMethodId, androidClassKey,
477 positioningMethodToInt(preferredMethods),
478 timeout, source->useAltitudeConverter());
479 switch (errorCode) {
480 case 0:
481 case 1:
482 case 2:
483 case 3:
484 return static_cast<QGeoPositionInfoSource::Error>(errorCode);
485 default:
486 break;
487 }
488 }
489 return QGeoPositionInfoSource::UnknownSourceError;
490 }
491
492 QGeoSatelliteInfoSource::Error startSatelliteUpdates(int androidClassKey, bool isSingleRequest, int requestTimeout)
493 {
494 QJniEnvironment env;
495 if (!env.jniEnv())
496 return QGeoSatelliteInfoSource::UnknownSourceError;
497
498 QGeoSatelliteInfoSourceAndroid *source = AndroidPositioning::idToSatSource()->value(androidClassKey);
499
500 if (source) {
501 // Satellite Info request does not make sense with Approximate
502 // location permissions, so always check for Precise
503 if (!hasPositioningPermissions(AccuracyType::Precise))
504 return QGeoSatelliteInfoSource::AccessError;
505
506 int interval = source->updateInterval();
507 if (isSingleRequest)
508 interval = requestTimeout;
509 int errorCode = QJniObject::callStaticMethod<jint>(positioningClass(),
510 startSatelliteUpdatesMethodId,
511 androidClassKey, interval,
512 isSingleRequest);
513 switch (errorCode) {
514 case -1:
515 case 0:
516 case 1:
517 case 2:
518 return static_cast<QGeoSatelliteInfoSource::Error>(errorCode);
519 default:
520 qCWarning(lcPositioning)
521 << "startSatelliteUpdates: Unknown error code" << errorCode;
522 break;
523 }
524 }
525 return QGeoSatelliteInfoSource::UnknownSourceError;
526 }
527
528
529 bool hasPositioningPermissions(AccuracyTypes accuracy)
530 {
531 QLocationPermission permission;
532
533 // The needed permission depends on whether we run as a service or as an activity
534 if (!QNativeInterface::QAndroidApplication::isActivityContext())
535 permission.setAvailability(QLocationPermission::Always); // background location
536
537 bool permitted = false;
538 if (accuracy & AccuracyType::Precise) {
539 permission.setAccuracy(QLocationPermission::Precise);
540 permitted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
541 }
542 if (accuracy & AccuracyType::Approximate) {
543 permission.setAccuracy(QLocationPermission::Approximate);
544 permitted |= qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
545 }
546
547 if (!permitted)
548 qCWarning(lcPositioning) << "Position data not available due to missing permission";
549
550 return permitted;
551 }
552}
553
554static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location,
555 jint androidClassKey, jboolean isSingleUpdate)
556{
557 Q_UNUSED(env);
558 Q_UNUSED(thiz);
559
560 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
561 if (!source) {
562 qCWarning(lcPositioning) << "positionUpdated: source == 0";
563 return;
564 }
565
566 const bool useAltitudeConverter = source->useAltitudeConverter();
567 QGeoPositionInfo info =
568 AndroidPositioning::positionInfoFromJavaLocation(location.object(), useAltitudeConverter);
569
570 //we need to invoke indirectly as the Looper thread is likely to be not the same thread
571 if (!isSingleUpdate)
572 QMetaObject::invokeMethod(source, "processPositionUpdate", Qt::AutoConnection,
573 Q_ARG(QGeoPositionInfo, info));
574 else
575 QMetaObject::invokeMethod(source, "processSinglePositionUpdate", Qt::AutoConnection,
576 Q_ARG(QGeoPositionInfo, info));
577}
578Q_DECLARE_JNI_NATIVE_METHOD(positionUpdated)
579
580static void locationProvidersDisabled(JNIEnv *env, jobject thiz, jint androidClassKey)
581{
582 Q_UNUSED(env);
583 Q_UNUSED(thiz);
584 QObject *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
585 if (!source)
586 source = AndroidPositioning::idToSatSource()->value(androidClassKey);
587 if (!source) {
588 qCWarning(lcPositioning) << "locationProvidersDisabled: source == 0";
589 return;
590 }
591
592 QMetaObject::invokeMethod(source, "locationProviderDisabled", Qt::AutoConnection);
593}
594Q_DECLARE_JNI_NATIVE_METHOD(locationProvidersDisabled)
595
596static void locationProvidersChanged(JNIEnv *env, jobject thiz, jint androidClassKey)
597{
598 Q_UNUSED(env);
599 Q_UNUSED(thiz);
600 QObject *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
601 if (!source) {
602 qCWarning(lcPositioning) << "locationProvidersChanged: source == 0";
603 return;
604 }
605
606 QMetaObject::invokeMethod(source, "locationProvidersChanged", Qt::AutoConnection);
607}
608Q_DECLARE_JNI_NATIVE_METHOD(locationProvidersChanged)
609
610static void notifySatelliteInfoUpdated(const QList<QGeoSatelliteInfo> &inView,
611 const QList<QGeoSatelliteInfo> &inUse,
612 jint androidClassKey, jboolean isSingleUpdate)
613{
614 QGeoSatelliteInfoSourceAndroid *source = AndroidPositioning::idToSatSource()->value(androidClassKey);
615 if (!source) {
616 qCWarning(lcPositioning) << "notifySatelliteInfoUpdated: source == 0";
617 return;
618 }
619
620 QMetaObject::invokeMethod(source, "processSatelliteUpdate", Qt::AutoConnection,
621 Q_ARG(QList<QGeoSatelliteInfo>, inView),
622 Q_ARG(QList<QGeoSatelliteInfo>, inUse),
623 Q_ARG(bool, isSingleUpdate));
624}
625
626static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, QtJniTypes::GnssStatus gnssStatus,
627 jint androidClassKey, jboolean isSingleUpdate)
628{
629 Q_UNUSED(env);
630 Q_UNUSED(thiz);
631
632 QList<QGeoSatelliteInfo> inUse;
633 QList<QGeoSatelliteInfo> sats =
634 AndroidPositioning::satelliteInfoFromJavaGnssStatus(gnssStatus.object(), &inUse);
635
636 notifySatelliteInfoUpdated(sats, inUse, androidClassKey, isSingleUpdate);
637}
638Q_DECLARE_JNI_NATIVE_METHOD(satelliteGnssUpdated)
639
640#define GET_AND_CHECK_STATIC_METHOD(VAR, METHOD_NAME, ...)
641 VAR = env.findStaticMethod<__VA_ARGS__>(positioningClass(), METHOD_NAME);
642 if (!VAR) {
643 __android_log_print(ANDROID_LOG_FATAL, logTag, methodErrorMsg, METHOD_NAME,
644 QtJniTypes::methodSignature<__VA_ARGS__>().data());
645 return false;
646 }
647
648static bool registerNatives()
649{
650 QJniEnvironment env;
651 if (!env.jniEnv()) {
652 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to create environment");
653 return false;
654 }
655
656 if (!positioningClass.init()) {
657 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to create global class ref");
658 return false;
659 }
660
661 if (!env.registerNativeMethods(positioningClass(), {
662 Q_JNI_NATIVE_METHOD(positionUpdated),
663 Q_JNI_NATIVE_METHOD(locationProvidersDisabled),
664 Q_JNI_NATIVE_METHOD(locationProvidersChanged),
665 Q_JNI_NATIVE_METHOD(satelliteGnssUpdated)
666 })) {
667 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to register native methods");
668 return false;
669 }
670
671 GET_AND_CHECK_STATIC_METHOD(providerListMethodId, "providerList", jintArray);
672 GET_AND_CHECK_STATIC_METHOD(lastKnownPositionMethodId, "lastKnownPosition",
673 QtJniTypes::Location, bool, bool);
674 GET_AND_CHECK_STATIC_METHOD(startUpdatesMethodId, "startUpdates", jint, jint, jint, jint,
675 bool);
676 GET_AND_CHECK_STATIC_METHOD(stopUpdatesMethodId, "stopUpdates", void, jint);
677 GET_AND_CHECK_STATIC_METHOD(requestUpdateMethodId, "requestUpdate", jint, jint, jint, jint,
678 bool);
679 GET_AND_CHECK_STATIC_METHOD(startSatelliteUpdatesMethodId, "startSatelliteUpdates",
680 jint, jint, jint, bool);
681
682 return true;
683}
684
685extern "C" Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/)
686{
687 static bool initialized = false;
688 if (initialized)
689 return JNI_VERSION_1_6;
690 initialized = true;
691
692 __android_log_print(ANDROID_LOG_INFO, logTag, "Positioning start");
693
694 const auto context = QNativeInterface::QAndroidApplication::context();
695 QtJniTypes::QtPositioning::callStaticMethod<void>("setContext", context);
696
697 if (!registerNatives()) {
698 __android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives() failed");
699 return -1;
700 }
701
702 if (!ConstellationMapper::init()) {
703 __android_log_print(ANDROID_LOG_ERROR, logTag,
704 "Failed to extract constellation type constants. "
705 "Satellite system will be undefined!");
706 }
707
708 return JNI_VERSION_1_6;
709}
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
GlobalClassRefWrapper()=default
static jmethodID startUpdatesMethodId
static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location, jint androidClassKey, jboolean isSingleUpdate)
static jmethodID requestUpdateMethodId
static void notifySatelliteInfoUpdated(const QList< QGeoSatelliteInfo > &inView, const QList< QGeoSatelliteInfo > &inUse, jint androidClassKey, jboolean isSingleUpdate)
static jmethodID providerListMethodId
static jmethodID lastKnownPositionMethodId
static GlobalClassRefWrapper< QtJniTypes::QtPositioning > positioningClass
static const char logTag[]
static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, QtJniTypes::GnssStatus gnssStatus, jint androidClassKey, jboolean isSingleUpdate)
static void locationProvidersChanged(JNIEnv *env, jobject thiz, jint androidClassKey)
static jmethodID stopUpdatesMethodId
static const char methodErrorMsg[]
static void locationProvidersDisabled(JNIEnv *env, jobject thiz, jint androidClassKey)
static bool registerNatives()
static jmethodID startSatelliteUpdatesMethodId
static UniqueId getUid(const QGeoSatelliteInfo &info)
QList< QGeoSatelliteInfo > satelliteInfoFromJavaGnssStatus(jobject gnssStatus, QList< QGeoSatelliteInfo > *usedInFix)
QMap< int, QGeoSatelliteInfoSourceAndroid * > SatelliteSourceMap
int positioningMethodToInt(QGeoPositionInfoSource::PositioningMethods m)
QGeoSatelliteInfoSource::Error startSatelliteUpdates(int androidClassKey, bool isSingleRequest, int requestTimeout)
QGeoPositionInfoSource::Error requestUpdate(int androidClassKey, int timeout)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly, bool useAltitudeConverter)
QGeoPositionInfoSource::Error startUpdates(int androidClassKey)
static AccuracyTypes accuracyFromPositioningMethods(QGeoPositionInfoSource::PositioningMethods m)
QMap< int, QGeoPositionInfoSourceAndroid * > PositionSourceMap
QGeoPositionInfoSource::PositioningMethods availableProviders()
QGeoPositionInfo positionInfoFromJavaLocation(const jobject &location, bool useAltConverter)
void stopUpdates(int androidClassKey)
bool hasPositioningPermissions(AccuracyTypes accuracy)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")