4package org.qtproject.qt.android.positioning;
7import android.location.altitude.AltitudeConverter;
8import android.location.GpsSatellite;
9import android.location.GpsStatus;
10import android.location.Location;
11import android.location.LocationListener;
12import android.location.LocationManager;
13import android.location.GnssStatus;
14import android.location.GnssStatus.Callback;
19import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.Iterator;
26class QtPositioning
implements LocationListener
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;
45 static final int QT_GPS_PROVIDER = 1;
46 static final int QT_NETWORK_PROVIDER = 2;
49 static final int QT_ACCESS_ERROR = 0;
50 static final int QT_CLOSED_ERROR = 1;
51 static final int QT_POSITION_UNKNOWN_SOURCE_ERROR = 2;
52 static final int QT_POSITION_NO_ERROR = 3;
53 static final int QT_SATELLITE_NO_ERROR = 2;
54 static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR = -1;
57 private boolean isSingleUpdate =
false;
59 private int updateIntervalTime = 0;
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)) {
114 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
117 if (altitudeConverter ==
null)
118 altitudeConverter =
new AltitudeConverter();
120 altitudeConverter.addMslAltitudeToLocation(appContext,
location);
121 }
catch (Exception e) {
127 static Location lastKnownPosition(
boolean fromSatelliteOnly,
128 boolean useAltitudeConverter)
133 gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
134 if (useAltitudeConverter)
136 }
catch (Exception e) {
139 if (fromSatelliteOnly)
143 if (!fromSatelliteOnly) {
145 network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
146 if (useAltitudeConverter)
148 }
catch(Exception e) {
154 if (gps !=
null &&
network !=
null) {
157 long delta =
network.getTime() - gps.getTime();
158 if (delta < 4*60*60*1000) {
163 }
else if (gps !=
null ) {
173 static private boolean expectedProvidersAvailable(
int desiredProviders)
175 List<String> enabledProviders = locationManager.getProviders(
true);
176 if ((desiredProviders & QT_GPS_PROVIDER) > 0) {
177 if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
181 if ((desiredProviders & QT_NETWORK_PROVIDER) > 0) {
182 if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
191 static private void addActiveListener(QtPositioning listener,
String provider,
long minTime,
float minDistance)
193 int androidClassKey = listener.nativeClassReference;
195 listener.setActiveLooper(
true);
197 if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) {
198 removeActiveListener(androidClassKey);
201 locationManager.requestLocationUpdates(provider,
202 minTime, minDistance,
206 runningListeners.put(androidClassKey, listener);
210 static private void removeActiveListener(QtPositioning listener)
212 removeActiveListener(listener.nativeClassReference);
216 static private void removeActiveListener(
int androidClassKey)
218 QtPositioning listener = runningListeners.remove(androidClassKey);
220 if (listener !=
null) {
221 locationManager.removeUpdates(listener);
222 listener.setActiveLooper(
false);
227 static int startUpdates(
int androidClassKey,
int locationProvider,
int updateInterval,
228 boolean useAltitudeConverter)
230 synchronized (m_syncObject) {
232 boolean providerStarted =
false;
233 SecurityException lastException =
null;
234 QtPositioning positioningListener =
new QtPositioning();
235 positioningListener.nativeClassReference = androidClassKey;
236 positioningListener.expectedProviders = locationProvider;
237 positioningListener.isSatelliteUpdate =
false;
238 positioningListener.useAltitudeConverter = useAltitudeConverter;
240 if (updateInterval == 0)
243 positioningListener.updateIntervalTime = updateInterval;
244 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
245 Log.d(
TAG,
"Regular updates using GPS " + updateInterval);
247 addActiveListener(positioningListener,
248 LocationManager.GPS_PROVIDER,
250 providerStarted =
true;
251 }
catch (SecurityException se) {
256 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
257 Log.d(
TAG,
"Regular updates using network " + updateInterval);
259 addActiveListener(positioningListener,
260 LocationManager.NETWORK_PROVIDER,
262 providerStarted =
true;
263 }
catch (SecurityException se) {
270 if (!providerStarted && lastException !=
null) {
271 lastException.printStackTrace();
272 removeActiveListener(positioningListener);
273 return QT_ACCESS_ERROR;
276 if (!expectedProvidersAvailable(locationProvider)) {
278 return QT_CLOSED_ERROR;
281 }
catch(Exception e) {
283 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
286 return QT_POSITION_NO_ERROR;
290 static void stopUpdates(
int androidClassKey)
292 synchronized (m_syncObject) {
294 Log.d(
TAG,
"Stopping updates");
295 removeActiveListener(androidClassKey);
296 }
catch(Exception e) {
303 static int requestUpdate(
int androidClassKey,
int locationProvider,
int timeout,
304 boolean useAltitudeConverter)
306 synchronized (m_syncObject) {
308 boolean providerStarted =
false;
309 SecurityException lastException =
null;
310 QtPositioning positioningListener =
new QtPositioning();
311 positioningListener.nativeClassReference = androidClassKey;
312 positioningListener.isSingleUpdate =
true;
313 positioningListener.expectedProviders = locationProvider;
314 positioningListener.isSatelliteUpdate =
false;
315 positioningListener.useAltitudeConverter = useAltitudeConverter;
317 if ((locationProvider & QT_GPS_PROVIDER) > 0) {
318 Log.d(
TAG,
"Single update using GPS");
320 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
322 providerStarted =
true;
323 }
catch (SecurityException se) {
328 if ((locationProvider & QT_NETWORK_PROVIDER) > 0) {
329 Log.d(
TAG,
"Single update using network");
331 addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER,
333 providerStarted =
true;
334 }
catch (SecurityException se) {
341 if (!providerStarted && lastException !=
null) {
342 lastException.printStackTrace();
343 removeActiveListener(positioningListener);
344 return QT_ACCESS_ERROR;
347 if (!expectedProvidersAvailable(locationProvider)) {
350 return QT_CLOSED_ERROR;
353 }
catch(Exception e) {
355 return QT_POSITION_UNKNOWN_SOURCE_ERROR;
358 return QT_POSITION_NO_ERROR;
362 static int startSatelliteUpdates(
int androidClassKey,
int updateInterval,
boolean isSingleRequest)
364 synchronized (m_syncObject) {
366 boolean exceptionOccurred =
false;
367 QtPositioning positioningListener =
new QtPositioning();
368 positioningListener.isSatelliteUpdate =
true;
369 positioningListener.nativeClassReference = androidClassKey;
370 positioningListener.expectedProviders = 1;
371 positioningListener.isSingleUpdate = isSingleRequest;
373 if (updateInterval == 0)
377 Log.d(
TAG,
"Single update for Satellites " + updateInterval);
379 Log.d(
TAG,
"Regular updates for Satellites " + updateInterval);
381 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
383 }
catch (SecurityException se) {
384 se.printStackTrace();
385 exceptionOccurred =
true;
388 if (exceptionOccurred) {
389 removeActiveListener(positioningListener);
390 return QT_ACCESS_ERROR;
393 if (!expectedProvidersAvailable(positioningListener.expectedProviders)) {
396 return QT_CLOSED_ERROR;
399 }
catch(Exception e) {
401 return QT_SATELLITE_UNKNOWN_SOURCE_ERROR;
404 return QT_SATELLITE_NO_ERROR;
412 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M)
413 looperThread =
new PositioningLooperGps();
415 looperThread =
new PositioningLooperGnss();
420 return looperThread.looper();
423 private void setActiveLooper(
boolean setActive)
427 if (looperThread.isAlive())
430 if (isSatelliteUpdate)
431 looperThread.isSatelliteListener(
true);
433 long start = System.currentTimeMillis();
434 looperThread.start();
437 while (!looperThread.isReady());
439 long stop = System.currentTimeMillis();
440 Log.d(
TAG,
"Looper Thread startup time in ms: " + (stop-
start));
442 looperThread.quitLooper();
444 }
catch(Exception e) {
449 private abstract class PositioningLooperBase
extends Thread
451 private boolean looperRunning;
452 private Looper posLooper;
453 private boolean isSatelliteLooper =
false;
455 abstract protected void addSatelliteInfoListener();
456 abstract protected void removeSatelliteInfoListener();
458 private PositioningLooperBase()
460 looperRunning =
false;
468 if (isSatelliteLooper)
469 addSatelliteInfoListener();
471 posLooper = Looper.myLooper();
472 synchronized (
this) {
473 looperRunning =
true;
476 synchronized (
this) {
477 looperRunning =
false;
483 if (isSatelliteLooper)
484 removeSatelliteInfoListener();
488 synchronized boolean isReady()
490 return looperRunning;
493 void isSatelliteListener(
boolean isListener)
495 isSatelliteLooper = isListener;
505 private class PositioningLooperGps
extends PositioningLooperBase implements GpsStatus.Listener
508 protected void addSatelliteInfoListener()
511 locationManager.addGpsStatusListener(
this);
512 }
catch(Exception e) {
518 protected void removeSatelliteInfoListener()
520 locationManager.removeGpsStatusListener(
this);
524 public void onGpsStatusChanged(
int event) {
526 case GpsStatus.GPS_EVENT_FIRST_FIX:
528 case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
529 GpsStatus status = locationManager.getGpsStatus(
null);
530 Iterable<GpsSatellite> iterable = status.getSatellites();
533 ArrayList<GpsSatellite>
list =
new ArrayList<GpsSatellite>();
534 while (
it.hasNext()) {
535 GpsSatellite sat =
it.next();
538 GpsSatellite[] sats =
list.toArray(
new GpsSatellite[
list.size()]);
542 case GpsStatus.GPS_EVENT_STARTED:
544 case GpsStatus.GPS_EVENT_STOPPED:
550 private class PositioningGnssListener
extends GnssStatus.
Callback
553 public void onSatelliteStatusChanged(GnssStatus status)
559 private class PositioningLooperGnss
extends PositioningLooperBase
561 private PositioningGnssListener gnssListener;
563 private PositioningLooperGnss()
565 gnssListener =
new PositioningGnssListener();
569 protected void addSatelliteInfoListener()
572 locationManager.registerGnssStatusCallback(gnssListener);
573 }
catch(Exception e) {
579 protected void removeSatelliteInfoListener()
581 locationManager.unregisterGnssStatusCallback(gnssListener);
589 static native
void satelliteGnssUpdated(GnssStatus update,
int androidClassKey,
boolean isSingleUpdate);
597 if (useAltitudeConverter)
600 if (isSatelliteUpdate)
603 if (isSingleUpdate || expectedProviders < 3) {
614 if (
location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
619 }
else if (
location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
622 if (lastGps ==
null) {
627 long delta =
location.getTime() - lastGps.getTime();
631 if (delta < updateIntervalTime)
643 public void onProviderEnabled(
String provider) {
644 Log.d(
TAG,
"Enabled provider: " + provider);
646 if (isLocationProvidersDisabledInvoked && expectedProvidersAvailable(expectedProviders))
647 isLocationProvidersDisabledInvoked =
false;
651 public void onProviderDisabled(
String provider) {
652 Log.d(
TAG,
"Disabled provider: " + provider);
654 if (!isLocationProvidersDisabledInvoked && !expectedProvidersAvailable(expectedProviders)) {
655 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 satelliteGpsUpdated(JNIEnv *env, jobject thiz, jobjectArray satellites, 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 **)
QJSValueIterator it(object)