From 128c08ca7f6e353c775f6224f3b262b18bdda915 Mon Sep 17 00:00:00 2001 From: max-klaus Date: Sun, 17 Jan 2021 22:11:57 +0300 Subject: [PATCH] Introduced gms location service --- OsmAnd/build.gradle | 27 ++- .../plus/LocationServiceHelperImpl.java | 158 +++++++++++++ .../plus/LocationServiceHelperImpl.java | 188 ++++++++++++++++ .../net/osmand/plus/NavigationService.java | 70 +++--- .../osmand/plus/OsmAndLocationProvider.java | 213 ++++++------------ .../net/osmand/plus/OsmandApplication.java | 7 +- .../osmand/plus/helpers/DayNightHelper.java | 29 ++- .../plus/helpers/LocationServiceHelper.java | 29 +++ 8 files changed, 519 insertions(+), 202 deletions(-) create mode 100644 OsmAnd/src-gms/net/osmand/plus/LocationServiceHelperImpl.java create mode 100644 OsmAnd/src-nogms/net/osmand/plus/LocationServiceHelperImpl.java create mode 100644 OsmAnd/src/net/osmand/plus/helpers/LocationServiceHelper.java diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index a3f80f4c46..24664da2a4 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -108,18 +108,25 @@ android { manifest.srcFile "AndroidManifest-debug.xml" } full { - java.srcDirs = ["src-google"] + java.srcDirs = ["src-nogms", "src-google"] + } + fullGms { + java.srcDirs = ["src-gms", "src-google"] } free { - java.srcDirs = ["src-google"] + java.srcDirs = ["src-nogms", "src-google"] + manifest.srcFile "AndroidManifest-free.xml" + } + freeGms { + java.srcDirs = ["src-gms", "src-google"] manifest.srcFile "AndroidManifest-free.xml" } freedev { - java.srcDirs = ["src-google"] + java.srcDirs = ["src-nogms", "src-google"] manifest.srcFile "AndroidManifest-freedev.xml" } freehuawei { - java.srcDirs = ["src-huawei"] + java.srcDirs = ["src-nogms", "src-google"] manifest.srcFile "AndroidManifest-freehuawei.xml" } @@ -172,10 +179,18 @@ android { dimension "version" applicationId "net.osmand" } + freeGms { + dimension "version" + applicationId "net.osmand" + } full { dimension "version" applicationId "net.osmand.plus" } + fullGms { + dimension "version" + applicationId "net.osmand.plus" + } freehuawei { dimension "version" applicationId "net.osmand.huawei" @@ -504,8 +519,10 @@ dependencies { exclude group: "com.fasterxml.jackson.core" } implementation 'com.jaredrummler:colorpicker:1.1.0' + implementation "org.bouncycastle:bcpkix-jdk15on:1.56" freehuaweiImplementation 'com.huawei.hms:iap:5.0.2.300' - implementation "org.bouncycastle:bcpkix-jdk15on:1.56" + freeGmsImplementation 'com.google.android.gms:play-services-location:17.1.0' + fullGmsImplementation 'com.google.android.gms:play-services-location:17.1.0' } diff --git a/OsmAnd/src-gms/net/osmand/plus/LocationServiceHelperImpl.java b/OsmAnd/src-gms/net/osmand/plus/LocationServiceHelperImpl.java new file mode 100644 index 0000000000..e8182955ec --- /dev/null +++ b/OsmAnd/src-gms/net/osmand/plus/LocationServiceHelperImpl.java @@ -0,0 +1,158 @@ +package net.osmand.plus; + +import android.location.Location; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationAvailability; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.Tasks; + +import net.osmand.PlatformUtil; +import net.osmand.plus.helpers.DayNightHelper; +import net.osmand.plus.helpers.LocationServiceHelper; + +import org.apache.commons.logging.Log; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class LocationServiceHelperImpl extends LocationServiceHelper { + + private static final Log LOG = PlatformUtil.getLog(DayNightHelper.class); + + private final OsmandApplication app; + + // FusedLocationProviderClient - Main class for receiving location updates. + private final FusedLocationProviderClient fusedLocationProviderClient; + + // LocationRequest - Requirements for the location updates, i.e., how often you should receive + // updates, the priority, etc. + private final LocationRequest fusedLocationRequest; + + // LocationCallback - Called when FusedLocationProviderClient has a new Location. + private final com.google.android.gms.location.LocationCallback fusedLocationCallback; + + private LocationCallback locationCallback; + + public LocationServiceHelperImpl(@NonNull OsmandApplication app) { + this.app = app; + + fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(app); + + fusedLocationRequest = new LocationRequest() + // Sets the desired interval for active location updates. This interval is inexact. You + // may not receive updates at all if no location sources are available, or you may + // receive them less frequently than requested. You may also receive updates more + // frequently than requested if other applications are requesting location at a more + // frequent interval. + // + // IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of + // targetSdkVersion) may receive updates less frequently than this interval when the app + // is no longer in the foreground. + .setInterval(100) + + // Sets the fastest rate for active location updates. This interval is exact, and your + // application will never receive updates more frequently than this value. + .setFastestInterval(50) + + // Sets the maximum time when batched location updates are delivered. Updates may be + // delivered sooner than this interval. + .setMaxWaitTime(200) + + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + + fusedLocationCallback = new com.google.android.gms.location.LocationCallback() { + @Override + public void onLocationResult(LocationResult locationResult) { + LocationCallback locationCallback = LocationServiceHelperImpl.this.locationCallback; + if (locationCallback != null) { + Location location = locationResult != null ? locationResult.getLastLocation() : null; + net.osmand.Location l = convertLocation(location); + locationCallback.onLocationResult(l == null + ? Collections.emptyList() : Collections.singletonList(l)); + } + + } + + @Override + public void onLocationAvailability(LocationAvailability locationAvailability) { + LocationCallback locationCallback = LocationServiceHelperImpl.this.locationCallback; + if (locationAvailability != null && locationCallback != null) { + locationCallback.onLocationAvailability(locationAvailability.isLocationAvailable()); + } + } + }; + } + + @Override + public void requestLocationUpdates(@NonNull LocationCallback locationCallback) { + this.locationCallback = locationCallback; + // request location updates + try { + fusedLocationProviderClient.requestLocationUpdates( + fusedLocationRequest, fusedLocationCallback, Looper.myLooper()); + } catch (SecurityException e) { + LOG.debug("Location service permission not granted"); + throw e; + } catch (IllegalArgumentException e) { + LOG.debug("GPS location provider not available"); + throw e; + } + } + + @Override + public boolean isNetworkLocationUpdatesSupported() { + return false; + } + + @Override + public void requestNetworkLocationUpdates(@NonNull LocationCallback locationCallback) { + } + + @Override + public void removeLocationUpdates() { + // remove location updates + try { + fusedLocationProviderClient.removeLocationUpdates(fusedLocationCallback); + } catch (SecurityException e) { + LOG.debug("Location service permission not granted", e); + throw e; + } + } + + @Nullable + public net.osmand.Location getFirstTimeRunDefaultLocation() { + final net.osmand.Location[] location = {null}; + /* + try { + Task lastLocation = fusedLocationProviderClient.getLastLocation(); + lastLocation.addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Location loc) { + location[0] = convertLocation(loc); + } + }); + } catch (SecurityException e) { + LOG.debug("Location service permission not granted"); + } catch (IllegalArgumentException e) { + LOG.debug("GPS location provider not available"); + } + */ + return location[0]; + } + + @Nullable + private net.osmand.Location convertLocation(@Nullable Location location) { + return location == null ? null : OsmAndLocationProvider.convertLocation(location, app); + } +} diff --git a/OsmAnd/src-nogms/net/osmand/plus/LocationServiceHelperImpl.java b/OsmAnd/src-nogms/net/osmand/plus/LocationServiceHelperImpl.java new file mode 100644 index 0000000000..5f49607954 --- /dev/null +++ b/OsmAnd/src-nogms/net/osmand/plus/LocationServiceHelperImpl.java @@ -0,0 +1,188 @@ +package net.osmand.plus; + +import android.content.Context; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.PlatformUtil; +import net.osmand.plus.helpers.DayNightHelper; +import net.osmand.plus.helpers.LocationServiceHelper; + +import org.apache.commons.logging.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import static android.content.Context.LOCATION_SERVICE; + +public class LocationServiceHelperImpl extends LocationServiceHelper implements LocationListener { + + private static final Log LOG = PlatformUtil.getLog(DayNightHelper.class); + + private final OsmandApplication app; + + private LocationCallback locationCallback; + private LocationCallback networkLocationCallback; + private final LinkedList networkListeners = new LinkedList<>(); + + // Working with location checkListeners + private class NetworkListener implements LocationListener { + + @Override + public void onLocationChanged(Location location) { + LocationCallback locationCallback = LocationServiceHelperImpl.this.networkLocationCallback; + if (locationCallback != null) { + net.osmand.Location l = convertLocation(location); + locationCallback.onLocationResult(l == null + ? Collections.emptyList() : Collections.singletonList(l)); + } + } + + @Override + public void onProviderDisabled(String provider) { + } + + @Override + public void onProviderEnabled(String provider) { + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + } + + public LocationServiceHelperImpl(@NonNull OsmandApplication app) { + this.app = app; + } + + @Override + public void requestLocationUpdates(@NonNull LocationCallback locationCallback) { + this.locationCallback = locationCallback; + // request location updates + LocationManager locationManager = (LocationManager) app.getSystemService(LOCATION_SERVICE); + try { + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + } catch (SecurityException e) { + LOG.debug("Location service permission not granted"); + throw e; + } catch (IllegalArgumentException e) { + LOG.debug("GPS location provider not available"); + throw e; + } + } + + @Override + public boolean isNetworkLocationUpdatesSupported() { + return true; + } + + @Override + public void requestNetworkLocationUpdates(@NonNull LocationCallback locationCallback) { + this.networkLocationCallback = locationCallback; + // request location updates + LocationManager locationManager = (LocationManager) app.getSystemService(LOCATION_SERVICE); + List providers = locationManager.getProviders(true); + for (String provider : providers) { + if (provider == null || provider.equals(LocationManager.GPS_PROVIDER)) { + continue; + } + try { + NetworkListener networkListener = new NetworkListener(); + locationManager.requestLocationUpdates(provider, 0, 0, networkListener); + networkListeners.add(networkListener); + } catch (SecurityException e) { + LOG.debug(provider + " location service permission not granted"); + } catch (IllegalArgumentException e) { + LOG.debug(provider + " location provider not available"); + } + } + } + + @Override + public void removeLocationUpdates() { + // remove location updates + LocationManager locationManager = (LocationManager) app.getSystemService(LOCATION_SERVICE); + try { + locationManager.removeUpdates(this); + } catch (SecurityException e) { + LOG.debug("Location service permission not granted", e); + throw e; + } finally { + while (!networkListeners.isEmpty()) { + LocationListener listener = networkListeners.poll(); + if (listener != null) { + locationManager.removeUpdates(listener); + } + } + } + } + + @Nullable + public net.osmand.Location getFirstTimeRunDefaultLocation() { + LocationManager locationManager = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE); + List providers = new ArrayList<>(locationManager.getProviders(true)); + // note, passive provider is from API_LEVEL 8 but it is a constant, we can check for it. + // constant should not be changed in future + int passiveFirst = providers.indexOf(LocationManager.PASSIVE_PROVIDER); + // put passive provider to first place + if (passiveFirst > -1) { + providers.add(0, providers.remove(passiveFirst)); + } + // find location + for (String provider : providers) { + try { + net.osmand.Location location = convertLocation(locationManager.getLastKnownLocation(provider)); + if (location != null) { + return location; + } + } catch (SecurityException e) { + // location service permission not granted + } catch (IllegalArgumentException e) { + // location provider not available + } + } + return null; + } + + @Nullable + private net.osmand.Location convertLocation(@Nullable Location location) { + return location == null ? null : OsmAndLocationProvider.convertLocation(location, app); + } + + @Override + public void onLocationChanged(Location location) { + LocationCallback locationCallback = this.locationCallback; + if (locationCallback != null) { + net.osmand.Location l = convertLocation(location); + locationCallback.onLocationResult(l == null + ? Collections.emptyList() : Collections.singletonList(l)); + } + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + @Override + public void onProviderEnabled(String provider) { + LocationCallback locationCallback = this.locationCallback; + if (locationCallback != null) { + locationCallback.onLocationAvailability(true); + } + } + + @Override + public void onProviderDisabled(String provider) { + LocationCallback locationCallback = this.locationCallback; + if (locationCallback != null) { + locationCallback.onLocationAvailability(false); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/NavigationService.java b/OsmAnd/src/net/osmand/plus/NavigationService.java index 3a824f937e..16f1afddcc 100644 --- a/OsmAnd/src/net/osmand/plus/NavigationService.java +++ b/OsmAnd/src/net/osmand/plus/NavigationService.java @@ -4,20 +4,24 @@ import android.app.Notification; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.location.Location; -import android.location.LocationListener; import android.location.LocationManager; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; + +import net.osmand.Location; import net.osmand.PlatformUtil; +import net.osmand.plus.helpers.LocationServiceHelper; +import net.osmand.plus.helpers.LocationServiceHelper.LocationCallback; import net.osmand.plus.notifications.OsmandNotification; import net.osmand.plus.settings.backend.OsmandSettings; -public class NavigationService extends Service implements LocationListener { +import java.util.List; + +public class NavigationService extends Service { public static class NavigationServiceBinder extends Binder { } @@ -29,11 +33,11 @@ public class NavigationService extends Service implements LocationListener { private final NavigationServiceBinder binder = new NavigationServiceBinder(); - private String serviceOffProvider; private OsmandSettings settings; protected int usedBy = 0; private OsmAndLocationProvider locationProvider; + private LocationServiceHelper locationServiceHelper; @Override public IBinder onBind(Intent intent) { @@ -72,21 +76,37 @@ public class NavigationService extends Service implements LocationListener { settings = app.getSettings(); usedBy = intent.getIntExtra(USAGE_INTENT, 0); - // use only gps provider - serviceOffProvider = LocationManager.GPS_PROVIDER; locationProvider = app.getLocationProvider(); + locationServiceHelper = app.createLocationServiceHelper(); app.setNavigationService(this); // request location updates - LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { - locationManager.requestLocationUpdates(serviceOffProvider, 0, 0, NavigationService.this); + locationServiceHelper.requestLocationUpdates(new LocationCallback() { + @Override + public void onLocationResult(@NonNull List locations) { + if (!locations.isEmpty()) { + Location location = locations.get(locations.size() - 1); + if (!settings.MAP_ACTIVITY_ENABLED.get()) { + locationProvider.setLocationFromService(location); + } + } + } + + @Override + public void onLocationAvailability(boolean locationAvailable) { + if (!locationAvailable) { + OsmandApplication app = (OsmandApplication) getApplication(); + if (app != null) { + app.showToastMessage(getString(R.string.off_router_service_no_gps_available)); + } + } + } + }); } catch (SecurityException e) { Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show(); - Log.d(PlatformUtil.TAG, "Location service permission not granted"); //$NON-NLS-1$ } catch (IllegalArgumentException e) { Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show(); - Log.d(PlatformUtil.TAG, "GPS location provider not available"); //$NON-NLS-1$ } // registering icon at top level @@ -117,11 +137,10 @@ public class NavigationService extends Service implements LocationListener { app.setNavigationService(null); usedBy = 0; // remove updates - LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { - locationManager.removeUpdates(this); + locationServiceHelper.removeLocationUpdates(); } catch (SecurityException e) { - Log.d(PlatformUtil.TAG, "Location service permission not granted"); //$NON-NLS-1$ + // Location service permission not granted } // remove notification stopForeground(Boolean.TRUE); @@ -134,29 +153,6 @@ public class NavigationService extends Service implements LocationListener { }, 500); } - @Override - public void onLocationChanged(Location l) { - if (l != null && !settings.MAP_ACTIVITY_ENABLED.get()) { - net.osmand.Location location = OsmAndLocationProvider.convertLocation(l, (OsmandApplication) getApplication()); - locationProvider.setLocationFromService(location); - } - } - - @Override - public void onProviderDisabled(String provider) { - Toast.makeText(this, getString(R.string.off_router_service_no_gps_available), Toast.LENGTH_LONG).show(); - } - - - @Override - public void onProviderEnabled(String provider) { - } - - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - } - @Override public void onTaskRemoved(Intent rootIntent) { OsmandApplication app = ((OsmandApplication) getApplication()); diff --git a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java index a19ebd3023..ee875fbb17 100644 --- a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java +++ b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java @@ -1,6 +1,7 @@ package net.osmand.plus; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; @@ -16,7 +17,6 @@ import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.GpsStatus.Listener; import android.location.Location; -import android.location.LocationListener; import android.location.LocationManager; import android.os.Build; import android.os.Build.VERSION; @@ -25,6 +25,7 @@ import android.os.Bundle; import android.provider.Settings; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; @@ -38,8 +39,9 @@ import net.osmand.binary.RouteDataObject; import net.osmand.data.LatLon; import net.osmand.data.QuadPoint; import net.osmand.plus.TargetPointsHelper.TargetPoint; -import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.helpers.LocationServiceHelper; import net.osmand.plus.routing.RouteSegmentSearchResult; +import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.router.RouteSegmentResult; @@ -47,8 +49,6 @@ import net.osmand.util.MapUtils; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -75,8 +75,6 @@ public class OsmAndLocationProvider implements SensorEventListener { private static final float ACCURACY_FOR_GPX_AND_ROUTING = 50; - private static final int GPS_TIMEOUT_REQUEST = 0; - private static final int GPS_DIST_REQUEST = 0; private static final int NOT_SWITCH_TO_NETWORK_WHEN_GPS_LOST_MS = 12000; private static final long LOCATION_TIMEOUT_TO_BE_STALE = 1000 * 60 * 2; // 2 minutes @@ -85,9 +83,8 @@ public class OsmAndLocationProvider implements SensorEventListener { private static final long AGPS_TO_REDOWNLOAD = 16 * 60 * 60 * 1000; // 16 hours private static final int REQUESTS_BEFORE_CHECK_LOCATION = 100; - private AtomicInteger locationRequestsCounter = new AtomicInteger(); - private AtomicInteger staleLocationRequestsCounter = new AtomicInteger(); - + private final AtomicInteger locationRequestsCounter = new AtomicInteger(); + private final AtomicInteger staleLocationRequestsCounter = new AtomicInteger(); private long lastTimeGPSLocationFixed = 0; @@ -121,23 +118,23 @@ public class OsmAndLocationProvider implements SensorEventListener { // Current screen orientation private int currentScreenOrientation; - private OsmandApplication app; + private final OsmandApplication app; - private NavigationInfo navigationInfo; - private CurrentPositionHelper currentPositionHelper; - private OsmAndLocationSimulation locationSimulation; + private final NavigationInfo navigationInfo; + private final CurrentPositionHelper currentPositionHelper; + private final OsmAndLocationSimulation locationSimulation; + private final LocationServiceHelper locationServiceHelper; private net.osmand.Location location = null; private GPSInfo gpsInfo = new GPSInfo(); - private List locationListeners = new ArrayList(); - private List compassListeners = new ArrayList(); + private List locationListeners = new ArrayList<>(); + private List compassListeners = new ArrayList<>(); private Object gpsStatusListener; private float[] mRotationM = new float[9]; - - public class SimulationProvider { + public static class SimulationProvider { private int currentRoad; private int currentSegment; private QuadPoint currentPoint; @@ -227,6 +224,7 @@ public class OsmAndLocationProvider implements SensorEventListener { navigationInfo = new NavigationInfo(app); currentPositionHelper = new CurrentPositionHelper(app); locationSimulation = new OsmAndLocationSimulation(app, this); + locationServiceHelper = app.createLocationServiceHelper(); addLocationListener(navigationInfo); addCompassListener(navigationInfo); } @@ -235,7 +233,7 @@ public class OsmAndLocationProvider implements SensorEventListener { final LocationManager service = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE); if (app.getSettings().isInternetConnectionAvailable()) { if (System.currentTimeMillis() - app.getSettings().AGPS_DATA_LAST_TIME_DOWNLOADED.get() > AGPS_TO_REDOWNLOAD) { - //force an updated check for internet connectivity here before destroying A-GPS-data + // force an updated check for internet connectivity here before destroying A-GPS-data if (app.getSettings().isInternetConnectionAvailable(true)) { redownloadAGPS(); } @@ -244,27 +242,34 @@ public class OsmAndLocationProvider implements SensorEventListener { if (isLocationPermissionAvailable(app)) { registerGpsStatusListener(service); try { - service.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_TIMEOUT_REQUEST, GPS_DIST_REQUEST, gpsListener); + locationServiceHelper.requestLocationUpdates(new LocationServiceHelper.LocationCallback() { + @Override + public void onLocationResult(@NonNull List locations) { + net.osmand.Location location = null; + if (!locations.isEmpty()) { + location = locations.get(locations.size() - 1); + lastTimeGPSLocationFixed = System.currentTimeMillis(); + } + if (!locationSimulation.isRouteAnimating()) { + setLocation(location); + } + } + }); + } catch (SecurityException e) { + // Location service permission not granted } catch (IllegalArgumentException e) { - Log.d(PlatformUtil.TAG, "GPS location provider not available"); //$NON-NLS-1$ + // GPS location provider not available } // try to always ask for network provide : it is faster way to find location - - List providers = service.getProviders(true); - if (providers == null) { - return; - } - for (String provider : providers) { - if (provider == null || provider.equals(LocationManager.GPS_PROVIDER)) { - continue; - } - try { - NetworkListener networkListener = new NetworkListener(); - service.requestLocationUpdates(provider, GPS_TIMEOUT_REQUEST, GPS_DIST_REQUEST, networkListener); - networkListeners.add(networkListener); - } catch (IllegalArgumentException e) { - Log.d(PlatformUtil.TAG, provider + " location provider not available"); //$NON-NLS-1$ - } + if (locationServiceHelper.isNetworkLocationUpdatesSupported()) { + locationServiceHelper.requestNetworkLocationUpdates(new LocationServiceHelper.LocationCallback() { + @Override + public void onLocationResult(@NonNull List locations) { + if (!locations.isEmpty() && !useOnlyGPS() && !locationSimulation.isRouteAnimating()) { + setLocation(locations.get(locations.size() - 1)); + } + } + }); } } } @@ -284,8 +289,9 @@ public class OsmAndLocationProvider implements SensorEventListener { } } - private void registerGpsStatusListener(final LocationManager service) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + @SuppressLint("MissingPermission") + private void registerGpsStatusListener(@NonNull final LocationManager service) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { gpsStatusListener = new GnssStatus.Callback() { @Override @@ -320,7 +326,7 @@ public class OsmAndLocationProvider implements SensorEventListener { updateLocation(location); } }; - service.registerGnssStatusCallback((GnssStatus.Callback) gpsStatusListener); + service.registerGnssStatusCallback((GnssStatus.Callback) gpsStatusListener, null); } else { gpsStatusListener = new Listener() { private GpsStatus gpsStatus; @@ -335,14 +341,12 @@ public class OsmAndLocationProvider implements SensorEventListener { } } - private void updateGPSInfo(GpsStatus s) { + private void updateGPSInfo(@Nullable GpsStatus s) { boolean fixed = false; int n = 0; int u = 0; if (s != null) { - Iterator iterator = s.getSatellites().iterator(); - while (iterator.hasNext()) { - GpsSatellite g = iterator.next(); + for (GpsSatellite g : s.getSatellites()) { n++; if (g.usedInFix()) { u++; @@ -354,7 +358,8 @@ public class OsmAndLocationProvider implements SensorEventListener { gpsInfo.foundSatellites = n; gpsInfo.usedSatellites = u; } - + + @NonNull public GPSInfo getGPSInfo(){ return gpsInfo; } @@ -363,51 +368,29 @@ public class OsmAndLocationProvider implements SensorEventListener { currentScreenOrientation = orientation; } - public void addLocationListener(OsmAndLocationListener listener){ - if(!locationListeners.contains(listener)) { + public void addLocationListener(@NonNull OsmAndLocationListener listener) { + if (!locationListeners.contains(listener)) { locationListeners.add(listener); } } - public void removeLocationListener(OsmAndLocationListener listener){ + public void removeLocationListener(@NonNull OsmAndLocationListener listener) { locationListeners.remove(listener); } - public void addCompassListener(OsmAndCompassListener listener){ - if(!compassListeners.contains(listener)) { + public void addCompassListener(@NonNull OsmAndCompassListener listener) { + if (!compassListeners.contains(listener)) { compassListeners.add(listener); } } - public void removeCompassListener(OsmAndCompassListener listener){ + public void removeCompassListener(@NonNull OsmAndCompassListener listener) { compassListeners.remove(listener); } + @Nullable public net.osmand.Location getFirstTimeRunDefaultLocation() { - if (!isLocationPermissionAvailable(app)) { - return null; - } - LocationManager service = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE); - List ps = service.getProviders(true); - if(ps == null) { - return null; - } - List providers = new ArrayList(ps); - // note, passive provider is from API_LEVEL 8 but it is a constant, we can check for it. - // constant should not be changed in future - int passiveFirst = providers.indexOf("passive"); // LocationManager.PASSIVE_PROVIDER - // put passive provider to first place - if (passiveFirst > -1) { - providers.add(0, providers.remove(passiveFirst)); - } - // find location - for (String provider : providers) { - net.osmand.Location location = convertLocation(service.getLastKnownLocation(provider), app); - if (location != null) { - return location; - } - } - return null; + return isLocationPermissionAvailable(app) ? locationServiceHelper.getFirstTimeRunDefaultLocation() : null; } public synchronized void registerOrUnregisterCompassListener(boolean register) { @@ -466,10 +449,7 @@ public class OsmAndLocationProvider implements SensorEventListener { } private boolean isRunningOnEmulator() { - if (Build.DEVICE.equals("generic")) { //$NON-NLS-1$ - return true; - } - return false; + return Build.DEVICE.equals("generic"); } @Override @@ -599,78 +579,25 @@ public class OsmAndLocationProvider implements SensorEventListener { return MapUtils.unifyRotationTo360((float) (Math.atan2(sinA, cosA) * 180 / Math.PI)); } - private void updateLocation(net.osmand.Location loc) { for (OsmAndLocationListener l : locationListeners) { l.updateLocation(loc); } } - - - private LocationListener gpsListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - if (location != null) { - // lastTimeGPSLocationFixed = location.getTime(); - lastTimeGPSLocationFixed = System.currentTimeMillis(); - } - if(!locationSimulation.isRouteAnimating()) { - setLocation(convertLocation(location, app)); - } - } - - @Override - public void onProviderDisabled(String provider) { - } - - @Override - public void onProviderEnabled(String provider) { - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - private LinkedList networkListeners = new LinkedList(); - private boolean useOnlyGPS() { - if(app.getRoutingHelper().isFollowingMode()) { + if (app.getRoutingHelper().isFollowingMode()) { return true; } - if((System.currentTimeMillis() - lastTimeGPSLocationFixed) < NOT_SWITCH_TO_NETWORK_WHEN_GPS_LOST_MS) { + if ((System.currentTimeMillis() - lastTimeGPSLocationFixed) < NOT_SWITCH_TO_NETWORK_WHEN_GPS_LOST_MS) { return true; } - if(isRunningOnEmulator()) { + if (isRunningOnEmulator()) { return true; } return false; } - // Working with location checkListeners - private class NetworkListener implements LocationListener { - - @Override - public void onLocationChanged(Location location) { - if (!useOnlyGPS() && !locationSimulation.isRouteAnimating()) { - setLocation(convertLocation(location, app)); - } - } - - @Override - public void onProviderDisabled(String provider) { - } - - @Override - public void onProviderEnabled(String provider) { - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - } - - }; - private void stopLocationRequests() { LocationManager service = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE); if (gpsStatusListener != null) { @@ -680,9 +607,10 @@ public class OsmAndLocationProvider implements SensorEventListener { service.removeGpsStatusListener((Listener) gpsStatusListener); } } - service.removeUpdates(gpsListener); - while (!networkListeners.isEmpty()) { - service.removeUpdates(networkListeners.poll()); + try { + locationServiceHelper.removeLocationUpdates(); + } catch (SecurityException e) { + // Location service permission not granted } } @@ -963,7 +891,7 @@ public class OsmAndLocationProvider implements SensorEventListener { } public static boolean isNotSimulatedLocation(net.osmand.Location l) { - if(l != null) { + if (l != null) { return !SIMULATED_PROVIDER.equals(l.getProvider()); } return true; @@ -984,7 +912,7 @@ public class OsmAndLocationProvider implements SensorEventListener { networkenabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } catch(Exception ex) {} - if(!gpsenabled && !networkenabled) { + if (!gpsenabled && !networkenabled) { // notify user AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setMessage(context.getResources().getString(R.string.gps_network_not_enabled)); @@ -1003,11 +931,8 @@ public class OsmAndLocationProvider implements SensorEventListener { } public static boolean isLocationPermissionAvailable(Context context) { - if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - return false; - } - return true; + return ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED; } public static void requestFineLocationPermissionIfNeeded(Activity activity) { diff --git a/OsmAnd/src/net/osmand/plus/OsmandApplication.java b/OsmAnd/src/net/osmand/plus/OsmandApplication.java index 8deb9c81a8..842a36237e 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandApplication.java +++ b/OsmAnd/src/net/osmand/plus/OsmandApplication.java @@ -57,6 +57,7 @@ import net.osmand.plus.download.DownloadService; import net.osmand.plus.download.IndexItem; import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.helpers.DayNightHelper; +import net.osmand.plus.helpers.LocationServiceHelper; import net.osmand.plus.helpers.LockHelper; import net.osmand.plus.helpers.WaypointHelper; import net.osmand.plus.helpers.enums.DrivingRegion; @@ -300,7 +301,11 @@ public class OsmandApplication extends MultiDexApplication { public QuickActionRegistry getQuickActionRegistry() { return quickActionRegistry; } - + + public LocationServiceHelper createLocationServiceHelper() { + return new LocationServiceHelperImpl(this); + } + public void setAppCustomization(OsmAndAppCustomization appCustomization) { this.appCustomization = appCustomization; this.appCustomization.setup(this); diff --git a/OsmAnd/src/net/osmand/plus/helpers/DayNightHelper.java b/OsmAnd/src/net/osmand/plus/helpers/DayNightHelper.java index d3ebe9d6ae..20820d379e 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/DayNightHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/DayNightHelper.java @@ -43,10 +43,10 @@ public class DayNightHelper implements SensorEventListener { private static final Log log = PlatformUtil.getLog(DayNightHelper.class); - private final OsmandApplication osmandApplication; + private final OsmandApplication app; - public DayNightHelper(OsmandApplication osmandApplication) { - this.osmandApplication = osmandApplication; + public DayNightHelper(OsmandApplication app) { + this.app = app; } private DayNightHelper listener; @@ -56,11 +56,11 @@ public class DayNightHelper implements SensorEventListener { private StateChangedListener sensorStateListener; public boolean isNightModeForMapControls() { - return isNightModeForMapControlsForProfile(osmandApplication.getSettings().APPLICATION_MODE.get()); + return isNightModeForMapControlsForProfile(app.getSettings().APPLICATION_MODE.get()); } public boolean isNightModeForMapControlsForProfile(ApplicationMode mode) { - if (osmandApplication.getSettings().isLightContentForMode(mode)) { + if (app.getSettings().isLightContentForMode(mode)) { return isNightModeForProfile(mode); } else { return true; @@ -72,11 +72,11 @@ public class DayNightHelper implements SensorEventListener { * @return true if day is supposed to be */ public boolean isNightMode() { - return isNightModeForProfile(osmandApplication.getSettings().APPLICATION_MODE.get()); + return isNightModeForProfile(app.getSettings().APPLICATION_MODE.get()); } public boolean isNightModeForProfile(ApplicationMode mode) { - DayNightMode dayNightMode = osmandApplication.getSettings().DAYNIGHT_MODE.getModeValue(mode); + DayNightMode dayNightMode = app.getSettings().DAYNIGHT_MODE.getModeValue(mode); if (dayNightMode.isDay()) { return false; } else if (dayNightMode.isNight()) { @@ -108,24 +108,23 @@ public class DayNightHelper implements SensorEventListener { } public SunriseSunset getSunriseSunset() { - Location lastKnownLocation = osmandApplication.getLocationProvider().getLastKnownLocation(); - if(lastKnownLocation == null) { - lastKnownLocation = osmandApplication.getLocationProvider().getFirstTimeRunDefaultLocation(); + Location lastKnownLocation = app.getLocationProvider().getLastKnownLocation(); + if (lastKnownLocation == null) { + lastKnownLocation = app.getLocationProvider().getFirstTimeRunDefaultLocation(); } if (lastKnownLocation == null) { return null; } double longitude = lastKnownLocation.getLongitude(); Date actualTime = new Date(); - SunriseSunset daynightSwitch = new SunriseSunset(lastKnownLocation.getLatitude(), + return new SunriseSunset(lastKnownLocation.getLatitude(), longitude < 0 ? 360 + longitude : longitude, actualTime, TimeZone.getDefault()); - return daynightSwitch; } public void stopSensorIfNeeded() { if (listener != null) { - SensorManager mSensorManager = (SensorManager) osmandApplication + SensorManager mSensorManager = (SensorManager) app .getSystemService(Context.SENSOR_SERVICE); Sensor mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); mSensorManager.unregisterListener(listener, mLight); @@ -135,9 +134,9 @@ public class DayNightHelper implements SensorEventListener { public void startSensorIfNeeded(StateChangedListener sensorStateListener) { this.sensorStateListener = sensorStateListener; - DayNightMode dayNightMode = osmandApplication.getSettings().DAYNIGHT_MODE.get(); + DayNightMode dayNightMode = app.getSettings().DAYNIGHT_MODE.get(); if (listener == null && dayNightMode.isSensor()) { - SensorManager mSensorManager = (SensorManager) osmandApplication.getSystemService(Context.SENSOR_SERVICE); + SensorManager mSensorManager = (SensorManager) app.getSystemService(Context.SENSOR_SERVICE); Sensor mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); List list = mSensorManager.getSensorList(Sensor.TYPE_LIGHT); log.info("Light sensors:" + list.size()); //$NON-NLS-1$ diff --git a/OsmAnd/src/net/osmand/plus/helpers/LocationServiceHelper.java b/OsmAnd/src/net/osmand/plus/helpers/LocationServiceHelper.java new file mode 100644 index 0000000000..94602e98fc --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/helpers/LocationServiceHelper.java @@ -0,0 +1,29 @@ +package net.osmand.plus.helpers; + +import androidx.annotation.NonNull; + +import net.osmand.Location; + +import java.util.List; + +public abstract class LocationServiceHelper { + + public static abstract class LocationCallback { + + public void onLocationResult(@NonNull List locations) { + } + + public void onLocationAvailability(boolean locationAvailable) { + } + } + + public abstract void requestLocationUpdates(@NonNull LocationCallback locationCallback); + + public abstract boolean isNetworkLocationUpdatesSupported(); + + public abstract void requestNetworkLocationUpdates(@NonNull LocationCallback locationCallback); + + public abstract void removeLocationUpdates(); + + public abstract Location getFirstTimeRunDefaultLocation(); +}