Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
4#include "jnipositioning.h"
7#include <QtPositioning/QGeoPositionInfo>
8#include <QtCore/QDateTime>
9#include <QtCore/QMap>
10#include <QtCore/QRandomGenerator>
11#include <QtCore/QJniEnvironment>
12#include <QtCore/QJniObject>
13#include <QtCore/QLoggingCategory>
14#include <QtCore/QPermission>
15#include <QtCore/QCoreApplication>
16#include <QtCore/QTimeZone>
17#include <QtCore/QSet>
18#include <android/log.h>
19
20Q_DECLARE_JNI_CLASS(QtPositioning, "org/qtproject/qt/android/positioning/QtPositioning")
21Q_DECLARE_JNI_CLASS(GnssStatus, "android/location/GnssStatus")
22Q_DECLARE_JNI_CLASS(Location, "android/location/Location")
23
24using namespace Qt::StringLiterals;
25
26template<typename T>
28{
29public:
32 {
33 if (m_classRef) {
35 if (env.jniEnv())
36 env->DeleteGlobalRef(m_classRef);
37 }
38 }
39
40 bool init()
41 {
43 if (env.jniEnv()) {
44 if (m_classRef) {
45 env->DeleteGlobalRef(m_classRef);
46 m_classRef = nullptr;
47 }
48
49 m_classRef = env.findClass<T>(); // it returns global ref!
50 }
51 return m_classRef != nullptr;
52 }
53
54 jclass operator()() { return m_classRef; }
55
56private:
57 jclass m_classRef = nullptr;
58};
59
60static GlobalClassRefWrapper<QtJniTypes::QtPositioning> positioningClass;
61
62static jmethodID providerListMethodId;
64static jmethodID startUpdatesMethodId;
65static jmethodID stopUpdatesMethodId;
66static jmethodID requestUpdateMethodId;
68
69static const char logTag[] = "qt.positioning.android";
70static const char methodErrorMsg[] = "Can't find method \"%s%s\"";
71
72Q_LOGGING_CATEGORY(lcPositioning, logTag)
73
74namespace {
75
82class ConstellationMapper
83{
84public:
85 static bool init()
86 {
87 m_gnssStatusObject = nullptr;
88 if (QNativeInterface::QAndroidApplication::sdkVersion() > 23) {
89 m_gnssStatusObject = QJniEnvironment().findClass<QtJniTypes::GnssStatus>();
90 if (!m_gnssStatusObject)
91 return false;
92 }
93 // no need to query it for API level <= 23
94 return true;
95 }
96
97 static QGeoSatelliteInfo::SatelliteSystem toSatelliteSystem(int constellationType)
98 {
99 if (!m_gnssStatusObject)
101
102 static const int gps =
103 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GPS");
104 static const int glonass =
105 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GLONASS");
106 static const int galileo =
107 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_GALILEO");
108 static const int beidou =
109 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_BEIDOU");
110 static const int qzss =
111 QJniObject::getStaticField<jint>(m_gnssStatusObject, "CONSTELLATION_QZSS");
112
113 if (constellationType == gps) {
115 } else if (constellationType == glonass) {
117 } else if (constellationType == galileo) {
119 } else if (constellationType == beidou) {
121 } else if (constellationType == qzss){
123 } else {
124 qCWarning(lcPositioning) << "Unknown satellite system" << constellationType;
126 }
127 }
128
129private:
130 static jclass m_gnssStatusObject;
131};
132
133jclass ConstellationMapper::m_gnssStatusObject = nullptr;
134
135} // anonymous namespace
136
138 typedef QMap<int, QGeoPositionInfoSourceAndroid * > PositionSourceMap;
139 typedef QMap<int, QGeoSatelliteInfoSourceAndroid * > SatelliteSourceMap;
140
141 Q_GLOBAL_STATIC(PositionSourceMap, idToPosSource)
142
143 Q_GLOBAL_STATIC(SatelliteSourceMap, idToSatSource)
144
146 {
147 int key = -1;
148 if (obj->inherits("QGeoPositionInfoSource")) {
149 QGeoPositionInfoSourceAndroid *src = qobject_cast<QGeoPositionInfoSourceAndroid *>(obj);
150 Q_ASSERT(src);
151 do {
152 key = qAbs(int(QRandomGenerator::global()->generate()));
153 } while (idToPosSource()->contains(key));
154
155 idToPosSource()->insert(key, src);
156 } else if (obj->inherits("QGeoSatelliteInfoSource")) {
157 QGeoSatelliteInfoSourceAndroid *src = qobject_cast<QGeoSatelliteInfoSourceAndroid *>(obj);
158 Q_ASSERT(src);
159 do {
160 key = qAbs(int(QRandomGenerator::global()->generate()));
161 } while (idToSatSource()->contains(key));
162
163 idToSatSource()->insert(key, src);
164 }
165
166 return key;
167 }
168
170 {
171 if (idToPosSource.exists())
172 idToPosSource->remove(key);
173
174 if (idToSatSource.exists())
175 idToSatSource->remove(key);
176 }
177
184
185
186 QGeoPositionInfoSource::PositioningMethods availableProviders()
187 {
188 QGeoPositionInfoSource::PositioningMethods ret = QGeoPositionInfoSource::NoPositioningMethods;
189 QJniEnvironment env;
190 if (!env.jniEnv())
191 return ret;
192 QJniObject jniProvidersObj =
193 QJniObject::callStaticMethod<jobject>(positioningClass(), providerListMethodId);
194 jintArray jProviders = jniProvidersObj.object<jintArray>();
195 if (!jProviders) {
196 // Work-around for QTBUG-116645
197 __android_log_print(ANDROID_LOG_INFO, logTag, "Got null providers array!");
198 return ret;
199 }
200 jint *providers = env->GetIntArrayElements(jProviders, nullptr);
201 const int size = env->GetArrayLength(jProviders);
202 for (int i = 0; i < size; i++) {
203 switch (providers[i]) {
204 case PROVIDER_GPS:
206 break;
207 case PROVIDER_NETWORK:
209 break;
210 case PROVIDER_PASSIVE:
211 //we ignore as Qt doesn't have interface for it right now
212 break;
213 default:
214 __android_log_print(ANDROID_LOG_INFO, logTag, "Unknown positioningMethod");
215 }
216 }
217
218 env->ReleaseIntArrayElements(jProviders, providers, 0);
219
220 return ret;
221 }
222
224 {
226
227 QJniObject jniObject(location);
228 if (!jniObject.isValid())
229 return QGeoPositionInfo();
230
231 const jdouble latitude = jniObject.callMethod<jdouble>("getLatitude");
232 const jdouble longitude = jniObject.callMethod<jdouble>("getLongitude");
233
234 QGeoCoordinate coordinate(latitude, longitude);
235
236 // altitude
237 jboolean attributeExists = jniObject.callMethod<jboolean>("hasAltitude");
238 if (attributeExists) {
239 const jdouble value = jniObject.callMethod<jdouble>("getAltitude");
240 if (!qFuzzyIsNull(value))
241 coordinate.setAltitude(value);
242 }
243 // MSL altitude, available in API Level 34+.
244 // It will be available only if we requested it when starting updates.
245 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 34) {
246 attributeExists = jniObject.callMethod<jboolean>("hasMslAltitude");
247 if (attributeExists) {
248 const jdouble value = jniObject.callMethod<jdouble>("getMslAltitudeMeters");
249 if (!qFuzzyIsNull(value))
250 coordinate.setAltitude(value);
251 }
252 }
253
254 info.setCoordinate(coordinate);
255
256 // time stamp
257 const jlong timestamp = jniObject.callMethod<jlong>("getTime");
258 info.setTimestamp(QDateTime::fromMSecsSinceEpoch(timestamp, QTimeZone::UTC));
259
260 // horizontal accuracy
261 attributeExists = jniObject.callMethod<jboolean>("hasAccuracy");
262 if (attributeExists) {
263 const jfloat accuracy = jniObject.callMethod<jfloat>("getAccuracy");
264 if (!qFuzzyIsNull(accuracy))
265 info.setAttribute(QGeoPositionInfo::HorizontalAccuracy, qreal(accuracy));
266 }
267
268 // vertical accuracy (available in API Level 26+)
269 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
270 attributeExists = jniObject.callMethod<jboolean>("hasVerticalAccuracy");
271 if (attributeExists) {
272 const jfloat accuracy = jniObject.callMethod<jfloat>("getVerticalAccuracyMeters");
273 if (!qFuzzyIsNull(accuracy))
274 info.setAttribute(QGeoPositionInfo::VerticalAccuracy, qreal(accuracy));
275 }
276 }
277
278 // ground speed
279 attributeExists = jniObject.callMethod<jboolean>("hasSpeed");
280 if (attributeExists) {
281 const jfloat speed = jniObject.callMethod<jfloat>("getSpeed");
282 if (!qFuzzyIsNull(speed))
283 info.setAttribute(QGeoPositionInfo::GroundSpeed, qreal(speed));
284 }
285
286 // bearing
287 attributeExists = jniObject.callMethod<jboolean>("hasBearing");
288 if (attributeExists) {
289 const jfloat bearing = jniObject.callMethod<jfloat>("getBearing");
290 if (!qFuzzyIsNull(bearing))
291 info.setAttribute(QGeoPositionInfo::Direction, qreal(bearing));
292
293 // bearingAccuracy is available in API Level 26+
294 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
295 const jfloat bearingAccuracy =
296 jniObject.callMethod<jfloat>("getBearingAccuracyDegrees");
297 if (!qFuzzyIsNull(bearingAccuracy))
298 info.setAttribute(QGeoPositionInfo::DirectionAccuracy, qreal(bearingAccuracy));
299 }
300 }
301
302 return info;
303 }
304
305 using UniqueId = std::pair<int, int>;
307 {
308 return std::make_pair(static_cast<int>(info.satelliteSystem()),
309 info.satelliteIdentifier());
310 }
311
312 QList<QGeoSatelliteInfo> satelliteInfoFromJavaLocation(JNIEnv *jniEnv,
313 jobjectArray satellites,
314 QList<QGeoSatelliteInfo>* usedInFix)
315 {
316 QSet<UniqueId> uids;
317 QList<QGeoSatelliteInfo> sats;
318 jsize length = jniEnv->GetArrayLength(satellites);
319 for (int i = 0; i<length; i++) {
320 jobject element = jniEnv->GetObjectArrayElement(satellites, i);
321 if (QJniEnvironment::checkAndClearExceptions(jniEnv)) {
322 qCWarning(lcPositioning) << "Cannot process all satellite data due to exception.";
323 break;
324 }
325
326 QJniObject jniObj = QJniObject::fromLocalRef(element);
327 if (!jniObj.isValid())
328 continue;
329
331
332 // signal strength
333 const jfloat snr = jniObj.callMethod<jfloat>("getSnr");
334 info.setSignalStrength(int(snr));
335
336 // ignore any satellite with no signal whatsoever
337 if (qFuzzyIsNull(snr))
338 continue;
339
340 // prn
341 const jint prn = jniObj.callMethod<jint>("getPrn");
342 info.setSatelliteIdentifier(prn);
343
344 if (prn >= 1 && prn <= 32)
345 info.setSatelliteSystem(QGeoSatelliteInfo::GPS);
346 else if (prn >= 65 && prn <= 96)
347 info.setSatelliteSystem(QGeoSatelliteInfo::GLONASS);
348 else if (prn >= 193 && prn <= 200)
349 info.setSatelliteSystem(QGeoSatelliteInfo::QZSS);
350 else if ((prn >= 201 && prn <= 235) || (prn >= 401 && prn <= 437))
351 info.setSatelliteSystem(QGeoSatelliteInfo::BEIDOU);
352 else if (prn >= 301 && prn <= 336)
353 info.setSatelliteSystem(QGeoSatelliteInfo::GALILEO);
354
355 // azimuth
356 const jfloat azimuth = jniObj.callMethod<jfloat>("getAzimuth");
357 info.setAttribute(QGeoSatelliteInfo::Azimuth, qreal(azimuth));
358
359 // elevation
360 const jfloat elevation = jniObj.callMethod<jfloat>("getElevation");
361 info.setAttribute(QGeoSatelliteInfo::Elevation, qreal(elevation));
362
363 // Used in fix - true if this satellite is actually used in
364 // determining the position.
365 const jboolean inFix = jniObj.callMethod<jboolean>("usedInFix");
366
367 const UniqueId id = getUid(info);
368 if (uids.contains(id))
369 continue;
370
371 sats.append(info);
372 uids.insert(id);
373
374 if (inFix)
375 usedInFix->append(info);
376 }
377
378 return sats;
379 }
380
381 QList<QGeoSatelliteInfo> satelliteInfoFromJavaGnssStatus(jobject gnssStatus,
382 QList<QGeoSatelliteInfo>* usedInFix)
383 {
384 QJniObject jniStatus(gnssStatus);
385 QList<QGeoSatelliteInfo> sats;
386 QSet<UniqueId> uids;
387
388 const int satellitesCount = jniStatus.callMethod<jint>("getSatelliteCount");
389 for (int i = 0; i < satellitesCount; ++i) {
391
392 // signal strength - this is actually a carrier-to-noise density,
393 // but the values are very close to what was previously returned by
394 // getSnr() method of the GpsSatellite API.
395 const jfloat cn0 = jniStatus.callMethod<jfloat>("getCn0DbHz", i);
396 info.setSignalStrength(static_cast<int>(cn0));
397
398 // satellite system
399 const jint constellationType =
400 jniStatus.callMethod<jint>("getConstellationType", i);
401 info.setSatelliteSystem(ConstellationMapper::toSatelliteSystem(constellationType));
402
403 // satellite identifier
404 const jint svId = jniStatus.callMethod<jint>("getSvid", i);
405 info.setSatelliteIdentifier(svId);
406
407 // azimuth
408 const jfloat azimuth = jniStatus.callMethod<jfloat>("getAzimuthDegrees", i);
409 info.setAttribute(QGeoSatelliteInfo::Azimuth, static_cast<qreal>(azimuth));
410
411 // elevation
412 const jfloat elevation = jniStatus.callMethod<jfloat>("getElevationDegrees", i);
413 info.setAttribute(QGeoSatelliteInfo::Elevation, static_cast<qreal>(elevation));
414
415 // Used in fix - true if this satellite is actually used in
416 // determining the position.
417 const jboolean inFix = jniStatus.callMethod<jboolean>("usedInFix", i);
418
419 const UniqueId id = getUid(info);
420 if (uids.contains(id))
421 continue;
422
423 sats.append(info);
424 uids.insert(id);
425
426 if (inFix)
427 usedInFix->append(info);
428 }
429
430 return sats;
431 }
432
433 QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly,
434 bool useAltitudeConverter)
435 {
436 QJniEnvironment env;
437 if (!env.jniEnv())
438 return QGeoPositionInfo();
439
441 return {};
442
443 QJniObject locationObj = QJniObject::callStaticMethod<jobject>(
444 positioningClass(), lastKnownPositionMethodId, fromSatellitePositioningMethodsOnly,
445 useAltitudeConverter);
446 jobject location = locationObj.object();
447 if (location == nullptr)
448 return QGeoPositionInfo();
449
451
452 return info;
453 }
454
455 inline int positioningMethodToInt(QGeoPositionInfoSource::PositioningMethods m)
456 {
457 int providerSelection = 0;
459 providerSelection |= 1;
461 providerSelection |= 2;
462
463 return providerSelection;
464 }
465
467 {
468 QJniEnvironment env;
469 if (!env.jniEnv())
471
472 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
473
474 if (source) {
477
478 int errorCode = QJniObject::callStaticMethod<jint>(
479 positioningClass(), startUpdatesMethodId, androidClassKey,
480 positioningMethodToInt(source->preferredPositioningMethods()),
481 source->updateInterval(), source->useAltitudeConverter());
482 switch (errorCode) {
483 case 0:
484 case 1:
485 case 2:
486 case 3:
487 return static_cast<QGeoPositionInfoSource::Error>(errorCode);
488 default:
489 break;
490 }
491 }
492
494 }
495
496 //used for stopping regular and single updates
497 void stopUpdates(int androidClassKey)
498 {
499 QJniObject::callStaticMethod<void>(positioningClass(), stopUpdatesMethodId,
500 androidClassKey);
501 }
502
504 {
505 QJniEnvironment env;
506 if (!env.jniEnv())
508
509 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
510
511 if (source) {
514
515 int errorCode = QJniObject::callStaticMethod<jint>(
516 positioningClass(), requestUpdateMethodId, androidClassKey,
517 positioningMethodToInt(source->preferredPositioningMethods()),
518 timeout, source->useAltitudeConverter());
519 switch (errorCode) {
520 case 0:
521 case 1:
522 case 2:
523 case 3:
524 return static_cast<QGeoPositionInfoSource::Error>(errorCode);
525 default:
526 break;
527 }
528 }
530 }
531
532 QGeoSatelliteInfoSource::Error startSatelliteUpdates(int androidClassKey, bool isSingleRequest, int requestTimeout)
533 {
534 QJniEnvironment env;
535 if (!env.jniEnv())
537
538 QGeoSatelliteInfoSourceAndroid *source = AndroidPositioning::idToSatSource()->value(androidClassKey);
539
540 if (source) {
543
544 int interval = source->updateInterval();
545 if (isSingleRequest)
546 interval = requestTimeout;
547 int errorCode = QJniObject::callStaticMethod<jint>(positioningClass(),
549 androidClassKey, interval,
550 isSingleRequest);
551 switch (errorCode) {
552 case -1:
553 case 0:
554 case 1:
555 case 2:
556 return static_cast<QGeoSatelliteInfoSource::Error>(errorCode);
557 default:
558 qCWarning(lcPositioning)
559 << "startSatelliteUpdates: Unknown error code" << errorCode;
560 break;
561 }
562 }
564 }
565
566
568 {
569 QLocationPermission permission;
570 permission.setAccuracy(QLocationPermission::Precise); // fine location (+ coarse on >= 31)
571
572 // The needed permission depends on whether we run as a service or as an activity
573 if (!QNativeInterface::QAndroidApplication::isActivityContext())
574 permission.setAvailability(QLocationPermission::Always); // background location
575
576 const bool permitted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
577
578 if (!permitted)
579 qCWarning(lcPositioning) << "Position data not available due to missing permission";
580
581 return permitted;
582 }
583}
584
585static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location,
586 jint androidClassKey, jboolean isSingleUpdate)
587{
588 Q_UNUSED(env);
589 Q_UNUSED(thiz);
591
592 QGeoPositionInfoSourceAndroid *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
593 if (!source) {
594 qCWarning(lcPositioning) << "positionUpdated: source == 0";
595 return;
596 }
597
598 //we need to invoke indirectly as the Looper thread is likely to be not the same thread
599 if (!isSingleUpdate)
600 QMetaObject::invokeMethod(source, "processPositionUpdate", Qt::AutoConnection,
602 else
603 QMetaObject::invokeMethod(source, "processSinglePositionUpdate", Qt::AutoConnection,
605}
606Q_DECLARE_JNI_NATIVE_METHOD(positionUpdated)
607
608static void locationProvidersDisabled(JNIEnv *env, jobject thiz, jint androidClassKey)
609{
610 Q_UNUSED(env);
611 Q_UNUSED(thiz);
612 QObject *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
613 if (!source)
614 source = AndroidPositioning::idToSatSource()->value(androidClassKey);
615 if (!source) {
616 qCWarning(lcPositioning) << "locationProvidersDisabled: source == 0";
617 return;
618 }
619
620 QMetaObject::invokeMethod(source, "locationProviderDisabled", Qt::AutoConnection);
621}
622Q_DECLARE_JNI_NATIVE_METHOD(locationProvidersDisabled)
623
624static void locationProvidersChanged(JNIEnv *env, jobject thiz, jint androidClassKey)
625{
626 Q_UNUSED(env);
627 Q_UNUSED(thiz);
628 QObject *source = AndroidPositioning::idToPosSource()->value(androidClassKey);
629 if (!source) {
630 qCWarning(lcPositioning) << "locationProvidersChanged: source == 0";
631 return;
632 }
633
634 QMetaObject::invokeMethod(source, "locationProvidersChanged", Qt::AutoConnection);
635}
636Q_DECLARE_JNI_NATIVE_METHOD(locationProvidersChanged)
637
639 const QList<QGeoSatelliteInfo> &inUse,
640 jint androidClassKey, jboolean isSingleUpdate)
641{
642 QGeoSatelliteInfoSourceAndroid *source = AndroidPositioning::idToSatSource()->value(androidClassKey);
643 if (!source) {
644 qCWarning(lcPositioning) << "notifySatelliteInfoUpdated: source == 0";
645 return;
646 }
647
648 QMetaObject::invokeMethod(source, "processSatelliteUpdate", Qt::AutoConnection,
649 Q_ARG(QList<QGeoSatelliteInfo>, inView),
650 Q_ARG(QList<QGeoSatelliteInfo>, inUse),
651 Q_ARG(bool, isSingleUpdate));
652}
653
654static void satelliteGpsUpdated(JNIEnv *env, jobject thiz,
655 jobjectArray satellites,
656 jint androidClassKey, jboolean isSingleUpdate)
657{
658 Q_UNUSED(thiz);
659 QList<QGeoSatelliteInfo> inUse;
660 QList<QGeoSatelliteInfo> sats =
662
663 notifySatelliteInfoUpdated(sats, inUse, androidClassKey, isSingleUpdate);
664}
665Q_DECLARE_JNI_NATIVE_METHOD(satelliteGpsUpdated)
666
667static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, QtJniTypes::GnssStatus gnssStatus,
668 jint androidClassKey, jboolean isSingleUpdate)
669{
670 Q_UNUSED(env);
671 Q_UNUSED(thiz);
672
673 QList<QGeoSatelliteInfo> inUse;
674 QList<QGeoSatelliteInfo> sats =
675 AndroidPositioning::satelliteInfoFromJavaGnssStatus(gnssStatus.object(), &inUse);
676
677 notifySatelliteInfoUpdated(sats, inUse, androidClassKey, isSingleUpdate);
678}
679Q_DECLARE_JNI_NATIVE_METHOD(satelliteGnssUpdated)
680
681#define GET_AND_CHECK_STATIC_METHOD(VAR, METHOD_NAME, ...) \
682 VAR = env.findStaticMethod<__VA_ARGS__>(positioningClass(), METHOD_NAME); \
683 if (!VAR) { \
684 __android_log_print(ANDROID_LOG_FATAL, logTag, methodErrorMsg, METHOD_NAME, \
685 QtJniTypes::methodSignature<__VA_ARGS__>().data()); \
686 return false; \
687 }
688
689static bool registerNatives()
690{
691 QJniEnvironment env;
692 if (!env.jniEnv()) {
693 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to create environment");
694 return false;
695 }
696
697 if (!positioningClass.init()) {
698 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to create global class ref");
699 return false;
700 }
701
702 if (!env.registerNativeMethods(positioningClass(), {
703 Q_JNI_NATIVE_METHOD(positionUpdated),
704 Q_JNI_NATIVE_METHOD(locationProvidersDisabled),
705 Q_JNI_NATIVE_METHOD(satelliteGpsUpdated),
706 Q_JNI_NATIVE_METHOD(locationProvidersChanged),
707 Q_JNI_NATIVE_METHOD(satelliteGnssUpdated)
708 })) {
709 __android_log_print(ANDROID_LOG_FATAL, logTag, "Failed to register native methods");
710 return false;
711 }
712
713 GET_AND_CHECK_STATIC_METHOD(providerListMethodId, "providerList", jintArray);
715 QtJniTypes::Location, bool, bool);
716 GET_AND_CHECK_STATIC_METHOD(startUpdatesMethodId, "startUpdates", jint, jint, jint, jint,
717 bool);
718 GET_AND_CHECK_STATIC_METHOD(stopUpdatesMethodId, "stopUpdates", void, jint);
719 GET_AND_CHECK_STATIC_METHOD(requestUpdateMethodId, "requestUpdate", jint, jint, jint, jint,
720 bool);
722 jint, jint, jint, bool);
723
724 return true;
725}
726
727Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/)
728{
729 static bool initialized = false;
730 if (initialized)
731 return JNI_VERSION_1_6;
732 initialized = true;
733
734 __android_log_print(ANDROID_LOG_INFO, logTag, "Positioning start");
735
736 if (!registerNatives()) {
737 __android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives() failed");
738 return -1;
739 }
740
741 if (!ConstellationMapper::init()) {
742 __android_log_print(ANDROID_LOG_ERROR, logTag,
743 "Failed to extract constellation type constants. "
744 "Satellite system will be undefined!");
745 }
746
747 return JNI_VERSION_1_6;
748}
749
GlobalClassRefWrapper()=default
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
\inmodule QtPositioning
Error
The Error enumeration represents the errors which can occur.
\inmodule QtPositioning
Error
The Error enumeration represents the errors which can occur.
int updateInterval
This property holds the requested interval in milliseconds between each update.
\inmodule QtPositioning
SatelliteSystem
Defines the GNSS system of the satellite.
\inmodule QtCore
\inmodule QtCore
Definition qlist.h:75
Access the user's location.
Q_CORE_EXPORT void setAvailability(Availability availability)
Sets the desired availability of the request.
Q_CORE_EXPORT void setAccuracy(Accuracy accuracy)
Sets the desired accuracy of the request.
\inmodule QtCore
Definition qobject.h:103
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
static const char logTag[]
static jmethodID providerListMethodId
#define GET_AND_CHECK_STATIC_METHOD(VAR, METHOD_NAME,...)
static jmethodID requestUpdateMethodId
static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location, jint androidClassKey, jboolean isSingleUpdate)
static jmethodID startSatelliteUpdatesMethodId
static const char logTag[]
static jmethodID stopUpdatesMethodId
static jmethodID startUpdatesMethodId
static void notifySatelliteInfoUpdated(const QList< QGeoSatelliteInfo > &inView, const QList< QGeoSatelliteInfo > &inUse, jint androidClassKey, jboolean isSingleUpdate)
static GlobalClassRefWrapper< QtJniTypes::QtPositioning > positioningClass
static void satelliteGpsUpdated(JNIEnv *env, jobject thiz, jobjectArray satellites, jint androidClassKey, jboolean isSingleUpdate)
static jmethodID lastKnownPositionMethodId
static const char methodErrorMsg[]
static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, QtJniTypes::GnssStatus gnssStatus, jint androidClassKey, jboolean isSingleUpdate)
static void locationProvidersChanged(JNIEnv *env, jobject thiz, jint androidClassKey)
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *, void *)
static void locationProvidersDisabled(JNIEnv *env, jobject thiz, jint androidClassKey)
static bool registerNatives()
void unregisterPositionInfoSource(int key)
static UniqueId getUid(const QGeoSatelliteInfo &info)
std::pair< int, int > UniqueId
QList< QGeoSatelliteInfo > satelliteInfoFromJavaGnssStatus(jobject gnssStatus, QList< QGeoSatelliteInfo > *usedInFix)
QMap< int, QGeoPositionInfoSourceAndroid * > PositionSourceMap
QMap< int, QGeoSatelliteInfoSourceAndroid * > SatelliteSourceMap
QGeoPositionInfo positionInfoFromJavaLocation(const jobject &location)
int positioningMethodToInt(QGeoPositionInfoSource::PositioningMethods m)
QGeoSatelliteInfoSource::Error startSatelliteUpdates(int androidClassKey, bool isSingleRequest, int requestTimeout)
QList< QGeoSatelliteInfo > satelliteInfoFromJavaLocation(JNIEnv *jniEnv, jobjectArray satellites, QList< QGeoSatelliteInfo > *usedInFix)
int registerPositionInfoSource(QObject *obj)
QGeoPositionInfoSource::Error requestUpdate(int androidClassKey, int timeout)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly, bool useAltitudeConverter)
QGeoPositionInfoSource::Error startUpdates(int androidClassKey)
QGeoPositionInfoSource::PositioningMethods availableProviders()
void stopUpdates(int androidClassKey)
Definition qcompare.h:63
@ AutoConnection
#define Q_DECL_EXPORT
#define qApp
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
return ret
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define Q_ARG(Type, data)
Definition qobjectdefs.h:63
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint location
const GLfloat * m
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLbitfield GLuint64 timeout
[4]
GLenum src
GLsizei GLsizei GLchar * source
GLhandleARB obj
[2]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment")
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
QHostInfo info
[0]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...