In this post we will develop an Android App to draw route on google maps (namely Google Maps Draw Route). Here we will first add our location on google map and then allow user to select two points. A marker will be added to those two points and a route will be drawn.
Pre-requisites
1) Android Studio installed on your PC (Unix or Windows).
2) A real time android device (Smartphone or Tablet) configured with Android Studio.
3) A basic knowledge of Android lifecycle and different classes & functions used in Android Studio.
Now let’s make it. We hope you would have already made an App to display current user location. So we are not repeating that part now.
Creating new project
Please follow following steps:
- Open Android Studio and make a new project with name “Google Maps Draw Route” and company domain application.example.com (I used my company domain i.e androidtutorialpoint.com. Similarly you can use yours).
- Click Next and choose android version Lollipop. Again Click Next and Choose Google Maps Activity (as shown in following pic).
- Leave all things remaining same and Click Finish.
Now you will be able to see three files:
- google_maps_api.xml (…/GoogleMapsApp/app/src/debug/res/values/google_maps_api.xml)
- MapsActivity.java (…/GoogleMapsApp/app/src/main/java/com/androidtutorialpoint/googlemapsapp/MapsActivity.java)
- AndroidManifest.xml ( …/GoogleMapsApp/app/src/main/AndroidManifest.xml)
Configuring Google Play Services
Open google_maps_api.xml. Here you will find a lot of information along with a link. Copy-Paste this link in your web browser. Make a Gmail account also through which you will configure google play services.
Now at the browser choose “Create New Project” and Click Continue. Following screen will be displayed:
Click on Go to credentials. Below screen will appear.
Create your key by clicking Create. Now a key will be created that you shall copy and paste in google_maps_api.xml. Copy paste it in place where YOUR_KEY_HERE is written:
Code inside google_maps_api.xml is complete.
google_maps_api.xml
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API key.
To get one, follow this link, follow the directions and press "Create" at the end:
https:
You can also add your credentials to an existing key, using this line:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx;com.androidtutorialpoint.googlemapsapp
Alternatively, follow the directions here:
https:
Once you have your key (it starts with "AIza"), replace the "google_maps_key"
string in this file.
-->
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">LVwrKoLOEMgwUBXGiut0bkFhoAjOiaVemoMlymg</string>
</resources>
Code Inside AndroidManifest.xml:
If you go inside AndroidManifest.xml then this key will be displayed in meta tags. Here you need to add permissions for accessing location of device. The required permission should be as follows:
ACCESS_NETWORK_STATE – To check network state i.e if we are connected to any network or not.
INTERNET – If we are connected to Internet or not.
ACCESS_COARSE_LOCATION – To determine user’s location using WiFi and mobile. It will give us an approximate location.
ACCESS_FINE_LOCATION – To determine user’s location using GPS. It will give us precise location.
OpenGL ES V2 – Required for Google Maps V2
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.androidtutorialpoint.googlemapsdrawroute"
xmlns:android="http://schemas.android.com/apk/res/android">
<!--
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="com.androidtutorialpoint.mymapsappsdirection.permission.MAPS_RECEIVE" />
<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"/>
<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>
Code inside MapsActivity.java:
This is heart of our code. We will divide this code into parts and debug it one by one. Here we won’t discuss code related to getting current user location.
1) Setting OnClickListener
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng point) {
if (MarkerPoints.size() > 1) {
MarkerPoints.clear();
mMap.clear();
}
MarkerPoints.add(point);
MarkerOptions options = new MarkerOptions();
options.position(point);
if (MarkerPoints.size() == 1) {
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
} else if (MarkerPoints.size() == 2) {
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
}
mMap.addMarker(options);
if (MarkerPoints.size() >= 2) {
LatLng origin = MarkerPoints.get(0);
LatLng dest = MarkerPoints.get(1);
String url = getUrl(origin, dest);
Log.d("onMapClick", url.toString());
FetchUrl FetchUrl = new FetchUrl();
FetchUrl.execute(url);
mMap.moveCamera(CameraUpdateFactory.newLatLng(origin));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
}
}
});
Above code will be executed as soon as user tap on Android screen. It will be used to place marker at the points between which path will be drawn. Coordinates of tapped points will be accessed and stored using MarkerPoints.get()
and LatLng origin
respectively.Url will be fetched and implemented using Async Task FetchUrl
.
2) Async Task
AsyncTask is an abstract class provided by Android which helps us to use the UI thread properly. This class allows us to perform long/background operations and show its result on the UI thread without having to manipulate threads. Here doInBackground
task will be implemented in background and onPostExecute
will be shown on GUI.
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);
}
}
downloadUrl
is used to fecth url from web service and result is parsed using ParserTask
(Async Task).
3) Code inside downloadUrl:
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;
}
Data returnd from web will be in json format which user can get using HttpURLConnection
. So this task will return json data returned from web.
4) Code inside Parser Task:
Define a new class with the name ParserTask
which will parse the Json data retuned by downloadUrl
.
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());
DataParser parser = new DataParser();
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");
}
}
}
In the above code doInBackground
will actually parse the data and onPostExecute
will draw route on Google Maps.
5) Parsing data:
Make a separate java class with the name DataParser
at the path: GoogleMapsDrawRoute/app/src/main/java/com/androidtutorialpoint/googlemapsdrawroute/
DataParser class
public class DataParser {
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;
}
}
In the above code, I have added comments wherever required. Still if you have doubt then please ask in comments.
6) Draw route on google maps:
Route is drawn using Google Maps polyline. Add following code in onPostExecute
:
onPostExecute
@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");
}
}
Finally in the above code points are fetched from result and drawn on Google Map.ArrayList points is used to store position on Google Map. Route is drawn using google maps polyline lineOptions.addAll(points)
.
You can see full code in following files:
MapsActivity.java
package com.androidtutorialpoint.googlemapsdrawroute;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
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.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
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,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private GoogleMap mMap;
ArrayList<LatLng> MarkerPoints;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
LocationRequest mLocationRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission();
}
MarkerPoints = new ArrayList<>();
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng point) {
if (MarkerPoints.size() > 1) {
MarkerPoints.clear();
mMap.clear();
}
MarkerPoints.add(point);
MarkerOptions options = new MarkerOptions();
options.position(point);
if (MarkerPoints.size() == 1) {
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
} else if (MarkerPoints.size() == 2) {
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
}
mMap.addMarker(options);
if (MarkerPoints.size() >= 2) {
LatLng origin = MarkerPoints.get(0);
LatLng dest = MarkerPoints.get(1);
String url = getUrl(origin, dest);
Log.d("onMapClick", url.toString());
FetchUrl FetchUrl = new FetchUrl();
FetchUrl.execute(url);
mMap.moveCamera(CameraUpdateFactory.newLatLng(origin));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
}
}
});
}
private String getUrl(LatLng origin, LatLng dest) {
String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
String str_dest = "destination=" + dest.latitude + "," + dest.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;
return url;
}
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;
}
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 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());
DataParser parser = new DataParser();
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");
}
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission(){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
} else {
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
}
}
}
DataParser.java
package com.androidtutorialpoint.googlemapsdrawroute;
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 DataParser {
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;
}
}
google_maps_api.xml
<resources>
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">LVwrKoLOEMgwUBXGiut0bkFhoAjOiaVemoMlymg</string>
</resources>
AndroidManifest.xml
="1.0"="utf-8"
<manifest package="com.androidtutorialpoint.googlemapsdrawroute"
xmlns:android="http://schemas.android.com/apk/res/android">
<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">
<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>
So finally our app is complete. We would suggest you to turn on GPS and Internet Connection. Run this route maker on any real android device. It will first display your location. Now tap on any two locations and it will show route between them.