1
package org.opensatnav.android.services;
3
import java.net.MalformedURLException;
5
import java.net.URLConnection;
6
import java.net.URLEncoder;
7
import java.util.ArrayList;
8
import java.util.Locale;
10
import javax.xml.parsers.DocumentBuilder;
11
import javax.xml.parsers.DocumentBuilderFactory;
13
import org.andnav.osm.util.GeoPoint;
14
import org.andnav.osm.views.util.HttpUserAgentHelper;
15
import org.opensatnav.android.OpenSatNavConstants;
16
import org.w3c.dom.Document;
17
import org.w3c.dom.NamedNodeMap;
18
import org.w3c.dom.NodeList;
20
import android.content.Context;
21
import android.os.Bundle;
22
import android.util.Log;
24
public class NominatimGeoCoder implements GeoCoder {
26
private ArrayList<String> locationNames;
27
private ArrayList locationLatitudes;
28
private ArrayList locationLongitudes;
29
private ArrayList<String> locationInfo;
34
public Bundle query(String query, GeoPoint userLocation, int mode, int maxResults,
36
locationNames = new ArrayList<String>();
37
locationLatitudes = new ArrayList<int[]>();
38
locationLongitudes = new ArrayList<int[]>();
39
locationInfo = new ArrayList<String>();
41
// see http://wiki.openstreetmap.org/wiki/Nominatim for URL available parameters
43
String language = Locale.getDefault().getLanguage();
44
ReverseGeoCoder revGeoCoder = new NominatimReverseGeoCoder();
45
Bundle locationData = revGeoCoder.query(userLocation, context);
46
url = new String("http://nominatim.openstreetmap.org/search?"
49
+ "&accept-language=" + language);
50
if(mode==FROM_POINT) {
51
String locationDescription = "";
52
if(locationData.containsKey("village"))
53
locationDescription += locationData.getString("village")+", ";
54
if(locationData.containsKey("town"))
55
locationDescription += locationData.getString("town")+", ";
56
if(locationData.containsKey("suburb"))
57
locationDescription += locationData.getString("suburb")+", ";
58
if(locationData.containsKey("city"))
59
locationDescription += locationData.getString("city")+", ";
60
if(locationData.containsKey("country"))
61
locationDescription += locationData.getString("country");
62
url += "&q="+URLEncoder.encode(query+" near "+locationDescription);
64
else if (mode == IN_AREA) {
65
String locationDescription = "";
66
if(locationData.containsKey("town"))
67
locationDescription += locationData.getString("town")+", ";
68
if(locationData.containsKey("city"))
69
locationDescription += locationData.getString("city")+", ";
70
if(locationData.containsKey("country"))
71
locationDescription += locationData.getString("country");
72
url += "&q="+URLEncoder.encode(query+", "+locationDescription);
76
encodedURL = new URL(url);
77
} catch (MalformedURLException e) {
78
Log.e(OpenSatNavConstants.LOG_TAG, e.getMessage(), e);
81
URLConnection urlConn = encodedURL.openConnection();
82
String userAgent = HttpUserAgentHelper.getUserAgent(context);
83
if (userAgent != null)
84
urlConn.setRequestProperty("User-Agent", userAgent);
85
urlConn.setReadTimeout(60000);
86
urlConn.setDoInput(true);
87
urlConn.setDoOutput(true);
88
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
89
DocumentBuilder db = dbf.newDocumentBuilder();
90
Document doc = db.parse(urlConn.getInputStream());
91
NodeList xml = doc.getChildNodes();
92
// if we have at least 1 result
93
//android 2.2 starts at item(0) while previous versions start at item(1) so we deal with both here
94
if ((xml.item(0).getChildNodes().item(1) != null) || (xml.item(1).getChildNodes().item(1) != null)) {
95
NodeList places = xml.item(0).getChildNodes();
96
if(places.getLength()==0)
97
places = xml.item(1).getChildNodes();
98
for (int i = 1; i < places.getLength(); i++) {
99
NamedNodeMap attributes = places.item(i).getAttributes();
100
Log.d("NOMINATIMGEOCODER", "found location: "
101
+ attributes.getNamedItem("display_name").getNodeValue());
102
locationNames.add(places.item(i).getChildNodes().item(0).getFirstChild().getNodeValue());
103
// convert to integer (E6 format)
104
locationLatitudes.add((int) (Float.parseFloat(attributes
105
.getNamedItem("lat").getNodeValue()) * 1000000));
106
locationLongitudes.add((int) (Float.parseFloat(attributes
107
.getNamedItem("lon").getNodeValue()) * 1000000));
108
//moreInfo is the second line, it displays the type followed by the full address
109
String moreInfo = null;
110
NodeList locationDetails = places.item(i).getChildNodes();
111
if (attributes.getNamedItem("type") != null)
112
moreInfo = attributes.getNamedItem("type").getNodeValue();
113
StringBuilder sb = new StringBuilder(moreInfo);
114
for(int j=1;j<locationDetails.getLength(); j++){
115
if(!locationDetails.item(j).getNodeName().equals("country_code")){
117
sb.append(locationDetails.item(j).getFirstChild().getNodeValue());
120
if (moreInfo != null)
121
locationInfo.add(sb.toString());
123
locationInfo.add(" ");
129
} catch (Exception e) {
131
Log.d("OSMGEOCODER", "Network timeout");
134
Bundle bundle = new Bundle();
135
// should have done this better - didn't know Java had issues like this!
136
int[] latArray = new int[locationLatitudes.size()];
137
int[] lonArray = new int[locationLatitudes.size()];
138
String[] nameArray = new String[locationNames.size()];
139
String[] infoArray = new String[locationInfo.size()];
141
System.arraycopy(locationNames.toArray(), 0, nameArray, 0,
142
locationNames.size());
143
System.arraycopy(locationInfo.toArray(), 0, infoArray, 0, locationInfo
145
for (int i = 0; i < locationLatitudes.size(); i++)
146
latArray[i] = (Integer) locationLatitudes.get(i);
147
for (int i = 0; i < locationLatitudes.size(); i++)
148
lonArray[i] = (Integer) locationLongitudes.get(i);
150
bundle.putStringArray("names", nameArray);
151
bundle.putIntArray("latitudes", latArray);
152
bundle.putIntArray("longitudes", lonArray);
153
bundle.putStringArray("info", infoArray);