[google-maps] Draw path between two points using Google Maps Android API v2

Google changed its map API for Android and introduced API V2. The previous codes for drawing path are not working with API V2.

I have managed to draw a path with API V2. I had searched a lot for the solution but did not find any answer. So I am sharing its answer.

The answer is


Dont know whether I should put this as answer or not...

I used @Zeeshan0026's solution to draw the path...and the problem was that if I draw path once, and then I do try to draw path once again, both two paths show and this continues...paths showing even when markers were deleted... while, ideally, old paths' shouldn't be there once new path is drawn / markers are deleted..

going through some other question over SO, I had the following solution

I add the following function in Zeeshan's class

 public void clearRoute(){

         for(Polyline line1 : polylines)
         {
             line1.remove();
         }

         polylines.clear();

     }

in my map activity, before drawing the path, I called this function.. example usage as per my app is

private Route rt;

rt.clearRoute();

            if (src == null) {
                Toast.makeText(getApplicationContext(), "Please select your Source", Toast.LENGTH_LONG).show();
            }else if (Destination == null) {
                Toast.makeText(getApplicationContext(), "Please select your Destination", Toast.LENGTH_LONG).show();
            }else if (src.equals(Destination)) {
                Toast.makeText(getApplicationContext(), "Source and Destinatin can not be the same..", Toast.LENGTH_LONG).show();
            }else{

                rt.drawRoute(mMap, MapsMainActivity.this, src,
                        Destination, false, "en");
            }

you can use rt.clearRoute(); as per your requirements.. Hoping that it will save a few minutes of someone else and will help some beginner in solving this issue..

Complete Class Code

see on github

Edit: here is part of code from mainactivity..

case R.id.mkrbtn_set_dest:
                    Destination = selmarker.getPosition();
                    destmarker = selmarker;
                    desShape = createRouteCircle(Destination, false);

                    if (src == null) {
                        Toast.makeText(getApplicationContext(),
                                "Please select your Source first...",
                                Toast.LENGTH_LONG).show();
                    } else if (src.equals(Destination)) {
                        Toast.makeText(getApplicationContext(),
                                "Source and Destinatin can not be the same..",
                                Toast.LENGTH_LONG).show();
                    } else {

                        if (isNetworkAvailable()) {
                            rt.drawRoute(mMap, MapsMainActivity.this, src,
                                    Destination, false, "en");
                            src = null;
                            Destination = null;

                        } else {
                            Toast.makeText(
                                    getApplicationContext(),
                                    "Internet Connection seems to be OFFLINE...!",
                                    Toast.LENGTH_LONG).show();

                        }

                    }

                    break;

Edit 2 as per comments

usage :

//variables as data members
GoogleMap mMap;
private Route rt;
static LatLng src;
static LatLng Destination;
//MapsMainActivity is my activity
//false for interim stops for traffic, google
// en language for html description returned

rt.drawRoute(mMap, MapsMainActivity.this, src,
                            Destination, false, "en");

in below code midpointsList is an ArrayList of waypoints

private String getMapsApiDirectionsUrl(GoogleMap googleMap, LatLng startLatLng, LatLng endLatLng, ArrayList<LatLng> midpointsList) {
    String origin = "origin=" + startLatLng.latitude + "," + startLatLng.longitude;

    String midpoints = "";
    for (int mid = 0; mid < midpointsList.size(); mid++) {
        midpoints += "|" + midpointsList.get(mid).latitude + "," + midpointsList.get(mid).longitude;
    }

    String waypoints = "waypoints=optimize:true" + midpoints + "|";

    String destination = "destination=" + endLatLng.latitude + "," + endLatLng.longitude;
    String key = "key=AIzaSyCV1sOa_7vASRBs6S3S6t1KofFvDhjohvI";

    String sensor = "sensor=false";
    String params = origin + "&" + waypoints + "&" + destination + "&" + sensor + "&" + key;
    String output = "json";
    String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + params;


    Log.e("url", url);
    parseDirectionApidata(url, googleMap);
    return url;
}

Then copy and paste this url in your browser to check And the below code is to parse the url

    private void parseDirectionApidata(String url, final GoogleMap googleMap) {

    final JSONObject jsonObject = new JSONObject();

    try {

        AppUtill.getJsonWithHTTPPost(ViewMapActivity.this, 1, new ServiceCallBack() {
            @Override
            public void serviceCallBack(int id, JSONObject jsonResult) throws JSONException {

                if (jsonResult != null) {

                    Log.e("jsonRes", jsonResult.toString());

                    String status = jsonResult.optString("status");

                    if (status.equalsIgnoreCase("ok")) {
                        drawPath(jsonResult, googleMap);
                    }

                } else {

                    Toast.makeText(ViewMapActivity.this, "Unable to parse Directions Data", Toast.LENGTH_LONG).show();
                }

            }
        }, url, jsonObject);

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

    }
}

And then pass the result to the drawPath method

    public void drawPath(JSONObject jObject, GoogleMap googleMap) {

    List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
    JSONArray jRoutes = null;
    JSONArray jLegs = null;
    JSONArray jSteps = null;
    List<LatLng> list = null;
    try {

        Toast.makeText(ViewMapActivity.this, "Drawing Path...", Toast.LENGTH_SHORT).show();
        jRoutes = jObject.getJSONArray("routes");

        /** Traversing all routes */
        for (int i = 0; i < jRoutes.length(); i++) {
            jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
            List path = new ArrayList<HashMap<String, String>>();

            /** Traversing all legs */
            for (int j = 0; j < jLegs.length(); j++) {
                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 = decodePoly(polyline);
                }
                Log.e("list", list.toString());
                routes.add(path);
                Log.e("routes", routes.toString());
                if (list != null) {
                    Polyline line = googleMap.addPolyline(new PolylineOptions()
                            .addAll(list)
                            .width(12)
                            .color(Color.parseColor("#FF0000"))//Google maps blue color #05b1fb
                            .geodesic(true)
                    );
                }
            }
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }

}

  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;
}

decode poly function is to decode the points(lat and long) provided by Directions API in encoded form


Try below solution to draw path with animation and also get time and distance between two points.

DirectionHelper.java

public class DirectionHelper {

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

        List<List<HashMap<String, String>>> routes = new ArrayList<>();
        JSONArray jRoutes;
        JSONArray jLegs;
        JSONArray jSteps;
        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 path = new ArrayList<>();

                /** 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<>();
                            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;
    }

    //Method to decode polyline points
    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;
    }
}

GetPathFromLocation.java

public class GetPathFromLocation extends AsyncTask<String, Void, List<List<HashMap<String, String>>>> {

    private Context context;
    private String TAG = "GetPathFromLocation";
    private LatLng source, destination;
    private ArrayList<LatLng> wayPoint;
    private GoogleMap mMap;
    private boolean animatePath, repeatDrawingPath;
    private DirectionPointListener resultCallback;
    private ProgressDialog progressDialog;

    //https://www.mytrendin.com/draw-route-two-locations-google-maps-android/
    //https://www.androidtutorialpoint.com/intermediate/google-maps-draw-path-two-points-using-google-directions-google-map-android-api-v2/

    public GetPathFromLocation(Context context, LatLng source, LatLng destination, ArrayList<LatLng> wayPoint, GoogleMap mMap, boolean animatePath, boolean repeatDrawingPath, DirectionPointListener resultCallback) {
        this.context = context;
        this.source = source;
        this.destination = destination;
        this.wayPoint = wayPoint;
        this.mMap = mMap;
        this.animatePath = animatePath;
        this.repeatDrawingPath = repeatDrawingPath;
        this.resultCallback = resultCallback;
    }

    synchronized public String getUrl(LatLng source, LatLng dest, ArrayList<LatLng> wayPoint) {

        String url = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&origin="
                + source.latitude + "," + source.longitude + "&destination=" + dest.latitude + "," + dest.longitude;
        for (int centerPoint = 0; centerPoint < wayPoint.size(); centerPoint++) {
            if (centerPoint == 0) {
                url = url + "&waypoints=optimize:true|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
            } else {
                url = url + "|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
            }
        }
        url = url + "&key=" + context.getResources().getString(R.string.google_api_key);

        return url;
    }

    public int getRandomColor() {
        Random rnd = new Random();
        return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("Please wait...");
        progressDialog.setIndeterminate(false);
        progressDialog.setCancelable(false);
        progressDialog.show();
    }

    @Override
    protected List<List<HashMap<String, String>>> doInBackground(String... url) {

        String data;

        try {
            InputStream inputStream = null;
            HttpURLConnection connection = null;
            try {
                URL directionUrl = new URL(getUrl(source, destination, wayPoint));
                connection = (HttpURLConnection) directionUrl.openConnection();
                connection.connect();
                inputStream = connection.getInputStream();

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuffer stringBuffer = new StringBuffer();

                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuffer.append(line);
                }

                data = stringBuffer.toString();
                bufferedReader.close();

            } catch (Exception e) {
                Log.e(TAG, "Exception : " + e.toString());
                return null;
            } finally {
                inputStream.close();
                connection.disconnect();
            }
            Log.e(TAG, "Background Task data : " + data);

            //Second AsyncTask

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

            try {
                jsonObject = new JSONObject(data);
                // Starts parsing data
                DirectionHelper helper = new DirectionHelper();
                routes = helper.parse(jsonObject);
                Log.e(TAG, "Executing Routes : "/*, routes.toString()*/);

                return routes;

            } catch (Exception e) {
                Log.e(TAG, "Exception in Executing Routes : " + e.toString());
                return null;
            }

        } catch (Exception e) {
            Log.e(TAG, "Background Task Exception : " + e.toString());
            return null;
        }
    }

    @Override
    protected void onPostExecute(List<List<HashMap<String, String>>> result) {
        super.onPostExecute(result);

        if (progressDialog.isShowing()) {
            progressDialog.dismiss();
        }

        ArrayList<LatLng> points;
        PolylineOptions lineOptions = null;
        String distance = "";
        String duration = "";

        // Traversing through all the routes
        for (int i = 0; i < result.size(); i++) {
            points = new ArrayList<>();
            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(8);
            lineOptions.color(Color.RED);
            //lineOptions.color(getRandomColor());

            if (animatePath) {
                final ArrayList<LatLng> finalPoints = points;
                ((AppCompatActivity) context).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        PolylineOptions polylineOptions;
                        final Polyline greyPolyLine, blackPolyline;
                        final ValueAnimator polylineAnimator;

                        LatLngBounds.Builder builder = new LatLngBounds.Builder();
                        for (LatLng latLng : finalPoints) {
                            builder.include(latLng);
                        }
                        polylineOptions = new PolylineOptions();
                        polylineOptions.color(Color.RED);
                        polylineOptions.width(8);
                        polylineOptions.startCap(new SquareCap());
                        polylineOptions.endCap(new SquareCap());
                        polylineOptions.jointType(ROUND);
                        polylineOptions.addAll(finalPoints);
                        greyPolyLine = mMap.addPolyline(polylineOptions);

                        polylineOptions = new PolylineOptions();
                        polylineOptions.width(8);
                        polylineOptions.color(Color.WHITE);
                        polylineOptions.startCap(new SquareCap());
                        polylineOptions.endCap(new SquareCap());
                        polylineOptions.zIndex(5f);
                        polylineOptions.jointType(ROUND);

                        blackPolyline = mMap.addPolyline(polylineOptions);
                        polylineAnimator = ValueAnimator.ofInt(0, 100);
                        polylineAnimator.setDuration(5000);
                        polylineAnimator.setInterpolator(new LinearInterpolator());
                        polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                                List<LatLng> points = greyPolyLine.getPoints();
                                int percentValue = (int) valueAnimator.getAnimatedValue();
                                int size = points.size();
                                int newPoints = (int) (size * (percentValue / 100.0f));
                                List<LatLng> p = points.subList(0, newPoints);
                                blackPolyline.setPoints(p);
                            }
                        });

                        polylineAnimator.addListener(new Animator.AnimatorListener() {
                            @Override
                            public void onAnimationStart(Animator animation) {

                            }

                            @Override
                            public void onAnimationEnd(Animator animation) {
                                if (repeatDrawingPath) {
                                    List<LatLng> greyLatLng = greyPolyLine.getPoints();
                                    if (greyLatLng != null) {
                                        greyLatLng.clear();

                                    }
                                    polylineAnimator.start();
                                }
                            }

                            @Override
                            public void onAnimationCancel(Animator animation) {
                                polylineAnimator.cancel();
                            }

                            @Override
                            public void onAnimationRepeat(Animator animation) {
                            }
                        });
                        polylineAnimator.start();
                    }
                });
            }

            Log.e(TAG, "PolylineOptions Decoded");
        }

        // Drawing polyline in the Google Map for the i-th route
        if (resultCallback != null && lineOptions != null)
            resultCallback.onPath(lineOptions, distance, duration);
    }
}

DirectionPointListener

public interface DirectionPointListener {
    public void onPath(PolylineOptions polyLine,String distance,String duration);
}

Now draw path using below code in your Activity

private GoogleMap mMap;
private ArrayList<LatLng> wayPoint = new ArrayList<>();
private SupportMapFragment mapFragment;

mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

@Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
            @Override
            public void onMapLoaded() {
                LatLngBounds.Builder builder = new LatLngBounds.Builder();

                /*Add Source Marker*/
                MarkerOptions markerOptions = new MarkerOptions();
                markerOptions.position(source);
                markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
                mMap.addMarker(markerOptions);
                builder.include(source);

                /*Add Destination Marker*/
                markerOptions = new MarkerOptions();
                markerOptions.position(destination);
                markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
                mMap.addMarker(markerOptions);
                builder.include(destination);

                LatLngBounds bounds = builder.build();

                int width = mapFragment.getView().getMeasuredWidth();
                int height = mapFragment.getView().getMeasuredHeight();
                int padding = (int) (width * 0.15); // offset from edges of the map 10% of screen

                CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding);

                mMap.animateCamera(cu);

                new GetPathFromLocation(context, source, destination, wayPoint, mMap, true, false, new DirectionPointListener() {
                    @Override
                    public void onPath(PolylineOptions polyLine, String distance, String duration) {
                        mMap.addPolyline(polyLine);
                        Log.e(TAG, "onPath :: Distance :: " + distance + " Duration :: " + duration);

                        binding.txtDistance.setText(String.format(" %s", distance));
                        binding.txtDuration.setText(String.format(" %s", duration));
                    }
                }).execute();
            }
        });
    }

OutPut

enter image description here

I hope this can help you!

Thank You.


Examples related to google-maps

GoogleMaps API KEY for testing Google Maps shows "For development purposes only" java.lang.NoClassDefFoundError:failed resolution of :Lorg/apache/http/ProtocolVersion How to import JSON File into a TypeScript file? Googlemaps API Key for Localhost Getting "Cannot call a class as a function" in my React Project ERROR: Google Maps API error: MissingKeyMapError This page didn't load Google Maps correctly. See the JavaScript console for technical details Google Maps API warning: NoApiKeys ApiNotActivatedMapError for simple html page using google-places-api

Examples related to path

Get Path from another app (WhatsApp) How to serve up images in Angular2? How to create multiple output paths in Webpack config Setting the correct PATH for Eclipse How to change the Jupyter start-up folder Setting up enviromental variables in Windows 10 to use java and javac How do I edit $PATH (.bash_profile) on OSX? Can't find SDK folder inside Android studio path, and SDK manager not opening Get the directory from a file path in java (android) Graphviz's executables are not found (Python 3.4)

Examples related to google-maps-markers

How to change icon on Google map marker Auto-center map with multiple markers in Google Maps API v3 Resize Google Maps marker icon image How to create a custom-shaped bitmap marker with Android map API v2 Draw path between two points using Google Maps Android API v2 Google Maps API Multiple Markers with Infowindows Javascript, Change google map marker color How do you create a Marker with a custom icon for google maps API v3? Selecting last element in JavaScript array google maps v3 marker info window on mouseover

Examples related to routes

How to open a link in new tab using angular? How to Refresh a Component in Angular laravel Unable to prepare route ... for serialization. Uses Closure How to use router.navigateByUrl and router.navigate in Angular No provider for Router? Difference between [routerLink] and routerLink How to force Laravel Project to use HTTPS for all routes? Change route params without reloading in Angular 2 Angular 2 router no base href set How to redirect to a route in laravel 5 by using href tag if I'm not using blade or any template?

Examples related to google-maps-android-api-2

How can I show current location on a Google Map on Android Marshmallow? Adding Google Play services version to your app's manifest? Android Google Maps API V2 Zoom to Current Location How to draw interactive Polyline on route google maps v2 android How to display my location on Google Maps for Android API v2 Android map v2 zoom to show all the markers How to create a custom-shaped bitmap marker with Android map API v2 Draw path between two points using Google Maps Android API v2 How to download Google Play Services in an Android emulator? Get driving directions using Google Maps API v2