aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java12
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java3
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java2
-rw-r--r--main/src/cgeo/geocaching/playservices/LocationProvider.java5
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoData.java63
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoDataProvider.java129
6 files changed, 105 insertions, 109 deletions
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index 556acb8..73eaaee 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -16,6 +16,8 @@ import cgeo.geocaching.utils.RxUtils;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
+import org.eclipse.jdt.annotation.NonNull;
+
import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func1;
@@ -35,13 +37,15 @@ public class CgeoApplication extends Application {
private Observable<IGeoData> geoDataObservableLowPower;
private Observable<Float> directionObservable;
private Observable<Status> gpsStatusObservable;
- private volatile IGeoData currentGeo = GeoData.dummyLocation();
+ @NonNull private volatile IGeoData currentGeo = GeoData.DUMMY_LOCATION;
+ private volatile boolean hasValidLocation = false;
private volatile float currentDirection = 0.0f;
private boolean isGooglePlayServicesAvailable = false;
private final Action1<IGeoData> rememberGeodataAction = new Action1<IGeoData>() {
@Override
public void call(final IGeoData geoData) {
currentGeo = geoData;
+ hasValidLocation = true;
}
};
@@ -82,6 +86,7 @@ public class CgeoApplication extends Application {
}
// ensure initialization of lists
DataStore.getLists();
+
// Check if Google Play services is available
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
isGooglePlayServicesAvailable = true;
@@ -150,10 +155,15 @@ public class CgeoApplication extends Application {
return gpsStatusObservable;
}
+ @NonNull
public IGeoData currentGeo() {
return currentGeo;
}
+ public boolean hasValidLocation() {
+ return hasValidLocation;
+ }
+
public Float distanceNonBlocking(final ICoordinates target) {
if (target.getCoords() == null) {
return null;
diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java
index 8377091..7049712 100644
--- a/main/src/cgeo/geocaching/MainActivity.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -213,6 +213,9 @@ public class MainActivity extends AbstractActionBarActivity {
super.onResume(locationUpdater.start(GeoDirHandler.UPDATE_GEODATA | GeoDirHandler.LOW_POWER),
app.gpsStatusObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(satellitesHandler));
updateUserInfoHandler.sendEmptyMessage(-1);
+ if (app.hasValidLocation()) {
+ locationUpdater.updateGeoData(app.currentGeo());
+ }
startBackgroundLogin();
init();
}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index c9894e2..4b91fff 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -898,7 +898,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// minimum change of location in fraction of map width/height (whatever is smaller) for position overlay update
private static final float MIN_LOCATION_DELTA = 0.01f;
- Location currentLocation = new Location("");
+ Location currentLocation = CgeoApplication.getInstance().currentGeo().getLocation();
float currentHeading;
private long timeLastPositionOverlayCalculation = 0;
diff --git a/main/src/cgeo/geocaching/playservices/LocationProvider.java b/main/src/cgeo/geocaching/playservices/LocationProvider.java
index 4035078..ab2c057 100644
--- a/main/src/cgeo/geocaching/playservices/LocationProvider.java
+++ b/main/src/cgeo/geocaching/playservices/LocationProvider.java
@@ -124,7 +124,10 @@ public class LocationProvider implements ConnectionCallbacks, OnConnectionFailed
* @param context the context used to retrieve the system services
*/
private LocationProvider(final Context context) {
- subject.onNext(GeoData.dummyLocation());
+ final IGeoData initialLocation = GeoData.getInitialLocation(context);
+ if (initialLocation != null) {
+ subject.onNext(initialLocation);
+ }
locationClient = new LocationClient(context, this, this);
locationClient.connect();
}
diff --git a/main/src/cgeo/geocaching/sensors/GeoData.java b/main/src/cgeo/geocaching/sensors/GeoData.java
index 1291d3c..fabf0f6 100644
--- a/main/src/cgeo/geocaching/sensors/GeoData.java
+++ b/main/src/cgeo/geocaching/sensors/GeoData.java
@@ -2,20 +2,44 @@ package cgeo.geocaching.sensors;
import cgeo.geocaching.enumerations.LocationProviderType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.Log;
+import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
+import javax.annotation.Nullable;
+
public class GeoData extends Location implements IGeoData {
public static final String INITIAL_PROVIDER = "initial";
public static final String FUSED_PROVIDER = "fused";
public static final String LOW_POWER_PROVIDER = "low-power";
+ // Some devices will not have the last position available (for example the emulator). In this case,
+ // rather than waiting forever for a position update which might never come, we emulate it by placing
+ // the user arbitrarly at Paris Notre-Dame, one of the most visited free tourist attractions in the world.
+ final public static GeoData DUMMY_LOCATION = new GeoData(new Location(INITIAL_PROVIDER));
+ static {
+ DUMMY_LOCATION.setLatitude(48.85308);
+ DUMMY_LOCATION.setLongitude(2.34962);
+ }
+
public GeoData(final Location location) {
super(location);
}
+ @Nullable
+ static Location best(@Nullable final Location gpsLocation, @Nullable final Location netLocation) {
+ if (isRecent(gpsLocation) || !(netLocation != null)) {
+ return gpsLocation;
+ }
+ if (!(gpsLocation != null)) {
+ return netLocation;
+ }
+ return gpsLocation.getTime() >= netLocation.getTime() ? gpsLocation : netLocation;
+ }
+
@Override
public Location getLocation() {
return this;
@@ -48,13 +72,36 @@ public class GeoData extends Location implements IGeoData {
return new Geopoint(this);
}
- // Some devices will not have the last position available (for example the emulator). In this case,
- // rather than waiting forever for a position update which might never come, we emulate it by placing
- // the user arbitrarly at Paris Notre-Dame, one of the most visited free tourist attractions in the world.
- public static GeoData dummyLocation() {
- final Location location = new Location(INITIAL_PROVIDER);
- location.setLatitude(48.85308);
- location.setLongitude(2.34962);
- return new GeoData(location);
+ @Nullable public static GeoData getInitialLocation(final Context context) {
+ final LocationManager geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ if (geoManager == null) {
+ Log.w("No LocationManager available");
+ return null;
+ }
+ try {
+ // Try to find a sensible initial location from the last locations known to Android.
+ final Location lastGpsLocation = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ final Location lastNetworkLocation = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+ final Location bestLocation = best(lastGpsLocation, lastNetworkLocation);
+ if (bestLocation != null) {
+ bestLocation.setProvider(INITIAL_PROVIDER);
+ return new GeoData(bestLocation);
+ } else {
+ Log.i("No last known location available");
+ return null;
+ }
+ } catch (final Exception e) {
+ // This error is non-fatal as its only consequence is that we will start with a dummy location
+ // instead of a previously known one.
+ Log.e("Error when retrieving last known location", e);
+ return null;
+ }
}
+
+
+
+ public static boolean isRecent(@Nullable final Location location) {
+ return location != null && System.currentTimeMillis() <= location.getTime() + 30000;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
index 19eef6a..4694c62 100644
--- a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
+++ b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
@@ -3,6 +3,8 @@ package cgeo.geocaching.sensors;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.RxUtils.LooperCallbacks;
+import org.apache.commons.lang3.StringUtils;
+
import rx.Observable;
import android.content.Context;
@@ -15,29 +17,11 @@ import java.util.concurrent.TimeUnit;
public class GeoDataProvider extends LooperCallbacks<IGeoData> {
+ private final Context context;
private final LocationManager geoManager;
- private final LocationData gpsLocation = new LocationData();
- private final LocationData netLocation = new LocationData();
- private final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
- private final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
-
- private static class LocationData {
- public Location location;
- public long timestamp = 0;
-
- public void update(final Location location) {
- this.location = location;
- timestamp = System.currentTimeMillis();
- }
-
- public boolean isRecent() {
- return isValid() && System.currentTimeMillis() < timestamp + 30000;
- }
-
- public boolean isValid() {
- return location != null;
- }
- }
+ private Location latestGPSLocation = null;
+ private final Listener networkListener = new Listener();
+ private final Listener gpsListener = new Listener();
/**
* Build a new geo data provider object.
@@ -49,7 +33,8 @@ public class GeoDataProvider extends LooperCallbacks<IGeoData> {
*/
protected GeoDataProvider(final Context context) {
super(2500, TimeUnit.MILLISECONDS);
- geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ this.context = context.getApplicationContext();
+ geoManager = (LocationManager) this.context.getSystemService(Context.LOCATION_SERVICE);
}
public static Observable<IGeoData> create(final Context context) {
@@ -58,14 +43,20 @@ public class GeoDataProvider extends LooperCallbacks<IGeoData> {
@Override
public void onStart() {
- subscriber.onNext(findInitialLocation());
+ final IGeoData initialLocation = GeoData.getInitialLocation(context);
+ if (initialLocation != null) {
+ subscriber.onNext(initialLocation);
+ }
Log.d("GeoDataProvider: starting the GPS and network listeners");
- for (final Listener listener : new Listener[]{networkListener, gpsListener}) {
- try {
- geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener);
- } catch (final Exception e) {
- Log.w("There is no location provider " + listener.locationProvider, e);
- }
+ try {
+ geoManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsListener);
+ } catch (final Exception e) {
+ Log.w("No GPS provider available", e);
+ }
+ try {
+ geoManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
+ } catch (final Exception e) {
+ Log.w("No network provider available", e);
}
}
@@ -76,50 +67,16 @@ public class GeoDataProvider extends LooperCallbacks<IGeoData> {
geoManager.removeUpdates(gpsListener);
}
- private IGeoData findInitialLocation() {
- final Location initialLocation = new Location(GeoData.INITIAL_PROVIDER);
- try {
- // Try to find a sensible initial location from the last locations known to Android.
- final Location lastGpsLocation = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
- final Location lastNetworkLocation = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
-
- // If both providers are non-null, take the most recent one
- if (lastGpsLocation != null && lastNetworkLocation != null) {
- if (lastGpsLocation.getTime() >= lastNetworkLocation.getTime()) {
- copyCoords(initialLocation, lastGpsLocation);
- } else {
- copyCoords(initialLocation, lastNetworkLocation);
- }
- } else if (lastGpsLocation != null) {
- copyCoords(initialLocation, lastGpsLocation);
- } else if (lastNetworkLocation != null) {
- copyCoords(initialLocation, lastNetworkLocation);
- } else {
- Log.i("GeoDataProvider: no last known location available");
- return GeoData.dummyLocation();
- }
- } catch (final Exception e) {
- // This error is non-fatal as its only consequence is that we will start with a dummy location
- // instead of a previously known one.
- Log.e("GeoDataProvider: error when retrieving last known location", e);
- }
- // Start with an historical GeoData just in case someone queries it before we get
- // a chance to get any information.
- return new GeoData(initialLocation);
- }
-
- private static void copyCoords(final Location target, final Location source) {
- target.setLatitude(source.getLatitude());
- target.setLongitude(source.getLongitude());
- }
-
private class Listener implements LocationListener {
- private final String locationProvider;
- private final LocationData locationData;
- Listener(final String locationProvider, final LocationData locationData) {
- this.locationProvider = locationProvider;
- this.locationData = locationData;
+ @Override
+ public void onLocationChanged(final Location location) {
+ if (StringUtils.equals(location.getProvider(), LocationManager.GPS_PROVIDER)) {
+ latestGPSLocation = location;
+ assign(latestGPSLocation);
+ } else {
+ assign(GeoData.best(latestGPSLocation, location));
+ }
}
@Override
@@ -136,35 +93,11 @@ public class GeoDataProvider extends LooperCallbacks<IGeoData> {
public void onProviderEnabled(final String provider) {
// nothing
}
-
- @Override
- public void onLocationChanged(final Location location) {
- locationData.update(location);
- selectBest();
- }
- }
-
- private LocationData best() {
- if (gpsLocation.isRecent() || !netLocation.isValid()) {
- return gpsLocation.isValid() ? gpsLocation : null;
- }
- if (!gpsLocation.isValid()) {
- return netLocation;
- }
- return gpsLocation.timestamp > netLocation.timestamp ? gpsLocation : netLocation;
}
- private void selectBest() {
- assign(best());
- }
-
- private void assign(final LocationData locationData) {
- if (locationData == null) {
- return;
- }
-
+ private void assign(final Location location) {
// We do not necessarily get signalled when satellites go to 0/0.
- final IGeoData current = new GeoData(locationData.location);
+ final IGeoData current = new GeoData(location);
subscriber.onNext(current);
}