diff --git a/geolocator/lib/geolocator.dart b/geolocator/lib/geolocator.dart index 008796a3c..9662d7a84 100644 --- a/geolocator/lib/geolocator.dart +++ b/geolocator/lib/geolocator.dart @@ -8,6 +8,7 @@ import 'package:geolocator_platform_interface/geolocator_platform_interface.dart export 'package:geolocator_android/geolocator_android.dart' show AndroidSettings, + AndroidLocationProvider, ForegroundNotificationConfig, AndroidResource, AndroidPosition; diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/errors/ErrorCodes.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/errors/ErrorCodes.java index cea4141e1..38ef1f046 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/errors/ErrorCodes.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/errors/ErrorCodes.java @@ -34,7 +34,7 @@ public String toDescription() { case errorWhileAcquiringPosition: return "An unexpected error occurred while trying to acquire the device's position."; case locationServicesDisabled: - return "Location services are disabled. To receive location updates the location services should be enabled."; + return "Location services are disabled or requested location provider is unavailable. To receive location updates the location services must be enabled. When forcing a specific provider, it must be available on the device."; case permissionDefinitionsNotFound: return "No location permissions are defined in the manifest. Make sure at least ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION are defined in the manifest."; case permissionDenied: diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java index c8b3e59a0..e2b9fa31c 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java @@ -77,11 +77,14 @@ static boolean isBetterLocation(Location location, Location bestLocation) { private static @Nullable String determineProvider( @NonNull LocationManager locationManager, - @NonNull LocationAccuracy accuracy) { + @NonNull LocationAccuracy accuracy, + @Nullable String forceProvider) { final List enabledProviders = locationManager.getProviders(true); - if (accuracy == LocationAccuracy.lowest) { + if (forceProvider != null) { + return enabledProviders.contains(forceProvider) ? forceProvider : null; + } else 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; @@ -172,7 +175,10 @@ public void startPositionUpdates( quality = accuracyToQuality(accuracy); } - this.currentLocationProvider = determineProvider(this.locationManager, accuracy); + this.currentLocationProvider = determineProvider( + this.locationManager, + accuracy, + locationOptions != null ? locationOptions.getForceProvider() : null); if (this.currentLocationProvider == null) { errorCallback.onError(ErrorCodes.locationServicesDisabled); diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationOptions.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationOptions.java index 9087c8270..ee2764f4e 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationOptions.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationOptions.java @@ -1,5 +1,7 @@ package com.baseflow.geolocator.location; +import androidx.annotation.Nullable; + import java.util.Map; public class LocationOptions { @@ -9,24 +11,27 @@ public class LocationOptions { private final long distanceFilter; private final long timeInterval; private final boolean useMSLAltitude; + private final String forceProvider; private LocationOptions( - LocationAccuracy accuracy, long distanceFilter, long timeInterval, boolean useMSLAltitude) { + LocationAccuracy accuracy, long distanceFilter, long timeInterval, boolean useMSLAltitude, String provider) { this.accuracy = accuracy; this.distanceFilter = distanceFilter; this.timeInterval = timeInterval; this.useMSLAltitude = useMSLAltitude; + this.forceProvider = provider; } public static LocationOptions parseArguments(Map arguments) { if (arguments == null) { - return new LocationOptions(LocationAccuracy.best, 0, 5000, false); + return new LocationOptions(LocationAccuracy.best, 0, 5000, false, null); } final Integer accuracy = (Integer) arguments.get("accuracy"); final Integer distanceFilter = (Integer) arguments.get("distanceFilter"); final Integer timeInterval = (Integer) arguments.get("timeInterval"); final Boolean useMSLAltitude = (Boolean) arguments.get("useMSLAltitude"); + final String provider = (String) arguments.get("forceProvider"); LocationAccuracy locationAccuracy = LocationAccuracy.best; @@ -54,10 +59,11 @@ public static LocationOptions parseArguments(Map arguments) { } return new LocationOptions( - locationAccuracy, - distanceFilter != null ? distanceFilter : 0, - timeInterval != null ? timeInterval : 5000, - useMSLAltitude != null && useMSLAltitude); + locationAccuracy, + distanceFilter != null ? distanceFilter : 0, + timeInterval != null ? timeInterval : 5000, + useMSLAltitude != null && useMSLAltitude, + provider); } public LocationAccuracy getAccuracy() { @@ -75,4 +81,9 @@ public long getTimeInterval() { public boolean isUseMSLAltitude() { return useMSLAltitude; } + + @Nullable + public String getForceProvider() { + return forceProvider; + } } diff --git a/geolocator_android/lib/geolocator_android.dart b/geolocator_android/lib/geolocator_android.dart index c15a7c21f..dabc9fd7a 100644 --- a/geolocator_android/lib/geolocator_android.dart +++ b/geolocator_android/lib/geolocator_android.dart @@ -16,7 +16,8 @@ export 'package:geolocator_platform_interface/geolocator_platform_interface.dart ServiceStatus; export 'src/geolocator_android.dart'; -export 'src/types/android_settings.dart' show AndroidSettings; +export 'src/types/android_settings.dart' + show AndroidSettings, AndroidLocationProvider; export 'src/types/android_position.dart' show AndroidPosition; export 'src/types/foreground_settings.dart' show AndroidResource, ForegroundNotificationConfig; diff --git a/geolocator_android/lib/src/types/android_settings.dart b/geolocator_android/lib/src/types/android_settings.dart index fea5dfb01..ad674056d 100644 --- a/geolocator_android/lib/src/types/android_settings.dart +++ b/geolocator_android/lib/src/types/android_settings.dart @@ -17,6 +17,7 @@ class AndroidSettings extends LocationSettings { Duration? timeLimit, this.foregroundNotificationConfig, this.useMSLAltitude = false, + this.forceProvider, }) : super( accuracy: accuracy, distanceFilter: distanceFilter, @@ -74,6 +75,11 @@ class AndroidSettings extends LocationSettings { /// Defaults to false final bool useMSLAltitude; + /// Set this to use a specific [AndroidLocationProvider]. + /// Set this value only in conjunction with [forceLocationManager] set to true. Be sure the provider is available on your targeted devices. + /// Defaults to null. + final AndroidLocationProvider? forceProvider; + @override Map toJson() { return super.toJson() @@ -82,6 +88,22 @@ class AndroidSettings extends LocationSettings { 'timeInterval': intervalDuration?.inMilliseconds, 'foregroundNotificationConfig': foregroundNotificationConfig?.toJson(), 'useMSLAltitude': useMSLAltitude, + 'forceProvider': forceProvider?.name, }); } } + +/// Represents the different [Android location providers](https://developer.android.com/reference/android/location/LocationManager#constants_1) +enum AndroidLocationProvider { + /// [GPS_PROVIDER](https://developer.android.com/reference/android/location/LocationManager#GPS_PROVIDER) + gps, + + /// [FUSED_PROVIDER](https://developer.android.com/reference/android/location/LocationManager#FUSED_PROVIDER) + fused, + + /// [NETWORK_PROVIDER](https://developer.android.com/reference/android/location/LocationManager#NETWORK_PROVIDER) + network, + + /// [PASSIVE_PROVIDER](https://developer.android.com/reference/android/location/LocationManager#PASSIVE_PROVIDER) + passive, +}