From 3aeb0bf45f605d03fa9c506ae2d06e9ec09eec9f Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 29 Sep 2020 12:00:42 +0300 Subject: QtPositioning: rename Android's package name for Qt 6 Rename Android package name org.qtproject.qt5.android to org.qtproject.qt.android to avoid inconsistency with Qt 6 name. Also, we include the major version number in the jar target. Task-number: QTBUG-86969 Task-number: QTBUG-90491 Change-Id: I89e9a709cc9379b0359aceabdabd1676a4943ffa Reviewed-by: Alex Blasche --- .../position/android/jar/AndroidManifest.xml | 2 +- src/plugins/position/android/jar/CMakeLists.txt | 6 +- src/plugins/position/android/jar/jar.pro | 4 +- .../qt/android/positioning/QtPositioning.java | 590 +++++++++++++++++++++ .../qt5/android/positioning/QtPositioning.java | 590 --------------------- .../position/android/src/jnipositioning.cpp | 2 +- src/positioning/CMakeLists.txt | 2 +- src/positioning/positioning.pro | 2 +- 8 files changed, 599 insertions(+), 599 deletions(-) create mode 100644 src/plugins/position/android/jar/src/org/qtproject/qt/android/positioning/QtPositioning.java delete mode 100644 src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java diff --git a/src/plugins/position/android/jar/AndroidManifest.xml b/src/plugins/position/android/jar/AndroidManifest.xml index 2d066dbb..2e847fd1 100644 --- a/src/plugins/position/android/jar/AndroidManifest.xml +++ b/src/plugins/position/android/jar/AndroidManifest.xml @@ -1,5 +1,5 @@ diff --git a/src/plugins/position/android/jar/CMakeLists.txt b/src/plugins/position/android/jar/CMakeLists.txt index db40330d..8eadc79c 100644 --- a/src/plugins/position/android/jar/CMakeLists.txt +++ b/src/plugins/position/android/jar/CMakeLists.txt @@ -1,16 +1,16 @@ # Generated from jar.pro. set(java_sources - src/org/qtproject/qt5/android/positioning/QtPositioning.java + src/org/qtproject/qt/android/positioning/QtPositioning.java # special case ) -qt_internal_add_jar(QtPositioning +qt_internal_add_jar(Qt${QtLocation_VERSION_MAJOR}AndroidPositioning # special case INCLUDE_JARS ${QT_ANDROID_JAR} SOURCES ${java_sources} OUTPUT_DIR "${QT_BUILD_DIR}/jar" ) -install_jar(QtPositioning +install_jar(Qt${QtLocation_VERSION_MAJOR}AndroidPositioning # special case DESTINATION jar COMPONENT Devel ) diff --git a/src/plugins/position/android/jar/jar.pro b/src/plugins/position/android/jar/jar.pro index 661f172e..fae1f855 100644 --- a/src/plugins/position/android/jar/jar.pro +++ b/src/plugins/position/android/jar/jar.pro @@ -1,4 +1,4 @@ -TARGET = QtPositioning +TARGET = Qt$${QT_MAJOR_VERSION}AndroidPositioning load(qt_build_paths) @@ -8,7 +8,7 @@ DESTDIR = $$MODULE_BASE_OUTDIR/jar JAVACLASSPATH += $$PWD/src JAVASOURCES += \ - $$PWD/src/org/qtproject/qt5/android/positioning/QtPositioning.java + $$PWD/src/org/qtproject/qt/android/positioning/QtPositioning.java # install target.path = $$[QT_INSTALL_PREFIX]/jar diff --git a/src/plugins/position/android/jar/src/org/qtproject/qt/android/positioning/QtPositioning.java b/src/plugins/position/android/jar/src/org/qtproject/qt/android/positioning/QtPositioning.java new file mode 100644 index 00000000..b9a39807 --- /dev/null +++ b/src/plugins/position/android/jar/src/org/qtproject/qt/android/positioning/QtPositioning.java @@ -0,0 +1,590 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtLocation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +package org.qtproject.qt.android.positioning; + +import android.content.Context; +import android.location.GpsSatellite; +import android.location.GpsStatus; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import android.util.Log; + +public class QtPositioning implements LocationListener +{ + + private static final String TAG = "QtPositioning"; + static LocationManager locationManager = null; + static Object m_syncObject = new Object(); + static HashMap runningListeners = new HashMap(); + + /* + The positionInfo instance to which this + QtPositioning instance is attached to. + */ + private int nativeClassReference = 0; + + /* + The provider type requested by Qt + */ + private int expectedProviders = 0; + + public static final int QT_GPS_PROVIDER = 1; + public static final int QT_NETWORK_PROVIDER = 2; + + /* The following values must match the corresponding error enums in the Qt API*/ + public static final int QT_ACCESS_ERROR = 0; + public static final int QT_CLOSED_ERROR = 1; + public static final int QT_POSITION_UNKNOWN_SOURCE_ERROR = 2; + public static final int QT_POSITION_NO_ERROR = 3; + public static final int QT_SATELLITE_NO_ERROR = 2; + public static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR = -1; + + /* True, if updates were caused by requestUpdate() */ + private boolean isSingleUpdate = false; + /* The length requested for regular intervals in msec. */ + private int updateIntervalTime = 0; + + /* The last received GPS update */ + private Location lastGps = null; + /* The last received network update */ + private Location lastNetwork = null; + /* If true this class acts as satellite signal monitor rather than location monitor */ + private boolean isSatelliteUpdate = false; + + private PositioningLooper looperThread; + + static public void setContext(Context context) + { + try { + locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); + } catch(Exception e) { + e.printStackTrace(); + } + } + + static private int[] providerList() + { + if (locationManager == null) { + Log.w(TAG, "No locationManager available in QtPositioning"); + return new int[0]; + } + List providers = locationManager.getProviders(true); + int retList[] = new int[providers.size()]; + for (int i = 0; i < providers.size(); i++) { + if (providers.get(i).equals(LocationManager.GPS_PROVIDER)) { + //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_GPS + retList[i] = 0; + } else if (providers.get(i).equals(LocationManager.NETWORK_PROVIDER)) { + //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_NETWORK + retList[i] = 1; + } else if (providers.get(i).equals(LocationManager.PASSIVE_PROVIDER)) { + //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_PASSIVE + retList[i] = 2; + } else { + retList[i] = -1; + } + } + return retList; + } + + static public Location lastKnownPosition(boolean fromSatelliteOnly) + { + Location gps = null; + Location network = null; + try { + gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (!fromSatelliteOnly) + network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + } catch(Exception e) { + e.printStackTrace(); + gps = network = null; + } + + if (gps != null && network != null) { + //we return the most recent location but slightly prefer GPS + //prefer GPS if it is max 4 hrs older than network + long delta = network.getTime() - gps.getTime(); + if (delta < 4*60*60*1000) { + return gps; + } else { + return network; + } + } else if (gps != null ) { + return gps; + } else if (network != null) { + return network; + } + + return null; + } + + /* Returns true if at least on of the given providers is enabled. */ + static private boolean expectedProvidersAvailable(int desiredProviders) + { + List enabledProviders = locationManager.getProviders(true); + if ((desiredProviders & QT_GPS_PROVIDER) > 0) { //gps desired + if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) { + return true; + } + } + if ((desiredProviders & QT_NETWORK_PROVIDER) > 0) { //network desired + if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) { + return true; + } + } + + return false; + } + + + static private void addActiveListener(QtPositioning listener, String provider) + { + int androidClassKey = listener.nativeClassReference; + //start update thread + listener.setActiveLooper(true); + + if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { + removeActiveListener(androidClassKey); + } + + locationManager.requestSingleUpdate(provider, + listener, + listener.looper()); + + runningListeners.put(androidClassKey, listener); + } + + + static private void addActiveListener(QtPositioning listener, String provider, long minTime, float minDistance) + { + int androidClassKey = listener.nativeClassReference; + //start update thread + listener.setActiveLooper(true); + + if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { + removeActiveListener(androidClassKey); + } + + locationManager.requestLocationUpdates(provider, + minTime, minDistance, + listener, + listener.looper()); + + runningListeners.put(androidClassKey, listener); + } + + + static private void removeActiveListener(QtPositioning listener) + { + removeActiveListener(listener.nativeClassReference); + } + + + static private void removeActiveListener(int androidClassKey) + { + QtPositioning listener = runningListeners.remove(androidClassKey); + + if (listener != null) { + locationManager.removeUpdates(listener); + listener.setActiveLooper(false); + } + } + + + static public int startUpdates(int androidClassKey, int locationProvider, int updateInterval) + { + synchronized (m_syncObject) { + try { + boolean exceptionOccurred = false; + QtPositioning positioningListener = new QtPositioning(); + positioningListener.nativeClassReference = androidClassKey; + positioningListener.expectedProviders = locationProvider; + positioningListener.isSatelliteUpdate = false; + + if (updateInterval == 0) + updateInterval = 50; //don't update more often than once per 50ms + + positioningListener.updateIntervalTime = updateInterval; + if ((locationProvider & QT_GPS_PROVIDER) > 0) { + Log.d(TAG, "Regular updates using GPS " + updateInterval); + try { + addActiveListener(positioningListener, + LocationManager.GPS_PROVIDER, + updateInterval, 0); + } catch (SecurityException se) { + se.printStackTrace(); + exceptionOccurred = true; + } + } + + if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { + Log.d(TAG, "Regular updates using network " + updateInterval); + try { + addActiveListener(positioningListener, + LocationManager.NETWORK_PROVIDER, + updateInterval, 0); + } catch (SecurityException se) { + se.printStackTrace(); + exceptionOccurred = true; + } + } + if (exceptionOccurred) { + removeActiveListener(positioningListener); + return QT_ACCESS_ERROR; + } + + if (!expectedProvidersAvailable(locationProvider)) { + //all location providers unavailbe -> when they come back we resume automatically + return QT_CLOSED_ERROR; + } + + } catch(Exception e) { + e.printStackTrace(); + return QT_POSITION_UNKNOWN_SOURCE_ERROR; + } + + return QT_POSITION_NO_ERROR; + } + } + + static public void stopUpdates(int androidClassKey) + { + synchronized (m_syncObject) { + try { + Log.d(TAG, "Stopping updates"); + removeActiveListener(androidClassKey); + } catch(Exception e) { + e.printStackTrace(); + return; + } + } + } + + static public int requestUpdate(int androidClassKey, int locationProvider) + { + synchronized (m_syncObject) { + try { + boolean exceptionOccurred = false; + QtPositioning positioningListener = new QtPositioning(); + positioningListener.nativeClassReference = androidClassKey; + positioningListener.isSingleUpdate = true; + positioningListener.expectedProviders = locationProvider; + positioningListener.isSatelliteUpdate = false; + + if ((locationProvider & QT_GPS_PROVIDER) > 0) { + Log.d(TAG, "Single update using GPS"); + try { + addActiveListener(positioningListener, LocationManager.GPS_PROVIDER); + } catch (SecurityException se) { + se.printStackTrace(); + exceptionOccurred = true; + } + } + + if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { + Log.d(TAG, "Single update using network"); + try { + addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER); + } catch (SecurityException se) { + se.printStackTrace(); + exceptionOccurred = true; + } + } + if (exceptionOccurred) { + removeActiveListener(positioningListener); + return QT_ACCESS_ERROR; + } + + if (!expectedProvidersAvailable(locationProvider)) { + //all location providers unavailable -> when they come back we resume automatically + //in the mean time return ClosedError + return QT_CLOSED_ERROR; + } + + } catch(Exception e) { + e.printStackTrace(); + return QT_POSITION_UNKNOWN_SOURCE_ERROR; + } + + return QT_POSITION_NO_ERROR; + } + } + + static public int startSatelliteUpdates(int androidClassKey, int updateInterval, boolean isSingleRequest) + { + synchronized (m_syncObject) { + try { + boolean exceptionOccurred = false; + QtPositioning positioningListener = new QtPositioning(); + positioningListener.isSatelliteUpdate = true; + positioningListener.nativeClassReference = androidClassKey; + positioningListener.expectedProviders = 1; //always satellite provider + positioningListener.isSingleUpdate = isSingleRequest; + + if (updateInterval == 0) + updateInterval = 50; //don't update more often than once per 50ms + + if (isSingleRequest) + Log.d(TAG, "Single update for Satellites " + updateInterval); + else + Log.d(TAG, "Regular updates for Satellites " + updateInterval); + try { + addActiveListener(positioningListener, LocationManager.GPS_PROVIDER, + updateInterval, 0); + } catch (SecurityException se) { + se.printStackTrace(); + exceptionOccurred = true; + } + + if (exceptionOccurred) { + removeActiveListener(positioningListener); + return QT_ACCESS_ERROR; + } + + if (!expectedProvidersAvailable(positioningListener.expectedProviders)) { + //all location providers unavailable -> when they come back we resume automatically + //in the mean time return ClosedError + return QT_CLOSED_ERROR; + } + + } catch(Exception e) { + e.printStackTrace(); + return QT_SATELLITE_UNKNOWN_SOURCE_ERROR; + } + + return QT_SATELLITE_NO_ERROR; + } + } + + public QtPositioning() + { + looperThread = new PositioningLooper(); + } + + public Looper looper() + { + return looperThread.looper(); + } + + private void setActiveLooper(boolean setActive) + { + try{ + if (setActive) { + if (looperThread.isAlive()) + return; + + if (isSatelliteUpdate) + looperThread.isSatelliteListener(true); + + long start = System.currentTimeMillis(); + looperThread.start(); + + //busy wait but lasts ~20-30 ms only + while (!looperThread.isReady()); + + long stop = System.currentTimeMillis(); + Log.d(TAG, "Looper Thread startup time in ms: " + (stop-start)); + } else { + looperThread.quitLooper(); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + private class PositioningLooper extends Thread implements GpsStatus.Listener{ + private boolean looperRunning; + private Looper posLooper; + private boolean isSatelliteLooper = false; + private LocationManager locManager = null; + + private PositioningLooper() + { + looperRunning = false; + } + + public void run() + { + Looper.prepare(); + Handler handler = new Handler(); + + if (isSatelliteLooper) { + try { + locationManager.addGpsStatusListener(this); + } catch(Exception e) { + e.printStackTrace(); + } + } + + posLooper = Looper.myLooper(); + synchronized (this) { + looperRunning = true; + } + Looper.loop(); + synchronized (this) { + looperRunning = false; + } + } + + public void quitLooper() + { + if (isSatelliteLooper) + locationManager.removeGpsStatusListener(this); + looper().quit(); + } + + public synchronized boolean isReady() + { + return looperRunning; + } + + public void isSatelliteListener(boolean isListener) + { + isSatelliteLooper = isListener; + } + + public Looper looper() + { + return posLooper; + } + + @Override + public void onGpsStatusChanged(int event) { + switch (event) { + case GpsStatus.GPS_EVENT_FIRST_FIX: + break; + case GpsStatus.GPS_EVENT_SATELLITE_STATUS: + GpsStatus status = locationManager.getGpsStatus(null); + Iterable iterable = status.getSatellites(); + Iterator it = iterable.iterator(); + + ArrayList list = new ArrayList(); + while (it.hasNext()) { + GpsSatellite sat = (GpsSatellite) it.next(); + list.add(sat); + } + GpsSatellite[] sats = list.toArray(new GpsSatellite[list.size()]); + satelliteUpdated(sats, nativeClassReference, isSingleUpdate); + + break; + case GpsStatus.GPS_EVENT_STARTED: + break; + case GpsStatus.GPS_EVENT_STOPPED: + break; + } + } + } + + public static native void positionUpdated(Location update, int androidClassKey, boolean isSingleUpdate); + public static native void locationProvidersDisabled(int androidClassKey); + public static native void locationProvidersChanged(int androidClassKey); + public static native void satelliteUpdated(GpsSatellite[] update, int androidClassKey, boolean isSingleUpdate); + + @Override + public void onLocationChanged(Location location) { + //Log.d(TAG, "**** Position Update ****: " + location.toString() + " " + isSingleUpdate); + if (location == null) + return; + + if (isSatelliteUpdate) //we are a QGeoSatelliteInfoSource -> ignore + return; + + if (isSingleUpdate || expectedProviders < 3) { + positionUpdated(location, nativeClassReference, isSingleUpdate); + return; + } + + /* + We can use GPS and Network, pick the better location provider. + Generally we prefer GPS data due to their higher accurancy but we + let Network data pass until GPS fix is available + */ + + if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { + lastGps = location; + + // assumption: GPS always better -> pass it on + positionUpdated(location, nativeClassReference, isSingleUpdate); + } else if (location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { + lastNetwork = location; + + if (lastGps == null) { //no GPS fix yet use network location + positionUpdated(location, nativeClassReference, isSingleUpdate); + return; + } + + long delta = location.getTime() - lastGps.getTime(); + + // Ignore if network update is older than last GPS (delta < 0) + // Ignore if gps update still has time to provide next location (delta < updateInterval) + if (delta < updateIntervalTime) + return; + + // Use network data -> GPS has timed out on updateInterval + positionUpdated(location, nativeClassReference, isSingleUpdate); + } + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) {} + + @Override + public void onProviderEnabled(String provider) { + Log.d(TAG, "Enabled provider: " + provider); + locationProvidersChanged(nativeClassReference); + } + + @Override + public void onProviderDisabled(String provider) { + Log.d(TAG, "Disabled provider: " + provider); + locationProvidersChanged(nativeClassReference); + if (!expectedProvidersAvailable(expectedProviders)) + locationProvidersDisabled(nativeClassReference); + } +} diff --git a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java deleted file mode 100644 index d819e627..00000000 --- a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java +++ /dev/null @@ -1,590 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -package org.qtproject.qt5.android.positioning; - -import android.content.Context; -import android.location.GpsSatellite; -import android.location.GpsStatus; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import android.util.Log; - -public class QtPositioning implements LocationListener -{ - - private static final String TAG = "QtPositioning"; - static LocationManager locationManager = null; - static Object m_syncObject = new Object(); - static HashMap runningListeners = new HashMap(); - - /* - The positionInfo instance to which this - QtPositioning instance is attached to. - */ - private int nativeClassReference = 0; - - /* - The provider type requested by Qt - */ - private int expectedProviders = 0; - - public static final int QT_GPS_PROVIDER = 1; - public static final int QT_NETWORK_PROVIDER = 2; - - /* The following values must match the corresponding error enums in the Qt API*/ - public static final int QT_ACCESS_ERROR = 0; - public static final int QT_CLOSED_ERROR = 1; - public static final int QT_POSITION_UNKNOWN_SOURCE_ERROR = 2; - public static final int QT_POSITION_NO_ERROR = 3; - public static final int QT_SATELLITE_NO_ERROR = 2; - public static final int QT_SATELLITE_UNKNOWN_SOURCE_ERROR = -1; - - /* True, if updates were caused by requestUpdate() */ - private boolean isSingleUpdate = false; - /* The length requested for regular intervals in msec. */ - private int updateIntervalTime = 0; - - /* The last received GPS update */ - private Location lastGps = null; - /* The last received network update */ - private Location lastNetwork = null; - /* If true this class acts as satellite signal monitor rather than location monitor */ - private boolean isSatelliteUpdate = false; - - private PositioningLooper looperThread; - - static public void setContext(Context context) - { - try { - locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); - } catch(Exception e) { - e.printStackTrace(); - } - } - - static private int[] providerList() - { - if (locationManager == null) { - Log.w(TAG, "No locationManager available in QtPositioning"); - return new int[0]; - } - List providers = locationManager.getProviders(true); - int retList[] = new int[providers.size()]; - for (int i = 0; i < providers.size(); i++) { - if (providers.get(i).equals(LocationManager.GPS_PROVIDER)) { - //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_GPS - retList[i] = 0; - } else if (providers.get(i).equals(LocationManager.NETWORK_PROVIDER)) { - //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_NETWORK - retList[i] = 1; - } else if (providers.get(i).equals(LocationManager.PASSIVE_PROVIDER)) { - //must be in sync with AndroidPositioning::PositionProvider::PROVIDER_PASSIVE - retList[i] = 2; - } else { - retList[i] = -1; - } - } - return retList; - } - - static public Location lastKnownPosition(boolean fromSatelliteOnly) - { - Location gps = null; - Location network = null; - try { - gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - if (!fromSatelliteOnly) - network = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); - } catch(Exception e) { - e.printStackTrace(); - gps = network = null; - } - - if (gps != null && network != null) { - //we return the most recent location but slightly prefer GPS - //prefer GPS if it is max 4 hrs older than network - long delta = network.getTime() - gps.getTime(); - if (delta < 4*60*60*1000) { - return gps; - } else { - return network; - } - } else if (gps != null ) { - return gps; - } else if (network != null) { - return network; - } - - return null; - } - - /* Returns true if at least on of the given providers is enabled. */ - static private boolean expectedProvidersAvailable(int desiredProviders) - { - List enabledProviders = locationManager.getProviders(true); - if ((desiredProviders & QT_GPS_PROVIDER) > 0) { //gps desired - if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) { - return true; - } - } - if ((desiredProviders & QT_NETWORK_PROVIDER) > 0) { //network desired - if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) { - return true; - } - } - - return false; - } - - - static private void addActiveListener(QtPositioning listener, String provider) - { - int androidClassKey = listener.nativeClassReference; - //start update thread - listener.setActiveLooper(true); - - if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { - removeActiveListener(androidClassKey); - } - - locationManager.requestSingleUpdate(provider, - listener, - listener.looper()); - - runningListeners.put(androidClassKey, listener); - } - - - static private void addActiveListener(QtPositioning listener, String provider, long minTime, float minDistance) - { - int androidClassKey = listener.nativeClassReference; - //start update thread - listener.setActiveLooper(true); - - if (runningListeners.containsKey(androidClassKey) && runningListeners.get(androidClassKey) != listener) { - removeActiveListener(androidClassKey); - } - - locationManager.requestLocationUpdates(provider, - minTime, minDistance, - listener, - listener.looper()); - - runningListeners.put(androidClassKey, listener); - } - - - static private void removeActiveListener(QtPositioning listener) - { - removeActiveListener(listener.nativeClassReference); - } - - - static private void removeActiveListener(int androidClassKey) - { - QtPositioning listener = runningListeners.remove(androidClassKey); - - if (listener != null) { - locationManager.removeUpdates(listener); - listener.setActiveLooper(false); - } - } - - - static public int startUpdates(int androidClassKey, int locationProvider, int updateInterval) - { - synchronized (m_syncObject) { - try { - boolean exceptionOccurred = false; - QtPositioning positioningListener = new QtPositioning(); - positioningListener.nativeClassReference = androidClassKey; - positioningListener.expectedProviders = locationProvider; - positioningListener.isSatelliteUpdate = false; - - if (updateInterval == 0) - updateInterval = 50; //don't update more often than once per 50ms - - positioningListener.updateIntervalTime = updateInterval; - if ((locationProvider & QT_GPS_PROVIDER) > 0) { - Log.d(TAG, "Regular updates using GPS " + updateInterval); - try { - addActiveListener(positioningListener, - LocationManager.GPS_PROVIDER, - updateInterval, 0); - } catch (SecurityException se) { - se.printStackTrace(); - exceptionOccurred = true; - } - } - - if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { - Log.d(TAG, "Regular updates using network " + updateInterval); - try { - addActiveListener(positioningListener, - LocationManager.NETWORK_PROVIDER, - updateInterval, 0); - } catch (SecurityException se) { - se.printStackTrace(); - exceptionOccurred = true; - } - } - if (exceptionOccurred) { - removeActiveListener(positioningListener); - return QT_ACCESS_ERROR; - } - - if (!expectedProvidersAvailable(locationProvider)) { - //all location providers unavailbe -> when they come back we resume automatically - return QT_CLOSED_ERROR; - } - - } catch(Exception e) { - e.printStackTrace(); - return QT_POSITION_UNKNOWN_SOURCE_ERROR; - } - - return QT_POSITION_NO_ERROR; - } - } - - static public void stopUpdates(int androidClassKey) - { - synchronized (m_syncObject) { - try { - Log.d(TAG, "Stopping updates"); - removeActiveListener(androidClassKey); - } catch(Exception e) { - e.printStackTrace(); - return; - } - } - } - - static public int requestUpdate(int androidClassKey, int locationProvider) - { - synchronized (m_syncObject) { - try { - boolean exceptionOccurred = false; - QtPositioning positioningListener = new QtPositioning(); - positioningListener.nativeClassReference = androidClassKey; - positioningListener.isSingleUpdate = true; - positioningListener.expectedProviders = locationProvider; - positioningListener.isSatelliteUpdate = false; - - if ((locationProvider & QT_GPS_PROVIDER) > 0) { - Log.d(TAG, "Single update using GPS"); - try { - addActiveListener(positioningListener, LocationManager.GPS_PROVIDER); - } catch (SecurityException se) { - se.printStackTrace(); - exceptionOccurred = true; - } - } - - if ((locationProvider & QT_NETWORK_PROVIDER) > 0) { - Log.d(TAG, "Single update using network"); - try { - addActiveListener(positioningListener, LocationManager.NETWORK_PROVIDER); - } catch (SecurityException se) { - se.printStackTrace(); - exceptionOccurred = true; - } - } - if (exceptionOccurred) { - removeActiveListener(positioningListener); - return QT_ACCESS_ERROR; - } - - if (!expectedProvidersAvailable(locationProvider)) { - //all location providers unavailable -> when they come back we resume automatically - //in the mean time return ClosedError - return QT_CLOSED_ERROR; - } - - } catch(Exception e) { - e.printStackTrace(); - return QT_POSITION_UNKNOWN_SOURCE_ERROR; - } - - return QT_POSITION_NO_ERROR; - } - } - - static public int startSatelliteUpdates(int androidClassKey, int updateInterval, boolean isSingleRequest) - { - synchronized (m_syncObject) { - try { - boolean exceptionOccurred = false; - QtPositioning positioningListener = new QtPositioning(); - positioningListener.isSatelliteUpdate = true; - positioningListener.nativeClassReference = androidClassKey; - positioningListener.expectedProviders = 1; //always satellite provider - positioningListener.isSingleUpdate = isSingleRequest; - - if (updateInterval == 0) - updateInterval = 50; //don't update more often than once per 50ms - - if (isSingleRequest) - Log.d(TAG, "Single update for Satellites " + updateInterval); - else - Log.d(TAG, "Regular updates for Satellites " + updateInterval); - try { - addActiveListener(positioningListener, LocationManager.GPS_PROVIDER, - updateInterval, 0); - } catch (SecurityException se) { - se.printStackTrace(); - exceptionOccurred = true; - } - - if (exceptionOccurred) { - removeActiveListener(positioningListener); - return QT_ACCESS_ERROR; - } - - if (!expectedProvidersAvailable(positioningListener.expectedProviders)) { - //all location providers unavailable -> when they come back we resume automatically - //in the mean time return ClosedError - return QT_CLOSED_ERROR; - } - - } catch(Exception e) { - e.printStackTrace(); - return QT_SATELLITE_UNKNOWN_SOURCE_ERROR; - } - - return QT_SATELLITE_NO_ERROR; - } - } - - public QtPositioning() - { - looperThread = new PositioningLooper(); - } - - public Looper looper() - { - return looperThread.looper(); - } - - private void setActiveLooper(boolean setActive) - { - try{ - if (setActive) { - if (looperThread.isAlive()) - return; - - if (isSatelliteUpdate) - looperThread.isSatelliteListener(true); - - long start = System.currentTimeMillis(); - looperThread.start(); - - //busy wait but lasts ~20-30 ms only - while (!looperThread.isReady()); - - long stop = System.currentTimeMillis(); - Log.d(TAG, "Looper Thread startup time in ms: " + (stop-start)); - } else { - looperThread.quitLooper(); - } - } catch(Exception e) { - e.printStackTrace(); - } - } - - private class PositioningLooper extends Thread implements GpsStatus.Listener{ - private boolean looperRunning; - private Looper posLooper; - private boolean isSatelliteLooper = false; - private LocationManager locManager = null; - - private PositioningLooper() - { - looperRunning = false; - } - - public void run() - { - Looper.prepare(); - Handler handler = new Handler(); - - if (isSatelliteLooper) { - try { - locationManager.addGpsStatusListener(this); - } catch(Exception e) { - e.printStackTrace(); - } - } - - posLooper = Looper.myLooper(); - synchronized (this) { - looperRunning = true; - } - Looper.loop(); - synchronized (this) { - looperRunning = false; - } - } - - public void quitLooper() - { - if (isSatelliteLooper) - locationManager.removeGpsStatusListener(this); - looper().quit(); - } - - public synchronized boolean isReady() - { - return looperRunning; - } - - public void isSatelliteListener(boolean isListener) - { - isSatelliteLooper = isListener; - } - - public Looper looper() - { - return posLooper; - } - - @Override - public void onGpsStatusChanged(int event) { - switch (event) { - case GpsStatus.GPS_EVENT_FIRST_FIX: - break; - case GpsStatus.GPS_EVENT_SATELLITE_STATUS: - GpsStatus status = locationManager.getGpsStatus(null); - Iterable iterable = status.getSatellites(); - Iterator it = iterable.iterator(); - - ArrayList list = new ArrayList(); - while (it.hasNext()) { - GpsSatellite sat = (GpsSatellite) it.next(); - list.add(sat); - } - GpsSatellite[] sats = list.toArray(new GpsSatellite[list.size()]); - satelliteUpdated(sats, nativeClassReference, isSingleUpdate); - - break; - case GpsStatus.GPS_EVENT_STARTED: - break; - case GpsStatus.GPS_EVENT_STOPPED: - break; - } - } - } - - public static native void positionUpdated(Location update, int androidClassKey, boolean isSingleUpdate); - public static native void locationProvidersDisabled(int androidClassKey); - public static native void locationProvidersChanged(int androidClassKey); - public static native void satelliteUpdated(GpsSatellite[] update, int androidClassKey, boolean isSingleUpdate); - - @Override - public void onLocationChanged(Location location) { - //Log.d(TAG, "**** Position Update ****: " + location.toString() + " " + isSingleUpdate); - if (location == null) - return; - - if (isSatelliteUpdate) //we are a QGeoSatelliteInfoSource -> ignore - return; - - if (isSingleUpdate || expectedProviders < 3) { - positionUpdated(location, nativeClassReference, isSingleUpdate); - return; - } - - /* - We can use GPS and Network, pick the better location provider. - Generally we prefer GPS data due to their higher accurancy but we - let Network data pass until GPS fix is available - */ - - if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { - lastGps = location; - - // assumption: GPS always better -> pass it on - positionUpdated(location, nativeClassReference, isSingleUpdate); - } else if (location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { - lastNetwork = location; - - if (lastGps == null) { //no GPS fix yet use network location - positionUpdated(location, nativeClassReference, isSingleUpdate); - return; - } - - long delta = location.getTime() - lastGps.getTime(); - - // Ignore if network update is older than last GPS (delta < 0) - // Ignore if gps update still has time to provide next location (delta < updateInterval) - if (delta < updateIntervalTime) - return; - - // Use network data -> GPS has timed out on updateInterval - positionUpdated(location, nativeClassReference, isSingleUpdate); - } - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) {} - - @Override - public void onProviderEnabled(String provider) { - Log.d(TAG, "Enabled provider: " + provider); - locationProvidersChanged(nativeClassReference); - } - - @Override - public void onProviderDisabled(String provider) { - Log.d(TAG, "Disabled provider: " + provider); - locationProvidersChanged(nativeClassReference); - if (!expectedProvidersAvailable(expectedProviders)) - locationProvidersDisabled(nativeClassReference); - } -} diff --git a/src/plugins/position/android/src/jnipositioning.cpp b/src/plugins/position/android/src/jnipositioning.cpp index 05b25d98..ac349fe6 100644 --- a/src/plugins/position/android/src/jnipositioning.cpp +++ b/src/plugins/position/android/src/jnipositioning.cpp @@ -587,7 +587,7 @@ static JNINativeMethod methods[] = { static bool registerNatives(JNIEnv *env) { jclass clazz; - FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/positioning/QtPositioning"); + FIND_AND_CHECK_CLASS("org/qtproject/qt/android/positioning/QtPositioning"); positioningClass = static_cast(env->NewGlobalRef(clazz)); if (env->RegisterNatives(positioningClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { diff --git a/src/positioning/CMakeLists.txt b/src/positioning/CMakeLists.txt index 13aeef8f..5dfe2d58 100644 --- a/src/positioning/CMakeLists.txt +++ b/src/positioning/CMakeLists.txt @@ -47,7 +47,7 @@ qt_add_module(Positioning if(ANDROID) set_property(TARGET Positioning APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES - jar/QtPositioning.jar:org.qtproject.qt5.android.positioning.QtPositioning + jar/Qt${QtLocation_VERSION_MAJOR}AndroidPositioning.jar:org.qtproject.qt.android.positioning.QtPositioning # special case ) set_property(TARGET Positioning APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES plugins/position/libplugins_position_qtposition_android.so diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro index db499212..cf4e01c6 100644 --- a/src/positioning/positioning.pro +++ b/src/positioning/positioning.pro @@ -10,7 +10,7 @@ QMAKE_DOCS = $$PWD/doc/qtpositioning.qdocconf OTHER_FILES += configure.json doc/src/*.qdoc doc/src/plugins/*.qdoc # show .qdoc files in Qt Creator ANDROID_BUNDLED_JAR_DEPENDENCIES = \ - jar/QtPositioning.jar:org.qtproject.qt5.android.positioning.QtPositioning + jar/Qt$${QT_MAJOR_VERSION}AndroidPositioning.jar:org.qtproject.qt.android.positioning.QtPositioning ANDROID_PERMISSIONS += \ android.permission.ACCESS_FINE_LOCATION ANDROID_FEATURES += \ -- cgit v1.2.1