Skip to content

Commit

Permalink
Fix inaccurate location readings (#1324)
Browse files Browse the repository at this point in the history
* Use LocationManagerCompat

* Update version and CHANGELOG

* Use `PASSIVE_PROVIDER` on `LocationAccuracy.lowest`

* Update provider resolving logic and use PASSIVE_INTERVAL
  • Loading branch information
JeroenWeener authored Sep 14, 2023
1 parent 22d0c4e commit 035227d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 57 deletions.
6 changes: 5 additions & 1 deletion geolocator_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## 4.2.4

* Fixes a bug where location readings were very inaccurate when using `forceLocationManager: true`.

## 4.2.3

* Fixes a bug when requesting a position stream where positions are unnecessarily filtered based off their accuracy.
* Fixes a bug where the position stream was unnecessarily filtered when using `forceLocationManager: true`.

## 4.2.2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.location.LocationListenerCompat;
import androidx.core.location.LocationManagerCompat;
import androidx.core.location.LocationRequestCompat;

import com.baseflow.geolocator.errors.ErrorCallback;
import com.baseflow.geolocator.errors.ErrorCodes;

import java.util.List;

class LocationManagerClient implements LocationClient, LocationListener {
class LocationManagerClient implements LocationClient, LocationListenerCompat {

private static final long TWO_MINUTES = 120000;
private final LocationManager locationManager;
Expand Down Expand Up @@ -73,45 +75,40 @@ static boolean isBetterLocation(Location location, Location bestLocation) {
return false;
}

private static String getBestProvider(
LocationManager locationManager, LocationAccuracy accuracy) {
Criteria criteria = new Criteria();

criteria.setBearingRequired(false);
criteria.setAltitudeRequired(false);
criteria.setSpeedRequired(false);

switch (accuracy) {
case lowest:
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
break;
case low:
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
criteria.setHorizontalAccuracy(Criteria.ACCURACY_LOW);
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
break;
case medium:
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
criteria.setHorizontalAccuracy(Criteria.ACCURACY_MEDIUM);
criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
break;
default:
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
break;
}

String provider = locationManager.getBestProvider(criteria, true);

if (provider.trim().isEmpty()) {
List<String> providers = locationManager.getProviders(true);
if (providers.size() > 0) provider = providers.get(0);
}
private static @Nullable String determineProvider(
@NonNull LocationManager locationManager,
@NonNull LocationAccuracy accuracy) {

final List<String> enabledProviders = locationManager.getProviders(true);

if (accuracy == LocationAccuracy.lowest) {
return LocationManager.PASSIVE_PROVIDER;
} else if (enabledProviders.contains(LocationManager.FUSED_PROVIDER) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
return LocationManager.FUSED_PROVIDER;
} else if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
return LocationManager.GPS_PROVIDER;
} else if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
return LocationManager.NETWORK_PROVIDER;
} else if (!enabledProviders.isEmpty()){
return enabledProviders.get(0);
} else {
return null;
}
}

return provider;
private static @LocationRequestCompat.Quality int accuracyToQuality(@NonNull LocationAccuracy accuracy) {
switch (accuracy) {
case lowest:
case low:
return LocationRequestCompat.QUALITY_LOW_POWER;
case high:
case best:
case bestForNavigation:
return LocationRequestCompat.QUALITY_HIGH_ACCURACY;
case medium:
default:
return LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY;
}
}

@Override
Expand Down Expand Up @@ -161,27 +158,41 @@ public void startPositionUpdates(
this.positionChangedCallback = positionChangedCallback;
this.errorCallback = errorCallback;

LocationAccuracy locationAccuracy =
this.locationOptions != null ? this.locationOptions.getAccuracy() : LocationAccuracy.best;
LocationAccuracy accuracy = LocationAccuracy.best;
long timeInterval = 0;
float distanceFilter = 0;
@LocationRequestCompat.Quality int quality = LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY;

this.currentLocationProvider = getBestProvider(this.locationManager, locationAccuracy);
if (this.locationOptions != null) {
distanceFilter = locationOptions.getDistanceFilter();
accuracy = locationOptions.getAccuracy();
timeInterval = accuracy == LocationAccuracy.lowest
? LocationRequestCompat.PASSIVE_INTERVAL
: locationOptions.getTimeInterval();
quality = accuracyToQuality(accuracy);
}

this.currentLocationProvider = determineProvider(this.locationManager, accuracy);

if (this.currentLocationProvider.trim().isEmpty()) {
if (this.currentLocationProvider == null) {
errorCallback.onError(ErrorCodes.locationServicesDisabled);
return;
}

long timeInterval = 0;
float distanceFilter = 0;
if (this.locationOptions != null) {
timeInterval = locationOptions.getTimeInterval();
distanceFilter = locationOptions.getDistanceFilter();
}
final LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(timeInterval)
.setMinUpdateDistanceMeters(distanceFilter)
.setQuality(quality)
.build();

this.isListening = true;
this.nmeaClient.start();
this.locationManager.requestLocationUpdates(
this.currentLocationProvider, timeInterval, distanceFilter, this, Looper.getMainLooper());

LocationManagerCompat.requestLocationUpdates(
this.locationManager,
this.currentLocationProvider,
locationRequest,
this,
Looper.getMainLooper());
}

@SuppressLint("MissingPermission")
Expand All @@ -206,7 +217,7 @@ public synchronized void onLocationChanged(Location location) {

@TargetApi(28)
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
public void onStatusChanged(@NonNull String provider, int status, Bundle extras) {
if (status == android.location.LocationProvider.AVAILABLE) {
onProviderEnabled(provider);
} else if (status == android.location.LocationProvider.OUT_OF_SERVICE) {
Expand All @@ -215,7 +226,7 @@ public void onStatusChanged(String provider, int status, Bundle extras) {
}

@Override
public void onProviderEnabled(String provider) {}
public void onProviderEnabled(@NonNull String provider) {}

@SuppressLint("MissingPermission")
@Override
Expand Down
2 changes: 1 addition & 1 deletion geolocator_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: geolocator_android
description: Geolocation plugin for Flutter. This plugin provides the Android implementation for the geolocator.
repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_android
issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen
version: 4.2.3
version: 4.2.4

environment:
sdk: ">=2.15.0 <4.0.0"
Expand Down

0 comments on commit 035227d

Please sign in to comment.