4package org.qtproject.qt.android.positioning;
6import android.content.Context;
7import android.location.GpsSatellite;
8import android.location.GpsStatus;
9import android.location.Location;
10import android.location.LocationListener;
11import android.location.LocationManager;
12import android.location.GnssStatus;
13import android.location.GnssStatus.Callback;
14import android.os.Bundle;
15import android.os.Handler;
16import android.os.Looper;
17import android.os.Build;
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.Iterator;
23import android.util.Log;
28 private static final String TAG =
"qt.positioning.android";
29 static LocationManager locationManager =
null;
31 static HashMap<Integer, QtPositioning> runningListeners =
new HashMap<Integer, QtPositioning>();
37 private int nativeClassReference = 0;
42 private int expectedProviders = 0;
56 private boolean isSingleUpdate =
false;
58 private int updateIntervalTime = 0;
61 private Location lastGps =
null;
63 private Location lastNetwork =
null;
65 private boolean isSatelliteUpdate =
false;
67 private PositioningLooperBase looperThread;
69 private boolean isLocationProvidersDisabledInvoked =
false;
74 locationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
75 }
catch(Exception
e) {
80 static private int[] providerList()
82 if (locationManager ==
null) {
83 Log.w(TAG,
"No locationManager available in QtPositioning");
86 List<String> providers = locationManager.getProviders(
true);
87 int retList[] =
new int[providers.size()];
88 for (
int i = 0;
i < providers.size();
i++) {
89 if (providers.get(
i).equals(LocationManager.GPS_PROVIDER)) {
92 }
else if (providers.get(
i).equals(LocationManager.NETWORK_PROVIDER)) {
95 }
else if (providers.get(
i).equals(LocationManager.PASSIVE_PROVIDER)) {
108 Location network =
null;
110 gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
111 if (!fromSatelliteOnly)
112 network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
113 }
catch(Exception
e) {
115 gps = network =
null;
118 if (gps !=
null && network !=
null) {
121 long delta = network.getTime() - gps.getTime();
122 if (delta < 4*60*60*1000) {
127 }
else if (gps !=
null ) {
129 }
else if (network !=
null) {
137 static private boolean expectedProvidersAvailable(
int desiredProviders)
139 List<String> enabledProviders = locationManager.getProviders(
true);
141 if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
146 if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
155 static private void addActiveListener(
QtPositioning listener, String provider,
long minTime,
float minDistance)
157 int androidClassKey = listener.nativeClassReference;
159 listener.setActiveLooper(
true);
161 if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) {
162 removeActiveListener(androidClassKey);
165 locationManager.requestLocationUpdates(provider,
166 minTime, minDistance,
170 runningListeners.put(androidClassKey, listener);
174 static private void removeActiveListener(
QtPositioning listener)
176 removeActiveListener(listener.nativeClassReference);
180 static private void removeActiveListener(
int androidClassKey)
182 QtPositioning listener = runningListeners.remove(androidClassKey);
184 if (listener !=
null) {
185 locationManager.removeUpdates(listener);
186 listener.setActiveLooper(
false);
191 static public int startUpdates(
int androidClassKey,
int locationProvider,
int updateInterval)
193 synchronized (m_syncObject) {
195 boolean exceptionOccurred =
false;
197 positioningListener.nativeClassReference = androidClassKey;
198 positioningListener.expectedProviders = locationProvider;
199 positioningListener.isSatelliteUpdate =
false;
201 if (updateInterval == 0)
204 positioningListener.updateIntervalTime = updateInterval;
206 Log.d(
TAG,
"Regular updates using GPS " + updateInterval);
208 addActiveListener(positioningListener,
209 LocationManager.GPS_PROVIDER,
211 }
catch (SecurityException se) {
212 se.printStackTrace();
213 exceptionOccurred =
true;
218 Log.d(
TAG,
"Regular updates using network " + updateInterval);
220 addActiveListener(positioningListener,
221 LocationManager.NETWORK_PROVIDER,
223 }
catch (SecurityException se) {
224 se.printStackTrace();
225 exceptionOccurred =
true;
228 if (exceptionOccurred) {
229 removeActiveListener(positioningListener);
233 if (!expectedProvidersAvailable(locationProvider)) {
238 }
catch(Exception
e) {
249 synchronized (m_syncObject) {
251 Log.d(
TAG,
"Stopping updates");
252 removeActiveListener(androidClassKey);
253 }
catch(Exception
e) {
262 synchronized (m_syncObject) {
264 boolean exceptionOccurred =
false;
266 positioningListener.nativeClassReference = androidClassKey;
267 positioningListener.isSingleUpdate =
true;
268 positioningListener.expectedProviders = locationProvider;
269 positioningListener.isSatelliteUpdate =
false;
272 Log.d(
TAG,
"Single update using GPS");
274 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
276 }
catch (SecurityException se) {
277 se.printStackTrace();
278 exceptionOccurred =
true;
283 Log.d(
TAG,
"Single update using network");
285 addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER,
287 }
catch (SecurityException se) {
288 se.printStackTrace();
289 exceptionOccurred =
true;
292 if (exceptionOccurred) {
293 removeActiveListener(positioningListener);
297 if (!expectedProvidersAvailable(locationProvider)) {
303 }
catch(Exception
e) {
314 synchronized (m_syncObject) {
316 boolean exceptionOccurred =
false;
318 positioningListener.isSatelliteUpdate =
true;
319 positioningListener.nativeClassReference = androidClassKey;
320 positioningListener.expectedProviders = 1;
321 positioningListener.isSingleUpdate = isSingleRequest;
323 if (updateInterval == 0)
327 Log.d(
TAG,
"Single update for Satellites " + updateInterval);
329 Log.d(
TAG,
"Regular updates for Satellites " + updateInterval);
331 addActiveListener(positioningListener, LocationManager.GPS_PROVIDER,
333 }
catch (SecurityException se) {
334 se.printStackTrace();
335 exceptionOccurred =
true;
338 if (exceptionOccurred) {
339 removeActiveListener(positioningListener);
343 if (!expectedProvidersAvailable(positioningListener.expectedProviders)) {
349 }
catch(Exception
e) {
362 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M)
363 looperThread =
new PositioningLooperGps();
365 looperThread =
new PositioningLooperGnss();
370 return looperThread.looper();
373 private void setActiveLooper(
boolean setActive)
377 if (looperThread.isAlive())
380 if (isSatelliteUpdate)
381 looperThread.isSatelliteListener(
true);
383 long start = System.currentTimeMillis();
384 looperThread.start();
387 while (!looperThread.isReady());
389 long stop = System.currentTimeMillis();
390 Log.d(TAG,
"Looper Thread startup time in ms: " + (stop-
start));
392 looperThread.quitLooper();
394 }
catch(Exception
e) {
399 private abstract class PositioningLooperBase
extends Thread
401 private boolean looperRunning;
402 private Looper posLooper;
403 private boolean isSatelliteLooper =
false;
405 abstract protected void addSatelliteInfoListener();
406 abstract protected void removeSatelliteInfoListener();
408 private PositioningLooperBase()
410 looperRunning =
false;
416 Handler handler =
new Handler();
418 if (isSatelliteLooper)
419 addSatelliteInfoListener();
421 posLooper = Looper.myLooper();
422 synchronized (
this) {
423 looperRunning =
true;
426 synchronized (
this) {
427 looperRunning =
false;
431 public void quitLooper()
433 if (isSatelliteLooper)
434 removeSatelliteInfoListener();
438 public synchronized boolean isReady()
440 return looperRunning;
443 public void isSatelliteListener(
boolean isListener)
445 isSatelliteLooper = isListener;
448 public Looper looper()
455 private class PositioningLooperGps
extends PositioningLooperBase implements GpsStatus.Listener
458 protected void addSatelliteInfoListener()
461 locationManager.addGpsStatusListener(
this);
462 }
catch(Exception
e) {
468 protected void removeSatelliteInfoListener()
470 locationManager.removeGpsStatusListener(
this);
474 public void onGpsStatusChanged(
int event) {
476 case GpsStatus.GPS_EVENT_FIRST_FIX:
478 case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
479 GpsStatus status = locationManager.getGpsStatus(
null);
480 Iterable<GpsSatellite> iterable = status.getSatellites();
481 Iterator<GpsSatellite>
it = iterable.
iterator();
483 ArrayList<GpsSatellite>
list =
new ArrayList<GpsSatellite>();
484 while (
it.hasNext()) {
485 GpsSatellite sat = (GpsSatellite)
it.next();
488 GpsSatellite[] sats =
list.toArray(
new GpsSatellite[
list.
size()]);
492 case GpsStatus.GPS_EVENT_STARTED:
494 case GpsStatus.GPS_EVENT_STOPPED:
500 private class PositioningGnssListener
extends GnssStatus.
Callback
503 public void onSatelliteStatusChanged(GnssStatus status)
509 private class PositioningLooperGnss
extends PositioningLooperBase
511 private PositioningGnssListener gnssListener;
513 private PositioningLooperGnss()
515 gnssListener =
new PositioningGnssListener();
519 protected void addSatelliteInfoListener()
522 locationManager.registerGnssStatusCallback(gnssListener);
523 }
catch(Exception
e) {
529 protected void removeSatelliteInfoListener()
531 locationManager.unregisterGnssStatusCallback(gnssListener);
535 public static native
void positionUpdated(Location update,
int androidClassKey,
boolean isSingleUpdate);
539 public static native
void satelliteGnssUpdated(GnssStatus update,
int androidClassKey,
boolean isSingleUpdate);
547 if (isSatelliteUpdate)
550 if (isSingleUpdate || expectedProviders < 3) {
561 if (
location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
566 }
else if (
location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
569 if (lastGps ==
null) {
574 long delta =
location.getTime() - lastGps.getTime();
578 if (delta < updateIntervalTime)
591 Log.d(
TAG,
"Enabled provider: " + provider);
593 if (isLocationProvidersDisabledInvoked && expectedProvidersAvailable(expectedProviders))
594 isLocationProvidersDisabledInvoked =
false;
599 Log.d(
TAG,
"Disabled provider: " + provider);
601 if (!isLocationProvidersDisabledInvoked && !expectedProvidersAvailable(expectedProviders)) {
602 isLocationProvidersDisabledInvoked =
true;
qsizetype size() const noexcept
static final int QT_NETWORK_PROVIDER
void onProviderDisabled(String provider)
static final int QT_POSITION_NO_ERROR
static native void satelliteGpsUpdated(Object[] update, int androidClassKey, boolean isSingleUpdate)
static int requestUpdate(int androidClassKey, int locationProvider, int timeout)
static final int QT_SATELLITE_NO_ERROR
static final int QT_GPS_PROVIDER
static native void locationProvidersChanged(int androidClassKey)
static final int QT_POSITION_UNKNOWN_SOURCE_ERROR
void onProviderEnabled(String provider)
static int startUpdates(int androidClassKey, int locationProvider, int updateInterval)
void onLocationChanged(Location location)
static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR
void onStatusChanged(String provider, int status, Bundle extras)
static void stopUpdates(int androidClassKey)
static Location lastKnownPosition(boolean fromSatelliteOnly)
static int startSatelliteUpdates(int androidClassKey, int updateInterval, boolean isSingleRequest)
static final int QT_ACCESS_ERROR
static native void locationProvidersDisabled(int androidClassKey)
static void setContext(Context context)
static final int QT_CLOSED_ERROR
static native void positionUpdated(Location update, int androidClassKey, boolean isSingleUpdate)
static native void satelliteGnssUpdated(GnssStatus update, int androidClassKey, boolean isSingleUpdate)
QSet< QString >::iterator it
auto run(QThreadPool *pool, Function &&f, Args &&...args)
GLbitfield GLuint64 timeout
[4]
QT_BEGIN_NAMESPACE typedef void(* Callback)(QQmlNotifierEndpoint *, void **)