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>
17#include <android/log.h>
23using namespace
Qt::StringLiterals;
35 env->DeleteGlobalRef(m_classRef);
44 env->DeleteGlobalRef(m_classRef);
48 m_classRef = env.findClass<T>();
50 return m_classRef !=
nullptr;
56 jclass m_classRef =
nullptr;
68static const char logTag[] =
"qt.positioning.android";
81class ConstellationMapper
86 m_gnssStatusObject =
nullptr;
87 if (QNativeInterface::QAndroidApplication::sdkVersion() > 23) {
88 m_gnssStatusObject =
QJniEnvironment().findClass<QtJniTypes::GnssStatus>();
89 if (!m_gnssStatusObject)
98 if (!m_gnssStatusObject)
101 static const int gps =
102 QJniObject::getStaticField<jint>(m_gnssStatusObject,
"CONSTELLATION_GPS");
103 static const int glonass =
104 QJniObject::getStaticField<jint>(m_gnssStatusObject,
"CONSTELLATION_GLONASS");
105 static const int galileo =
106 QJniObject::getStaticField<jint>(m_gnssStatusObject,
"CONSTELLATION_GALILEO");
107 static const int beidou =
108 QJniObject::getStaticField<jint>(m_gnssStatusObject,
"CONSTELLATION_BEIDOU");
109 static const int qzss =
110 QJniObject::getStaticField<jint>(m_gnssStatusObject,
"CONSTELLATION_QZSS");
112 if (constellationType == gps) {
114 }
else if (constellationType == glonass) {
116 }
else if (constellationType == galileo) {
118 }
else if (constellationType == beidou) {
120 }
else if (constellationType == qzss){
123 qCWarning(lcPositioning) <<
"Unknown satellite system" << constellationType;
129 static jclass m_gnssStatusObject;
132jclass ConstellationMapper::m_gnssStatusObject =
nullptr;
147 if (
obj->inherits(
"QGeoPositionInfoSource")) {
154 idToPosSource()->insert(
key,
src);
155 }
else if (
obj->inherits(
"QGeoSatelliteInfoSource")) {
162 idToSatSource()->insert(
key,
src);
170 if (idToPosSource.exists())
171 idToPosSource->remove(
key);
173 if (idToSatSource.exists())
174 idToSatSource->remove(
key);
193 jintArray jProviders = jniProvidersObj.object<jintArray>();
194 jint *providers = env->GetIntArrayElements(jProviders,
nullptr);
195 const int size = env->GetArrayLength(jProviders);
196 for (
int i = 0;
i <
size;
i++) {
197 switch (providers[
i]) {
208 __android_log_print(ANDROID_LOG_INFO,
logTag,
"Unknown positioningMethod");
212 env->ReleaseIntArrayElements(jProviders, providers, 0);
222 if (!jniObject.isValid())
225 const jdouble latitude = jniObject.callMethod<jdouble>(
"getLatitude");
226 const jdouble longitude = jniObject.callMethod<jdouble>(
"getLongitude");
231 jboolean attributeExists = jniObject.callMethod<jboolean>(
"hasAltitude");
232 if (attributeExists) {
233 const jdouble
value = jniObject.callMethod<jdouble>(
"getAltitude");
235 coordinate.setAltitude(
value);
238 info.setCoordinate(coordinate);
241 const jlong timestamp = jniObject.callMethod<jlong>(
"getTime");
245 attributeExists = jniObject.callMethod<jboolean>(
"hasAccuracy");
246 if (attributeExists) {
247 const jfloat accuracy = jniObject.callMethod<jfloat>(
"getAccuracy");
253 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
254 attributeExists = jniObject.callMethod<jboolean>(
"hasVerticalAccuracy");
255 if (attributeExists) {
256 const jfloat accuracy = jniObject.callMethod<jfloat>(
"getVerticalAccuracyMeters");
263 attributeExists = jniObject.callMethod<jboolean>(
"hasSpeed");
264 if (attributeExists) {
265 const jfloat speed = jniObject.callMethod<jfloat>(
"getSpeed");
271 attributeExists = jniObject.callMethod<jboolean>(
"hasBearing");
272 if (attributeExists) {
273 const jfloat bearing = jniObject.callMethod<jfloat>(
"getBearing");
278 if (QNativeInterface::QAndroidApplication::sdkVersion() > 25) {
279 const jfloat bearingAccuracy =
280 jniObject.callMethod<jfloat>(
"getBearingAccuracyDegrees");
290 jobjectArray satellites,
294 jsize
length = jniEnv->GetArrayLength(satellites);
296 jobject element = jniEnv->GetObjectArrayElement(satellites,
i);
297 if (QJniEnvironment::checkAndClearExceptions(jniEnv)) {
298 qCWarning(lcPositioning) <<
"Cannot process all satellite data due to exception.";
302 QJniObject jniObj = QJniObject::fromLocalRef(element);
303 if (!jniObj.isValid())
309 const jfloat snr = jniObj.callMethod<jfloat>(
"getSnr");
310 info.setSignalStrength(
int(snr));
317 const jint prn = jniObj.callMethod<jint>(
"getPrn");
318 info.setSatelliteIdentifier(prn);
320 if (prn >= 1 && prn <= 32)
322 else if (prn >= 65 && prn <= 96)
324 else if (prn >= 193 && prn <= 200)
326 else if ((prn >= 201 && prn <= 235) || (prn >= 401 && prn <= 437))
328 else if (prn >= 301 && prn <= 336)
332 const jfloat azimuth = jniObj.callMethod<jfloat>(
"getAzimuth");
336 const jfloat elevation = jniObj.callMethod<jfloat>(
"getElevation");
341 const jboolean inFix = jniObj.callMethod<jboolean>(
"usedInFix");
358 const int satellitesCount = jniStatus.callMethod<jint>(
"getSatelliteCount");
359 for (
int i = 0;
i < satellitesCount; ++
i) {
365 const jfloat cn0 = jniStatus.callMethod<jfloat>(
"getCn0DbHz",
i);
366 info.setSignalStrength(
static_cast<int>(cn0));
369 const jint constellationType =
370 jniStatus.callMethod<jint>(
"getConstellationType",
i);
371 info.setSatelliteSystem(ConstellationMapper::toSatelliteSystem(constellationType));
374 const jint svId = jniStatus.callMethod<jint>(
"getSvid",
i);
375 info.setSatelliteIdentifier(svId);
378 const jfloat azimuth = jniStatus.callMethod<jfloat>(
"getAzimuthDegrees",
i);
382 const jfloat elevation = jniStatus.callMethod<jfloat>(
"getElevationDegrees",
i);
387 const jboolean inFix = jniStatus.callMethod<jboolean>(
"usedInFix",
i);
407 QJniObject locationObj = QJniObject::callStaticMethod<jobject>(
409 jobject
location = locationObj.object();
420 int providerSelection = 0;
422 providerSelection |= 1;
424 providerSelection |= 2;
426 return providerSelection;
441 int errorCode = QJniObject::callStaticMethod<jint>(
444 source->updateInterval());
478 int errorCode = QJniObject::callStaticMethod<jint>(
507 int interval =
source->updateInterval();
509 interval = requestTimeout;
512 androidClassKey, interval,
522 <<
"startSatelliteUpdates: Unknown error code" << errorCode;
536 if (!QNativeInterface::QAndroidApplication::isActivityContext())
542 qCWarning(lcPositioning) <<
"Position data not available due to missing permission";
549 jint androidClassKey, jboolean isSingleUpdate)
557 qCWarning(lcPositioning) <<
"positionUpdated: source == 0";
575 QObject *
source = AndroidPositioning::idToPosSource()->value(androidClassKey);
577 source = AndroidPositioning::idToSatSource()->value(androidClassKey);
579 qCWarning(lcPositioning) <<
"locationProvidersDisabled: source == 0";
591 QObject *
source = AndroidPositioning::idToPosSource()->value(androidClassKey);
593 qCWarning(lcPositioning) <<
"locationProvidersChanged: source == 0";
603 jint androidClassKey, jboolean isSingleUpdate)
607 qCWarning(lcPositioning) <<
"notifySatelliteInfoUpdated: source == 0";
614 Q_ARG(
bool, isSingleUpdate));
618 jobjectArray satellites,
619 jint androidClassKey, jboolean isSingleUpdate)
631 jint androidClassKey, jboolean isSingleUpdate)
644#define GET_AND_CHECK_STATIC_METHOD(VAR, METHOD_NAME, ...) \
645 VAR = env.findStaticMethod<__VA_ARGS__>(positioningClass(), METHOD_NAME); \
647 __android_log_print(ANDROID_LOG_FATAL, logTag, methodErrorMsg, METHOD_NAME, \
648 QtJniTypes::methodSignature<__VA_ARGS__>().data()); \
656 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to create environment");
661 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to create global class ref");
672 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"Failed to register native methods");
678 QtJniTypes::Location,
bool);
683 jint, jint, jint,
bool);
690 static bool initialized =
false;
692 return JNI_VERSION_1_6;
695 __android_log_print(ANDROID_LOG_INFO,
logTag,
"Positioning start");
698 __android_log_print(ANDROID_LOG_FATAL,
logTag,
"registerNatives() failed");
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!");
708 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.
SatelliteSystem
Defines the GNSS system of the satellite.
void append(parameter_type t)
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()
QList< QGeoSatelliteInfo > satelliteInfoFromJavaGnssStatus(jobject gnssStatus, QList< QGeoSatelliteInfo > *usedInFix)
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly)
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)
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)
QFileInfo info(fileName)
[8]