4package org.qtproject.qt.android.positioning;
7import android.location.altitude.AltitudeConverter;
9import android.location.LocationListener;
10import android.location.LocationManager;
11import android.location.GnssStatus;
15import java.util.HashMap;
20class QtPositioning
implements LocationListener
23 private static final String TAG =
"qt.positioning.android";
24 static LocationManager locationManager =
null;
26 static HashMap<Integer, QtPositioning> runningListeners =
new HashMap<Integer, QtPositioning>();
32 private int nativeClassReference = 0;
37 private int expectedProviders = 0;
39 static final int QT_GPS_PROVIDER = 1;
40 static final int QT_NETWORK_PROVIDER = 2;
43 static final int QT_ACCESS_ERROR = 0;
44 static final int QT_CLOSED_ERROR = 1;
45 static final int QT_POSITION_UNKNOWN_SOURCE_ERROR = 2;
46 static final int QT_POSITION_NO_ERROR = 3;
47 static final int QT_SATELLITE_NO_ERROR = 2;
48 static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR = -1;
51 private boolean isSingleUpdate =
false;
53 private int updateIntervalTime = 0;
60 private boolean isSatelliteUpdate =
false;
62 private boolean useAltitudeConverter =
false;
64 private PositioningLooperGnss looperThread;
66 private boolean isLocationProvidersDisabledInvoked =
false;
68 private static Context appContext =
null;
69 private static AltitudeConverter altitudeConverter =
null;
75 locationManager = (LocationManager)
context.getSystemService(
Context.LOCATION_SERVICE);
76 }
catch(Exception e) {
81 static private int[] providerList()
83 if (locationManager ==
null) {
84 Log.w(
TAG,
"No locationManager available in QtPositioning");
87 List<String> providers = locationManager.getProviders(
true);
88 int retList[] =
new int[providers.size()];
89 for (
int i = 0; i < providers.size(); i++) {
90 if (providers.get(i).equals(LocationManager.GPS_PROVIDER)) {
93 }
else if (providers.get(i).equals(LocationManager.NETWORK_PROVIDER)) {
96 }
else if (providers.get(i).equals(LocationManager.PASSIVE_PROVIDER)) {
108 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
111 if (altitudeConverter ==
null)
112 altitudeConverter =
new AltitudeConverter();
114 altitudeConverter.addMslAltitudeToLocation(appContext,
location);
115 }
catch (Exception e) {
121 static Location lastKnownPosition(
boolean fromSatelliteOnly,
122 boolean useAltitudeConverter)
127 gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
128 if (useAltitudeConverter)
130 }
catch (Exception e) {
133 if (fromSatelliteOnly)
137 if (!fromSatelliteOnly) {
139 network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
140 if (useAltitudeConverter)
142 }
catch(Exception e) {
148 if (gps !=
null &&
network !=
null) {
151 long delta =
network.getTime() - gps.getTime();
152 if (delta < 4*60*60*1000) {
157 }
else if (gps !=
null ) {
167 static private boolean expectedProvidersAvailable(
int desiredProviders)
169 List<String> enabledProviders = locationManager.getProviders(
true);
170 if ((desiredProviders & QT_GPS_PROVIDER) > 0) {
171 if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
175 if ((desiredProviders & QT_NETWORK_PROVIDER) > 0) {
176 if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
185 static private void addActiveListener(QtPositioning listener,
String provider,
long minTime,
float minDistance)
187 int androidClassKey = listener.nativeClassReference;
189 listener.setActiveLooper(
true);
191 if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) {
192 removeActiveListener(androidClassKey);
195 locationManager.requestLocationUpdates(provider,
196 minTime, minDistance,
200 runningListeners.put(androidClassKey, listener);
204 static private void removeActiveListener(QtPositioning listener)
206 removeActiveListener(listener.nativeClassReference);
210 static private void removeActiveListener(
int androidClassKey)
212 QtPositioning listener = runningListeners.remove(androidClassKey);
214 if (listener !=
null) {
215 locationManager.removeUpdates(listener);
216 listener.setActiveLooper(
false);
221 static int startUpdates(
int androidClassKey,
int locationProvider,
int updateInterval,
222 boolean useAltitudeConverter)
224 synchronized (m_syncObject) {
226 boolean providerStarted =
false;
227 SecurityException lastException =
null;
228 QtPositioning positioningListener =
new QtPositioning();
229 positioningListener.nativeClassReference = androidClassKey;
230 positioningListener.expectedProviders = locationProvider;
231 positioningListener.isSatelliteUpdate =
false;
232 positioningListener.useAltitudeConverter = useAltitudeConverter;
234 if (updateInterval == 0)
237 positioningListener.updateIntervalTime = updateInterval;
238 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
239 Log.d(
TAG,
"Regular updates using GPS " + updateInterval);
241 addActiveListener(positioningListener,
242 LocationManager.GPS_PROVIDER,
244 providerStarted =
true;
245 }
catch (SecurityException se) {
250 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
251 Log.d(
TAG,
"Regular updates using network " + updateInterval);
253 addActiveListener(positioningListener,
254 LocationManager.NETWORK_PROVIDER,
256 providerStarted =
true;
257 }
catch (SecurityException se) {
264 if (!providerStarted && lastException !=
null) {
265 lastException.printStackTrace();
266 removeActiveListener(positioningListener);
267 return QT_ACCESS_ERROR;
270 if (!expectedProvidersAvailable(locationProvider)) {
272 return QT_CLOSED_ERROR;
275 }
catch(Exception e) {
277 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
280 return QT_POSITION_NO_ERROR;
284 static void stopUpdates(
int androidClassKey)
286 synchronized (m_syncObject) {
288 Log.d(
TAG,
"Stopping updates");
289 removeActiveListener(androidClassKey);
290 }
catch(Exception e) {
297 static int requestUpdate(
int androidClassKey,
int locationProvider,
int timeout,
298 boolean useAltitudeConverter)
300 synchronized (m_syncObject) {
302 boolean providerStarted =
false;
303 SecurityException lastException =
null;
304 QtPositioning positioningListener =
new QtPositioning();
305 positioningListener.nativeClassReference = androidClassKey;
306 positioningListener.isSingleUpdate =
true;
307 positioningListener.expectedProviders = locationProvider;
308 positioningListener.isSatelliteUpdate =
false;
309 positioningListener.useAltitudeConverter = useAltitudeConverter;
311 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
312 Log.d(
TAG,
"Single update using GPS");
314 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
316 providerStarted =
true;
317 }
catch (SecurityException se) {
322 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
323 Log.d(
TAG,
"Single update using network");
325 addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER,
327 providerStarted =
true;
328 }
catch (SecurityException se) {
335 if (!providerStarted && lastException !=
null) {
336 lastException.printStackTrace();
337 removeActiveListener(positioningListener);
338 return QT_ACCESS_ERROR;
341 if (!expectedProvidersAvailable(locationProvider)) {
344 return QT_CLOSED_ERROR;
347 }
catch(Exception e) {
349 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
352 return QT_POSITION_NO_ERROR;
356 static int startSatelliteUpdates(
int androidClassKey,
int updateInterval,
boolean isSingleRequest)
358 synchronized (m_syncObject) {
360 boolean exceptionOccurred =
false;
361 QtPositioning positioningListener =
new QtPositioning();
362 positioningListener.isSatelliteUpdate =
true;
363 positioningListener.nativeClassReference = androidClassKey;
364 positioningListener.expectedProviders = 1;
365 positioningListener.isSingleUpdate = isSingleRequest;
367 if (updateInterval == 0)
371 Log.d(
TAG,
"Single update for Satellites " + updateInterval);
373 Log.d(
TAG,
"Regular updates for Satellites " + updateInterval);
375 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
377 }
catch (SecurityException se) {
378 se.printStackTrace();
379 exceptionOccurred =
true;
382 if (exceptionOccurred) {
383 removeActiveListener(positioningListener);
384 return QT_ACCESS_ERROR;
387 if (!expectedProvidersAvailable(positioningListener.expectedProviders)) {
390 return QT_CLOSED_ERROR;
393 }
catch(Exception e) {
395 return QT_SATELLITE_UNKNOWN_SOURCE_ERROR;
398 return QT_SATELLITE_NO_ERROR;
404 looperThread =
new PositioningLooperGnss();
409 return looperThread.looper();
412 private void setActiveLooper(
boolean setActive)
416 if (looperThread.isAlive())
419 if (isSatelliteUpdate)
420 looperThread.isSatelliteListener(
true);
422 long start = System.currentTimeMillis();
423 looperThread.start();
426 while (!looperThread.isReady());
428 long stop = System.currentTimeMillis();
429 Log.d(
TAG,
"Looper Thread startup time in ms: " + (stop-
start));
431 looperThread.quitLooper();
433 }
catch(Exception e) {
438 private class PositioningGnssListener
extends GnssStatus.
Callback
441 public void onSatelliteStatusChanged(GnssStatus status)
447 private class PositioningLooperGnss
extends Thread
449 private boolean looperRunning;
450 private Looper posLooper;
451 private boolean isSatelliteLooper =
false;
452 private PositioningGnssListener gnssListener;
454 private PositioningLooperGnss()
456 looperRunning =
false;
457 gnssListener =
new PositioningGnssListener();
465 if (isSatelliteLooper)
466 addSatelliteInfoListener();
468 posLooper = Looper.myLooper();
469 synchronized (
this) {
470 looperRunning =
true;
473 synchronized (
this) {
474 looperRunning =
false;
480 if (isSatelliteLooper)
481 removeSatelliteInfoListener();
485 synchronized boolean isReady()
487 return looperRunning;
490 void isSatelliteListener(
boolean isListener)
492 isSatelliteLooper = isListener;
500 private void addSatelliteInfoListener()
503 locationManager.registerGnssStatusCallback(gnssListener,
null);
504 }
catch(Exception e) {
509 private void removeSatelliteInfoListener()
511 locationManager.unregisterGnssStatusCallback(gnssListener);
518 static native
void satelliteGnssUpdated(GnssStatus update,
int androidClassKey,
boolean isSingleUpdate);
526 if (useAltitudeConverter)
529 if (isSatelliteUpdate)
532 if (isSingleUpdate || expectedProviders < 3) {
543 if (
location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
548 }
else if (
location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
551 if (lastGps ==
null) {
556 long delta =
location.getTime() - lastGps.getTime();
560 if (delta < updateIntervalTime)
570 @SuppressWarnings(
"deprecation")
575 public void onProviderEnabled(
String provider) {
576 Log.d(
TAG,
"Enabled provider: " + provider);
578 if (isLocationProvidersDisabledInvoked && expectedProvidersAvailable(expectedProviders))
579 isLocationProvidersDisabledInvoked =
false;
583 public void onProviderDisabled(
String provider) {
584 Log.d(
TAG,
"Disabled provider: " + provider);
586 if (!isLocationProvidersDisabledInvoked && !expectedProvidersAvailable(expectedProviders)) {
587 isLocationProvidersDisabledInvoked =
true;
The Location class provides a way to mark a location in a file.
static const QString context()
static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location, jint androidClassKey, jboolean isSingleUpdate)
static void satelliteGnssUpdated(JNIEnv *env, jobject thiz, QtJniTypes::GnssStatus gnssStatus, jint androidClassKey, jboolean isSingleUpdate)
static void locationProvidersChanged(JNIEnv *env, jobject thiz, jint androidClassKey)
static void locationProvidersDisabled(JNIEnv *env, jobject thiz, jint androidClassKey)
QMap< Name, StatePointer > Bundle
[vector_of_multirole_objects_0]
GLbitfield GLuint64 timeout
QT_BEGIN_NAMESPACE typedef void(* Callback)(QQmlNotifierEndpoint *, void **)