summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2024-01-04 21:21:53 +0200
committerTarja Sundqvist <tarja.sundqvist@qt.io>2024-01-04 21:21:53 +0200
commitf6953a8d604b906b170fb4610e124e7c31260a18 (patch)
treed437744854c4947a1e3490a50809470b9e311b07
parentb6d96559cb9f5e0d79936c89887ea924b2c3514a (diff)
parentc0c8901c9ef20da419f7d9ddaec779d88445299d (diff)
Merge remote-tracking branch 'origin/tqtc/lts-5.15.13' into tqtc/lts-5.15-opensourcev5.15.13-lts-lgpl5.15
-rw-r--r--.qmake.conf2
-rw-r--r--src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java92
-rw-r--r--src/plugins/position/android/src/jnipositioning.cpp162
3 files changed, 233 insertions, 23 deletions
diff --git a/.qmake.conf b/.qmake.conf
index a6fe7a56..092e259b 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -3,7 +3,7 @@ CONFIG += warning_clean
DEFINES += QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST
-MODULE_VERSION = 5.15.12
+MODULE_VERSION = 5.15.13
# Adds a way to debug location. The define is needed for multiple subprojects as they
# include the essential headers.
diff --git a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
index d819e627..3df31d70 100644
--- a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
+++ b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
@@ -45,9 +45,12 @@ import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.location.GnssStatus;
+import android.location.GnssStatus.Callback;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.Build;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -97,7 +100,7 @@ public class QtPositioning implements LocationListener
/* If true this class acts as satellite signal monitor rather than location monitor */
private boolean isSatelliteUpdate = false;
- private PositioningLooper looperThread;
+ private PositioningLooperBase looperThread;
static public void setContext(Context context)
{
@@ -404,7 +407,12 @@ public class QtPositioning implements LocationListener
public QtPositioning()
{
- looperThread = new PositioningLooper();
+ // Use GpsStatus for API Level <= 23 (version M and below) and
+ // GnssStatus for other API levels.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M)
+ looperThread = new PositioningLooperGps();
+ else
+ looperThread = new PositioningLooperGnss();
}
public Looper looper()
@@ -438,13 +446,16 @@ public class QtPositioning implements LocationListener
}
}
- private class PositioningLooper extends Thread implements GpsStatus.Listener{
+ private abstract class PositioningLooperBase extends Thread
+ {
private boolean looperRunning;
private Looper posLooper;
private boolean isSatelliteLooper = false;
- private LocationManager locManager = null;
- private PositioningLooper()
+ abstract protected void addSatelliteInfoListener();
+ abstract protected void removeSatelliteInfoListener();
+
+ private PositioningLooperBase()
{
looperRunning = false;
}
@@ -454,13 +465,8 @@ public class QtPositioning implements LocationListener
Looper.prepare();
Handler handler = new Handler();
- if (isSatelliteLooper) {
- try {
- locationManager.addGpsStatusListener(this);
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
+ if (isSatelliteLooper)
+ addSatelliteInfoListener();
posLooper = Looper.myLooper();
synchronized (this) {
@@ -475,7 +481,7 @@ public class QtPositioning implements LocationListener
public void quitLooper()
{
if (isSatelliteLooper)
- locationManager.removeGpsStatusListener(this);
+ removeSatelliteInfoListener();
looper().quit();
}
@@ -494,6 +500,26 @@ public class QtPositioning implements LocationListener
return posLooper;
}
+ }
+
+ private class PositioningLooperGps extends PositioningLooperBase implements GpsStatus.Listener
+ {
+ @Override
+ protected void addSatelliteInfoListener()
+ {
+ try {
+ locationManager.addGpsStatusListener(this);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void removeSatelliteInfoListener()
+ {
+ locationManager.removeGpsStatusListener(this);
+ }
+
@Override
public void onGpsStatusChanged(int event) {
switch (event) {
@@ -510,7 +536,7 @@ public class QtPositioning implements LocationListener
list.add(sat);
}
GpsSatellite[] sats = list.toArray(new GpsSatellite[list.size()]);
- satelliteUpdated(sats, nativeClassReference, isSingleUpdate);
+ satelliteGpsUpdated(sats, nativeClassReference, isSingleUpdate);
break;
case GpsStatus.GPS_EVENT_STARTED:
@@ -521,10 +547,46 @@ public class QtPositioning implements LocationListener
}
}
+ private class PositioningGnssListener extends GnssStatus.Callback
+ {
+ @Override
+ public void onSatelliteStatusChanged(GnssStatus status)
+ {
+ satelliteGnssUpdated(status, nativeClassReference, isSingleUpdate);
+ }
+ }
+
+ private class PositioningLooperGnss extends PositioningLooperBase
+ {
+ private PositioningGnssListener gnssListener;
+
+ private PositioningLooperGnss()
+ {
+ gnssListener = new PositioningGnssListener();
+ }
+
+ @Override
+ protected void addSatelliteInfoListener()
+ {
+ try {
+ locationManager.registerGnssStatusCallback(gnssListener);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void removeSatelliteInfoListener()
+ {
+ locationManager.unregisterGnssStatusCallback(gnssListener);
+ }
+ }
+
public static native void positionUpdated(Location update, int androidClassKey, boolean isSingleUpdate);
public static native void locationProvidersDisabled(int androidClassKey);
public static native void locationProvidersChanged(int androidClassKey);
- public static native void satelliteUpdated(GpsSatellite[] update, int androidClassKey, boolean isSingleUpdate);
+ public static native void satelliteGpsUpdated(GpsSatellite[] update, int androidClassKey, boolean isSingleUpdate);
+ public static native void satelliteGnssUpdated(GnssStatus update, int androidClassKey, boolean isSingleUpdate);
@Override
public void onLocationChanged(Location location) {
diff --git a/src/plugins/position/android/src/jnipositioning.cpp b/src/plugins/position/android/src/jnipositioning.cpp
index 8854a677..8e38d55c 100644
--- a/src/plugins/position/android/src/jnipositioning.cpp
+++ b/src/plugins/position/android/src/jnipositioning.cpp
@@ -64,6 +64,58 @@ static const char logTag[] = "QtPositioning";
static const char classErrorMsg[] = "Can't find class \"%s\"";
static const char methodErrorMsg[] = "Can't find method \"%s%s\"";
+namespace {
+
+/*!
+ \internal
+ This class encapsulates satellite system types, as defined by Android
+ GnssStatus API. Initialize during JNI_OnLoad() by the init() method, from
+ the Java side, rather than hard-coding.
+*/
+class ConstellationMapper
+{
+public:
+ static bool init(JNIEnv *jniEnv)
+ {
+ if (QtAndroidPrivate::androidSdkVersion() > 23) {
+ jclass gnssStatusObject = jniEnv->FindClass("android/location/GnssStatus");
+ if (!gnssStatusObject)
+ return false;
+
+ jfieldID gpsFieldId = jniEnv->GetStaticFieldID(gnssStatusObject,
+ "CONSTELLATION_GPS", "I");
+ jfieldID glonassFieldId = jniEnv->GetStaticFieldID(gnssStatusObject,
+ "CONSTELLATION_GLONASS", "I");
+ if (!gpsFieldId || !glonassFieldId)
+ return false;
+
+ m_gpsId = jniEnv->GetStaticIntField(gnssStatusObject, gpsFieldId);
+ m_glonassId = jniEnv->GetStaticIntField(gnssStatusObject, glonassFieldId);
+ }
+ // no need to query it for API level <= 23
+ return true;
+ }
+
+ static QGeoSatelliteInfo::SatelliteSystem toSatelliteSystem(int constellationType)
+ {
+ if (constellationType == m_gpsId)
+ return QGeoSatelliteInfo::GPS;
+ else if (constellationType == m_glonassId)
+ return QGeoSatelliteInfo::GLONASS;
+
+ return QGeoSatelliteInfo::Undefined;
+ }
+
+private:
+ static int m_gpsId;
+ static int m_glonassId;
+};
+
+int ConstellationMapper::m_gpsId = -1;
+int ConstellationMapper::m_glonassId = -1;
+
+} // anonymous namespace
+
namespace AndroidPositioning {
typedef QMap<int, QGeoPositionInfoSourceAndroid * > PositionSourceMap;
typedef QMap<int, QGeoSatelliteInfoSourceAndroid * > SatelliteSourceMap;
@@ -362,6 +414,74 @@ namespace AndroidPositioning {
return sats;
}
+ QList<QGeoSatelliteInfo> satelliteInfoFromJavaGnssStatus(JNIEnv *jniEnv, jobject gnssStatus,
+ QList<QGeoSatelliteInfo>* usedInFix)
+ {
+ QList<QGeoSatelliteInfo> sats;
+
+ jclass statusClass = jniEnv->GetObjectClass(gnssStatus);
+ if (!statusClass)
+ return sats;
+
+ jmethodID satCountMethod = getCachedMethodID(jniEnv, statusClass,
+ "getSatelliteCount", "()I");
+ jmethodID sigStrengthMethod = getCachedMethodID(jniEnv, statusClass, "getCn0DbHz", "(I)F");
+ jmethodID constTypeMethod = getCachedMethodID(jniEnv, statusClass,
+ "getConstellationType", "(I)I");
+ jmethodID svIdMethod = getCachedMethodID(jniEnv, statusClass, "getSvid", "(I)I");
+ jmethodID azimuthMethod = getCachedMethodID(jniEnv, statusClass,
+ "getAzimuthDegrees", "(I)F");
+ jmethodID elevationMethod = getCachedMethodID(jniEnv, statusClass,
+ "getElevationDegrees", "(I)F");
+ jmethodID usedInFixMethod = getCachedMethodID(jniEnv, statusClass,
+ "usedInFix", "(I)Z");
+
+ if (!satCountMethod || !sigStrengthMethod || !constTypeMethod || !svIdMethod
+ || !azimuthMethod || !elevationMethod || !usedInFixMethod) {
+ jniEnv->DeleteLocalRef(statusClass);
+ return sats;
+ }
+
+ const int satellitesCount = jniEnv->CallIntMethod(gnssStatus, satCountMethod);
+ for (int i = 0; i < satellitesCount; ++i) {
+ QGeoSatelliteInfo info;
+
+ // signal strength - this is actually a carrier-to-noise density,
+ // but the values are very close to what was previously returned by
+ // getSnr() method of the GpsSatellite API.
+ const jfloat cn0 = jniEnv->CallFloatMethod(gnssStatus, sigStrengthMethod, i);
+ info.setSignalStrength(static_cast<int>(cn0));
+
+ // satellite system
+ const jint constellationType = jniEnv->CallIntMethod(gnssStatus, constTypeMethod, i);
+ info.setSatelliteSystem(ConstellationMapper::toSatelliteSystem(constellationType));
+
+ // satellite identifier
+ const jint svId = jniEnv->CallIntMethod(gnssStatus, svIdMethod, i);
+ info.setSatelliteIdentifier(svId);
+
+ // azimuth
+ const jfloat azimuth = jniEnv->CallFloatMethod(gnssStatus, azimuthMethod, i);
+ info.setAttribute(QGeoSatelliteInfo::Azimuth, static_cast<qreal>(azimuth));
+
+ // elevation
+ const jfloat elevation = jniEnv->CallFloatMethod(gnssStatus, elevationMethod, i);
+ info.setAttribute(QGeoSatelliteInfo::Elevation, static_cast<qreal>(elevation));
+
+ // Used in fix - true if this satellite is actually used in
+ // determining the position.
+ const jboolean inFix = jniEnv->CallBooleanMethod(gnssStatus, usedInFixMethod, i);
+
+ sats.append(info);
+
+ if (inFix)
+ usedInFix->append(info);
+ }
+
+ jniEnv->DeleteLocalRef(statusClass);
+ return sats;
+ }
+
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly)
{
AttachedJNIEnv env;
@@ -562,11 +682,10 @@ static void locationProvidersChanged(JNIEnv *env, jobject /*thiz*/, jint android
QMetaObject::invokeMethod(source, "locationProvidersChanged", Qt::AutoConnection);
}
-static void satelliteUpdated(JNIEnv *env, jobject /*thiz*/, jobjectArray satellites, jint androidClassKey, jboolean isSingleUpdate)
+static void notifySatelliteInfoUpdated(const QList<QGeoSatelliteInfo> &inView,
+ const QList<QGeoSatelliteInfo> &inUse,
+ jint androidClassKey, jboolean isSingleUpdate)
{
- QList<QGeoSatelliteInfo> inUse;
- QList<QGeoSatelliteInfo> sats = AndroidPositioning::satelliteInfoFromJavaLocation(env, satellites, &inUse);
-
QGeoSatelliteInfoSourceAndroid *source = AndroidPositioning::idToSatSource()->value(androidClassKey);
if (!source) {
qWarning("satelliteUpdated: source == 0");
@@ -574,12 +693,34 @@ static void satelliteUpdated(JNIEnv *env, jobject /*thiz*/, jobjectArray satelli
}
QMetaObject::invokeMethod(source, "processSatelliteUpdateInView", Qt::AutoConnection,
- Q_ARG(QList<QGeoSatelliteInfo>, sats), Q_ARG(bool, isSingleUpdate));
+ Q_ARG(QList<QGeoSatelliteInfo>, inView), Q_ARG(bool, isSingleUpdate));
QMetaObject::invokeMethod(source, "processSatelliteUpdateInUse", Qt::AutoConnection,
Q_ARG(QList<QGeoSatelliteInfo>, inUse), Q_ARG(bool, isSingleUpdate));
}
+static void satelliteGpsUpdated(JNIEnv *env, jobject thiz, jobjectArray satellites,
+ jint androidClassKey, jboolean isSingleUpdate)
+{
+ Q_UNUSED(thiz);
+ QList<QGeoSatelliteInfo> inUse;
+ QList<QGeoSatelliteInfo> sats =
+ AndroidPositioning::satelliteInfoFromJavaLocation(env, satellites, &inUse);
+
+ notifySatelliteInfoUpdated(sats, inUse, androidClassKey, isSingleUpdate);
+}
+
+static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, jobject gnssStatus,
+ jint androidClassKey, jboolean isSingleUpdate)
+{
+ Q_UNUSED(thiz);
+ QList<QGeoSatelliteInfo> inUse;
+ QList<QGeoSatelliteInfo> sats =
+ AndroidPositioning::satelliteInfoFromJavaGnssStatus(env, gnssStatus, &inUse);
+
+ notifySatelliteInfoUpdated(sats, inUse, androidClassKey, isSingleUpdate);
+}
+
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
clazz = env->FindClass(CLASS_NAME); \
@@ -598,8 +739,9 @@ if (!VAR) { \
static JNINativeMethod methods[] = {
{"positionUpdated", "(Landroid/location/Location;IZ)V", (void *)positionUpdated},
{"locationProvidersDisabled", "(I)V", (void *) locationProvidersDisabled},
- {"satelliteUpdated", "([Landroid/location/GpsSatellite;IZ)V", (void *)satelliteUpdated},
- {"locationProvidersChanged", "(I)V", (void *) locationProvidersChanged}
+ {"satelliteGpsUpdated", "([Landroid/location/GpsSatellite;IZ)V", (void *)satelliteGpsUpdated},
+ {"locationProvidersChanged", "(I)V", (void *) locationProvidersChanged},
+ {"satelliteGnssUpdated", "(Landroid/location/GnssStatus;IZ)V", (void *)satelliteGnssUpdated}
};
static bool registerNatives(JNIEnv *env)
@@ -650,6 +792,12 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
return -1;
}
+ if (!ConstellationMapper::init(env)) {
+ __android_log_print(ANDROID_LOG_ERROR, logTag,
+ "Failed to extract constellation type constants. "
+ "Satellite system will be undefined!");
+ }
+
javaVM = vm;
return JNI_VERSION_1_6;
}