Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Improve getCurrentPosition API #15094

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ android_library(
"PUBLIC",
],
deps = [
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/bridge:bridge"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;

import com.facebook.react.common.ReactConstants;
import com.facebook.common.logging.FLog;

import javax.annotation.Nullable;

/**
Expand Down Expand Up @@ -129,13 +132,13 @@ public void getCurrentPosition(
return;
}
Location location = locationManager.getLastKnownLocation(provider);
if (location != null &&
SystemClock.currentTimeMillis() - location.getTime() < locationOptions.maximumAge) {
if (location != null && (SystemClock.currentTimeMillis() - location.getTime()) < locationOptions.maximumAge) {
success.invoke(locationToMap(location));
return;
}

new SingleUpdateRequest(locationManager, provider, locationOptions.timeout, success, error)
.invoke();
.invoke(location);
} catch (SecurityException e) {
throwLocationPermissionMissing(e);
}
Expand Down Expand Up @@ -246,6 +249,7 @@ private static class SingleUpdateRequest {
private final LocationManager mLocationManager;
private final String mProvider;
private final long mTimeout;
private Location mOldLocation;
private final Handler mHandler = new Handler();
private final Runnable mTimeoutRunnable = new Runnable() {
@Override
Expand All @@ -254,6 +258,7 @@ public void run() {
if (!mTriggered) {
mError.invoke(PositionError.buildError(PositionError.TIMEOUT, "Location request timed out"));
mLocationManager.removeUpdates(mLocationListener);
FLog.i(ReactConstants.TAG, "LocationModule: Location request timed out");
mTriggered = true;
}
}
Expand All @@ -263,11 +268,14 @@ public void run() {
@Override
public void onLocationChanged(Location location) {
synchronized (SingleUpdateRequest.this) {
if (!mTriggered) {
if (!mTriggered && isBetterLocation(location, mOldLocation)) {
mSuccess.invoke(locationToMap(location));
mHandler.removeCallbacks(mTimeoutRunnable);
mTriggered = true;
mLocationManager.removeUpdates(mLocationListener);
}

mOldLocation = location;
}
}

Expand Down Expand Up @@ -295,9 +303,69 @@ private SingleUpdateRequest(
mError = error;
}

public void invoke() {
mLocationManager.requestSingleUpdate(mProvider, mLocationListener, null);
public void invoke(Location location) {
mOldLocation = location;
mLocationManager.requestLocationUpdates(mProvider, 100, 1, mLocationListener);
mHandler.postDelayed(mTimeoutRunnable, mTimeout);
}

private static final int TWO_MINUTES = 1000 * 60 * 2;

/** Determines whether one Location reading is better than the current Location fix
* taken from Android Examples https://developer.android.com/guide/topics/location/strategies.html
*
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
private boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}

// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;

// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}

// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;

// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());

// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}

return false;
}

/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
}
}