package direction.json; 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 org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; import com.google.android.maps.GeoPoint; ; public class GoogleParser extends XMLParser implements Parser { /** Distance covered. **/ private int distance; public GoogleParser(String feedUrl) { super(feedUrl); } /** * Parses a url pointing to a Google JSON object to a Route object. * * @return a Route object based on the JSON object. */ public Route parse() { // turn the stream into a string final String result = convertStreamToString(this.getInputStream()); // Create an empty route final Route route = new Route(); // Create an empty segment final Segment segment = new Segment(); try { // Tranform the string into a json object final JSONObject json = new JSONObject(result); // Get the route object final JSONObject jsonRoute = json.getJSONArray("routes") .getJSONObject(0); // Get the leg, only one leg as we don't support waypoints final JSONObject leg = jsonRoute.getJSONArray("legs") .getJSONObject(0); // Get the steps for this leg final JSONArray steps = leg.getJSONArray("steps"); // Number of steps for use in for loop final int numSteps = steps.length(); // Set the name of this route using the start & end addresses route.setName(leg.getString("start_address") + " to " + leg.getString("end_address")); // Get google's copyright notice (tos requirement) route.setCopyright(jsonRoute.getString("copyrights")); // Get the total length of the route. route.setLength(leg.getJSONObject("distance").getInt("value")); // Get any warnings provided (tos requirement) if (!jsonRoute.getJSONArray("warnings").isNull(0)) { route.setWarning(jsonRoute.getJSONArray("warnings") .getString(0)); } /* * Loop through the steps, creating a segment for each one and * decoding any polylines found as we go to add to the route * object's map array. Using an explicit for loop because it is * faster! */ for (int i = 0; i < numSteps; i++) { // Get the individual step final JSONObject step = steps.getJSONObject(i); // Get the start position for this step and set it on the // segment final JSONObject start = step.getJSONObject("start_location"); final GeoPoint position = new GeoPoint( (int) (start.getDouble("lat") * 1E6), (int) (start.getDouble("lng") * 1E6)); segment.setPoint(position); // Set the length of this segment in metres final int length = step.getJSONObject("distance").getInt( "value"); distance += length; segment.setLength(length); segment.setDistance(distance / 1000); // Strip html from google directions and set as turn instruction segment.setInstruction(step.getString("html_instructions") .replaceAll("<(.*?)*>", "")); // Retrieve & decode this segment's polyline and add it to the // route. route.addPoints(decodePolyLine(step.getJSONObject("polyline") .getString("points"))); // Push a copy of the segment to the route route.addSegment(segment.copy()); } } catch (JSONException e) { Log.e(e.getMessage(), "Google JSON Parser - " + feedUrl); } return route; } /** * Convert an inputstream to a string. * * @param input * inputstream to convert. * @return a String of the inputstream. */ private static String convertStreamToString(final InputStream input) { final BufferedReader reader = new BufferedReader(new InputStreamReader( input)); final StringBuilder sBuf = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sBuf.append(line); } } catch (IOException e) { Log.e(e.getMessage(), "Google parser, stream2string"); } finally { try { input.close(); } catch (IOException e) { Log.e(e.getMessage(), "Google parser, stream2string"); } } return sBuf.toString(); } /** * Decode a polyline string into a list of GeoPoints. * * @param poly * polyline encoded string to decode. * @return the list of GeoPoints represented by this polystring. */ private List<GeoPoint> decodePolyLine(final String poly) { int len = poly.length(); int index = 0; List<GeoPoint> decoded = new ArrayList<GeoPoint>(); int lat = 0; int lng = 0; while (index < len) { int b; int shift = 0; int result = 0; do { b = poly.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = poly.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += dlng; decoded.add(new GeoPoint((int) (lat * 1E6 / 1E5), (int) (lng * 1E6 / 1E5))); } return decoded; } }