Sun. Dec 16th, 2018

Draw route and calculate distance between two locations in Google Maps Android

Draw route and calculate the distance between two specific locations Google Maps in Android | In this tutorial, we will learn to show routes between two specific location on Google Maps. We will be adding markers to both locations and then route between this two location is drawn. Then, we will learn how to calculate the distance between these locations and show them in an alertDialog. wants to Learn Advanced Android application development from Scratch- Beyond Basics

Project:  :DrivingDirection

Sample Apk: route between two location

Sample Output:

Let’s get started!

Creating a New Project

Open Android Studio & create a new project, give name whatever you like and while selecting starting activity, select Google Maps activity as shown here

Manifest File

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

    <!--
         The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
         Google Maps Android API v2, but you must specify either coarse or fine
         location permissions for the 'MyLocation' functionality. 
    -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!--
             The API key for Google Maps-based APIs is defined as a string resource.
             (See the file "res/values/google_maps_api.xml").
             Note that the API key is linked to the encryption key used to sign the APK.
             You need a different API key for each encryption key, including the release key that is used to
             sign the APK for publishing.
             You can define the keys for the debug and release targets in src/debug/ and src/release/. 
        -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity
            android:name=".MapsActivity"
            android:label="@string/title_activity_maps">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Configuring Google Play Services

For this open a XML file named “google_maps_api.xml” from res/value directory. You will find a link there, open it in your browser. Create your new project there and then go to credentials in the side menu. Add your package name and SHA-1 fingerprint of your project there.Finally, You can copy your generated API key to your project.

activity_maps.xml

It will be self-generated when you select Google Maps Activity. You don’t have to make any changes here.

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="direction_delhi_to_chandigarh.mytrendin.com.drivingdirection.MapsActivity" />

MapsActivity.java

package direction_delhi_to_chandigarh.mytrendin.com.drivingdirection;


import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
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 MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private LatLng delhi= new LatLng(28.6139,77.2090);
    private LatLng chandigarh = new LatLng(30.7333,76.7794);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }
    private class FetchUrl extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... url) {
            String data = "";

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

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            ParserTask parserTask = new ParserTask();
            parserTask.execute(result);

        }
    }
    private String downloadUrl(String strUrl) throws IOException {
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try {
            URL url = new URL(strUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.connect();
            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();
            Log.d("downloadUrl", data.toString());
            br.close();
        } catch (Exception e) {
            Log.d("Exception", e.toString());
        } finally {
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.addMarker(new MarkerOptions().position(chandigarh).title("Chandigarh"));
        mMap.addMarker(new MarkerOptions().position(delhi).title("Delhi"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(delhi));

        String str_origin = "origin=" + delhi.latitude + "," + delhi.longitude;
        String str_dest = "destination=" + chandigarh.latitude + "," + chandigarh.longitude;
        String sensor = "sensor=false";
        String parameters = str_origin + "&" + str_dest + "&" + sensor;
        String output = "json";
        String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;

                    Log.d("onMapClick", url.toString());
                    FetchUrl FetchUrl = new FetchUrl();
                    FetchUrl.execute(url);
                    mMap.moveCamera(CameraUpdateFactory.newLatLng(delhi));
                   mMap.animateCamera(CameraUpdateFactory.zoomTo(7));

        Location delhi_location = new Location("Delhi");
        delhi_location.setLatitude(delhi.latitude);
        delhi_location.setLongitude(delhi.longitude);

        Location chandigarh_location = new Location("Chandigarh");
        chandigarh_location.setLatitude(chandigarh.latitude);
        chandigarh_location.setLongitude(chandigarh.longitude);

        double distance = (delhi_location.distanceTo(chandigarh_location))* 0.000621371 ;

        AlertDialog alertDialog = new AlertDialog.Builder(MapsActivity.this).create();
        alertDialog.setTitle("Info");
        alertDialog.setMessage("Distance between these two location is : "+distance +" miles");
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.show();
}

    private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
        @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]);
                Log.d("ParserTask",jsonData[0].toString());
                JSONParserTask parser = new JSONParserTask();
                Log.d("ParserTask", parser.toString());
                routes = parser.parse(jObject);
                Log.d("ParserTask","Executing routes");
                Log.d("ParserTask",routes.toString());

            } catch (Exception e) {
                Log.d("ParserTask",e.toString());
                e.printStackTrace();
            }
            return routes;
        }
        @Override
        protected void onPostExecute(List<List<HashMap<String, String>>> result) {
            ArrayList<LatLng> points;
            PolylineOptions lineOptions = null;
            for (int i = 0; i < result.size(); i++) {
                points = new ArrayList<>();
                lineOptions = new PolylineOptions();
                List<HashMap<String, String>> path = result.get(i);
                for (int j = 0; j < path.size(); j++) {
                    HashMap<String, String> point = path.get(j);
                    double lat = Double.parseDouble(point.get("lat"));
                    double lng = Double.parseDouble(point.get("lng"));
                    LatLng position = new LatLng(lat, lng);
                     points.add(position);
                }
                lineOptions.addAll(points);
                lineOptions.width(10);
                lineOptions.color(Color.RED);

                Log.d("onPostExecute","onPostExecute lineoptions decoded");

            }
            if(lineOptions != null) {
                mMap.addPolyline(lineOptions);
            }
            else {
                Log.d("onPostExecute","without Polylines drawn");
            }
        }
    }
}

Related:

Draw route between two locations with Google Maps, using Kotlin, Android

Draw route between two locations, Google Maps in Android

Periodically send GPS location to Firebase with custom time frame in Android

Display current location(latitude and longitude) in google map and save it to the Firebase database in Android

Handle Multiple Geofencing in Common Areas in google map in android application

You can find latitude and longitude of your desired location on Google.

OnMapReady is triggered when the map is ready to use. Here we add markers to both locations. In case GooglePlay Services is not installed in user phone, MapSupportFragment .it will ask the user MapSupportFragment.This method will only be triggered once the user is done with the installation and returned to the app.

One more thing while calculation distance between this two-location we used distanceTo, it does the calculation work and provides us result in a meter. So, you can multiply with an appropriate constant to convert it into kilometer, miles etc.

Here we retrieving JSON Object from the Google API. We have to parse this JSON and fetch data of routes between two locations. It is done using AsyncTask in above code. We always try to use a different thread for loading data, so here we created a ParserTask that extends AsyncTask. The data will be parsed in the doInBackground method of AsyncTask. After parsing data for the route, we have drawn the route in the onPostExecute method.

In the onPostExecute method, we run a loop to traverse through all the routes. Fetch all the with the route and then add all the points to the line options.

 

JSONParserTask.java

package direction_delhi_to_chandigarh.mytrendin.com.drivingdirection;

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;

public class JSONParserTask {
    public List<List<HashMap<String,String>>> parse(JSONObject jObject){

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

        try {

            jRoutes = jObject.getJSONArray("routes");
            for(int i=0;i<jRoutes.length();i++){
                jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");
                List path = new ArrayList<>();

                for(int j=0;j<jLegs.length();j++){
                    jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("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);

                        for(int l=0;l<list.size();l++){
                            HashMap<String, String> hm = new HashMap<>();
                            hm.put("lat", Double.toString((list.get(l)).latitude) );
                            hm.put("lng", Double.toString((list.get(l)).longitude) );
                            path.add(hm);
                        }
                    }
                    routes.add(path);
                }
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }catch (Exception e){
        }


        return routes;
    }
    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<>();
        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;
    }
}

So finally our app is complete. Please turn on your internet connection while running the app. If you are a beginner Learn Android Application Development from Scratch


If you really liked the article, please subscribe to our YouTube Channel for videos related to this article.Please find us on Twitter and Facebook.

7 thoughts on “Draw route and calculate distance between two locations in Google Maps Android

  1. OK. Let’s assume you are traveling from Delhi to Chandigarh (via Flight or Train or Car).

    And now you have to show your current location marker on Polyline Path…

    I have to get this… https://i.stack.imgur.com/3a9xb.jpg

    (If I can get curved Polyline then it’s more than awesome, otherwise consider curved Polyline as optional, straight Polyline is enough)

    I already given huge tries to this one, have a look : https://stackoverflow.com/q/46103680

    I believe you can help me in getting, please share an updated code with us… I already switched to your code.

  2. Mate you just save me. I spent last two days (8 hours / day) looking for this type of tutorial. Everything I check online was either not working or been too old. Many thanks for that

  3. hi your tutorial is very useful
    i have a question can we get online image instead of marker on the map in android studio

  4. hi can you help me i want to get online image instead of marker on google map can you please tell me is it possible if it is then please tell me how

Leave a Reply

Your email address will not be published. Required fields are marked *