Sunday, December 4, 2016

Android Displaying Distance, Duration and Route in Application Using Google Maps

In this article i going to share a tutorial about how to display distance, duration and route in your application using Google Maps. You guys pretty sure have been know about the navigation feature of Google Maps, right?. Look at Figure 1

Figure 1

This tutorial will showing something like that. Like Figure 1, you can see how long the distance and duration to the destination. Also you can see which route that recommend by Google Maps

From the Video, is this similar as what you're looking for? If yes, please kindly follow the next steps. But if not, it's also ok for me :D


PREPARATION


1. Get the API KEY from Google
2. Start Development with Android Studio

IMPLEMENTATION


2. Get the KEY and activating the Google Maps API

Open this link : https://developers.google.com/maps/documentation/android-api/ , After in, click the GET API button at the top right side. Take a look at Figure 2

Figure 2

Next, create new project. The name of the project must be similar with your project in Android Studio. But it's up to you! It's ok. Take a look at Figure 3

Figure 3

Choose +Create a new project, Fill the project name and press button ENALBE API. After your press the button enable api, you'll given a Server Key. This Server Key that will you use and set in your AndroidManifest. Take a look Figure 4

Figure 4

As you can see ad Figure 4, you have got the API KEY. You also can open the console by press the button GO TO CONSOLE. Take a look at Figure 5

Figure 5

You can change the name. Write whatever so make you easy to remember. Because next when you have much project, you'll confusing haha. private experience.

2. Start Development in Android Studio

Before start, the first thing you have to know is the endpoint and the json format. It makes you easy to create the model class. You can check the json format here :

https://maps.googleapis.com/maps/api/directions/json?origin=-8.60815684,115.18285993&destination=-8.1246437,115.3133908&sensor=false&mode=driving&alternatives=true


Several term inside the model that you'll create must be same as the attribute name of the respon json above.

Ok, let's start. In order you don't get confuse while following this tutorial, for a while, please kindly follow my project structure. Take a look at Figure 6

Figure 6

Let start create the class one by one. First give some permissions on your AndroidManifest.xml and declare the API-KEY-SERVER that we have got.

Second, compile several libraries in your build.gradle (Module:app) that we'll use in this project. Look at the code below :

PACKAGE MODELS


There are some models that we'll use in this tutorial, the function of there method is to do getter and setter. Let's create one by one.

Data.java

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
/**
* Created by putuguna on 5/23/2016.
*/
public class Data {
private String latitude;
private String longitude;
@SerializedName("created_at")
private String modified;
@SerializedName("legs")
private Legs legs;
public Legs getLegs() {
return legs;
}
public void setLegs(Legs legs) {
this.legs = legs;
}
public Data() {
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getModified() {
return modified;
}
public void setModified(String modified) {
this.modified = modified;
}
}
view raw Data.java hosted with ❤ by GitHub
Legs.java

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
/**
* Created by putuguna on 10/2/2015.
*/
public class Legs {
@SerializedName("distance")
private Distance distance;
@SerializedName("duration")
private Duration duration;
@SerializedName("end_address")
private String end_address;
@SerializedName("end_location")
private EndLocation end_location;
@SerializedName("start_address")
private String start_address;
@SerializedName("start_location")
private StartLocation start_location;
public Distance getDistance() {
return distance;
}
public void setDistance(Distance distance) {
this.distance = distance;
}
public Duration getDuration() {
return duration;
}
public void setDuration(Duration duration) {
this.duration = duration;
}
public String getEnd_address() {
return end_address;
}
public void setEnd_address(String end_address) {
this.end_address = end_address;
}
public EndLocation getEnd_location() {
return end_location;
}
public void setEnd_location(EndLocation end_location) {
this.end_location = end_location;
}
public String getStart_address() {
return start_address;
}
public void setStart_address(String start_address) {
this.start_address = start_address;
}
public StartLocation getStart_location() {
return start_location;
}
public void setStart_location(StartLocation start_location) {
this.start_location = start_location;
}
}
view raw Legs.java hosted with ❤ by GitHub
Distance.java

package putugunation.com.mapsroute.models;
/**
* Created by putuguna on 5/23/2016.
*/
public class Distance {
private String text;
private String value;
public Distance(String text, String value) {
this.text = text;
this.value = value;
}
public String getText() {
return text;
}
public String getValue() {
return value;
}
public void setText(String text) {
this.text = text;
}
public void setValue(String value) {
this.value = value;
}
}
view raw Distance.java hosted with ❤ by GitHub
Duration.java

package putugunation.com.mapsroute.models;
/**
* Created by putuguna on 5/23/2016.
*/
public class Duration {
private String text;
private String value;
public String getText() {
return text;
}
public String getValue() {
return value;
}
public void setText(String text) {
this.text = text;
}
public void setValue(String value) {
this.value = value;
}
}
view raw Duration.java hosted with ❤ by GitHub
DirectionResultModel.java

This class used to take route's data from json

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by putuguna on 5/23/2016.
*/
public class DirectionResultsModel {
@SerializedName("routes")
private List<Route> routes;
public List<Route> getRoutes() {
return routes;
}
public void setRoutes(List<Route> routes) {
this.routes = routes;
}
}
EndLocation.java

This class used to take LatLng from the Destination (End Location)

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
/**
* Created by putuguna on 5/23/2016.
*/
public class EndLocation {
@SerializedName("lat")
private String lat;
@SerializedName("lng")
private String lng;
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getLng() {
return lng;
}
public void setLng(String lng) {
this.lng = lng;
}
}
Route.java

This class used to take all of Leg's data from json

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by putuguna on 5/23/2016.
*/
public class Route {
@SerializedName("legs")
private List<Legs> legs;
public List<Legs> getLegs() {
return legs;
}
public void setLegs(List<Legs> legs) {
this.legs = legs;
}
}
view raw Route.java hosted with ❤ by GitHub
StartLocation.java

This class used ti take LatLng's data from Origin (Start Location)

package putugunation.com.mapsroute.models;
import com.google.gson.annotations.SerializedName;
/**
* Created by putuguna on 5/23/2016.
*/
public class StartLocation {
@SerializedName("lat")
private String lat;
@SerializedName("lng")
private String lng;
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getLng() {
return lng;
}
public void setLng(String lng) {
this.lng = lng;
}
}

PACKAGE HELPERS


In this package contains several class.java that used to make easy development proccess

Constant.java

This class contains variables that used as key in storing data in SharedPreference and Storing URL/Endpoint

package putugunation.com.mapsroute.helpers;
/**
* Created by putuguna on 5/14/2016.
*/
public class Constant {
public static final String CURRENT_LAT = "current-lat";
public static final String CURRENT_LONG = "current-long";
public static final String GOOGLE_END_POINT = "https://maps.googleapis.com/";
public static final String GOOGLE_DIRECTION = "https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&key=";
public static final String LAT_CHOSEN = "lat-chosen";
public static final String LONG_CHOSEN = "long-chosen";
public static final String NAME_CHOSEN = "name-chosen";
public static final String DURATION_CHOSEN = "dur-chosen";
public static final String DISTANCE_CHOSEN = "dis-chosen";
}
view raw Constant.java hosted with ❤ by GitHub
DirectionJSONParser.java

This class used to parse JSON. In this class also contains method that create polyline  

package putugunation.com.mapsroute.helpers;
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;
/**
* Created by putuguna on 5/22/2016.
*/
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 : 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;
}
}
LoggingInterceptorGoogle.java

As previous tutorials, class LoggingInterceptor used to make easy for debugging

package putugunation.com.mapsroute.helpers;
import android.util.Log;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import java.io.IOException;
import okio.Buffer;
/**
* Created by putuguna on 1/27/2016.
*/
public class LoggingInterceptorGoogle implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
String requestLog = String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers());
//YLog.d(String.format("Sending request %s on %s%n%s",
// request.url(), chain.connection(), request.headers()));
if (request.method().compareToIgnoreCase("post") == 0) {
requestLog = "\n" + requestLog + "\n" + bodyToString(request);
}
Log.d("TAG", "request" + "\n" + requestLog);
Response response = chain.proceed(request);
long t2 = System.nanoTime();
String responseLog = String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
String bodyString = response.body().string();
Log.d("TAG", "response" + "\n" + responseLog + "\n" + bodyString);
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), bodyString))
.build();
}
public static String bodyToString(final Request request) {
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
return "did not work";
}
}
}
Utils.java

package putuguna.com.mapsnomatrix;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
/**
* Created by putuguna on 5/14/2016.
*/
public class Utils {
public static String getStrings(Context ctx, String key) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(ctx);
String value = sharedPreferences.getString(
key, null);
return value;
}
//save string
public static void saveString(Context context, String key, String value){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = sharedPreferences.edit();
edit.putString(key, value);
edit.commit();
}
}
view raw Utils.java hosted with ❤ by GitHub
This class cointains method SharedPreferences that used to store data

PACKAGE APISERVICES


In this package contains an interface. This interface contains method that i used to execute the URL/Endpoint that has been prepared

ApiService.java

package putuguna.com.mapsnomatrix;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Query;
/**
* Created by putuguna on 1/27/2016.
*/
public interface ApiService {
/* @GET("api/gateways")
public Call<DataResponse> getAllData();
@GET("api/gateways")
public Call<DataResponse> getListData(@Query("api_key") String api_key);*/
@GET("/maps/api/distancematrix/json")
public Call<Data> getDirection(@Query("origin") String origin, @Query("destination") String destination);
@GET("/maps/api/directions/json")
public Call<DirectionResultsModel> getDistanceAndDuration(@Query("origin") String origin, @Query("destination") String destination, @Query("sensor") String sensor, @Query("mode") String mode, @Query("alternatives") String alternatives);
}
view raw ApiService.java hosted with ❤ by GitHub

PACKAGE ADAPTER


In this package only contains adapter class. The function of this adapter is set and show list object location

AdapterListView.java


package putuguna.com.mapsnomatrix.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import putuguna.com.mapsnomatrix.Data;
import putuguna.com.mapsnomatrix.R;
/**
* Created by gunaputu on 20/10/2015.
*/
public class AdapterListVIew extends ArrayAdapter<Data> {
private Context context;
int layoutResourceId;
private List<Data> listData;
private List<String> list;
LayoutInflater inflater;
private ArrayList<Data> arraylist;
public AdapterListVIew(Context context, int layoutResourceId, List<Data> listData, List<String> list) {
super(context, layoutResourceId, listData);
this.list= list;
this.context = context;
this.layoutResourceId = layoutResourceId;
this.listData = listData;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<>();
this.arraylist.addAll(listData);
}
public AdapterListVIew(Context context, int layoutResourceId, List<Data> listData) {
super(context, layoutResourceId, listData);
this.context = context;
this.layoutResourceId = layoutResourceId;
this.listData = listData;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<>();
this.arraylist.addAll(listData);
}
public View getView(int position,View view,ViewGroup parent){
Data datas = listData.get(position);
Holder holder ;
if(view == null){
holder =new Holder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.row_item_data,parent, false);
holder.name = (TextView) view.findViewById(R.id.name_of_data);
holder.distance = (TextView) view.findViewById(R.id.distance);
holder.duration = (TextView) view.findViewById(R.id.duration);
holder.latitude = (TextView) view.findViewById(R.id.latitude);
holder.longitude = (TextView) view.findViewById(R.id.longitude);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
holder.name.setText(datas.getModified());
holder.duration.setText("Duration from current position, it's about " + datas.getLegs().getDuration().getText());
holder.distance.setText("from current position, it's about " + datas.getLegs().getDistance().getText());
holder.latitude.setText("Latitude : " + datas.getLatitude());
holder.longitude.setText("Longitude : " + datas.getLongitude());
return view;
}
static class Holder{
private TextView name;
private TextView distance;
private TextView duration;
private TextView latitude;
private TextView longitude;
}
@Override
public Data getItem(int position) {
if(this.listData != null) {
this.list.get(position);
} else {
return null;
}
return null;
}
//Filter for mSearch function
/* public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
listData.clear();
if (charText.length() == 0) {
listData.addAll(arraylist);
} else {
for (int i=0; i<listData.size(); i++) {
if (listData.get(i).getName().toLowerCase(Locale.getDefault())
.contains(charText)) {
listData.add(listData.get(i));
}
}
}
notifyDataSetChanged();
}*/
}

PACKAGE ACTIVITIES


In this package contains only Activity classes

ListDestinationActivity.java

This class used to show all the destination list. Later, when we choose one location from the list, it will direct to the maps and show the route between origin and destination
package putugunation.com.mapsroute.activities;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import java.util.Comparator;
import java.util.List;
import putugunation.com.mapsroute.R;
import putugunation.com.mapsroute.adapters.AdapterListVIew;
import putugunation.com.mapsroute.helpers.Constant;
import putugunation.com.mapsroute.helpers.Utils;
import putugunation.com.mapsroute.models.Data;
public class ListDestinationActivity extends AppCompatActivity {
private ListView listView;
private AdapterListVIew adapter;
private List<Data> listData;
private ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
listView = (ListView) findViewById(R.id.recyclerView_data);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
progressDialog = new ProgressDialog(this);
setListAdapter(MainActivity.data);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intents = new Intent(ListDestinationActivity.this, ViewRouteActivity.class);
startActivity(intents);
Utils.saveString(ListDestinationActivity.this, Constant.LAT_CHOSEN, MainActivity.data.get(position).getLatitude());
Utils.saveString(ListDestinationActivity.this, Constant.LONG_CHOSEN, MainActivity.data.get(position).getLongitude());
Utils.saveString(ListDestinationActivity.this,Constant.NAME_CHOSEN, MainActivity.data.get(position).getModified());
Utils.saveString(ListDestinationActivity.this,Constant.DURATION_CHOSEN, MainActivity.data.get(position).getLegs().getDuration().getText());
Utils.saveString(ListDestinationActivity.this,Constant.DISTANCE_CHOSEN, MainActivity.data.get(position).getLegs().getDistance().getText());
}
});
}
private void setListAdapter(final List<Data> list){
try {
adapter = new AdapterListVIew(ListDestinationActivity.this,R.layout.row_item_data,list);
listView.setAdapter(adapter);
adapter.sort(new Comparator<Data>() {
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public int compare(Data lhs, Data rhs) {
int value1 = Integer.parseInt(lhs.getLegs().getDistance().getValue());
int value2 = Integer.parseInt(lhs.getLegs().getDuration().getValue());
return Integer.compare(value1, value2);
}
});
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id== android.R.id.home){
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
}
ViewRouteActivity.java

This class will showing the destination, duration and route from the origin to the destination.

package putugunation.com.mapsroute.activities;
import android.Manifest;
import android.app.Dialog;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
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;
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;
import putugunation.com.mapsroute.R;
import putugunation.com.mapsroute.helpers.Constant;
import putugunation.com.mapsroute.helpers.DirectionsJSONParser;
import putugunation.com.mapsroute.helpers.Utils;
/**
* Created by putuguna on 9/20/2016.
*/
public class ViewRouteActivity extends FragmentActivity implements LocationListener {
private GoogleMap mGoogleMap;
private double mLatitude = 0;
private double mLongitude = 0;
private double latChosen;
private double longChosen;
private String namePlace;
private String duration;
private String distance;
private TextView detail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_route);
detail = (TextView) findViewById(R.id.detail);
latChosen = Double.parseDouble(Utils.getStrings(this, Constant.LAT_CHOSEN));
longChosen = Double.parseDouble(Utils.getStrings(this, Constant.LONG_CHOSEN));
namePlace = Utils.getStrings(this, Constant.NAME_CHOSEN);
duration = Utils.getStrings(this, Constant.DURATION_CHOSEN);
distance = Utils.getStrings(this, Constant.DISTANCE_CHOSEN);
Log.d("TAG", "CHOSEN : " + latChosen + " : " + longChosen);
detail.setText("Distance : " + distance + ", Duration : " + duration);
// Getting Google Play availability status
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
if (status != ConnectionResult.SUCCESS) { // Google Play Services are not available
int requestCode = 10;
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
dialog.show();
} else { // Google Play Services are available
// Getting reference to SupportMapFragment of the activity_main
MapFragment fm = (MapFragment) getFragmentManager().findFragmentById(R.id.map_view);
// Getting Map for the SupportMapFragment
mGoogleMap = fm.getMapAsync(this);
// Enable MyLocation Button in the Map
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mGoogleMap.setMyLocationEnabled(true);
// Getting LocationManager object from System Service LOCATION_SERVICE
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// Creating a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Getting the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Getting Current Location From GPS
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
onLocationChanged(location);
}
locationManager.requestLocationUpdates(provider, 20000, 0, this);
LatLng origin = new LatLng(mLatitude, mLongitude);
LatLng dest = new LatLng(latChosen, longChosen);
// 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);
}
// otherMarker();
}
@Override
public void onLocationChanged(Location location) {
// Draw the marker, if destination location is not set
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
LatLng point = new LatLng(mLatitude, mLongitude);
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(point));
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(12));
drawMarker(point);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
/**
* this method used to get LatLng of origin and destination
* @param origin
* @param dest
* @return
*/
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
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters;
return url;
}
/**
* this method used to download json's data from URL
* @param strUrl
* @return
* @throws IOException
*/
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("TAG","Exception while downloading url"+ e.toString());
}finally{
iStream.close();
urlConnection.disconnect();
}
return data;
}
/** A class to download data from Google Directions URL */
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 Directions 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;
// 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
mGoogleMap.addPolyline(lineOptions);
}
}
/**
* this method used to draw a marker from LatLng
* @param point
*/
private void drawMarker(LatLng point){
// Creating MarkerOptions
MarkerOptions options = new MarkerOptions();
options.position(point);
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
options.title("Hi You!");
options.snippet("Your Location");
mGoogleMap.addMarker(options).showInfoWindow();
//map others
mGoogleMap.addMarker(new MarkerOptions().position(new LatLng(latChosen, longChosen)).title(namePlace).snippet("Your Destination")).showInfoWindow();
}
}
MainActivity.java

This class will showing the map include the marker from the list location that we have.

package putugunation.com.mapsroute.activities;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.squareup.okhttp.OkHttpClient;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import putugunation.com.mapsroute.R;
import putugunation.com.mapsroute.apiservices.ApiService;
import putugunation.com.mapsroute.helpers.Constant;
import putugunation.com.mapsroute.helpers.LoggingInterceptorGoogle;
import putugunation.com.mapsroute.helpers.Utils;
import putugunation.com.mapsroute.models.Data;
import putugunation.com.mapsroute.models.DirectionResultsModel;
import putugunation.com.mapsroute.models.Legs;
import retrofit.Call;
import retrofit.GsonConverterFactory;
import retrofit.Retrofit;
public class MainActivity extends AppCompatActivity implements LocationListener{
public static final int REQUEST_CODE_LOCATION = 121;
private GoogleMap googleMap;
private ApiService serviceGoogleDirection;
public static List<Data> data;
private LatLng currentPosition;
private LocationManager locationManager;
private Button buttonCheckList;
private ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonCheckList = (Button) findViewById(R.id.buttonCekList);
requestPermission();
}
/**
* Update Juni 2018
* For users that use OS version 7 and 8, it must be crash because the permission of location is denied
* Please use code below to fix it.
*/
private void requestPermission() {
ActivityCompat.requestPermissions(this,
new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},
REQUEST_CODE_LOCATION);
}
private void setDataListAfterPermissionAllowed(){
//1. initialization your maps
//2. set your lat and lang
try {
initilizeMap();
Data d1 = new Data();
d1.setLatitude(-8.6947 + "");
d1.setLongitude(115.263 + "");
d1.setModified("Sanur Beach");
Data d2 = new Data();
d2.setLatitude(-8.7208 + "");
d2.setLongitude(115.1692 + "");
d2.setModified("Kuta Beach");
Data d3 = new Data();
d3.setLatitude(-8.8 + "");
d3.setLongitude(115.2333 + "");
d3.setModified("Dreamland Beach");
Data d4 = new Data();
d4.setLatitude(-8.8453597 + "");
d4.setLongitude(115.1110346 + "");
d4.setModified("Nyang-Nyang Beach");
Data d5 = new Data();
d5.setLatitude(-8.1246437 + "");
d5.setLongitude(115.3133908 + "");
d5.setModified("Bondalem Village");
List<Data> addata = new ArrayList<>();
addata.add(d1);
addata.add(d2);
addata.add(d3);
addata.add(d4);
addata.add(d5);
data = addata;
setDistanceForAll(data);
addMarker(data);
}catch (Exception e){e.printStackTrace();}
buttonCheckList.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ListDestinationActivity.class);
startActivity(intent);
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case REQUEST_CODE_LOCATION:
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
setDataListAfterPermissionAllowed()
}else{
Toast.makeText(this, "Permission denied!. Please enable manualy at menu setting in your device", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onResume() {
super.onResume();
try {
initilizeMap();
}catch (Exception e){e.printStackTrace();}
}
/**
* this method used to get direction and duration between 2 LatLng
* @param origin
* @param destination
* @return
*/
private Legs getDirectionAndDuration(final LatLng origin, final LatLng destination){
OkHttpClient clientGoogleApi = new OkHttpClient();
clientGoogleApi.interceptors().add(new LoggingInterceptorGoogle());
Retrofit retrofitGoogleApi = new Retrofit.Builder()
.baseUrl(Constant.GOOGLE_END_POINT)
.client(clientGoogleApi)
.addConverterFactory(GsonConverterFactory.create())
.build();
serviceGoogleDirection = retrofitGoogleApi.create(ApiService.class);
final Legs[] distanceDurationModel = new Legs[1];
final CountDownLatch latch = new CountDownLatch(1);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Call<DirectionResultsModel> directionResultsCall;
directionResultsCall = serviceGoogleDirection.getDistanceAndDuration(origin.latitude + "," + origin.longitude , destination.latitude + "," + destination.longitude, "false","driving","true");
try {
DirectionResultsModel results = directionResultsCall.execute().body();
distanceDurationModel[0] = results.getRoutes().get(0).getLegs().get(0);
} catch (IOException e) {
e.printStackTrace();
}
latch.countDown();
}
});
thread.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return distanceDurationModel[0];
}
/**
* this method used to set distance of all Data
* @param listData
* @return
*/
private List<Data> setDistanceForAll(List<Data> listData){
for(Data data : listData){
double destLat = Double.parseDouble(data.getLatitude());
double destLng = Double.parseDouble(data.getLongitude());
LatLng destination = new LatLng(destLat,destLng);
Legs legs = getDirectionAndDuration(currentPosition, destination);
data.setLegs(legs);
Log.d("TAG", "TEST : " + data.getLegs().getDistance().getText());
Log.d("TAG", "TEST : " + data.getLegs().getDuration().getText());
}
return listData;
}
/**
* this method used to show a map
*/
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.maps)).getMapAsync(this);
//check if map created successful or not
if (googleMap == null) {
Toast.makeText(getApplicationContext(), "Sorry unable to crated map", Toast.LENGTH_SHORT).show();
}
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
googleMap.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria,true);
//get current location from gps
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
onLocationChanged(location);
}
locationManager.requestLocationUpdates(provider,20000,0,this);
String latitude = Utils.getStrings(MainActivity.this, Constant.CURRENT_LAT);
String longitude = Utils.getStrings(MainActivity.this, Constant.CURRENT_LONG);
Toast.makeText(this, "LOKASIKU : " + location.getLongitude(), Toast.LENGTH_SHORT).show();
currentPosition = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude));
//creating marker
MarkerOptions marker = new MarkerOptions().position(new LatLng(Double.parseDouble(Utils.getStrings(this, Constant.CURRENT_LAT)), Double.parseDouble(Utils.getStrings(this,Constant.CURRENT_LONG)))).title("Hi You!").snippet("This is your location");
googleMap.addMarker(marker).showInfoWindow();
// googleMap.addMarker(new MarkerOptions().position(new LatLng(-8.6947, 115.263)).title("Sanur Beach").snippet("One of Sunrise spot")).showInfoWindow();
// googleMap.addMarker(new MarkerOptions().position(new LatLng(-8.7208, 115.1692)).title("Kuta Beach").snippet("One of Sunset spot")).showInfoWindow();
CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(Double.parseDouble(Utils.getStrings(this, Constant.CURRENT_LAT)), Double.parseDouble(Utils.getStrings(this,Constant.CURRENT_LONG)))).zoom(12).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
/**
* this method used to draw a marker using LatLng in List
* @param data
*/
private void addMarker(List<Data> data){
for(Data d : data){
googleMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble(d.getLatitude()), Double.parseDouble(d.getLongitude()))).title(d.getModified()).snippet("Your Destination")).showInfoWindow();
}
}
@Override
public void onLocationChanged(Location location) {
Utils.saveString(MainActivity.this, Constant.CURRENT_LAT, location.getLatitude() + "");
Utils.saveString(MainActivity.this, Constant.CURRENT_LONG, location.getLongitude() + "");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
That's all the steps that you can follow to display distance, duration and route in Application using Google Maps.

If done, then running your project. Hope there is no error :D

Related Posts


EmoticonEmoticon

:)
:(
hihi
:-)
:D
=D
:-d
;(
;-(
@-)
:o
:>)
(o)
:p
:-?
(p)
:-s
8-)
:-t
:-b
b-(
(y)
x-)
(h)