Friday, 18 March 2016

Driving distance and travel time duration between two locations in Google Map Android API V2

Get the API key for Google Maps Android API V2
We need to get an API key from Google to use Google Maps in Android application.
Please follow the given below link to get the API key for Google Maps Android API v2.

 Add Android Support library to this project
By default, Android support library (android-support-v4.jar ) is added to this project by Eclipse IDE to the directory libs. If it is not added, we can do it manually by doing the following steps :
  • Open Project Explorer by Clicking “Window -> Show View -> Project Explorer”
  • Right click this project
  • Then from popup menu, Click “Android Tools -> Add Support Library “

Put Your Google map Api key in android mainfest.file.

manifest.file 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  package="com.example.vinod.locationdistance">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-feature android:name="android.hardware.camera" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <permission android:name="com.example.vinod.locationdistance.permission.MAPS_RECEIVE"     
   android:protectionLevel="signature" />

    <uses-permission android:name="com.example.vinod.locationdistance.permission.MAPS_RECEIVE" />

    <uses-feature android:glEsVersion="0x00020000"      
  android:required="true"/>
    <application android:allowBackup="true"        
android:icon="@mipmap/ic_launcher"  
android:label="@string/app_name"       
 android:supportsRtl="true"        
android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data   android:name="com.google.android.maps.v2.API_KEY"           
 android:value="AIzaSyAMqBbV-_9E-AAp0LE97XYbIfS7FXC2HdA" />
        <meta-data   android:name="com.google.android.gms.version"           
 android:value="@integer/google_play_services_version" />

    </application>

</manifest>




main.xml file

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
   xmlns:tools="http://schemas.android.com/tools"    
android:layout_width="match_parent"    
android:layout_height="match_parent"
    tools:context="com.example.vinod.locationdistance.MainActivity">

    <TextView        android:id="@+id/tv_distance_time"      
  android:layout_width="wrap_content"       
 android:layout_height="wrap_content"       
 android:layout_alignParentTop="true"    
    android:text="hello_world" />
    <fragment        
android:id="@+id/map"   
     class="com.google.android.gms.maps.SupportMapFragment"  
      android:layout_width="wrap_content"      
  android:layout_height="wrap_content"      
  android:layout_below="@id/tv_distance_time" />
</RelativeLayout>



main.java file


package com.example.vinod.locationdistance;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends FragmentActivity {

    GoogleMap map;
    ArrayList<LatLng> markerPoints;
    TextView tvDistanceDuration;

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvDistanceDuration = (TextView) findViewById(R.id.tv_distance_time);

        // Initializing        markerPoints = new ArrayList<LatLng>();

        // Getting reference to SupportMapFragment of the activity_main     
   SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        // Getting Map for the SupportMapFragment        map = fm.getMap();

        // Enable MyLocation Button in the Map      
  if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
 {
            // TODO: Consider calling            // 
   ActivityCompat#requestPermissions       
     // here to request the missing permissions, and then overriding            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,            //                                          int[] grantResults)            // to handle the case where the user grants the permission. See the documentation            // for ActivityCompat#requestPermissions for more details.            return;
        }
        map.setMyLocationEnabled(true);

        // Setting onclick event listener for the map     
   map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

            @Override            public void onMapClick(LatLng point) {

                // Already two locations                if (markerPoints.size() > 1) {
                    markerPoints.clear();
                    map.clear();
                }

                // Adding new item to the ArrayList                markerPoints.add(point);
                // Creating MarkerOptions                
MarkerOptions options = new MarkerOptions();

                // Setting the position of the marker          
      options.position(point);

                /**                 * For the start location, the color of marker is GREEN and                 * for the end location, the color of marker is RED.                 */            
    if (markerPoints.size() == 1) {
                    options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
                } else if (markerPoints.size() == 2) {
     options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
                }

                // Add new marker to the Google Map Android API V2                map.addMarker(options);

                // Checks, whether start and end locations are captured                if (markerPoints.size() >= 2) {
                    LatLng origin = markerPoints.get(0);
                    LatLng dest = markerPoints.get(1);

                    // Getting URL to the Google Directions API                    String url = getDirectionsUrl(origin, dest);

                    DownloadTask downloadTask = new DownloadTask();

                    // Start downloading json data from Google Directions API                    downloadTask.execute(url);
                }
            }
        });
    }

    private String getDirectionsUrl(LatLng origin, LatLng dest) {

        // Origin of route       
 String str_origin = "origin=" + origin.latitude + "," + origin.longitude;

        // Destination of route        
String str_dest = "destination=" + dest.latitude + "," + dest.longitude;

        // Sensor enabled        String sensor = "sensor=false";

        // Building the parameters to the web service       
 String parameters = str_origin + "&" + str_dest + "&" + sensor;

        // Output format        String output = "json";

        // Building the url to the web service       
 String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;

        return url;
    }

    /**     * A method to download json data from url     */  
  private String downloadUrl(String strUrl) throws IOException {
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try {
            URL url = new URL(strUrl);

            // Creating an http connection to communicate with url        
    urlConnection = (HttpURLConnection) url.openConnection();

            // Connecting to url            urlConnection.connect();

            // Reading data from url            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

            StringBuffer sb = new StringBuffer();

            String line = "";
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            data = sb.toString();

            br.close();

        } catch (Exception e) {
            Log.d("Exception while downloading url", e.toString());
        } finally {
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }

    // Fetches data from url passed  
  private class DownloadTask extends AsyncTask<String, Void, String> {

        // Downloading data in non-ui thread       
 @Override        protected String doInBackground(String... url) {

            // For storing data from web service            String data = "";

            try {
                // Fetching the data from web service             
   data = downloadUrl(url[0]);
            } catch (Exception e) {
                Log.d("Background Task", e.toString());
            }
            return data;
        }

        // Executes in UI thread, after the execution of        
// doInBackground()        
@Override       
 protected void onPostExecute(String result) {
            super.onPostExecute(result);

            ParserTask parserTask = new ParserTask();

            // Invokes the thread for parsing the JSON data     
       parserTask.execute(result);
        }
    }

    /**     * A class to parse the Google Places in JSON format     */   

 private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {

        // Parsing the data in non-ui thread       
 @Override       
 protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {

            JSONObject jObject;
            List<List<HashMap<String, String>>> routes = null;

            try {
                jObject = new JSONObject(jsonData[0]);
                DirectionsJSONParser parser = new DirectionsJSONParser();

                // Starts parsing data                routes = parser.parse(jObject);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return routes;
        }

        // Executes in UI thread, after the parsing process      
  @Override      
  protected void onPostExecute(List<List<HashMap<String, String>>> result) {
            ArrayList<LatLng> points = null;
            PolylineOptions lineOptions = null;
            MarkerOptions markerOptions = new MarkerOptions();
            String distance = "";
            String duration = "";

            if (result.size() < 1) {
                Toast.makeText(getBaseContext(), "No Points", Toast.LENGTH_SHORT).show();
                return;
            }

            // Traversing through all the routes         
   for (int i = 0; i < result.size(); i++) {
                points = new ArrayList<LatLng>();
                lineOptions = new PolylineOptions();

                // Fetching i-th route              
  List<HashMap<String, String>> path = result.get(i);

                // Fetching all the points in i-th route           
     for (int j = 0; j < path.size(); j++) {
                    HashMap<String, String> point = path.get(j);

                    if (j == 0) {    // Get distance from the list         
               distance = (String) point.get("distance");
                        continue;
                    } else if (j == 1) { // Get duration from the list       
                 duration = (String) point.get("duration");
                        continue;
                    }

                    double lat = Double.parseDouble(point.get("lat"));
                    double lng = Double.parseDouble(point.get("lng"));
                    LatLng position = new LatLng(lat, lng);

                    points.add(position);
                }

                // Adding all the points in the route to LineOptions             
   lineOptions.addAll(points);
                lineOptions.width(2);
                lineOptions.color(Color.RED);
            }

            tvDistanceDuration.setText("Distance:" + distance + ", Duration:" + duration);

            // Drawing polyline in the Google Map for the i-th route        
    map.addPolyline(lineOptions);
        }
    }
}


DirectionsJSONParser.java file


package com.example.vinod.locationdistance;

import com.google.android.gms.maps.model.LatLng;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/** * Created by admin on 3/18/2016. */public class DirectionsJSONParser {

    /**     * Receives a JSONObject and returns a list of lists containing latitude and longitude    
 */    public List<List<HashMap<String, String>>> parse(JSONObject jObject) {

       
 List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
        JSONArray jRoutes = null;
        JSONArray jLegs = null;
        JSONArray jSteps = null;
        JSONObject jDistance = null;
        JSONObject jDuration = null;

        try {

            jRoutes = jObject.getJSONArray("routes");

            /** Traversing all routes */        
    for (int i = 0; i < jRoutes.length(); i++) {
                jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");

                
List<HashMap<String, String>> path = new ArrayList<HashMap<String, String>>();

                /** Traversing all legs */              
  for (int j = 0; j < jLegs.length(); j++) {

                    /** Getting distance from the json data */                   
 jDistance = ((JSONObject) jLegs.get(j)).getJSONObject("distance");
                  
  HashMap<String, String> hmDistance = new HashMap<String, String>();
                    hmDistance.put("distance", jDistance.getString("text"));

                    /** Getting duration from the json data */                  
  jDuration = ((JSONObject) jLegs.get(j)).getJSONObject("duration");
                    HashMap<String, String> hmDuration = new HashMap<String, String>();
                    hmDuration.put("duration", jDuration.getString("text"));

                    /** Adding distance object to the path */               
     path.add(hmDistance);

                    /** Adding duration object to the path */                  
  path.add(hmDuration);
                  
  jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");

                    /** Traversing all steps */                  
  for (int k = 0; k < jSteps.length(); k++) {
                        String polyline = "";
                        
polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
                        List<LatLng> list = decodePoly(polyline);

                        /** Traversing all points */                       
 for (int l = 0; l < list.size(); l++) {
                           
 HashMap<String, String> hm = new HashMap<String, String>();
                           
 hm.put("lat", Double.toString(((LatLng) list.get(l)).latitude));
                           
 hm.put("lng", Double.toString(((LatLng) list.get(l)).longitude));
                           
 path.add(hm);
                        }
                    }
                }
                routes.add(path);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
        }
        return routes;
    }

    /**     * Method to decode polyline points    
 * Courtesy : jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java     */
    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<LatLng>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.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 = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }
        return poly;
    }
}

No comments:

Post a Comment