From 109036b4c4b530c04c394c48e43319ca91ca2d53 Mon Sep 17 00:00:00 2001 From: Christopher Dro Date: Fri, 5 Feb 2016 16:54:14 -0800 Subject: [PATCH] Expose option for distance filtering on location updates. Summary: My original implementation involved creating a `RCT_ENUM_CONVERTER` with `CLLocationAccuracy` on iOS and a Hashmap on Android that would convert `string` values to `doubles` for distance filtering. I got this to work just fine but realized that I made things more complicated than they needed to be and simplified everything by just have the option be a decimal value (in meters) that works both for iOS and Android. The only thing i'm not sure about is if we can set arbitrary values for CLLocationManager's distance filter. nicklockwood Any idea? Closes https://github.com/facebook/react-native/pull/5563 Reviewed By: svcscm Differential Revision: D2908250 Pulled By: nicklockwood fb-gh-sync-id: d83c12b3ce7c343f413749a2cd614b3bf04d6750 --- Libraries/Geolocation/Geolocation.js | 3 ++- Libraries/Geolocation/RCTLocationObserver.m | 10 ++++++++-- .../react/modules/location/LocationModule.java | 11 ++++++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index 82bc1c9a0..42d7378eb 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -26,6 +26,7 @@ type GeoOptions = { timeout: number; maximumAge: number; enableHighAccuracy: bool; + distanceFilter: number; } /** @@ -68,7 +69,7 @@ var Geolocation = { /* * Invokes the success callback whenever the location changes. Supported - * options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool) + * options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool), distanceFilter(m) */ watchPosition: function(success: Function, error?: Function, options?: GeoOptions): number { if (!updatesEnabled) { diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m index 63ceb7c9d..7320fae89 100644 --- a/Libraries/Geolocation/RCTLocationObserver.m +++ b/Libraries/Geolocation/RCTLocationObserver.m @@ -31,6 +31,7 @@ typedef struct { double timeout; double maximumAge; double accuracy; + double distanceFilter; } RCTLocationOptions; @implementation RCTConvert (RCTLocationOptions) @@ -38,10 +39,15 @@ typedef struct { + (RCTLocationOptions)RCTLocationOptions:(id)json { NSDictionary *options = [RCTConvert NSDictionary:json]; + + double distanceFilter = options[@"distanceFilter"] == NULL ? RCT_DEFAULT_LOCATION_ACCURACY + : [RCTConvert double:options[@"distanceFilter"]] ?: kCLDistanceFilterNone; + return (RCTLocationOptions){ .timeout = [RCTConvert NSTimeInterval:options[@"timeout"]] ?: INFINITY, .maximumAge = [RCTConvert NSTimeInterval:options[@"maximumAge"]] ?: INFINITY, - .accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY + .accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY, + .distanceFilter = distanceFilter }; } @@ -128,7 +134,7 @@ RCT_EXPORT_MODULE() { if (!_locationManager) { _locationManager = [CLLocationManager new]; - _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY; + _locationManager.distanceFilter = _observerOptions.distanceFilter; _locationManager.delegate = self; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java index 9973563fc..86dec164b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java @@ -36,6 +36,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEm public class LocationModule extends ReactContextBaseJavaModule { private @Nullable String mWatchedProvider; + private static final float RCT_DEFAULT_LOCATION_ACCURACY = 100; private final LocationListener mLocationListener = new LocationListener() { @Override @@ -73,11 +74,13 @@ public class LocationModule extends ReactContextBaseJavaModule { private final long timeout; private final double maximumAge; private final boolean highAccuracy; + private final float distanceFilter; - private LocationOptions(long timeout, double maximumAge, boolean highAccuracy) { + private LocationOptions(long timeout, double maximumAge, boolean highAccuracy, float distanceFilter) { this.timeout = timeout; this.maximumAge = maximumAge; this.highAccuracy = highAccuracy; + this.distanceFilter = distanceFilter; } private static LocationOptions fromReactMap(ReadableMap map) { @@ -88,8 +91,10 @@ public class LocationModule extends ReactContextBaseJavaModule { map.hasKey("maximumAge") ? map.getDouble("maximumAge") : Double.POSITIVE_INFINITY; boolean highAccuracy = map.hasKey("enableHighAccuracy") && map.getBoolean("enableHighAccuracy"); + float distanceFilter = + map.hasKey("distanceFilter") ? (float) map.getDouble("distanceFilter") : RCT_DEFAULT_LOCATION_ACCURACY; - return new LocationOptions(timeout, maximumAge, highAccuracy); + return new LocationOptions(timeout, maximumAge, highAccuracy, distanceFilter); } } @@ -151,7 +156,7 @@ public class LocationModule extends ReactContextBaseJavaModule { } if (!provider.equals(mWatchedProvider)) { locationManager.removeUpdates(mLocationListener); - locationManager.requestLocationUpdates(provider, 1000, 0, mLocationListener); + locationManager.requestLocationUpdates(provider, 1000, locationOptions.distanceFilter, mLocationListener); } mWatchedProvider = provider; } catch (SecurityException e) {