package ca.psiphon.ploggy; import java.util.ArrayList; import java.util.List; import java.util.Locale; import android.location.Address; import android.util.Pair; import com.google.gson.JsonObject; import com.google.gson.JsonParser; public class Nominatim { private static final String LOG_TAG = "Nominatim"; private static final String SERVER_CERT = "MIIDdjCCAl4CCQDRQO1f49f5yDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEQMA4GA1UEBwwHVG9yb250bzEVMBMGA1UECgwMUHNpcGhvbiBJbmMuMRIwEAYDVQQLDAlOb21pbmF0aW0xHzAdBgNVBAMMFmR5dWlndXZrbml5c3ZxZ2Iub25pb24wHhcNMTMxMjE5MjAzODU2WhcNMTQwMTE4MjAzODU2WjB9MQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEQMA4GA1UEBwwHVG9yb250bzEVMBMGA1UECgwMUHNpcGhvbiBJbmMuMRIwEAYDVQQLDAlOb21pbmF0aW0xHzAdBgNVBAMMFmR5dWlndXZrbml5c3ZxZ2Iub25pb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCezDWDljtTizOIY5mXiW2rWRGblRyIaYoUrgFoW+UTjVMM6pqFKu8CgKCgVdyyunZA8hAn7bRnmMS2nJ2BVO27nWLe6CtG9/YCf8ZkNafr8re2AqQT6OOK3v5DPKM/Kkr1VO2xwgDaZnB2r/XiDwhEnKuOD2XpdEKWtpdCAscv7+K/iyKd4EuvXWsL3PGG17Ukd1BcGpAb6yt0JpGsVoKv5A/e6BmjJtNPyhcQYWDonKCJC2YNggMIYF6IGJbK4VUWoVY/eRX064T+GIgJQnIET1tJWWLFli5eWEkOhAMKRpzem27eIHUSMZNRKK1VVK4rNdCzNVlqnAvTmOt9Dh0fAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAH1IIT0bXeQokwZ0vaEeOO+NKPC/WOj3FKnj7q1DctBQw4sgkyA9ABwgkdPh/0hUKjypuc7LMBlGdvJOYvr+CbVe8C0xp9X7nyx8QQQSpOCLKU2DXcswWM4pD5JK9PL9Gm0fpvDyp27fmnuuSjZRVEgwwWvcj3Zdu5tAvjdUI2YYi66rnphIt033sdpIgWrvOFbv64cE6Z4Q/K909pNrettz1W4DITk5tExARngt7IqcwUKhhLwtXmk8Nu9T1zGElAsug08Bjy17ZgdH4t3fVmtxrEHVSXI01ACJlZMMQL3E3aY+M97BACMKEAZ48GsN90v9+jBNY3YdI7f1BcHGvh0="; private static final String SERVER_ADDRESS = "dyuiguvkniysvqgb.onion"; private static final int SERVER_PORT = 443; private static final String REQUEST_PATH = "/nominatim/reverse"; public static class NominatimAddress extends Address { public NominatimAddress(Locale locale) { super(locale); } private String mDisplayName; public String getDisplayName() { return mDisplayName; } public void setDisplayName(String displayName) { mDisplayName = displayName; } @Override public String toString() { if (mDisplayName != null) { return mDisplayName; } return ""; } } public static NominatimAddress getFromLocation(int torSocksProxyPort, double latitude, double longitude) { Locale locale = Locale.getDefault(); NominatimAddress address = new NominatimAddress(locale); address.setLatitude(latitude); address.setLongitude(longitude); List<Pair<String,String>> requestParameters = new ArrayList<Pair<String, String>>(); requestParameters.add(new Pair<String, String>("format", "json")); requestParameters.add(new Pair<String, String>("lat", String.valueOf(latitude))); requestParameters.add(new Pair<String, String>("lon", String.valueOf(longitude))); requestParameters.add(new Pair<String, String>("zoom", "18")); requestParameters.add(new Pair<String, String>("addressdetails", "1")); requestParameters.add(new Pair<String, String>("accept-language", locale.getLanguage())); String response; try { response = WebClient.makeGetRequest( null, SERVER_CERT, torSocksProxyPort, SERVER_ADDRESS, SERVER_PORT, REQUEST_PATH, requestParameters); } catch (Utils.ApplicationError e) { Log.addEntry(LOG_TAG, "reverse geocode failed: " + e.getMessage()); return address; } JsonParser parser = new JsonParser(); JsonObject responseObj = parser.parse(response).getAsJsonObject(); if (responseObj.has("display_name")) { address.setDisplayName(responseObj.get("display_name").getAsString()); } if (!responseObj.has("address")) { return address; } JsonObject addressObj = responseObj.get("address").getAsJsonObject(); // Adapted from: http://code.google.com/p/osmbonuspack/source/browse/trunk/OSMBonusPack/src/org/osmdroid/bonuspack/location/GeocoderNominatim.java int addressIndex = 0; if (addressObj.has("road")) { address.setAddressLine(addressIndex++, addressObj.get("road").getAsString()); address.setThoroughfare(addressObj.get("road").getAsString()); } if (addressObj.has("suburb")) { //address.setAddressLine(addressIndex++, addressObj.getString("suburb")); //not kept => often introduce "noise" in the address. address.setSubLocality(addressObj.get("suburb").getAsString()); } if (addressObj.has("postcode")) { address.setAddressLine(addressIndex++, addressObj.get("postcode").getAsString()); address.setPostalCode(addressObj.get("postcode").getAsString()); } if (addressObj.has("city")) { address.setAddressLine(addressIndex++, addressObj.get("city").getAsString()); address.setLocality(addressObj.get("city").getAsString()); } else if (addressObj.has("town")) { address.setAddressLine(addressIndex++, addressObj.get("town").getAsString()); address.setLocality(addressObj.get("town").getAsString()); } else if (addressObj.has("village")) { address.setAddressLine(addressIndex++, addressObj.get("village").getAsString()); address.setLocality(addressObj.get("village").getAsString()); } if (addressObj.has("county")) { //France: departement address.setSubAdminArea(addressObj.get("county").getAsString()); } if (addressObj.has("state")) { //France: region address.setAdminArea(addressObj.get("state").getAsString()); } if (addressObj.has("country")) { address.setAddressLine(addressIndex++, addressObj.get("country").getAsString()); address.setCountryName(addressObj.get("country").getAsString()); } if (addressObj.has("country_code")) { address.setCountryCode(addressObj.get("country_code").getAsString()); } /* Other possible OSM tags in Nominatim results not handled yet: * subway, golf_course, bus_stop, parking,... * house, house_number, building * city_district (13e Arrondissement) * road => or highway, ... * sub-city (like suburb) => locality, isolated_dwelling, hamlet ... * state_district */ return address; } }