aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2014-12-11 19:10:55 +0100
committerSamuel Tardieu <sam@rfc1149.net>2014-12-12 02:27:20 +0100
commitf1787fec5d99a97e212e12b0aa34732f7b69cf13 (patch)
tree251c47c4bfbc947377a0acb1f295a4fadb8db5f1
parent22053233129471bd225d9310a104c3c67310acb0 (diff)
downloadcgeo-f1787fec5d99a97e212e12b0aa34732f7b69cf13.zip
cgeo-f1787fec5d99a97e212e12b0aa34732f7b69cf13.tar.gz
cgeo-f1787fec5d99a97e212e12b0aa34732f7b69cf13.tar.bz2
Add MapQuest geocoder
Part of #4522.
-rw-r--r--main/res/values/strings_not_translatable.xml2
-rw-r--r--main/src/cgeo/geocaching/AddressListActivity.java5
-rw-r--r--main/src/cgeo/geocaching/location/MapQuestGeocoder.java111
3 files changed, 117 insertions, 1 deletions
diff --git a/main/res/values/strings_not_translatable.xml b/main/res/values/strings_not_translatable.xml
index 585500f..35fef08 100644
--- a/main/res/values/strings_not_translatable.xml
+++ b/main/res/values/strings_not_translatable.xml
@@ -81,6 +81,8 @@
· <a href="http://rrze-icon-set.berlios.de/index.html">RRZE Icon set</a> (<a href="http://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA 3.0</a>)\n
· <a href="http://iconfindr.com/1mNr3rl">Layers icon by Cole Bemis</a> (<a href="http://creativecommons.org/licenses/by/3.0/">CC-BY 3.0</a>)\n
· <a href="https://github.com/amlcurran/Showcaseview">ShowcaseView by Alex Curran</a> (<a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</a>)\n
+ · <a href="http://www.mapquest.com/">Geocoding courtesy of MapQuest</a>\n
+ · <a href="http://www.openstreetmap.org/">Geocoding data from OpenStreetMap</a>\n
</string>
<!-- cache menu -->
diff --git a/main/src/cgeo/geocaching/AddressListActivity.java b/main/src/cgeo/geocaching/AddressListActivity.java
index 48f761b..4f81f8b 100644
--- a/main/src/cgeo/geocaching/AddressListActivity.java
+++ b/main/src/cgeo/geocaching/AddressListActivity.java
@@ -3,6 +3,7 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractListActivity;
import cgeo.geocaching.location.AndroidGeocoder;
import cgeo.geocaching.location.GCGeocoder;
+import cgeo.geocaching.location.MapQuestGeocoder;
import cgeo.geocaching.ui.AddressListAdapter;
import rx.Observable;
@@ -33,7 +34,9 @@ public class AddressListActivity extends AbstractListActivity {
}
private void lookupAddressInBackground(final String keyword, final AddressListAdapter adapter, final ProgressDialog waitDialog) {
- final Observable<Address> geocoderObservable = new AndroidGeocoder(this).getFromLocationName(keyword).onErrorResumeNext(GCGeocoder.getFromLocationName(keyword));
+ final Observable<Address> geocoderObservable = new AndroidGeocoder(this).getFromLocationName(keyword)
+ .onErrorResumeNext(MapQuestGeocoder.getFromLocationName(keyword))
+ .onErrorResumeNext(GCGeocoder.getFromLocationName(keyword));
AndroidObservable.bindActivity(this, geocoderObservable.toList()).subscribe(new Action1<List<Address>>() {
@Override
public void call(final List<Address> addresses) {
diff --git a/main/src/cgeo/geocaching/location/MapQuestGeocoder.java b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java
new file mode 100644
index 0000000..1ba14f2
--- /dev/null
+++ b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java
@@ -0,0 +1,111 @@
+package cgeo.geocaching.location;
+
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Subscriber;
+import rx.functions.Func0;
+
+import android.location.Address;
+
+import java.util.Locale;
+
+public class MapQuestGeocoder {
+
+ private static final String MAPQUEST_KEY = "Fmjtd|luurn1u2n9,bs=o5-9wynua";
+
+ private MapQuestGeocoder() {
+ // Do not instantiate
+ }
+
+ /**
+ * Retrieve addresses from a textual location using MapQuest geocoding API. The works happens on the network scheduler.
+ *
+ * @param address the location
+ * @return an observable containing zero or more locations
+ *
+ * @see android.location.Geocoder#getFromLocationName(String, int)
+ */
+ public static Observable<Address> getFromLocationName(@NonNull final String address) {
+ return Observable.defer(new Func0<Observable<Address>>() {
+ @Override
+ public Observable<Address> call() {
+ final ObjectNode response = Network.requestJSON("https://www.mapquestapi.com/geocoding/v1/address",
+ new Parameters("key", MAPQUEST_KEY, "location", address, "maxResults", "20", "thumbMaps", "false"));
+ final int statusCode = response != null ? response.path("info").path("statuscode").asInt(-1) : -1;
+ if (statusCode != 0) {
+ Log.w("MapQuest decoder error: statuscode is not 0");
+ return Observable.error(new RuntimeException("no correct answer from MapQuest geocoder"));
+ }
+ return Observable.create(new OnSubscribe<Address>() {
+ @Override
+ public void call(final Subscriber<? super Address> subscriber) {
+ try {
+ for (final JsonNode address: response.get("results").get(0).get("locations")) {
+ subscriber.onNext(mapquestToAddress(address));
+ }
+ subscriber.onCompleted();
+ } catch (final Exception e) {
+ Log.e("Error decoding MapQuest address", e);
+ subscriber.onError(e);
+ }
+ }
+ });
+ }
+ }).subscribeOn(RxUtils.networkScheduler);
+ }
+
+ private static Address mapquestToAddress(final JsonNode mapquestAddress) {
+ final Address address = new Address(Locale.getDefault());
+ for (int i = 1; i <= 6; i++) {
+ final String adminAreaName = "adminArea" + i;
+ setComponent(address, mapquestAddress, adminAreaName, mapquestAddress.path(adminAreaName + "Type").asText());
+ }
+ setComponent(address, mapquestAddress, "postalCode", "PostalCode");
+ int index = 0;
+ for (final String addressComponent: new String[]{ mapquestAddress.path("street").asText(), address.getSubLocality(), address.getLocality(),
+ address.getPostalCode(), address.getSubAdminArea(), address.getAdminArea(), address.getCountryCode() }) {
+ if (StringUtils.isNotBlank(addressComponent)) {
+ address.setAddressLine(index++, addressComponent);
+ }
+ }
+ address.setLatitude(mapquestAddress.get("latLng").get("lat").asDouble());
+ address.setLongitude(mapquestAddress.get("latLng").get("lng").asDouble());
+ return address;
+ }
+
+ private static void setComponent(final Address address, final JsonNode mapquestAddress, final String adminArea, final String adminAreaType) {
+ final String content = StringUtils.trimToNull(mapquestAddress.path(adminArea).asText());
+ switch (adminAreaType) {
+ case "City":
+ address.setLocality(content);
+ break;
+ case "Neighborhood":
+ address.setSubLocality(content);
+ break;
+ case "PostalCode":
+ address.setPostalCode(content);
+ break;
+ case "State":
+ address.setAdminArea(content);
+ break;
+ case "County":
+ address.setSubAdminArea(content);
+ break;
+ case "Country":
+ address.setCountryCode(content);
+ break;
+ }
+ }
+
+}