diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 17d4d16..2d707c7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,29 +1,29 @@ + android:versionName="1.1.0" + android:versionCode="1100" + package="org.microg.nlp.backend.nominatim"> - - - - - - + + + + + + - - - - - - - - + + + + + + + + diff --git a/src/org/microg/nlp/backend/nominatim/BackendService.java b/src/org/microg/nlp/backend/nominatim/BackendService.java index 5f85cd2..0a4ec07 100644 --- a/src/org/microg/nlp/backend/nominatim/BackendService.java +++ b/src/org/microg/nlp/backend/nominatim/BackendService.java @@ -1,10 +1,13 @@ package org.microg.nlp.backend.nominatim; +import android.content.Context; import android.content.pm.PackageManager; import android.location.Address; +import android.net.Uri; import android.os.Build; import android.util.Log; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.microg.nlp.api.GeocoderBackendService; @@ -18,13 +21,19 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; public class BackendService extends GeocoderBackendService { - private static final String TAG = BackendService.class.getName(); + private static final String TAG = "NominatimGeocoderBackend"; private static final String SERVICE_URL_MAPQUEST = "http://open.mapquestapi.com/nominatim/v1/"; private static final String SERVICE_URL_OSM = " http://nominatim.openstreetmap.org/"; private static final String REVERSE_GEOCODE_URL = "%sreverse?format=json&accept-language=%s&lat=%f&lon=%f"; + private static final String SEARCH_GEOCODE_URL = + "%ssearch?format=json&accept-language=%s&addressdetails=1&bounded=1&q=%s&limit=%d"; + private static final String SEARCH_GEOCODE_WITH_BOX_URL = + "%ssearch?format=json&accept-language=%s&addressdetails=1&bounded=1&q=%s&limit=%d" + + "&viewbox=%f,%f,%f,%f"; private static final String WIRE_LATITUDE = "lat"; private static final String WIRE_LONGITUDE = "lon"; private static final String WIRE_ADDRESS = "address"; @@ -45,51 +54,20 @@ protected List
getFromLocation(double latitude, double longitude, int m String url = String.format(Locale.US, REVERSE_GEOCODE_URL, SERVICE_URL_MAPQUEST, locale.split("_")[0], latitude, longitude); try { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - setUserAgentOnConnection(connection); - connection.setDoInput(true); - InputStream inputStream = connection.getInputStream(); - JSONObject result = new JSONObject(new String(readStreamToEnd(inputStream))); + JSONObject result = new JSONObject(new AsyncGetRequest(this, + url).asyncStart().retrieveString()); Address address = parseResponse(localeFromLocaleString(locale), result); if (address != null) { - List
addresses = new ArrayList
(); + List
addresses = new ArrayList<>(); addresses.add(address); return addresses; } - } catch (IOException | JSONException e) { + } catch (Exception e) { Log.w(TAG, e); } return null; } - public static byte[] readStreamToEnd(InputStream is) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - if (is != null) { - byte[] buff = new byte[1024]; - while (true) { - int nb = is.read(buff); - if (nb < 0) { - break; - } - bos.write(buff, 0, nb); - } - is.close(); - } - return bos.toByteArray(); - } - - public void setUserAgentOnConnection(URLConnection connection) { - try { - connection.setRequestProperty("User-Agent", - String.format("UnifiedNlp/%s (Linux; Android %s)", - getPackageManager().getPackageInfo(getPackageName(), 0).versionName, - Build.VERSION.RELEASE)); - } catch (PackageManager.NameNotFoundException e) { - connection.setRequestProperty("User-Agent", - String.format("UnifiedNlp (Linux; Android %s)", Build.VERSION.RELEASE)); - } - } - private static Locale localeFromLocaleString(String localeString) { String[] split = localeString.split("_"); if (split.length == 1) { @@ -106,6 +84,31 @@ private static Locale localeFromLocaleString(String localeString) { protected List
getFromLocationName(String locationName, int maxResults, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude, String locale) { + String query = Uri.encode(locationName); + String url; + if (lowerLeftLatitude == 0 && lowerLeftLongitude == 0 && upperRightLatitude == 0 && + upperRightLongitude == 0) { + url = String.format(Locale.US, SEARCH_GEOCODE_URL, SERVICE_URL_MAPQUEST, + locale.split("_")[0], query, maxResults); + } else { + url = String.format(Locale.US, SEARCH_GEOCODE_WITH_BOX_URL, SERVICE_URL_MAPQUEST, + locale.split("_")[0], query, maxResults, lowerLeftLongitude, + upperRightLatitude, upperRightLongitude, lowerLeftLatitude); + } + try { + JSONArray result = new JSONArray(new AsyncGetRequest(this, + url).asyncStart().retrieveString()); + List
addresses = new ArrayList<>(); + for (int i = 0; i < result.length(); i++) { + Address address = parseResponse(localeFromLocaleString(locale), + result.getJSONObject(i)); + if (address != null) + addresses.add(address); + } + if (!addresses.isEmpty()) return addresses; + } catch (Exception e) { + Log.w(TAG, e); + } return null; } @@ -160,4 +163,88 @@ private Address parseResponse(Locale locale, JSONObject result) throws JSONExcep return address; } + + private class AsyncGetRequest extends Thread { + public static final String USER_AGENT = "User-Agent"; + public static final String USER_AGENT_TEMPLATE = "UnifiedNlp/%s (Linux; Android %s)"; + private final AtomicBoolean done = new AtomicBoolean(false); + private final Context context; + private final String url; + private byte[] result; + + private AsyncGetRequest(Context context, String url) { + this.context = context; + this.url = url; + } + + @Override + public void run() { + synchronized (done) { + try { + Log.d(TAG, "Requesting " + url); + HttpURLConnection connection = (HttpURLConnection) new URL(url) + .openConnection(); + setUserAgentOnConnection(connection); + connection.setDoInput(true); + InputStream inputStream = connection.getInputStream(); + result = readStreamToEnd(inputStream); + } catch (Exception e) { + Log.w(TAG, e); + } + done.set(true); + done.notifyAll(); + } + } + + public AsyncGetRequest asyncStart() { + start(); + return this; + } + + public byte[] retrieveAllBytes() { + if (!done.get()) { + synchronized (done) { + while (!done.get()) { + try { + done.wait(); + } catch (InterruptedException e) { + break; + } + } + } + } + return result; + } + + public String retrieveString() { + return new String(retrieveAllBytes()); + } + + private void setUserAgentOnConnection(URLConnection connection) { + try { + connection.setRequestProperty(USER_AGENT, String.format(USER_AGENT_TEMPLATE, + context.getPackageManager().getPackageInfo(context.getPackageName(), + 0).versionName, Build.VERSION.RELEASE)); + } catch (PackageManager.NameNotFoundException e) { + connection.setRequestProperty(USER_AGENT, String.format(USER_AGENT_TEMPLATE, 0, + Build.VERSION.RELEASE)); + } + } + + private byte[] readStreamToEnd(InputStream is) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + if (is != null) { + byte[] buff = new byte[1024]; + while (true) { + int nb = is.read(buff); + if (nb < 0) { + break; + } + bos.write(buff, 0, nb); + } + is.close(); + } + return bos.toByteArray(); + } + } }