7#include <QtPositioning/QGeoPositionInfo>
8#include <QtCore/QDateTime>
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>
18#include <android/log.h>
24using namespace
Qt::StringLiterals;
36 env->DeleteGlobalRef(m_classRef);
45 env->DeleteGlobalRef(m_classRef);
49 m_classRef = env.findClass<T>();
51 return m_classRef !=
nullptr;
57 jclass m_classRef =
nullptr;
69static const char logTag[] =
"qt.positioning.android";
82class ConstellationMapper
87 m_gnssStatusObject =
nullptr;
88 if (QNativeInterface::QAndroidApplication::sdkVersion() > 23) {
89 m_gnssStatusObject =
QJniEnvironment().findClass<QtJniTypes::GnssStatus>();
90 if (!m_gnssStatusObject)
99 if (!m_gnssStatusObject)
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");
113 if (constellationType == gps) {
115 }
else if (constellationType == glonass) {
117 }
else if (constellationType == galileo) {
119 }
else if (constellationType == beidou) {
121 }
else if (constellationType == qzss){
124 qCWarning(lcPositioning) <<
"Unknown satellite system" << constellationType;
130 static jclass m_gnssStatusObject;
133jclass ConstellationMapper::m_gnssStatusObject =
nullptr;
148 if (
obj->inherits(
"QGeoPositionInfoSource")) {
155 idToPosSource()->insert(
key,
src);
156 }
else if (
obj->inherits(
"QGeoSatelliteInfoSource")) {
163 idToSatSource()->insert(
key,
src);
171 if (idToPosSource.exists())
172 idToPosSource->remove(
key);
174 if (idToSatSource.exists())
175 idToSatSource->remove(
key);
194 jintArray jProviders = jniProvidersObj.object<jintArray>();
197 __android_log_print(ANDROID_LOG_INFO,
logTag,
"Got null providers array!");
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]) {
214 __android_log_print(ANDROID_LOG_INFO,
logTag,
"Unknown positioningMethod");
218 env->ReleaseIntArrayElements(jProviders, providers, 0);
228 if (!jniObject.isValid())
231 const jdouble latitude = jniObject.callMethod<jdouble>(
"getLatitude");
232 const jdouble longitude = jniObject.callMethod<jdouble>(
"getLongitude");
237 jboolean attributeExists = jniObject.callMethod<jboolean>(
"hasAltitude");
238 if (attributeExists) {
239 const jdouble
value = jniObject.callMethod<jdouble>(
"getAltitude");
241 coordinate.setAltitude(
value);
245 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 34) {
246 attributeExists = jniObject.callMethod<jboolean>(
"hasMslAltitude");
247 if (attributeExists) {
248 const jdouble
value = jniObject.callMethod<jdouble>(
"getMslAltitudeMeters");
250 coordinate.setAltitude(
value);
254 info.setCoordinate(coordinate);
257 const jlong timestamp = jniObject.callMethod<jlong>(
"getTime");
261 attributeExists = jniObject.callMethod<jboolean>(
"hasAccuracy");
262 if (attributeExists) {
263 const jfloat accuracy = jniObject.callMethod<jfloat>(
"getAccuracy");
269 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
270 attributeExists = jniObject.callMethod<jboolean>(
"hasVerticalAccuracy");
271 if (attributeExists) {
272 const jfloat accuracy = jniObject.callMethod<jfloat>(
"getVerticalAccuracyMeters");
279 attributeExists = jniObject.callMethod<jboolean>(
"hasSpeed");
280 if (attributeExists) {
281 const jfloat speed = jniObject.callMethod<jfloat>(
"getSpeed");
287 attributeExists = jniObject.callMethod<jboolean>(
"hasBearing");
288 if (attributeExists) {
289 const jfloat bearing = jniObject.callMethod<jfloat>(
"getBearing");
294 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
295 const jfloat bearingAccuracy =
296 jniObject.callMethod<jfloat>(
"getBearingAccuracyDegrees");
308 return std::make_pair(
static_cast<int>(
info.satelliteSystem()),
309 info.satelliteIdentifier());
313 jobjectArray satellites,
314 QList<QGeoSatelliteInfo>* usedInFix)
317 QList<QGeoSatelliteInfo> sats;
318 jsize
length = jniEnv->GetArrayLength(satellites);
320 jobject element = jniEnv->GetObjectArrayElement(satellites,
i);
321 if (QJniEnvironment::checkAndClearExceptions(jniEnv)) {
322 qCWarning(lcPositioning) <<
"Cannot process all satellite data due to exception.";
326 QJniObject jniObj = QJniObject::fromLocalRef(element);
327 if (!jniObj.isValid())
333 const jfloat snr = jniObj.callMethod<jfloat>(
"getSnr");
334 info.setSignalStrength(
int(snr));
341 const jint prn = jniObj.callMethod<jint>(
"getPrn");
342 info.setSatelliteIdentifier(prn);
344 if (prn >= 1 && prn <= 32)
346 else if (prn >= 65 && prn <= 96)
348 else if (prn >= 193 && prn <= 200)
350 else if ((prn >= 201 && prn <= 235) || (prn >= 401 && prn <= 437))
352 else if (prn >= 301 && prn <= 336)
356 const jfloat azimuth = jniObj.callMethod<jfloat>(
"getAzimuth");
360 const jfloat elevation = jniObj.callMethod<jfloat>(
"getElevation");
365 const jboolean inFix = jniObj.callMethod<jboolean>(
"usedInFix");
368 if (uids.contains(
id))
375 usedInFix->append(
info);
382 QList<QGeoSatelliteInfo>* usedInFix)
385 QList<QGeoSatelliteInfo> sats;
388 const int satellitesCount = jniStatus.callMethod<jint>(
"getSatelliteCount");
389 for (
int i = 0;
i < satellitesCount; ++
i) {
395 const jfloat cn0 = jniStatus.callMethod<jfloat>(
"getCn0DbHz",
i);
396 info.setSignalStrength(
static_cast<int>(cn0));
399 const jint constellationType =
400 jniStatus.callMethod<jint>(
"getConstellationType",
i);
401 info.setSatelliteSystem(ConstellationMapper::toSatelliteSystem(constellationType));
404 const jint svId = jniStatus.callMethod<jint>(
"getSvid",
i);
405 info.setSatelliteIdentifier(svId);
408 const jfloat azimuth = jniStatus.callMethod<jfloat>(
"getAzimuthDegrees",
i);
412 const jfloat elevation = jniStatus.callMethod<jfloat>(
"getElevationDegrees",
i);
417 const jboolean inFix = jniStatus.callMethod<jboolean>(
"usedInFix",
i);
420 if (uids.contains(
id))
427 usedInFix->append(
info);
434 bool useAltitudeConverter)
443 QJniObject locationObj = QJniObject::callStaticMethod<jobject>(
445 useAltitudeConverter);
446 jobject
location = locationObj.object();
457 int providerSelection = 0;
459 providerSelection |= 1;
461 providerSelection |= 2;
463 return providerSelection;
478 int errorCode = QJniObject::callStaticMethod<jint>(
481 source->updateInterval(),
source->useAltitudeConverter());
515 int errorCode = QJniObject::callStaticMethod<jint>(
546 interval = requestTimeout;
549 androidClassKey, interval,
559 <<
"startSatelliteUpdates: Unknown error code" << errorCode;
573 if (!QNativeInterface::QAndroidApplication::isActivityContext())
579 qCWarning(lcPositioning) <<
"Position data not available due to missing permission";
586 jint androidClassKey, jboolean isSingleUpdate)
594 qCWarning(lcPositioning) <<
"positionUpdated: source == 0";
612 QObject *
source = AndroidPositioning::idToPosSource()->value(androidClassKey);
614 source = AndroidPositioning::idToSatSource()->value(androidClassKey);
616 qCWarning(lcPositioning) <<
"locationProvidersDisabled: source == 0";
628 QObject *
source = AndroidPositioning::idToPosSource()->value(androidClassKey);
630 qCWarning(lcPositioning) <<
"locationProvidersChanged: source == 0";
640 jint androidClassKey, jboolean isSingleUpdate)
644 qCWarning(lcPositioning) <<
"notifySatelliteInfoUpdated: source == 0";
649 Q_ARG(QList<QGeoSatelliteInfo>, inView),
650 Q_ARG(QList<QGeoSatelliteInfo>, inUse),
651 Q_ARG(
bool, isSingleUpdate));
655 jobjectArray satellites,
656 jint androidClassKey, jboolean isSingleUpdate)
659 QList<QGeoSatelliteInfo> inUse;
660 QList<QGeoSatelliteInfo> sats =
668 jint androidClassKey, jboolean isSingleUpdate)
673 QList<QGeoSatelliteInfo> inUse;
674 QList<QGeoSatelliteInfo> sats =
681#define GET_AND_CHECK_STATIC_METHOD(VAR, METHOD_NAME, ...) \
682 VAR = env.findStaticMethod<__VA_ARGS__>(positioningClass(), METHOD_NAME); \
684 __android_log_print(ANDROID_LOG_FATAL, logTag, methodErrorMsg, METHOD_NAME, \
685 QtJniTypes::methodSignature<__VA_ARGS__>().data()); \
693 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to create environment");
698 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to create global class ref");
709 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to register native methods");
715 QtJniTypes::Location,
bool,
bool);
722 jint, jint, jint,
bool);
729 static bool initialized =
false;
731 return JNI_VERSION_1_6;
734 __android_log_print(ANDROID_LOG_INFO,
logTag,
"Positioning start");
737 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"registerNatives() failed");
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!");
747 return JNI_VERSION_1_6;
GlobalClassRefWrapper()=default
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
@ SatellitePositioningMethods
@ NonSatellitePositioningMethods
Error
The Error enumeration represents the errors which can occur.
Error
The Error enumeration represents the errors which can occur.
int updateInterval
This property holds the requested interval in milliseconds between each update.
SatelliteSystem
Defines the GNSS system of the satellite.
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.
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
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)
bool hasPositioningPermissions()
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)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyIsNull(qfloat16 f) noexcept
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
constexpr T qAbs(const T &t)
#define Q_ARG(Type, data)
static bool contains(const QJsonArray &haystack, unsigned needle)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLbitfield GLuint64 timeout
[4]
GLsizei GLsizei GLchar * source
QT_BEGIN_NAMESPACE Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment")
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)