4package org.qtproject.qt.android.positioning;
7import android.location.altitude.AltitudeConverter;
9import android.location.LocationListener;
10import android.location.LocationManager;
11import android.location.GnssStatus;
12import android.location.GnssStatus.Callback;
17import java.util.ArrayList;
18import java.util.HashMap;
19import java.util.Iterator;
24class QtPositioning
implements LocationListener
27 private static final String TAG =
"qt.positioning.android";
28 static LocationManager locationManager =
null;
30 static HashMap<Integer, QtPositioning> runningListeners =
new HashMap<Integer, QtPositioning>();
36 private int nativeClassReference = 0;
41 private int expectedProviders = 0;
43 static final int QT_GPS_PROVIDER = 1;
44 static final int QT_NETWORK_PROVIDER = 2;
47 static final int QT_ACCESS_ERROR = 0;
48 static final int QT_CLOSED_ERROR = 1;
49 static final int QT_POSITION_UNKNOWN_SOURCE_ERROR = 2;
50 static final int QT_POSITION_NO_ERROR = 3;
51 static final int QT_SATELLITE_NO_ERROR = 2;
52 static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR = -1;
55 private boolean isSingleUpdate =
false;
57 private int updateIntervalTime = 0;
64 private boolean isSatelliteUpdate =
false;
66 private boolean useAltitudeConverter =
false;
68 private PositioningLooperGnss looperThread;
70 private boolean isLocationProvidersDisabledInvoked =
false;
72 private static Context appContext =
null;
73 private static AltitudeConverter altitudeConverter =
null;
79 locationManager = (LocationManager)
context.getSystemService(
Context.LOCATION_SERVICE);
80 }
catch(Exception e) {
85 static private int[] providerList()
87 if (locationManager ==
null) {
88 Log.w(
TAG,
"No locationManager available in QtPositioning");
91 List<String> providers = locationManager.getProviders(
true);
92 int retList[] =
new int[providers.size()];
93 for (
int i = 0; i < providers.size(); i++) {
94 if (providers.get(i).equals(LocationManager.GPS_PROVIDER)) {
97 }
else if (providers.get(i).equals(LocationManager.NETWORK_PROVIDER)) {
100 }
else if (providers.get(i).equals(LocationManager.PASSIVE_PROVIDER)) {
112 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
115 if (altitudeConverter ==
null)
116 altitudeConverter =
new AltitudeConverter();
118 altitudeConverter.addMslAltitudeToLocation(appContext,
location);
119 }
catch (Exception e) {
125 static Location lastKnownPosition(
boolean fromSatelliteOnly,
126 boolean useAltitudeConverter)
131 gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
132 if (useAltitudeConverter)
134 }
catch (Exception e) {
137 if (fromSatelliteOnly)
141 if (!fromSatelliteOnly) {
143 network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
144 if (useAltitudeConverter)
146 }
catch(Exception e) {
152 if (gps !=
null &&
network !=
null) {
155 long delta =
network.getTime() - gps.getTime();
156 if (delta < 4*60*60*1000) {
161 }
else if (gps !=
null ) {
171 static private boolean expectedProvidersAvailable(
int desiredProviders)
173 List<String> enabledProviders = locationManager.getProviders(
true);
174 if ((desiredProviders & QT_GPS_PROVIDER) > 0) {
175 if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
179 if ((desiredProviders & QT_NETWORK_PROVIDER) > 0) {
180 if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
189 static private void addActiveListener(QtPositioning listener,
String provider,
long minTime,
float minDistance)
191 int androidClassKey = listener.nativeClassReference;
193 listener.setActiveLooper(
true);
195 if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) {
196 removeActiveListener(androidClassKey);
199 locationManager.requestLocationUpdates(provider,
200 minTime, minDistance,
204 runningListeners.put(androidClassKey, listener);
208 static private void removeActiveListener(QtPositioning listener)
210 removeActiveListener(listener.nativeClassReference);
214 static private void removeActiveListener(
int androidClassKey)
216 QtPositioning listener = runningListeners.remove(androidClassKey);
218 if (listener !=
null) {
219 locationManager.removeUpdates(listener);
220 listener.setActiveLooper(
false);
225 static int startUpdates(
int androidClassKey,
int locationProvider,
int updateInterval,
226 boolean useAltitudeConverter)
228 synchronized (m_syncObject) {
230 boolean providerStarted =
false;
231 SecurityException lastException =
null;
232 QtPositioning positioningListener =
new QtPositioning();
233 positioningListener.nativeClassReference = androidClassKey;
234 positioningListener.expectedProviders = locationProvider;
235 positioningListener.isSatelliteUpdate =
false;
236 positioningListener.useAltitudeConverter = useAltitudeConverter;
238 if (updateInterval == 0)
241 positioningListener.updateIntervalTime = updateInterval;
242 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
243 Log.d(
TAG,
"Regular updates using GPS " + updateInterval);
245 addActiveListener(positioningListener,
246 LocationManager.GPS_PROVIDER,
248 providerStarted =
true;
249 }
catch (SecurityException se) {
254 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
255 Log.d(
TAG,
"Regular updates using network " + updateInterval);
257 addActiveListener(positioningListener,
258 LocationManager.NETWORK_PROVIDER,
260 providerStarted =
true;
261 }
catch (SecurityException se) {
268 if (!providerStarted && lastException !=
null) {
269 lastException.printStackTrace();
270 removeActiveListener(positioningListener);
271 return QT_ACCESS_ERROR;
274 if (!expectedProvidersAvailable(locationProvider)) {
276 return QT_CLOSED_ERROR;
279 }
catch(Exception e) {
281 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
284 return QT_POSITION_NO_ERROR;
288 static void stopUpdates(
int androidClassKey)
290 synchronized (m_syncObject) {
292 Log.d(
TAG,
"Stopping updates");
293 removeActiveListener(androidClassKey);
294 }
catch(Exception e) {
301 static int requestUpdate(
int androidClassKey,
int locationProvider,
int timeout,
302 boolean useAltitudeConverter)
304 synchronized (m_syncObject) {
306 boolean providerStarted =
false;
307 SecurityException lastException =
null;
308 QtPositioning positioningListener =
new QtPositioning();
309 positioningListener.nativeClassReference = androidClassKey;
310 positioningListener.isSingleUpdate =
true;
311 positioningListener.expectedProviders = locationProvider;
312 positioningListener.isSatelliteUpdate =
false;
313 positioningListener.useAltitudeConverter = useAltitudeConverter;
315 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
316 Log.d(
TAG,
"Single update using GPS");
318 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
320 providerStarted =
true;
321 }
catch (SecurityException se) {
326 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
327 Log.d(
TAG,
"Single update using network");
329 addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER,
331 providerStarted =
true;
332 }
catch (SecurityException se) {
339 if (!providerStarted && lastException !=
null) {
340 lastException.printStackTrace();
341 removeActiveListener(positioningListener);
342 return QT_ACCESS_ERROR;
345 if (!expectedProvidersAvailable(locationProvider)) {
348 return QT_CLOSED_ERROR;
351 }
catch(Exception e) {
353 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
356 return QT_POSITION_NO_ERROR;
360 static int startSatelliteUpdates(
int androidClassKey,
int updateInterval,
boolean isSingleRequest)
362 synchronized (m_syncObject) {
364 boolean exceptionOccurred =
false;
365 QtPositioning positioningListener =
new QtPositioning();
366 positioningListener.isSatelliteUpdate =
true;
367 positioningListener.nativeClassReference = androidClassKey;
368 positioningListener.expectedProviders = 1;
369 positioningListener.isSingleUpdate = isSingleRequest;
371 if (updateInterval == 0)
375 Log.d(
TAG,
"Single update for Satellites " + updateInterval);
377 Log.d(
TAG,
"Regular updates for Satellites " + updateInterval);
379 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
381 }
catch (SecurityException se) {
382 se.printStackTrace();
383 exceptionOccurred =
true;
386 if (exceptionOccurred) {
387 removeActiveListener(positioningListener);
388 return QT_ACCESS_ERROR;
391 if (!expectedProvidersAvailable(positioningListener.expectedProviders)) {
394 return QT_CLOSED_ERROR;
397 }
catch(Exception e) {
399 return QT_SATELLITE_UNKNOWN_SOURCE_ERROR;
402 return QT_SATELLITE_NO_ERROR;
408 looperThread =
new PositioningLooperGnss();
413 return looperThread.looper();
416 private void setActiveLooper(
boolean setActive)
420 if (looperThread.isAlive())
423 if (isSatelliteUpdate)
424 looperThread.isSatelliteListener(
true);
426 long start = System.currentTimeMillis();
427 looperThread.start();
430 while (!looperThread.isReady());
432 long stop = System.currentTimeMillis();
433 Log.d(
TAG,
"Looper Thread startup time in ms: " + (stop-
start));
435 looperThread.quitLooper();
437 }
catch(Exception e) {
442 private class PositioningGnssListener
extends GnssStatus.
Callback
445 public void onSatelliteStatusChanged(GnssStatus status)
451 private class PositioningLooperGnss
extends Thread
453 private boolean looperRunning;
454 private Looper posLooper;
455 private boolean isSatelliteLooper =
false;
456 private PositioningGnssListener gnssListener;
458 private PositioningLooperGnss()
460 looperRunning =
false;
461 gnssListener =
new PositioningGnssListener();
469 if (isSatelliteLooper)
470 addSatelliteInfoListener();
472 posLooper = Looper.myLooper();
473 synchronized (
this) {
474 looperRunning =
true;
477 synchronized (
this) {
478 looperRunning =
false;
484 if (isSatelliteLooper)
485 removeSatelliteInfoListener();
489 synchronized boolean isReady()
491 return looperRunning;
494 void isSatelliteListener(
boolean isListener)
496 isSatelliteLooper = isListener;
504 private void addSatelliteInfoListener()
507 locationManager.registerGnssStatusCallback(gnssListener,
null);
508 }
catch(Exception e) {
513 private void removeSatelliteInfoListener()
515 locationManager.unregisterGnssStatusCallback(gnssListener);
522 static native
void satelliteGnssUpdated(GnssStatus update,
int androidClassKey,
boolean isSingleUpdate);
530 if (useAltitudeConverter)
533 if (isSatelliteUpdate)
536 if (isSingleUpdate || expectedProviders < 3) {
547 if (
location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
552 }
else if (
location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
555 if (lastGps ==
null) {
560 long delta =
location.getTime() - lastGps.getTime();
564 if (delta < updateIntervalTime)
574 @SuppressWarnings(
"deprecation")
579 public void onProviderEnabled(
String provider) {
580 Log.d(
TAG,
"Enabled provider: " + provider);
582 if (isLocationProvidersDisabledInvoked && expectedProvidersAvailable(expectedProviders))
583 isLocationProvidersDisabledInvoked =
false;
587 public void onProviderDisabled(
String provider) {
588 Log.d(
TAG,
"Disabled provider: " + provider);
590 if (!isLocationProvidersDisabledInvoked && !expectedProvidersAvailable(expectedProviders)) {
591 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 **)