Using Google maps to find alternate routes

Sasha Ram
wavelength.company
Published in
4 min readJun 25, 2017

More often than not, to go from point A to B, there is more than one route. When you use the default Google Maps application, Google shows you two or three different routes to reach your destination. But how do you enable this for your application needs?

Getting Started with Google Maps

You can skip this section if you already know how to include Google Maps in your application.

In Android Studio, create a new Android project with a Google Maps activity. The IDE will create a google_maps_api.xml file by default.

Navigate to the following URL on your browser and log in with your default Google account.

https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID…

Create a new project and follow the instructions on the console to generate an API key. Replace the generated API key for the google_maps_key in your XML file on Android Studio.

Build and run your project to see a Maps Activity on your emulator/device.

Enabling Alternate routes in your Application

Create a layout XML file with the following views.

  • EditText field for the user to input the origination point
  • EditText field for the user to input the destination
  • Button to search for alternate routes

To fetch the latitude and longitude of the origination and destination we will be using the Geocoder API and RxJava2.

Add the following line in your app’s build.gradle file.

compile'io.reactivex.rxjava2:rxjava:2.0.6'

We’ll need a model class to collect the source and destination coordinates.

CoordinateDetails.java

import com.google.android.gms.maps.model.LatLng;
public class CoordinateDetails {
public LatLng fromAddress;
public LatLng toAddress;
}

Add the following lines of code to your MapActivity class.

private void getSourceDestCoordinates(final String startingPoint, final String destination) {
Observable<CoordinateDetails> latLonObs = Observable.fromCallable(new Callable<CoordinateDetails>() {
@Override
public CoordinateDetails call() throws Exception {
return getCoordinates(startingPoint, destination);
}
});
private void getSourceDestCoordinates(final String startingPoint, final String destination) {
Observable<CoordinateDetails> latLonObs = Observable.fromCallable(new Callable<CoordinateDetails>() {
@Override
public CoordinateDetails call() throws Exception {
return getCoordinates(startingPoint, destination);
}
});
try {
List fromAddressData = geocoder.getFromLocationName(fromLocation, 1);
if (fromAddressData != null && fromAddressData.size() > 0) {
Address address = (Address) fromAddressData.get(0);
coordinateDetails.fromAddress = new LatLng(address.getLatitude(),
address.getLongitude());
}
List toAddressData = geocoder.getFromLocationName(toLocation, 1);
if (toAddressData != null && toAddressData.size() > 0) {
Address address = (Address) toAddressData.get(0);
coordinateDetails.toAddress = new LatLng(address.getLatitude(),
address.getLongitude());
}
} catch (IOException e) {
Log.e(TAG, ”Unable to connect to Geocoder”, e);
}
return coordinateDetails;
}

With the co-ordinates available for the origination and destination points, we can send them to Google Maps and get all alternate routes.

To get the routes, we shall use the directions API from Google maps. You can obtain your API key from the following URL.

https://developers.google.com/maps/documentation/directions/get-api-key

To test if your api key is working, you can hit the following URL from your browser, Replace the DIRECTION_API_KEY with your API key.

https://maps.googleapis.com/maps/api/directions/json?origin=13.0826802,80.2707184&destination=12.9715987,77.5945627&key=/*DIRECTION_API_KEY*/&mode=driving&alternatives=true

We will be using Retrofit2 to make the web-service calls. Include the following lines in your build.gradle file.

compile'com.squareup.retrofit2:converter-gson:2.2.0'
compile'com.squareup.retrofit2:retrofit:2.2.0'

Create the following model classes for Retrofit to de-serialize the service response.

RoutesDetail.java

public class RoutesDetail {
public List routes;
public String status;
}

Route.java

public class Route {
@SerializedName(”overview_polyline")
public OverviewPolyline overviewPolyLine;
}

OverviewPolyline.java

public class OverviewPolyline {
private String points;
}

To use Retrofit in your application, create an interface for retrofit service API

ServiceApi.java

public interface ServiceApi {
@GET("/maps/api/directions/json?")
Call<RoutesDetail> getDirection(@Query("origin") String origin,
@Query("destination") String destination,
@Query("key") String key,
@Query("mode") String mode,
@Query("alternatives") boolean alternatives);
}

Concatenate the latitude and longitude with a comma separator. For instance if your origination latitude is 12.37 and your longitude is 73.54, then your startLatLong will be ‘12.37,73.54’

private void getDirections(String startLatLong, String destLatLong, final LatLng startCoordinates) {Retrofit retrofitInstance = new Retrofit.Builder()
.baseUrl("https://maps.googleapis.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
Call<RoutesDetail> routeQuery = retrofitInstance.create(ServiceApi.class)
.getDirection(startLatLong, destLatLong, DIRECTION_API_KEY, "driving", true);
routeQuery.enqueue(new Callback<RoutesDetail>() {
@Override
public void onResponse(Call<RoutesDetail> call, Response<RoutesDetail> response) {
RoutesDetail routesDetail = response.body();
if (response.isSuccessful() && routesDetail != null) {
//plot the obtained routes in the map }
}
@Override
public void onFailure(Call<RoutesDetail> call, Throwable t) {
Log.e(TAG, "onFailure(): ", t);
}
});
}

The service call returns 2 or 3 alternate routes. Each route has an Overviewpolyine which will be in an encrypted format. The point data should be decrypted to display the routes in the map. We are going to use the PolyUtil class provided by Google maps to decrypt the point data.

Include the following line in your app’s build.gradle file.

compile ’com.google.maps.android:android-maps-utils:0.5+’

Add the following lines to the OverviewPolyline.java class.

public List getPoints(){
return PolyUtil.decode(points);
}

Include the following lines in your MapActivity.java class.

private void displayMap(final List<Route> travelRoutes, final LatLng startCoordinates) {
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
googleMap.moveCamera(CameraUpdateFactory.newLatLng(startCoordinates));
googleMap.animateCamera(CameraUpdateFactory.zoomTo(7.0f));
for (Route route : travelRoutes) {
if (route != null && route.overviewPolyLine = null) {
List<LatLng> routePoints = route.overviewPolyLine.getPoints();
PolylineOptions polylineOptions = new PolylineOptions();
polylineOptions.color(Color.BLUE);
polylineOptions.addAll(routePoints);
googleMap.addPolyline(polylineOptions).setClickable(true);
googleMap.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
@Override
public void onPolylineClick(Polyline polyline) {
polyline.setColor(Color.GREEN);
}
});
}
}
}
});
}

After Build and Run, you should be able to see alternate routes on your Google Maps activity. To enable actions on your alternate routes, you can include event listeners on your polylines.

--

--