Java tutorial
/******************************************************************************* * @contributor(s): Freerider Team (Group 4, IT2901 Fall 2012, NTNU) * @contributor(s): Freerider Team 2 (Group 3, IT2901 Spring 2013, NTNU) * @version: 2.0 * * Copyright 2013 Freerider Team 2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package no.ntnu.idi.socialhitchhiking.map; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import no.ntnu.idi.freerider.model.Location; import no.ntnu.idi.freerider.model.MapLocation; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.location.Address; import android.location.Geocoder; import com.google.android.maps.GeoPoint; /** * A helper class for everything that has to do with geocoding/reverse geocoding and * converting between different kinds of"geo"-objects. * * @author Thomas Gjerde */ public class GeoHelper { private static Geocoder fancyGeocoder = null; public static void initGeocoder(Context context) { fancyGeocoder = new Geocoder(context); } /** * Gets a list of addresses from a set of coordinates * @param lat * @param lon * @param maxResults * @return */ public static List<Address> getAddressesFromLocation(double lat, double lon, int maxResults) { JSONArray responseArray = getJSONArrayFromLocation(lat, lon, maxResults); List<Address> addresses = new ArrayList<Address>(); JSONObject jsonObj; for (int i = 0; i < responseArray.length(); i++) { Address address = new Address(Locale.getDefault()); String addressLine; try { jsonObj = responseArray.getJSONObject(i); addressLine = jsonObj.getString("formatted_address"); if (addressLine.contains(",")) { String[] lines = addressLine.split(","); for (int j = 0; j < lines.length; j++) { address.setAddressLine(j, lines[j].trim()); } } addresses.add(address); } catch (JSONException e) { continue; } } return addresses; } /** * Retrieves the address at the given {@link GeoPoint}, by calling {@link #getAddressesAtPressedPoint(GeoPoint, int, int)} * and returns the first {@link String} in the {@link List} returned. * * @param location The location that you want the address of * @return Returns the address at the given {@link GeoPoint}, or "Could not find the address." if it is not found. */ public static String getAddressAtPointString(GeoPoint location) { List<String> addresses = getAddressesAtPoint(location, 1, 5); if (addresses.size() > 0) { return addresses.get(0); } return "Could not find the address."; } /** * Retrieves a {@link List} of addresses that match the given {@link GeoPoint}. * The first element in the list has the best match (but is not guaranteed to be correct). <br><br> * * This method tries to use the {@link Geocoder} to transform a (latitude, longitude) * coordinate into addresses, and if this fails (witch it most likely will under emulation), it * tries to use a method from the {@link GeoHelper}-class. * * @param location The location that is transformed into a list of addresses * @param maxResults The maximum number of addresses to retrieve (should be small). * @param maxAddressLines The maximum number of lines in the addresses. This should be high if you want a complete address! If it is smaller than the total number of lines in the address, it cuts off the last part...) * @return Returns the {@link List} of addresses (as {@link String}s). */ public static List<String> getAddressesAtPoint(final GeoPoint location, final int maxResults, int maxAddressLines) { List<String> addressList = new ArrayList<String>(); List<Address> possibleAddresses = new ArrayList<Address>(); Address address = new Address(Locale.getDefault()); String addressString = "Could not find the address..."; ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<List<Address>> callable = new Callable<List<Address>>() { @Override public List<Address> call() throws IOException { return fancyGeocoder.getFromLocation(location.getLatitudeE6() / 1E6, location.getLongitudeE6() / 1E6, maxResults); } }; Future<List<Address>> future = executor.submit(callable); try { possibleAddresses = future.get(); } catch (InterruptedException e1) { possibleAddresses = GeoHelper.getAddressesFromLocation(location.getLatitudeE6() / 1E6, location.getLongitudeE6() / 1E6, maxResults); } catch (ExecutionException e1) { possibleAddresses = GeoHelper.getAddressesFromLocation(location.getLatitudeE6() / 1E6, location.getLongitudeE6() / 1E6, maxResults); } executor.shutdown(); if (possibleAddresses.size() > 0) { for (int i = 0; i < possibleAddresses.size(); i++) { addressString = ""; address = possibleAddresses.get(i); for (int j = 0; j <= address.getMaxAddressLineIndex() && j <= maxAddressLines; j++) { addressString += address.getAddressLine(j); addressString += "\n"; } addressList.add(addressString.trim()); } } return addressList; } /** * Gets a {@link JSONArray} from the Google Maps API from a set of coordinates * @param lat * @param lon * @param maxResults * @return JSONArray of locations */ private static JSONArray getJSONArrayFromLocation(final double lat, final double lon, int maxResults) { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<JSONArray> callable = new Callable<JSONArray>() { @Override public JSONArray call() throws IOException { String urlStr = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + lat + "," + lon + "&sensor=false"; String response = ""; HttpClient client = new DefaultHttpClient(); HttpResponse hr = client.execute(new HttpGet(urlStr)); HttpEntity entity = hr.getEntity(); BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent())); String buff = null; while ((buff = br.readLine()) != null) response += buff; br.close(); JSONArray responseArray = null; try { JSONObject jsonObject = new JSONObject(response); responseArray = jsonObject.getJSONArray("results"); } catch (JSONException e) { return null; } return responseArray; } }; Future<JSONArray> future = executor.submit(callable); JSONArray ret; try { ret = future.get(); } catch (InterruptedException e) { // TODO Auto-generated catch block ret = null; } catch (ExecutionException e) { // TODO Auto-generated catch block ret = null; } return ret; } /** * Converts a {@link GeoPoint}-object to a {@link Location}-object. * @param gp The {@link GeoPoint} to convert * @return The returned {@link Location} */ public static Location getLocation(GeoPoint gp) { return new MapLocation((gp.getLatitudeE6() / 1E6), (gp.getLongitudeE6() / 1E6), getAddressAtPointString(gp)); } /** * Creates a {@link MapLocation}-object from two doubles (latitude and longitude). * Retrieves the address by using the method {@link #getAddressAtPointString(GeoPoint)}. * @param lat The Latitude of the location * @param lon The Longitude of the location * @return The returned {@link MapLocation} */ public static MapLocation getMapLocation(double lat, double lon) { return new MapLocation(lat, lon, getAddressAtPointString(new GeoPoint((int) (lat * 1E6), (int) (lon * 1E6)))); } /** * Converts an address ({@link String}) to a {@link MapLocation}. */ public static MapLocation getLocation(String address) { GeoPoint gp = getGeoPoint(address); double lat = (gp.getLatitudeE6() / 1E6); double lon = (gp.getLongitudeE6() / 1E6); String detailedAddress = getAddressAtPointString(gp); return new MapLocation(lat, lon, detailedAddress); } /** * Converts an address ({@link String}) to a {@link GeoPoint}. */ public static GeoPoint getGeoPoint(String address) { return GeoHelper.getLatLong(getLocationInfo(address)); } /** * Gets a {@link GeoPoint} from a {@link JSONObject} * @param jsonObject * @return */ private static GeoPoint getLatLong(JSONObject jsonObject) { Double lon = new Double(0); Double lat = new Double(0); try { lon = ((JSONArray) jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry") .getJSONObject("location").getDouble("lng"); lat = ((JSONArray) jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry") .getJSONObject("location").getDouble("lat"); } catch (Exception e) { e.printStackTrace(); } return new GeoPoint((int) (lat * 1E6), (int) (lon * 1E6)); } /** * Gets a {@link JSONObject} from an address string * @param adr * @return */ private static JSONObject getLocationInfo(final String adr) { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<StringBuilder> callable = new Callable<StringBuilder>() { @Override public StringBuilder call() throws ClientProtocolException, IOException { StringBuilder stringBuilder = new StringBuilder(); String address; address = adr.replaceAll(" ", "%20"); address = address.replaceAll("\n", "%20"); HttpPost httppost = new HttpPost( "http://maps.google.com/maps/api/geocode/json?address=" + address + "&sensor=false"); HttpClient client = new DefaultHttpClient(); HttpResponse response; stringBuilder = new StringBuilder(); response = client.execute(httppost); HttpEntity entity = response.getEntity(); InputStream stream = entity.getContent(); int b; while ((b = stream.read()) != -1) { stringBuilder.append((char) b); } return stringBuilder; } }; Future<StringBuilder> future = executor.submit(callable); StringBuilder stringBuilder; try { stringBuilder = future.get(); } catch (InterruptedException e1) { // TODO Auto-generated catch block stringBuilder = new StringBuilder(); } catch (ExecutionException e1) { stringBuilder = new StringBuilder(); } executor.shutdown(); JSONObject jsonObject = new JSONObject(); try { jsonObject = new JSONObject(stringBuilder.toString()); } catch (JSONException e) { e.printStackTrace(); } return jsonObject; } /** * Converts a {@link Location} to a {@link GeoPoint}. */ public static GeoPoint getGeoPoint(Location loc) { return new GeoPoint((int) (loc.getLatitude() * 1E6), (int) (loc.getLongitude() * 1E6)); } /** * Converts an array of {@link String}s to a {@link List} of {@link MapLocation}s. */ public static List<MapLocation> getLocationList(String[] addresses) { List<MapLocation> list = new ArrayList<MapLocation>(); for (int i = 0; i < addresses.length; i++) { list.add(GeoHelper.getLocation(addresses[i])); } return list; } }