vtm-app: revive / update with latest VTM, closes #90
This commit is contained in:
163
vtm-app/src/org/osmdroid/location/FlickrPOIProvider.java
Normal file
163
vtm-app/src/org/osmdroid/location/FlickrPOIProvider.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* POI Provider using Flickr service to get geolocalized photos.
|
||||
*
|
||||
* @author M.Kergall
|
||||
* @see "http://www.flickr.com/services/api/flickr.photos.search.html"
|
||||
*/
|
||||
public class FlickrPOIProvider implements POIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(FlickrPOIProvider.class);
|
||||
|
||||
protected String mApiKey;
|
||||
private final static String PHOTO_URL = "http://www.flickr.com/photos/%s/%s/sizes/o/in/photostream/";
|
||||
|
||||
/**
|
||||
* @param apiKey the registered API key to give to Flickr service.
|
||||
* @see "http://www.flickr.com/help/api/"
|
||||
*/
|
||||
public FlickrPOIProvider(String apiKey) {
|
||||
mApiKey = apiKey;
|
||||
}
|
||||
|
||||
private String getUrlInside(BoundingBox boundingBox, int maxResults) {
|
||||
StringBuffer url = new StringBuffer(
|
||||
"http://api.flickr.com/services/rest/?method=flickr.photos.search");
|
||||
url.append("&api_key=" + mApiKey);
|
||||
url.append("&bbox=" + boundingBox.getMinLongitude());
|
||||
url.append("," + boundingBox.getMinLatitude());
|
||||
url.append("," + boundingBox.getMaxLongitude());
|
||||
url.append("," + boundingBox.getMaxLatitude());
|
||||
url.append("&has_geo=1");
|
||||
// url.append("&geo_context=2");
|
||||
// url.append("&is_commons=true");
|
||||
url.append("&format=json&nojsoncallback=1");
|
||||
url.append("&per_page=" + maxResults);
|
||||
// From Flickr doc:
|
||||
// "Geo queries require some sort of limiting agent in order to prevent the database from crying."
|
||||
// And min_date_upload is considered as a limiting agent. So:
|
||||
url.append("&min_upload_date=2005/01/01");
|
||||
|
||||
// Ask to provide some additional attributes we will need:
|
||||
url.append("&extras=geo,url_sq");
|
||||
url.append("&sort=interestingness-desc");
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/* public POI getPhoto(String photoId){ String url =
|
||||
* "http://api.flickr.com/services/rest/?method=flickr.photos.getInfo"
|
||||
* +
|
||||
* "&api_key=" + mApiKey + "&photo_id=" + photo Id +
|
||||
* "&format=json&nojsoncallback=1"; log.debug( * "getPhoto:"+url); String
|
||||
* jString =
|
||||
* BonusPackHelper.requestStringFromUrl(url); if (jString == null)
|
||||
* {
|
||||
* log.error( * "FlickrPOIProvider: request failed.");
|
||||
* return null; } try { POI poi = new POI(POI.POI_SERVICE_FLICKR);
|
||||
* JSONObject jRoot = new JSONObject(jString); JSONObject jPhoto =
|
||||
* jRoot.getJSONObject("photo"); JSONObject jLocation =
|
||||
* jPhoto.getJSONObject("location"); poi.mLocation = new GeoPoint(
|
||||
* jLocation.getDouble("latitude"),
|
||||
* jLocation.getDouble("longitude"));
|
||||
* poi.mId = Long.parseLong(photoId); JSONObject jTitle =
|
||||
* jPhoto.getJSONObject("title"); poi.mType =
|
||||
* jTitle.getString("_content");
|
||||
* JSONObject jDescription = jPhoto.getJSONObject("description");
|
||||
* poi.mDescription = jDescription.getString("_content");
|
||||
* //truncate
|
||||
* description if too long: if (poi.mDescription.length() > 300){
|
||||
* poi.mDescription = poi.mDescription.substring(0, 300) +
|
||||
* " (...)"; }
|
||||
* String farm = jPhoto.getString("farm"); String server =
|
||||
* jPhoto.getString("server"); String secret =
|
||||
* jPhoto.getString("secret");
|
||||
* JSONObject jOwner = jPhoto.getJSONObject("owner"); String nsid
|
||||
* =
|
||||
* jOwner.getString("nsid"); poi.mThumbnailPath =
|
||||
* "http://farm"+farm+".staticflickr.com/"
|
||||
* +server+"/"+photoId+"_"+secret+"_s.jpg"; poi.mUrl =
|
||||
* "http://www.flickr.com/photos/"+nsid+"/"+photoId; return poi;
|
||||
* }catch
|
||||
* (JSONException e) { e.printStackTrace(); return null; } } */
|
||||
|
||||
/**
|
||||
* @param fullUrl ...
|
||||
* @return the list of POI
|
||||
*/
|
||||
public ArrayList<POI> getThem(String fullUrl) {
|
||||
// for local debug: fullUrl = "http://10.0.2.2/flickr_mockup.json";
|
||||
log.debug("FlickrPOIProvider:get:" + fullUrl);
|
||||
String jString = BonusPackHelper.requestStringFromUrl(fullUrl);
|
||||
if (jString == null) {
|
||||
log.error("FlickrPOIProvider: request failed.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject jRoot = new JSONObject(jString);
|
||||
JSONObject jPhotos = jRoot.getJSONObject("photos");
|
||||
JSONArray jPhotoArray = jPhotos.getJSONArray("photo");
|
||||
int n = jPhotoArray.length();
|
||||
ArrayList<POI> pois = new ArrayList<POI>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
JSONObject jPhoto = jPhotoArray.getJSONObject(i);
|
||||
|
||||
String photoId = jPhoto.getString("id");
|
||||
if (mPrevious != null && mPrevious.containsKey(photoId))
|
||||
continue;
|
||||
|
||||
POI poi = new POI(POI.POI_SERVICE_FLICKR);
|
||||
poi.location = new GeoPoint(
|
||||
jPhoto.getDouble("latitude"),
|
||||
jPhoto.getDouble("longitude"));
|
||||
poi.id = photoId; //Long.parseLong(photoId);
|
||||
poi.type = jPhoto.getString("title");
|
||||
poi.thumbnailPath = jPhoto.getString("url_sq");
|
||||
String owner = jPhoto.getString("owner");
|
||||
// the default flickr link viewer doesnt work with mobile browsers...
|
||||
// poi.url = "http://www.flickr.com/photos/" + owner + "/" + photoId + "/sizes/o/in/photostream/";
|
||||
|
||||
poi.url = String.format(PHOTO_URL, owner, photoId);
|
||||
|
||||
pois.add(poi);
|
||||
}
|
||||
// int total = jPhotos.getInt("total");
|
||||
// log.debug(on a total of:" + total);
|
||||
return pois;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundingBox ...
|
||||
* @param maxResults ...
|
||||
* @return list of POI, Flickr photos inside the bounding box.
|
||||
* Null if
|
||||
* technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOIInside(BoundingBox boundingBox, String query, int maxResults) {
|
||||
String url = getUrlInside(boundingBox, maxResults);
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
HashMap<String, POI> mPrevious;
|
||||
|
||||
public void setPrevious(HashMap<String, POI> previous) {
|
||||
mPrevious = previous;
|
||||
}
|
||||
|
||||
}
|
||||
186
vtm-app/src/org/osmdroid/location/FourSquareProvider.java
Normal file
186
vtm-app/src/org/osmdroid/location/FourSquareProvider.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2012 Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.osmdroid.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class FourSquareProvider implements POIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(FourSquareProvider.class);
|
||||
|
||||
// https://developer.foursquare.com/docs/venues/search
|
||||
// https://developer.foursquare.com/docs/responses/venue
|
||||
// https://apigee.com/console/foursquare
|
||||
|
||||
protected String mApiKey;
|
||||
|
||||
// private static HashMap<String, Bitmap> mIcons =
|
||||
// (HashMap<String,Bitmap>)Collections.synchronizedMap(new HashMap<String, Bitmap>());
|
||||
|
||||
/**
|
||||
* @param clientSecret the registered API key to give to Flickr service.
|
||||
* @see "http://www.flickr.com/help/api/"
|
||||
*/
|
||||
public FourSquareProvider(String clientId, String clientSecret) {
|
||||
mApiKey = "client_id=" + clientId + "&client_secret=" + clientSecret;
|
||||
}
|
||||
|
||||
//"https://api.foursquare.com/v2/venues/search?v=20120321&intent=checkin&ll=53.06,8.8&client_id=ZUN4ZMNZUFT3Z5QQZNMQ3ACPL4OJMBFGO15TYX51D5MHCIL3&client_secret=X1RXCVF4VVSG1Y2FUDQJLKQUC1WF4XXKIMK2STXKACLPDGLY
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getUrlInside(BoundingBox boundingBox, String query, int maxResults) {
|
||||
StringBuffer url = new StringBuffer(
|
||||
"https://api.foursquare.com/v2/venues/search?v=20120321"
|
||||
+ "&intent=browse"
|
||||
+ "&client_id=ZUN4ZMNZUFT3Z5QQZNMQ3ACPL4OJMBFGO15TYX51D5MHCIL3"
|
||||
+ "&client_secret=X1RXCVF4VVSG1Y2FUDQJLKQUC1WF4XXKIMK2STXKACLPDGLY");
|
||||
url.append("&sw=");
|
||||
url.append(boundingBox.getMinLatitude());
|
||||
url.append(',');
|
||||
url.append(boundingBox.getMinLongitude());
|
||||
url.append("&ne=");
|
||||
url.append(boundingBox.getMaxLatitude());
|
||||
url.append(',');
|
||||
url.append(boundingBox.getMaxLongitude());
|
||||
url.append("&limit=");
|
||||
url.append(maxResults);
|
||||
if (query != null)
|
||||
url.append("&query=" + URLEncoder.encode(query));
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fullUrl ...
|
||||
* @return the list of POI
|
||||
*/
|
||||
public ArrayList<POI> getThem(String fullUrl) {
|
||||
// for local debug: fullUrl = "http://10.0.2.2/flickr_mockup.json";
|
||||
log.debug("FlickrPOIProvider:get:" + fullUrl);
|
||||
String jString = BonusPackHelper.requestStringFromUrl(fullUrl);
|
||||
if (jString == null) {
|
||||
log.error("FlickrPOIProvider: request failed.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject jRoot = new JSONObject(jString);
|
||||
|
||||
JSONObject jResponse = jRoot.getJSONObject("response");
|
||||
JSONArray jVenueArray = jResponse.getJSONArray("venues");
|
||||
int n = jVenueArray.length();
|
||||
ArrayList<POI> pois = new ArrayList<POI>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
JSONObject jVenue = jVenueArray.getJSONObject(i);
|
||||
|
||||
POI poi = new POI(POI.POI_SERVICE_4SQUARE);
|
||||
poi.id = jVenue.getString("id");
|
||||
poi.type = jVenue.getString("name");
|
||||
// poi.url = jVenue.optString("url", null);
|
||||
poi.url = "https://foursquare.com/v/" + poi.id;
|
||||
|
||||
JSONObject jLocation = jVenue.getJSONObject("location");
|
||||
poi.location = new GeoPoint(
|
||||
jLocation.getDouble("lat"),
|
||||
jLocation.getDouble("lng"));
|
||||
poi.description = jLocation.optString("address", null);
|
||||
|
||||
JSONArray jCategories = jVenue.getJSONArray("categories");
|
||||
if (jCategories.length() > 0) {
|
||||
JSONObject jCategory = jCategories.getJSONObject(0);
|
||||
String icon = jCategory.getJSONObject("icon").getString("prefix");
|
||||
poi.thumbnailPath = icon + 44 + ".png";
|
||||
poi.category = jCategory.optString("name");
|
||||
}
|
||||
pois.add(poi);
|
||||
}
|
||||
|
||||
return pois;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundingBox ...
|
||||
* @param maxResults ...
|
||||
* @return list of POI, Flickr photos inside the bounding box.
|
||||
* Null if
|
||||
* technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOIInside(BoundingBox boundingBox, String query, int maxResults) {
|
||||
String url = getUrlInside(boundingBox, query, maxResults);
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
public static void browse(final Context context, POI poi) {
|
||||
// get the right url from redirect, could also parse the result from querying venueid...
|
||||
new AsyncTask<POI, Void, String>() {
|
||||
|
||||
@Override
|
||||
protected String doInBackground(POI... params) {
|
||||
POI poi = params[0];
|
||||
if (poi == null)
|
||||
return null;
|
||||
try {
|
||||
URL url = new URL(poi.url);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setInstanceFollowRedirects(false);
|
||||
|
||||
String redirect = conn.getHeaderField("Location");
|
||||
if (redirect != null) {
|
||||
log.debug(redirect);
|
||||
return redirect;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://foursquare.com"
|
||||
+ result));
|
||||
context.startActivity(myIntent);
|
||||
|
||||
}
|
||||
}.execute(poi);
|
||||
|
||||
}
|
||||
}
|
||||
215
vtm-app/src/org/osmdroid/location/GeoNamesPOIProvider.java
Normal file
215
vtm-app/src/org/osmdroid/location/GeoNamesPOIProvider.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
import org.osmdroid.utils.HttpConnection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* POI Provider using GeoNames services. Currently, "find Nearby Wikipedia" and
|
||||
* "Wikipedia Articles in Bounding Box" services.
|
||||
*
|
||||
* @author M.Kergall
|
||||
* @see "http://www.geonames.org"
|
||||
*/
|
||||
public class GeoNamesPOIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(GeoNamesPOIProvider.class);
|
||||
|
||||
protected String mUserName;
|
||||
|
||||
/**
|
||||
* @param account the registered "username" to give to GeoNames service.
|
||||
* @see "http://www.geonames.org/login"
|
||||
*/
|
||||
public GeoNamesPOIProvider(String account) {
|
||||
mUserName = account;
|
||||
}
|
||||
|
||||
private String getUrlCloseTo(GeoPoint p, int maxResults, double maxDistance) {
|
||||
StringBuffer url = new StringBuffer("http://api.geonames.org/findNearbyWikipediaJSON?");
|
||||
url.append("lat=" + p.getLatitude());
|
||||
url.append("&lng=" + p.getLongitude());
|
||||
url.append("&maxRows=" + maxResults);
|
||||
url.append("&radius=" + maxDistance); //km
|
||||
url.append("&lang=" + Locale.getDefault().getLanguage());
|
||||
url.append("&username=" + mUserName);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private String getUrlInside(BoundingBox boundingBox, int maxResults) {
|
||||
StringBuffer url = new StringBuffer("http://api.geonames.org/wikipediaBoundingBoxJSON?");
|
||||
url.append("south=" + boundingBox.getMinLatitude());
|
||||
url.append("&north=" + boundingBox.getMaxLatitude());
|
||||
url.append("&west=" + boundingBox.getMinLongitude());
|
||||
url.append("&east=" + boundingBox.getMaxLongitude());
|
||||
url.append("&maxRows=" + maxResults);
|
||||
url.append("&lang=" + Locale.getDefault().getLanguage());
|
||||
url.append("&username=" + mUserName);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fullUrl ...
|
||||
* @return the list of POI
|
||||
*/
|
||||
public ArrayList<POI> getThem(String fullUrl) {
|
||||
log.debug("GeoNamesPOIProvider:get:" + fullUrl);
|
||||
String jString = BonusPackHelper.requestStringFromUrl(fullUrl);
|
||||
if (jString == null) {
|
||||
log.error("GeoNamesPOIProvider: request failed.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject jRoot = new JSONObject(jString);
|
||||
JSONArray jPlaceIds = jRoot.getJSONArray("geonames");
|
||||
int n = jPlaceIds.length();
|
||||
ArrayList<POI> pois = new ArrayList<POI>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
JSONObject jPlace = jPlaceIds.getJSONObject(i);
|
||||
POI poi = new POI(POI.POI_SERVICE_GEONAMES_WIKIPEDIA);
|
||||
poi.location = new GeoPoint(jPlace.getDouble("lat"),
|
||||
jPlace.getDouble("lng"));
|
||||
poi.category = jPlace.optString("feature");
|
||||
poi.type = jPlace.getString("title");
|
||||
poi.description = jPlace.optString("summary");
|
||||
poi.thumbnailPath = jPlace.optString("thumbnailImg", null);
|
||||
/* This makes loading too long. Thumbnail loading will be done
|
||||
* only when needed, with POI.getThumbnail() if
|
||||
* (poi.mThumbnailPath != null){ poi.mThumbnail =
|
||||
* BonusPackHelper.loadBitmap(poi.mThumbnailPath); } */
|
||||
poi.url = jPlace.optString("wikipediaUrl", null);
|
||||
if (poi.url != null)
|
||||
poi.url = "http://" + poi.url;
|
||||
poi.rank = jPlace.optInt("rank", 0);
|
||||
//other attributes: distance?
|
||||
pois.add(poi);
|
||||
}
|
||||
log.debug("done");
|
||||
return pois;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//XML parsing seems 2 times slower than JSON parsing
|
||||
public ArrayList<POI> getThemXML(String fullUrl) {
|
||||
log.debug("GeoNamesPOIProvider:get:" + fullUrl);
|
||||
HttpConnection connection = new HttpConnection();
|
||||
connection.doGet(fullUrl);
|
||||
InputStream stream = connection.getStream();
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
GeoNamesXMLHandler handler = new GeoNamesXMLHandler();
|
||||
try {
|
||||
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
|
||||
parser.parse(stream, handler);
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
connection.close();
|
||||
log.debug("done");
|
||||
return handler.mPOIs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param position ...
|
||||
* @param maxResults ...
|
||||
* @param maxDistance ... in km. 20 km max for the free service.
|
||||
* @return list of POI, Wikipedia entries close to the position. Null if
|
||||
* technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOICloseTo(GeoPoint position,
|
||||
int maxResults, double maxDistance) {
|
||||
String url = getUrlCloseTo(position, maxResults, maxDistance);
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundingBox ...
|
||||
* @param maxResults ...
|
||||
* @return list of POI, Wikipedia entries inside the bounding box. Null if
|
||||
* technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOIInside(BoundingBox boundingBox, int maxResults) {
|
||||
String url = getUrlInside(boundingBox, maxResults);
|
||||
return getThem(url);
|
||||
}
|
||||
}
|
||||
|
||||
class GeoNamesXMLHandler extends DefaultHandler {
|
||||
|
||||
private String mString;
|
||||
double mLat, mLng;
|
||||
POI mPOI;
|
||||
ArrayList<POI> mPOIs;
|
||||
|
||||
public GeoNamesXMLHandler() {
|
||||
mPOIs = new ArrayList<POI>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String name,
|
||||
Attributes attributes) {
|
||||
if (localName.equals("entry")) {
|
||||
mPOI = new POI(POI.POI_SERVICE_GEONAMES_WIKIPEDIA);
|
||||
}
|
||||
mString = new String();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) {
|
||||
String chars = new String(ch, start, length);
|
||||
mString = mString.concat(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String name) {
|
||||
if (localName.equals("lat")) {
|
||||
mLat = Double.parseDouble(mString);
|
||||
} else if (localName.equals("lng")) {
|
||||
mLng = Double.parseDouble(mString);
|
||||
} else if (localName.equals("feature")) {
|
||||
mPOI.category = mString;
|
||||
} else if (localName.equals("title")) {
|
||||
mPOI.type = mString;
|
||||
} else if (localName.equals("summary")) {
|
||||
mPOI.description = mString;
|
||||
} else if (localName.equals("thumbnailImg")) {
|
||||
if (mString != null && !mString.equals(""))
|
||||
mPOI.thumbnailPath = mString;
|
||||
} else if (localName.equals("wikipediaUrl")) {
|
||||
if (mString != null && !mString.equals(""))
|
||||
mPOI.url = "http://" + mString;
|
||||
} else if (localName.equals("rank")) {
|
||||
mPOI.rank = Integer.parseInt(mString);
|
||||
} else if (localName.equals("entry")) {
|
||||
mPOI.location = new GeoPoint(mLat, mLng);
|
||||
mPOIs.add(mPOI);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
208
vtm-app/src/org/osmdroid/location/GeocoderNominatim.java
Normal file
208
vtm-app/src/org/osmdroid/location/GeocoderNominatim.java
Normal file
@@ -0,0 +1,208 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Address;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Implements an equivalent to Android Geocoder class, based on OpenStreetMap
|
||||
* data and Nominatim API. <br>
|
||||
* See http://wiki.openstreetmap.org/wiki/Nominatim or
|
||||
* http://open.mapquestapi.com/nominatim/
|
||||
*
|
||||
* @author M.Kergall
|
||||
*/
|
||||
public class GeocoderNominatim {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(GeocoderNominatim.class);
|
||||
|
||||
public static final String NOMINATIM_SERVICE_URL = "http://nominatim.openstreetmap.org/";
|
||||
public static final String MAPQUEST_SERVICE_URL = "http://open.mapquestapi.com/nominatim/v1/";
|
||||
|
||||
protected Locale mLocale;
|
||||
protected String mServiceUrl;
|
||||
|
||||
/**
|
||||
* @param context ...
|
||||
* @param locale ...
|
||||
*/
|
||||
protected void init(Context context, Locale locale) {
|
||||
mLocale = locale;
|
||||
setService(NOMINATIM_SERVICE_URL); //default service
|
||||
}
|
||||
|
||||
public GeocoderNominatim(Context context, Locale locale) {
|
||||
init(context, locale);
|
||||
}
|
||||
|
||||
public GeocoderNominatim(Context context) {
|
||||
init(context, Locale.getDefault());
|
||||
}
|
||||
|
||||
static public boolean isPresent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the url of the Nominatim service provider to use. Can be one of
|
||||
* the predefined (NOMINATIM_SERVICE_URL or MAPQUEST_SERVICE_URL), or
|
||||
* another one, your local instance of Nominatim for instance.
|
||||
*
|
||||
* @param serviceUrl ...
|
||||
*/
|
||||
public void setService(String serviceUrl) {
|
||||
mServiceUrl = serviceUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Android Address object from the Nominatim address in JSON
|
||||
* format. Current implementation is mainly targeting french addresses, and
|
||||
* will be quite basic on other countries.
|
||||
*
|
||||
* @param jResult ...
|
||||
* @return ...
|
||||
* @throws JSONException ...
|
||||
*/
|
||||
protected Address buildAndroidAddress(JSONObject jResult) throws JSONException {
|
||||
Address gAddress = new Address(mLocale);
|
||||
gAddress.setLatitude(jResult.getDouble("lat"));
|
||||
gAddress.setLongitude(jResult.getDouble("lon"));
|
||||
|
||||
JSONObject jAddress = jResult.getJSONObject("address");
|
||||
|
||||
int addressIndex = 0;
|
||||
if (jAddress.has("road")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("road"));
|
||||
gAddress.setThoroughfare(jAddress.getString("road"));
|
||||
}
|
||||
if (jAddress.has("suburb")) {
|
||||
//gAddress.setAddressLine(addressIndex++, jAddress.getString("suburb"));
|
||||
//not kept => often introduce "noise" in the address.
|
||||
gAddress.setSubLocality(jAddress.getString("suburb"));
|
||||
}
|
||||
if (jAddress.has("postcode")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("postcode"));
|
||||
gAddress.setPostalCode(jAddress.getString("postcode"));
|
||||
}
|
||||
|
||||
if (jAddress.has("city")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("city"));
|
||||
gAddress.setLocality(jAddress.getString("city"));
|
||||
} else if (jAddress.has("town")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("town"));
|
||||
gAddress.setLocality(jAddress.getString("town"));
|
||||
} else if (jAddress.has("village")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("village"));
|
||||
gAddress.setLocality(jAddress.getString("village"));
|
||||
}
|
||||
|
||||
if (jAddress.has("county")) { //France: departement
|
||||
gAddress.setSubAdminArea(jAddress.getString("county"));
|
||||
}
|
||||
if (jAddress.has("state")) { //France: region
|
||||
gAddress.setAdminArea(jAddress.getString("state"));
|
||||
}
|
||||
if (jAddress.has("country")) {
|
||||
gAddress.setAddressLine(addressIndex++, jAddress.getString("country"));
|
||||
gAddress.setCountryName(jAddress.getString("country"));
|
||||
}
|
||||
if (jAddress.has("country_code"))
|
||||
gAddress.setCountryCode(jAddress.getString("country_code"));
|
||||
|
||||
/* 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 gAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param latitude ...
|
||||
* @param longitude ...
|
||||
* @param maxResults ...
|
||||
* @return ...
|
||||
* @throws IOException ...
|
||||
*/
|
||||
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
|
||||
throws IOException {
|
||||
String url = mServiceUrl
|
||||
+ "reverse?"
|
||||
+ "format=json"
|
||||
+ "&accept-language=" + mLocale.getLanguage()
|
||||
//+ "&addressdetails=1"
|
||||
+ "&lat=" + latitude
|
||||
+ "&lon=" + longitude;
|
||||
log.debug("GeocoderNominatim::getFromLocation:" + url);
|
||||
String result = BonusPackHelper.requestStringFromUrl(url);
|
||||
//log.debug(result);
|
||||
if (result == null)
|
||||
throw new IOException();
|
||||
try {
|
||||
JSONObject jResult = new JSONObject(result);
|
||||
Address gAddress = buildAndroidAddress(jResult);
|
||||
List<Address> list = new ArrayList<Address>();
|
||||
list.add(gAddress);
|
||||
return list;
|
||||
} catch (JSONException e) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Address> getFromLocationName(String locationName, int maxResults,
|
||||
double lowerLeftLatitude, double lowerLeftLongitude,
|
||||
double upperRightLatitude, double upperRightLongitude)
|
||||
throws IOException {
|
||||
String url = mServiceUrl
|
||||
+ "search?"
|
||||
+ "format=json"
|
||||
+ "&accept-language=" + mLocale.getLanguage()
|
||||
+ "&addressdetails=1"
|
||||
+ "&limit=" + maxResults
|
||||
+ "&q=" + URLEncoder.encode(locationName, "UTF-8");
|
||||
if (lowerLeftLatitude != 0.0 && lowerLeftLongitude != 0.0) {
|
||||
//viewbox = left, top, right, bottom:
|
||||
url += "&viewbox=" + lowerLeftLongitude
|
||||
+ "," + upperRightLatitude
|
||||
+ "," + upperRightLongitude
|
||||
+ "," + lowerLeftLatitude
|
||||
+ "&bounded=1";
|
||||
}
|
||||
log.debug("GeocoderNominatim::getFromLocationName:" + url);
|
||||
String result = BonusPackHelper.requestStringFromUrl(url);
|
||||
//log.debug(result);
|
||||
if (result == null)
|
||||
throw new IOException();
|
||||
try {
|
||||
JSONArray jResults = new JSONArray(result);
|
||||
List<Address> list = new ArrayList<Address>();
|
||||
for (int i = 0; i < jResults.length(); i++) {
|
||||
JSONObject jResult = jResults.getJSONObject(i);
|
||||
Address gAddress = buildAndroidAddress(jResult);
|
||||
list.add(gAddress);
|
||||
}
|
||||
return list;
|
||||
} catch (JSONException e) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Address> getFromLocationName(String locationName, int maxResults)
|
||||
throws IOException {
|
||||
return getFromLocationName(locationName, maxResults, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
192
vtm-app/src/org/osmdroid/location/NominatimPOIProvider.java
Normal file
192
vtm-app/src/org/osmdroid/location/NominatimPOIProvider.java
Normal file
@@ -0,0 +1,192 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* POI Provider using Nominatim service. <br>
|
||||
* See https://wiki.openstreetmap.org/wiki/Nominatim<br>
|
||||
* and http://open.mapquestapi.com/nominatim/<br>
|
||||
*
|
||||
* @author M.Kergall
|
||||
*/
|
||||
public class NominatimPOIProvider implements POIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(NominatimPOIProvider.class);
|
||||
|
||||
/* As the doc lacks a lot of features, source code may help:
|
||||
* https://trac.openstreetmap
|
||||
* .org/browser/applications/utils/nominatim/website/search.php featuretype=
|
||||
* to select on feature type (country, city, state, settlement)<br>
|
||||
* format=jsonv2 to get a place_rank<br> offset= to offset the result ?...
|
||||
* <br> polygon=1 to get the border of the poi as a polygon<br> nearlat &
|
||||
* nearlon = ???<br> routewidth/69 and routewidth/30 ???<br> */
|
||||
public static final String MAPQUEST_POI_SERVICE = "http://open.mapquestapi.com/nominatim/v1/";
|
||||
public static final String NOMINATIM_POI_SERVICE = "http://nominatim.openstreetmap.org/";
|
||||
protected String mService;
|
||||
|
||||
public NominatimPOIProvider() {
|
||||
mService = NOMINATIM_POI_SERVICE;
|
||||
}
|
||||
|
||||
public void setService(String serviceUrl) {
|
||||
mService = serviceUrl;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private StringBuffer getCommonUrl(String type, int maxResults) {
|
||||
StringBuffer urlString = new StringBuffer(mService);
|
||||
urlString.append("search?");
|
||||
urlString.append("format=json");
|
||||
urlString.append("&q=" + URLEncoder.encode(type));
|
||||
urlString.append("&limit=" + maxResults);
|
||||
//urlString.append("&bounded=1");
|
||||
// urlString.append("&addressdetails=0");
|
||||
return urlString;
|
||||
}
|
||||
|
||||
private String getUrlInside(BoundingBox bb, String type, int maxResults) {
|
||||
StringBuffer urlString = getCommonUrl(type, maxResults);
|
||||
urlString.append("&viewbox=" + bb.getMaxLongitude() + ","
|
||||
+ bb.getMaxLatitude() + ","
|
||||
+ bb.getMinLongitude() + ","
|
||||
+ bb.getMinLatitude());
|
||||
return urlString.toString();
|
||||
}
|
||||
|
||||
private String getUrlCloseTo(GeoPoint p, String type,
|
||||
int maxResults, double maxDistance) {
|
||||
int maxD = (int) (maxDistance * 1E6);
|
||||
BoundingBox bb = new BoundingBox(p.latitudeE6 + maxD,
|
||||
p.longitudeE6 + maxD,
|
||||
p.latitudeE6 - maxD,
|
||||
p.longitudeE6 - maxD);
|
||||
return getUrlInside(bb, type, maxResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url full URL request
|
||||
* @return the list of POI, of null if technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getThem(String url) {
|
||||
log.debug("NominatimPOIProvider:get:" + url);
|
||||
String jString = BonusPackHelper.requestStringFromUrl(url);
|
||||
if (jString == null) {
|
||||
log.error("NominatimPOIProvider: request failed.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONArray jPlaceIds = new JSONArray(jString);
|
||||
int n = jPlaceIds.length();
|
||||
ArrayList<POI> pois = new ArrayList<POI>(n);
|
||||
Bitmap thumbnail = null;
|
||||
for (int i = 0; i < n; i++) {
|
||||
JSONObject jPlace = jPlaceIds.getJSONObject(i);
|
||||
POI poi = new POI(POI.POI_SERVICE_NOMINATIM);
|
||||
poi.id = jPlace.getString("osm_id");
|
||||
// jPlace.optLong("osm_id");
|
||||
poi.location = new GeoPoint(jPlace.getDouble("lat"), jPlace.getDouble("lon"));
|
||||
JSONArray bbox = jPlace.optJSONArray("boundingbox");
|
||||
if (bbox != null) {
|
||||
try {
|
||||
poi.bbox = new BoundingBox(bbox.getDouble(0), bbox.getDouble(2),
|
||||
bbox.getDouble(1), bbox.getDouble(3));
|
||||
} catch (Exception e) {
|
||||
log.debug("could not parse " + bbox);
|
||||
}
|
||||
//log.debug("bbox " + poi.bbox);
|
||||
}
|
||||
poi.category = jPlace.optString("class");
|
||||
poi.type = jPlace.getString("type");
|
||||
poi.description = jPlace.optString("display_name");
|
||||
poi.thumbnailPath = jPlace.optString("icon", null);
|
||||
|
||||
if (i == 0 && poi.thumbnailPath != null) {
|
||||
//first POI, and we have a thumbnail: load it
|
||||
thumbnail = BonusPackHelper.loadBitmap(poi.thumbnailPath);
|
||||
}
|
||||
poi.thumbnail = thumbnail;
|
||||
pois.add(poi);
|
||||
}
|
||||
return pois;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param position ...
|
||||
* @param type an OpenStreetMap feature. See
|
||||
* http://wiki.openstreetmap.org/wiki/Map_Features or
|
||||
* http://code.google.com/p/osmbonuspack/source/browse/trunk/
|
||||
* OSMBonusPackDemo/res/values/poi_tags.xml
|
||||
* @param maxResults the maximum number of POI returned. Note that in any case,
|
||||
* Nominatim will have an absolute maximum of 100.
|
||||
* @param maxDistance to the position, in degrees. Note that it is used to build a
|
||||
* bounding box around the position, not a circle.
|
||||
* @return the list of POI, null if technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOICloseTo(GeoPoint position, String type,
|
||||
int maxResults, double maxDistance) {
|
||||
String url = getUrlCloseTo(position, type, maxResults, maxDistance);
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundingBox ...
|
||||
* @param type OpenStreetMap feature
|
||||
* @param maxResults ...
|
||||
* @return list of POIs, null if technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOIInside(BoundingBox boundingBox, String type, int maxResults) {
|
||||
String url = getUrlInside(boundingBox, type, maxResults);
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
public ArrayList<POI> getPOI(String query, int maxResults) {
|
||||
String url = getCommonUrl(query, maxResults).toString();
|
||||
return getThem(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path Warning: a long path may cause a failure due to the url to be
|
||||
* too long. Using a simplified route may help (see
|
||||
* Road.getRouteLow()).
|
||||
* @param type OpenStreetMap feature
|
||||
* @param maxResults ...
|
||||
* @param maxWidth to the path. Certainly not in degrees. Probably in km.
|
||||
* @return list of POIs, null if technical issue.
|
||||
*/
|
||||
public ArrayList<POI> getPOIAlong(ArrayList<GeoPoint> path, String type,
|
||||
int maxResults, double maxWidth) {
|
||||
StringBuffer urlString = getCommonUrl(type, maxResults);
|
||||
urlString.append("&routewidth=" + maxWidth);
|
||||
urlString.append("&route=");
|
||||
boolean isFirst = true;
|
||||
for (GeoPoint p : path) {
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
urlString.append(",");
|
||||
String lat = Double.toString(p.getLatitude());
|
||||
lat = lat.substring(0, Math.min(lat.length(), 7));
|
||||
String lon = Double.toString(p.getLongitude());
|
||||
lon = lon.substring(0, Math.min(lon.length(), 7));
|
||||
urlString.append(lat + "," + lon);
|
||||
//limit the size of url as much as possible, as post method is not supported.
|
||||
}
|
||||
return getThem(urlString.toString());
|
||||
}
|
||||
}
|
||||
67
vtm-app/src/org/osmdroid/location/OverpassPOIProvider.java
Normal file
67
vtm-app/src/org/osmdroid/location/OverpassPOIProvider.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.core.osm.OsmData;
|
||||
import org.oscim.core.osm.OsmNode;
|
||||
import org.oscim.utils.osmpbf.OsmPbfReader;
|
||||
import org.osmdroid.utils.HttpConnection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OverpassPOIProvider implements POIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory
|
||||
.getLogger(OverpassPOIProvider.class);
|
||||
|
||||
public static final String TAG_KEY_WEBSITE = "website".intern();
|
||||
|
||||
@Override
|
||||
public List<POI> getPOIInside(BoundingBox boundingBox, String query,
|
||||
int maxResults) {
|
||||
HttpConnection connection = new HttpConnection();
|
||||
boundingBox.toString();
|
||||
|
||||
String q = "node[\"amenity\"~\"^restaurant$|^pub$\"]("
|
||||
+ boundingBox.format() + ");out 100;";
|
||||
String url = "http://city.informatik.uni-bremen.de/oapi/pbf?data=";
|
||||
String encoded;
|
||||
try {
|
||||
encoded = URLEncoder.encode(q, "utf-8");
|
||||
} catch (UnsupportedEncodingException e1) {
|
||||
e1.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
log.debug("request " + url + encoded);
|
||||
connection.doGet(url + encoded);
|
||||
OsmData osmData = OsmPbfReader.process(connection.getStream());
|
||||
ArrayList<POI> pois = new ArrayList<POI>(osmData.getNodes().size());
|
||||
|
||||
for (OsmNode n : osmData.getNodes()) {
|
||||
POI p = new POI(POI.POI_SERVICE_4SQUARE);
|
||||
p.id = Long.toString(n.id);
|
||||
|
||||
p.location = new GeoPoint(n.lat, n.lon);
|
||||
Tag t;
|
||||
|
||||
if ((t = n.tags.get(Tag.KEY_NAME)) != null)
|
||||
p.description = t.value;
|
||||
|
||||
if ((t = n.tags.get(Tag.KEY_AMENITY)) != null)
|
||||
p.type = t.value;
|
||||
|
||||
if ((t = n.tags.get(TAG_KEY_WEBSITE)) != null) {
|
||||
log.debug(p.description + " " + t.value);
|
||||
p.url = t.value;
|
||||
}
|
||||
pois.add(p);
|
||||
}
|
||||
return pois;
|
||||
}
|
||||
}
|
||||
205
vtm-app/src/org/osmdroid/location/POI.java
Normal file
205
vtm-app/src/org/osmdroid/location/POI.java
Normal file
@@ -0,0 +1,205 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.oscim.app.R;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.BonusPackHelper;
|
||||
|
||||
/**
|
||||
* Point of Interest. Exact content may depend of the POI provider used.
|
||||
*
|
||||
* @author M.Kergall
|
||||
* @see NominatimPOIProvider
|
||||
* @see GeoNamesPOIProvider
|
||||
*/
|
||||
public class POI {
|
||||
|
||||
/**
|
||||
* IDs of POI services
|
||||
*/
|
||||
public static int POI_SERVICE_NOMINATIM = 100;
|
||||
public static int POI_SERVICE_GEONAMES_WIKIPEDIA = 200;
|
||||
public static int POI_SERVICE_FLICKR = 300;
|
||||
public static int POI_SERVICE_PICASA = 400;
|
||||
public static int POI_SERVICE_4SQUARE = 500;
|
||||
|
||||
/**
|
||||
* Identifies the service provider of this POI.
|
||||
*/
|
||||
public int serviceId;
|
||||
/**
|
||||
* Nominatim: OSM ID. GeoNames: 0
|
||||
*/
|
||||
public String id;
|
||||
/**
|
||||
* location of the POI
|
||||
*/
|
||||
public GeoPoint location;
|
||||
public BoundingBox bbox;
|
||||
/**
|
||||
* Nominatim "class", GeoNames "feature"
|
||||
*/
|
||||
public String category;
|
||||
/**
|
||||
* type or title
|
||||
*/
|
||||
public String type;
|
||||
/**
|
||||
* can be the name, the address, a short description
|
||||
*/
|
||||
public String description;
|
||||
/**
|
||||
* url of the thumbnail. Null if none
|
||||
*/
|
||||
public String thumbnailPath;
|
||||
/**
|
||||
* the thumbnail itself. Null if none
|
||||
*/
|
||||
public Bitmap thumbnail;
|
||||
/**
|
||||
* url to a more detailed information page about this POI. Null if none
|
||||
*/
|
||||
public String url;
|
||||
/**
|
||||
* popularity of this POI, from 1 (lowest) to 100 (highest). 0 if not
|
||||
* defined.
|
||||
*/
|
||||
public int rank;
|
||||
|
||||
/**
|
||||
* number of attempts to load the thumbnail that have failed
|
||||
*/
|
||||
protected int mThumbnailLoadingFailures;
|
||||
|
||||
public POI(int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
// lets all other fields empty or null. That's fine.
|
||||
}
|
||||
|
||||
protected static int MAX_LOADING_ATTEMPTS = 2;
|
||||
|
||||
/**
|
||||
* @return the POI thumbnail as a Bitmap, if any. If not done yet, it will
|
||||
* load the POI thumbnail from its url (in thumbnailPath field).
|
||||
*/
|
||||
public Bitmap getThumbnail() {
|
||||
if (thumbnail == null && thumbnailPath != null) {
|
||||
thumbnail = BonusPackHelper.loadBitmap(thumbnailPath);
|
||||
if (thumbnail == null) {
|
||||
mThumbnailLoadingFailures++;
|
||||
if (mThumbnailLoadingFailures >= MAX_LOADING_ATTEMPTS) {
|
||||
// this path really doesn't work, "kill" it for next calls:
|
||||
thumbnailPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/7729133/using-asynctask-to-load-images-in-listview
|
||||
// TODO see link, there might be a better solution
|
||||
|
||||
/**
|
||||
* Fetch the thumbnail from its url on a thread.
|
||||
*
|
||||
* @param imageView to update once the thumbnail is retrieved, or to hide if no
|
||||
* thumbnail.
|
||||
*/
|
||||
public void fetchThumbnail(final ImageView imageView) {
|
||||
if (thumbnail != null) {
|
||||
imageView.setImageBitmap(thumbnail);
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
} else if (thumbnailPath != null) {
|
||||
imageView.setImageResource(R.drawable.ic_empty);
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
new ThumbnailTask(imageView).execute(imageView);
|
||||
} else {
|
||||
imageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
class ThumbnailTask extends AsyncTask<ImageView, Void, ImageView> {
|
||||
|
||||
public ThumbnailTask(ImageView iv) {
|
||||
iv.setTag(thumbnailPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImageView doInBackground(ImageView... params) {
|
||||
getThumbnail();
|
||||
return params[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ImageView iv) {
|
||||
if (iv == null || thumbnail == null)
|
||||
return;
|
||||
if (thumbnailPath.equals(iv.getTag().toString()))
|
||||
iv.setImageBitmap(thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Parcelable implementation
|
||||
|
||||
// @Override
|
||||
// public int describeContents() {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public void writeToParcel(Parcel out, int flags) {
|
||||
// out.writeInt(serviceId);
|
||||
// out.writeString(id);
|
||||
// out.writeParcelable(location, 0);
|
||||
// out.writeString(category);
|
||||
// out.writeString(type);
|
||||
// out.writeString(description);
|
||||
// out.writeString(thumbnailPath);
|
||||
// out.writeParcelable(thumbnail, 0);
|
||||
// out.writeString(url);
|
||||
// out.writeInt(rank);
|
||||
// out.writeInt(mThumbnailLoadingFailures);
|
||||
// }
|
||||
//
|
||||
// public static final Parcelable.Creator<POI> CREATOR = new Parcelable.Creator<POI>() {
|
||||
// @Override
|
||||
// public POI createFromParcel(Parcel in) {
|
||||
// POI poi = new POI(in.readInt());
|
||||
// poi.id = in.readString();
|
||||
// poi.location = in.readParcelable(GeoPoint.class.getClassLoader());
|
||||
// poi.category = in.readString();
|
||||
// poi.type = in.readString();
|
||||
// poi.description = in.readString();
|
||||
// poi.thumbnailPath = in.readString();
|
||||
// poi.thumbnail = in.readParcelable(Bitmap.class.getClassLoader());
|
||||
// poi.url = in.readString();
|
||||
// poi.rank = in.readInt();
|
||||
// poi.mThumbnailLoadingFailures = in.readInt();
|
||||
// return poi;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public POI[] newArray(int size) {
|
||||
// return new POI[size];
|
||||
// }
|
||||
// };
|
||||
|
||||
// private POI(Parcel in) {
|
||||
// serviceId = in.readInt();
|
||||
// id = in.readLong();
|
||||
// location = in.readParcelable(GeoPoint.class.getClassLoader());
|
||||
// category = in.readString();
|
||||
// type = in.readString();
|
||||
// description = in.readString();
|
||||
// thumbnailPath = in.readString();
|
||||
// thumbnail = in.readParcelable(Bitmap.class.getClassLoader());
|
||||
// url = in.readString();
|
||||
// rank = in.readInt();
|
||||
// mThumbnailLoadingFailures = in.readInt();
|
||||
// }
|
||||
}
|
||||
10
vtm-app/src/org/osmdroid/location/POIProvider.java
Normal file
10
vtm-app/src/org/osmdroid/location/POIProvider.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import org.oscim.core.BoundingBox;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface POIProvider {
|
||||
|
||||
public List<POI> getPOIInside(BoundingBox boundingBox, String query, int maxResults);
|
||||
}
|
||||
161
vtm-app/src/org/osmdroid/location/PicasaPOIProvider.java
Normal file
161
vtm-app/src/org/osmdroid/location/PicasaPOIProvider.java
Normal file
@@ -0,0 +1,161 @@
|
||||
package org.osmdroid.location;
|
||||
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.osmdroid.utils.HttpConnection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* POI Provider using Picasa service.
|
||||
*
|
||||
* @author M.Kergall
|
||||
* @see "https://developers.google.com/picasa-web/docs/2.0/reference"
|
||||
*/
|
||||
public class PicasaPOIProvider implements POIProvider {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(PicasaPOIProvider.class);
|
||||
|
||||
String mAccessToken;
|
||||
|
||||
/**
|
||||
* @param accessToken the account to give to the service. Null for public access.
|
||||
* @see "https://developers.google.com/picasa-web/docs/2.0/developers_guide_protocol#CreatingAccount"
|
||||
*/
|
||||
public PicasaPOIProvider(String accessToken) {
|
||||
mAccessToken = accessToken;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getUrlInside(BoundingBox boundingBox, int maxResults, String query) {
|
||||
StringBuffer url = new StringBuffer("http://picasaweb.google.com/data/feed/api/all?");
|
||||
url.append("bbox=" + boundingBox.getMinLongitude());
|
||||
url.append("," + boundingBox.getMinLatitude());
|
||||
url.append("," + boundingBox.getMaxLongitude());
|
||||
url.append("," + boundingBox.getMaxLatitude());
|
||||
url.append("&max-results=" + maxResults);
|
||||
url.append("&thumbsize=64c"); //thumbnail size: 64, cropped.
|
||||
url.append("&fields=openSearch:totalResults,entry(summary,media:group/media:thumbnail,media:group/media:title,gphoto:*,georss:where,link)");
|
||||
if (query != null)
|
||||
url.append("&q=" + URLEncoder.encode(query));
|
||||
if (mAccessToken != null) {
|
||||
//TODO: warning: not tested...
|
||||
url.append("&access_token=" + mAccessToken);
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public ArrayList<POI> getThem(String fullUrl) {
|
||||
log.debug("PicasaPOIProvider:get:" + fullUrl);
|
||||
HttpConnection connection = new HttpConnection();
|
||||
connection.doGet(fullUrl);
|
||||
InputStream stream = connection.getStream();
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
PicasaXMLHandler handler = new PicasaXMLHandler();
|
||||
try {
|
||||
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
|
||||
parser.getXMLReader().setFeature("http://xml.org/sax/features/namespaces", false);
|
||||
parser.getXMLReader()
|
||||
.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
|
||||
parser.parse(stream, handler);
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
connection.close();
|
||||
if (handler.mPOIs != null)
|
||||
log.debug("done:" + handler.mPOIs.size() + " got on a total of:"
|
||||
+ handler.mTotalResults);
|
||||
return handler.mPOIs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundingBox ...
|
||||
* @param maxResults ...
|
||||
* @param query - optional - full-text query string. Searches the title,
|
||||
* caption and tags for the specified string value.
|
||||
* @return list of POI, Picasa photos inside the bounding box. Null if
|
||||
* technical issue.
|
||||
*/
|
||||
public List<POI> getPOIInside(BoundingBox boundingBox, String query, int maxResults) {
|
||||
String url = getUrlInside(boundingBox, maxResults, query);
|
||||
return getThem(url);
|
||||
}
|
||||
}
|
||||
|
||||
class PicasaXMLHandler extends DefaultHandler {
|
||||
|
||||
private String mString;
|
||||
double mLat, mLng;
|
||||
POI mPOI;
|
||||
ArrayList<POI> mPOIs;
|
||||
int mTotalResults;
|
||||
|
||||
public PicasaXMLHandler() {
|
||||
mPOIs = new ArrayList<POI>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) {
|
||||
if (qName.equals("entry")) {
|
||||
mPOI = new POI(POI.POI_SERVICE_PICASA);
|
||||
} else if (qName.equals("media:thumbnail")) {
|
||||
mPOI.thumbnailPath = attributes.getValue("url");
|
||||
} else if (qName.equals("link")) {
|
||||
String rel = attributes.getValue("rel");
|
||||
if ("http://schemas.google.com/photos/2007#canonical".equals(rel)) {
|
||||
mPOI.url = attributes.getValue("href");
|
||||
}
|
||||
}
|
||||
mString = new String();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) {
|
||||
String chars = new String(ch, start, length);
|
||||
mString = mString.concat(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
if (qName.equals("gml:pos")) {
|
||||
String[] coords = mString.split(" ");
|
||||
mLat = Double.parseDouble(coords[0]);
|
||||
mLng = Double.parseDouble(coords[1]);
|
||||
} else if (qName.equals("gphoto:id")) {
|
||||
mPOI.id = mString;
|
||||
} else if (qName.equals("media:title")) {
|
||||
mPOI.type = mString;
|
||||
} else if (qName.equals("summary")) {
|
||||
mPOI.description = mString;
|
||||
} else if (qName.equals("gphoto:albumtitle")) {
|
||||
mPOI.category = mString;
|
||||
} else if (qName.equals("entry")) {
|
||||
mPOI.location = new GeoPoint(mLat, mLng);
|
||||
mPOIs.add(mPOI);
|
||||
mPOI = null;
|
||||
} else if (qName.equals("openSearch:totalResults")) {
|
||||
mTotalResults = Integer.parseInt(mString);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user