diff options
| author | Samuel Tardieu <sam@rfc1149.net> | 2014-12-11 19:10:55 +0100 |
|---|---|---|
| committer | Samuel Tardieu <sam@rfc1149.net> | 2014-12-12 02:27:20 +0100 |
| commit | f1787fec5d99a97e212e12b0aa34732f7b69cf13 (patch) | |
| tree | 251c47c4bfbc947377a0acb1f295a4fadb8db5f1 | |
| parent | 22053233129471bd225d9310a104c3c67310acb0 (diff) | |
| download | cgeo-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.xml | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/AddressListActivity.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/location/MapQuestGeocoder.java | 111 |
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; + } + } + +} |
