Files
location_library/LocationLib/src/com/TwentyCodes/android/overlays/DirectionsOverlay.java
2012-07-01 11:19:46 -04:00

355 lines
9.3 KiB
Java

/**
* DirectionsOverlay.java
* @date Nov 10, 2011
* @author ricky barrette
* @author Twenty Codes, LLC
*/
package com.TwentyCodes.android.overlays;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.graphics.Color;
import android.util.Log;
import com.TwentyCodes.android.debug.Debug;
import com.TwentyCodes.android.location.MapView;
import com.google.android.maps.GeoPoint;
/**
* This Overlay class will be used to display provided by the Google Directions API on a map
* @author ricky barrette
*/
public class DirectionsOverlay {
/**
* @author ricky barrette
*/
public interface OnDirectionsCompleteListener{
public void onDirectionsComplete(DirectionsOverlay directionsOverlay);
}
private static final String TAG = "DirectionsOverlay";
private ArrayList<PathOverlay> mPath;
private ArrayList<String> mDirections;
private final MapView mMapView;
private final OnDirectionsCompleteListener mListener;
private String mCopyRights;
private ArrayList<GeoPoint> mPoints;
private ArrayList<String> mDistance;
private ArrayList<String> mDuration;
private ArrayList<String> mWarnings;
/**
* Downloads and Creates a new DirectionsOverlay from the provided points
* @param origin point
* @param destination point
* @author ricky barrette
* @throws IOException
* @throws ClientProtocolException
* @throws IllegalStateException
* @throws JSONException
*/
public DirectionsOverlay(final MapView map, final GeoPoint origin, final GeoPoint destination, final OnDirectionsCompleteListener listener) throws IllegalStateException, ClientProtocolException, IOException, JSONException {
mMapView = map;
mListener = listener;
final String json = downloadJSON(generateUrl(origin, destination));
drawPath(json);
}
/**
* Creates a new DirectionsOverlay from the provided String JSON
* @param json
* @throws JSONException
* @author ricky barrette
*/
public DirectionsOverlay(final MapView map, final String json, final OnDirectionsCompleteListener listener) throws JSONException{
mListener = listener;
mMapView = map;
drawPath(json);
}
/**
* Deocodes googles polyline
* @param encoded
* @return a list of geopoints representing the path
* @author Mark McClure http://facstaff.unca.edu/mcmcclur/googlemaps/encodepolyline/
* @author ricky barrette
* @throws JSONException
*/
private void decodePoly(final JSONObject step) throws JSONException {
if(Debug.DEBUG)
Log.d(TAG, "decodePoly");
final String encoded = step.getJSONObject("polyline").getString("points");
int index = 0;
final int len = encoded.length();
int lat = 0, lng = 0;
GeoPoint last = null;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
final int dlat = (result & 1) != 0 ? ~(result >> 1) : result >> 1;
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
final int dlng = (result & 1) != 0 ? ~(result >> 1) : result >> 1;
lng += dlng;
final GeoPoint p = new GeoPoint((int) (lat / 1E5 * 1E6), (int) (lng / 1E5 * 1E6));
if(Debug.DEBUG){
Log.d(TAG, "current = "+ p.toString());
if(last != null)
Log.d(TAG, "last = "+ last.toString());
}
if(last != null)
mPath.add(new PathOverlay(last, p, Color.RED));
// else
// mPath.add(new PathOverlay(p, 5, Color.GREEN));
last = p;
}
}
/**
* Downloads Google Directions JSON from the Internet
* @param url
* @return
* @throws IllegalStateException
* @throws ClientProtocolException
* @throws IOException
* @author ricky barrette
*/
private String downloadJSON(final String url) throws IllegalStateException, ClientProtocolException, IOException {
if(Debug.DEBUG)
Log.d(TAG, url);
if(url == null)
throw new NullPointerException();
final StringBuffer response = new StringBuffer();
final BufferedReader br = new BufferedReader(new InputStreamReader(new DefaultHttpClient().execute(new HttpGet(url)).getEntity().getContent()));
String buff = null;
while ((buff = br.readLine()) != null)
response.append(buff);
return response.toString();
}
/**
* Creates a new DirectionsOverlay from the json provided
* @param json of Google Directions API
* @author ricky barrette
* @return
* @throws JSONException
*/
public void drawPath(final String json) throws JSONException{
if(Debug.DEBUG){
Log.d(TAG, "drawPath");
Log.d(TAG, json);
}
mPath = new ArrayList<PathOverlay>();
mDirections = new ArrayList<String>();
mPoints = new ArrayList<GeoPoint>();
mDistance = new ArrayList<String>();
mDuration = new ArrayList<String>();
//get first route
final JSONObject route = new JSONObject(json).getJSONArray("routes").getJSONObject(0);
mCopyRights = route.getString("copyrights");
//route.getString("status");
final JSONObject leg = route.getJSONArray("legs").getJSONObject(0);
getDistance(leg);
getDuration(leg);
// mMapView.getOverlays().add(new PathOverlay(getGeoPoint(leg.getJSONObject("start_location")), 12, Color.GREEN));
// mMapView.getOverlays().add(new PathOverlay(getGeoPoint(leg.getJSONObject("end_location")), 12, Color.RED));
leg.getString("start_address");
leg.getString("end_address");
// JSONArray warnings = leg.getJSONArray("warnings");
// for(int i = 0; i < warnings.length(); i++){
// mWarnings.add(warnings.get)w
// }w
/*
* here we will parse the steps of the directions
*/
if(Debug.DEBUG)
Log.d(TAG, "processing steps");
final JSONArray steps = leg.getJSONArray("steps");
JSONObject step = null;
for(int i = 0; i < steps.length(); i++){
if(Debug.DEBUG)
Log.d(TAG, "step "+i);
step = steps.getJSONObject(i);
if(Debug.DEBUG){
Log.d(TAG, "start "+getGeoPoint(step.getJSONObject("start_location")).toString());
Log.d(TAG, "end "+getGeoPoint(step.getJSONObject("end_location")).toString());
}
// if(Debug.DEBUG)
// mMapView.getOverlays().add(new PathOverlay(getGeoPoint(step.getJSONObject("start_location")), getGeoPoint(step.getJSONObject("end_location")), Color.MAGENTA));
decodePoly(step);
mDuration.add(getDuration(step));
mDistance.add(getDistance(step));
mDirections.add(step.getString("html_instructions"));
// Log.d("TEST", step.getString("html_instructions"));
mPoints.add(getGeoPoint(step.getJSONObject("start_location")));
}
if(Debug.DEBUG)
Log.d(TAG, "finished parsing");
if(mMapView != null){
mMapView.getOverlays().addAll(mPath);
mMapView.postInvalidate();
}
if(mListener != null)
mListener.onDirectionsComplete(DirectionsOverlay.this);
}
/**
* @param origin
* @param destination
* @return The Google API url for our directions
* @author ricky barrette
*/
private String generateUrl(final GeoPoint origin, final GeoPoint destination){
return "http://maps.googleapis.com/maps/api/directions/json?&origin="+
Double.toString(origin.getLatitudeE6() / 1.0E6)+
","+
Double.toString(origin.getLongitudeE6() / 1.0E6)+
"&destination="+
Double.toString(destination.getLatitudeE6() / 1.0E6)+
","+
Double.toString(destination.getLongitudeE6() / 1.0E6)+
"&sensor=true&mode=walking";
}
/**
* @return
* @author ricky barrette
*/
public String getCopyrights(){
return mCopyRights;
}
/**
* @return
* @author ricky barrette
*/
public ArrayList<String> getDirections() {
return mDirections;
}
/**
* @param step
* @return the distance of a step
* @throws JSONException
* @author ricky barrette
*/
private String getDistance(final JSONObject step) throws JSONException{
return step.getJSONObject("distance").getString("text");
}
/**
* @return
* @author ricky barrette
*/
public ArrayList<String> getDistances(){
return mDistance;
}
/**
* @param step
* @return the duration of a step
* @throws JSONException
* @author ricky barrette
*/
private String getDuration(final JSONObject step) throws JSONException{
return step.getJSONObject("duration").getString("text");
}
/**
* @return
* @author ricky barrette
*/
public ArrayList<String> getDurations(){
return mDuration;
}
/**
* Converts a JSON location object into a GeoPoint
* @param point
* @return Geopoint parsed from the provided JSON Object
* @throws JSONException
* @author ricky barrette
*/
private GeoPoint getGeoPoint(final JSONObject point) throws JSONException{
return new GeoPoint((int) (point.getDouble("lat")*1E6), (int) (point.getDouble("lng")*1E6));
}
/**
* @return the array of PathOverlays
* @author ricky barrette
*/
public ArrayList<PathOverlay> getPath(){
return mPath;
}
/**
* @return
* @author ricky barrette
*/
public ArrayList<GeoPoint> getPoints() {
return mPoints;
}
/**
* @return
* @author ricky barrette
*/
public ArrayList<String> getWarnings() {
return mWarnings;
}
/**
* Removes the directions overlay from the map view
* @author ricky barrette
*/
public void removePath() {
if(mMapView.getOverlays().removeAll(mPath));
}
}