by
Karthikeyan R
In this article, we will develop an Android application which facilitates users to tap two locations in the Google Map. On taping the second point, a driving route will be drawn in the Google Map Android API V2 using Google Directions API.
This application is developed in Eclipse (4.2.1) with ADT plugin (21.1.0) and Android SDK (21.1.0) and tested in a real device (Android 2.3.6 - GingerBread ).
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 “
Update the layout file res/layout/activity_main.xml
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
tools:context
=
".MainActivity"
>
<
fragment
android:id
=
"@+id/map"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
class
=
"com.google.android.gms.maps.SupportMapFragment"
/>
</
RelativeLayout
>
Create a new class namely “DirectionsJSONParser” in the file src/in/wptrafficanalyzer/locationroutedirectionmapv2/DirectionsJSONParser.java
package
in.wptrafficanalyzer.locationroutedirectionmapv2;
import
java.util.ArrayList;
import
java.util.HashMap;
import
java.util.List;
import
org.json.JSONArray;
import
org.json.JSONException;
import
org.json.JSONObject;
import
com.google.android.gms.maps.model.LatLng;
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
;
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<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<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 : http://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;
}
}
Update the class “MainActivity” in the file src/in/wptrafficanalyzer/locationroutedirectionmapv2/MainActivity.java
package
in.wptrafficanalyzer.locationroutedirectionmapv2;
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;
import
org.json.JSONObject;
import
android.graphics.Color;
import
android.os.AsyncTask;
import
android.os.Bundle;
import
android.support.v4.app.FragmentActivity;
import
android.util.Log;
import
android.view.Menu;
import
com.google.android.gms.maps.GoogleMap;
import
com.google.android.gms.maps.GoogleMap.OnMapClickListener;
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;
public
class
MainActivity
extends
FragmentActivity {
GoogleMap map;
ArrayList<LatLng> markerPoints;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 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();
if
(map!=
null
){
// Enable MyLocation Button in the Map
map.setMyLocationEnabled(
true
);
// Setting onclick event listener for the map
map.setOnMapClickListener(
new
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
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();
// 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);
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);
}
// Drawing polyline in the Google Map for the i-th route
map.addPolyline(lineOptions);
}
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return
true
;
}
}
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
package
=
"in.wptrafficanalyzer.locationroutedirectionmapv2"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"8"
android:targetSdkVersion
=
"17"
/>
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
<
permission
android:name
=
"in.wptrafficanalyzer.locationroutedirectionmapv2.permission.MAPS_RECEIVE"
android:protectionLevel
=
"signature"
/>
<
uses-permission
android:name
=
"in.wptrafficanalyzer.locationroutedirectionmapv2.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"
/>
<
uses-feature
android:glEsVersion
=
"0x00020000"
android:required
=
"true"
/>
<
application
android:allowBackup
=
"true"
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
android:theme
=
"@style/AppTheme"
>
<
activity
android:name
=
"in.wptrafficanalyzer.locationroutedirectionmapv2.MainActivity"
android:label
=
"@string/app_name"
>
<
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
=
"YOUR_API_KEY"
/>
</
application
>
</
manifest
>
Replace “YOUR_API_KEY” at the line 46 with the API key obtained from Api Console