29 private static final String TAG =
"qt.positioning.android";
30 static LocationManager locationManager =
null;
32 static HashMap<Integer, QtPositioning> runningListeners =
new HashMap<Integer, QtPositioning>();
38 private int nativeClassReference = 0;
43 private int expectedProviders = 0;
57 private boolean isSingleUpdate =
false;
59 private int updateIntervalTime = 0;
62 private Location lastGps =
null;
64 private Location lastNetwork =
null;
66 private boolean isSatelliteUpdate =
false;
68 private boolean useAltitudeConverter =
false;
70 private PositioningLooperBase looperThread;
72 private boolean isLocationProvidersDisabledInvoked =
false;
74 private static Context appContext =
null;
75 private static AltitudeConverter altitudeConverter =
null;
81 locationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
82 }
catch(Exception e) {
87 static private int[] providerList()
89 if (locationManager ==
null) {
90 Log.w(TAG,
"No locationManager available in QtPositioning");
93 List<String> providers = locationManager.getProviders(
true);
94 int retList[] =
new int[providers.size()];
95 for (
int i = 0;
i < providers.size();
i++) {
96 if (providers.get(
i).equals(LocationManager.GPS_PROVIDER)) {
99 }
else if (providers.get(
i).equals(LocationManager.NETWORK_PROVIDER)) {
102 }
else if (providers.get(
i).equals(LocationManager.PASSIVE_PROVIDER)) {
112 static private void addMslAltitude(Location
location)
114 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) {
126 boolean useAltitudeConverter)
129 Location network =
null;
131 gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
132 if (useAltitudeConverter)
134 if (!fromSatelliteOnly) {
135 network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
136 if (useAltitudeConverter)
137 addMslAltitude(network);
139 }
catch(Exception e) {
141 gps = network =
null;
144 if (gps !=
null && network !=
null) {
147 long delta = network.getTime() - gps.getTime();
148 if (delta < 4*60*60*1000) {
153 }
else if (gps !=
null ) {
155 }
else if (network !=
null) {
163 static private boolean expectedProvidersAvailable(
int desiredProviders)
165 List<String> enabledProviders = locationManager.getProviders(
true);
167 if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
172 if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
181 static private void addActiveListener(
QtPositioning listener, String provider,
long minTime,
float minDistance)
183 int androidClassKey = listener.nativeClassReference;
185 listener.setActiveLooper(
true);
187 if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) {
188 removeActiveListener(androidClassKey);
191 locationManager.requestLocationUpdates(provider,
192 minTime, minDistance,
196 runningListeners.put(androidClassKey, listener);
200 static private void removeActiveListener(
QtPositioning listener)
202 removeActiveListener(listener.nativeClassReference);
206 static private void removeActiveListener(
int androidClassKey)
208 QtPositioning listener = runningListeners.remove(androidClassKey);
210 if (listener !=
null) {
211 locationManager.removeUpdates(listener);
212 listener.setActiveLooper(
false);
217 static public int startUpdates(
int androidClassKey,
int locationProvider,
int updateInterval,
218 boolean useAltitudeConverter)
220 synchronized (m_syncObject) {
222 boolean exceptionOccurred =
false;
224 positioningListener.nativeClassReference = androidClassKey;
225 positioningListener.expectedProviders = locationProvider;
226 positioningListener.isSatelliteUpdate =
false;
227 positioningListener.useAltitudeConverter = useAltitudeConverter;
229 if (updateInterval == 0)
232 positioningListener.updateIntervalTime = updateInterval;
234 Log.d(
TAG,
"Regular updates using GPS " + updateInterval);
236 addActiveListener(positioningListener,
237 LocationManager.GPS_PROVIDER,
239 }
catch (SecurityException se) {
240 se.printStackTrace();
241 exceptionOccurred =
true;
246 Log.d(
TAG,
"Regular updates using network " + updateInterval);
248 addActiveListener(positioningListener,
249 LocationManager.NETWORK_PROVIDER,
251 }
catch (SecurityException se) {
252 se.printStackTrace();
253 exceptionOccurred =
true;
256 if (exceptionOccurred) {
257 removeActiveListener(positioningListener);
261 if (!expectedProvidersAvailable(locationProvider)) {
266 }
catch(Exception e) {
277 synchronized (m_syncObject) {
279 Log.d(
TAG,
"Stopping updates");
280 removeActiveListener(androidClassKey);
281 }
catch(Exception e) {
289 boolean useAltitudeConverter)
291 synchronized (m_syncObject) {
293 boolean exceptionOccurred =
false;
295 positioningListener.nativeClassReference = androidClassKey;
296 positioningListener.isSingleUpdate =
true;
297 positioningListener.expectedProviders = locationProvider;
298 positioningListener.isSatelliteUpdate =
false;
299 positioningListener.useAltitudeConverter = useAltitudeConverter;
302 Log.d(
TAG,
"Single update using GPS");
304 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
306 }
catch (SecurityException se) {
307 se.printStackTrace();
308 exceptionOccurred =
true;
313 Log.d(
TAG,
"Single update using network");
315 addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER,
317 }
catch (SecurityException se) {
318 se.printStackTrace();
319 exceptionOccurred =
true;
322 if (exceptionOccurred) {
323 removeActiveListener(positioningListener);
327 if (!expectedProvidersAvailable(locationProvider)) {
333 }
catch(Exception e) {
344 synchronized (m_syncObject) {
346 boolean exceptionOccurred =
false;
348 positioningListener.isSatelliteUpdate =
true;
349 positioningListener.nativeClassReference = androidClassKey;
350 positioningListener.expectedProviders = 1;
351 positioningListener.isSingleUpdate = isSingleRequest;
353 if (updateInterval == 0)
357 Log.d(
TAG,
"Single update for Satellites " + updateInterval);
359 Log.d(
TAG,
"Regular updates for Satellites " + updateInterval);
361 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
363 }
catch (SecurityException se) {
364 se.printStackTrace();
365 exceptionOccurred =
true;
368 if (exceptionOccurred) {
369 removeActiveListener(positioningListener);
373 if (!expectedProvidersAvailable(positioningListener.expectedProviders)) {
379 }
catch(Exception e) {
392 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M)
393 looperThread =
new PositioningLooperGps();
395 looperThread =
new PositioningLooperGnss();
400 return looperThread.looper();
403 private void setActiveLooper(
boolean setActive)
407 if (looperThread.isAlive())
410 if (isSatelliteUpdate)
411 looperThread.isSatelliteListener(
true);
413 long start = System.currentTimeMillis();
414 looperThread.start();
417 while (!looperThread.isReady());
419 long stop = System.currentTimeMillis();
420 Log.d(TAG,
"Looper Thread startup time in ms: " + (stop-
start));
422 looperThread.quitLooper();
424 }
catch(Exception e) {
429 private abstract class PositioningLooperBase
extends Thread
431 private boolean looperRunning;
432 private Looper posLooper;
433 private boolean isSatelliteLooper =
false;
435 abstract protected void addSatelliteInfoListener();
436 abstract protected void removeSatelliteInfoListener();
438 private PositioningLooperBase()
440 looperRunning =
false;
446 Handler handler =
new Handler();
448 if (isSatelliteLooper)
449 addSatelliteInfoListener();
451 posLooper = Looper.myLooper();
452 synchronized (
this) {
453 looperRunning =
true;
456 synchronized (
this) {
457 looperRunning =
false;
461 public void quitLooper()
463 if (isSatelliteLooper)
464 removeSatelliteInfoListener();
468 public synchronized boolean isReady()
470 return looperRunning;
473 public void isSatelliteListener(
boolean isListener)
475 isSatelliteLooper = isListener;
478 public Looper looper()
485 private class PositioningLooperGps
extends PositioningLooperBase implements GpsStatus.Listener
488 protected void addSatelliteInfoListener()
491 locationManager.addGpsStatusListener(
this);
492 }
catch(Exception e) {
498 protected void removeSatelliteInfoListener()
500 locationManager.removeGpsStatusListener(
this);
504 public void onGpsStatusChanged(
int event) {
506 case GpsStatus.GPS_EVENT_FIRST_FIX:
508 case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
509 GpsStatus status = locationManager.getGpsStatus(
null);
510 Iterable<GpsSatellite> iterable = status.getSatellites();
511 Iterator<GpsSatellite>
it = iterable.
iterator();
513 ArrayList<GpsSatellite>
list =
new ArrayList<GpsSatellite>();
514 while (
it.hasNext()) {
515 GpsSatellite sat = (GpsSatellite)
it.next();
518 GpsSatellite[] sats =
list.toArray(
new GpsSatellite[
list.
size()]);
522 case GpsStatus.GPS_EVENT_STARTED:
524 case GpsStatus.GPS_EVENT_STOPPED:
530 private class PositioningGnssListener
extends GnssStatus.Callback
533 public void onSatelliteStatusChanged(GnssStatus status)
539 private class PositioningLooperGnss
extends PositioningLooperBase
541 private PositioningGnssListener gnssListener;
543 private PositioningLooperGnss()
545 gnssListener =
new PositioningGnssListener();
549 protected void addSatelliteInfoListener()
552 locationManager.registerGnssStatusCallback(gnssListener);
553 }
catch(Exception e) {
559 protected void removeSatelliteInfoListener()
561 locationManager.unregisterGnssStatusCallback(gnssListener);
565 public static native
void positionUpdated(Location update,
int androidClassKey,
boolean isSingleUpdate);
569 public static native
void satelliteGnssUpdated(GnssStatus update,
int androidClassKey,
boolean isSingleUpdate);
577 if (useAltitudeConverter)
580 if (isSatelliteUpdate)
583 if (isSingleUpdate || expectedProviders < 3) {
594 if (
location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
599 }
else if (
location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
602 if (lastGps ==
null) {
607 long delta =
location.getTime() - lastGps.getTime();
611 if (delta < updateIntervalTime)
624 Log.d(
TAG,
"Enabled provider: " + provider);
626 if (isLocationProvidersDisabledInvoked && expectedProvidersAvailable(expectedProviders))
627 isLocationProvidersDisabledInvoked =
false;
632 Log.d(
TAG,
"Disabled provider: " + provider);
634 if (!isLocationProvidersDisabledInvoked && !expectedProvidersAvailable(expectedProviders)) {
635 isLocationProvidersDisabledInvoked =
true;