Create google map with directions one point to another point with distance and time
google
map
directions
distance
time
point
- By Code solution
- Jan 20th, 2021
- 0 comments
- 0
Create google map with directions one point to another point with distance and time
Creating New Project
- Create a new project in Android Studio from File ⇒ New Project. When selecting Empty Activity and proceed.
- Add WoWoViewPager dependency to your build.gradle and rebuild the project.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//noinspection GradleCompatible
implementation 'com.android.support:appcompat-v7:27.*'
implementation 'com.android.support:design:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.android.gms:play-services:11.2.0'
}
Create four XML layouts named activity_main.xml under res ⇒ layouts.
xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/etOrigin"
android:hint="Enter origin address" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter destination address"
android:id="@+id/etDestination" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Find path"
android:id="@+id/btnFindPath" />
<ImageView
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_distance"/>
<TextView
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0 km"
android:id="@+id/tvDistance" />
<ImageView
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="5dp"
android:src="@drawable/ic_clock"/>
<TextView
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0 min"
android:id="@+id/tvDuration" />
LinearLayout>
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
LinearLayout>
-
Create DirectionFinder.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap.Modules;
import android.os.AsyncTask;
import com.google.android.gms.maps.model.LatLng;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
public class DirectionFinder {
private static final String DIRECTION_URL_API = "https://maps.googleapis.com/maps/api/directions/json?";
private static final String GOOGLE_API_KEY = "@string/google_app_id";
private DirectionFinderListener listener;
private String origin;
private String destination;
public DirectionFinder(DirectionFinderListener listener, String origin, String destination) {
this.listener = listener;
this.origin = origin;
this.destination = destination;
}
public void execute() throws UnsupportedEncodingException {
listener.onDirectionFinderStart();
new DownloadRawData().execute(createUrl());
}
private String createUrl() throws UnsupportedEncodingException {
String urlOrigin = URLEncoder.encode(origin, "utf-8");
String urlDestination = URLEncoder.encode(destination, "utf-8");
return DIRECTION_URL_API + "origin=" + urlOrigin + "&destination=" + urlDestination + "&key=" + GOOGLE_API_KEY;
}
private class DownloadRawData extends AsyncTask {
@Override
protected String doInBackground(String... params) {
String link = params[0];
try {
URL url = new URL(link);
InputStream is = url.openConnection().getInputStream();
StringBuffer buffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String res) {
try {
parseJSon(res);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void parseJSon(String data) throws JSONException {
if (data == null)
return;
List routes = new ArrayList();
JSONObject jsonData = new JSONObject(data);
JSONArray jsonRoutes = jsonData.getJSONArray("routes");
for (int i = 0; i < jsonRoutes.length(); i++) {
JSONObject jsonRoute = jsonRoutes.getJSONObject(i);
Route route = new Route();
JSONObject overview_polylineJson = jsonRoute.getJSONObject("overview_polyline");
JSONArray jsonLegs = jsonRoute.getJSONArray("legs");
JSONObject jsonLeg = jsonLegs.getJSONObject(0);
JSONObject jsonDistance = jsonLeg.getJSONObject("distance");
JSONObject jsonDuration = jsonLeg.getJSONObject("duration");
JSONObject jsonEndLocation = jsonLeg.getJSONObject("end_location");
JSONObject jsonStartLocation = jsonLeg.getJSONObject("start_location");
route.distance = new Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"));
route.duration = new Duration(jsonDuration.getString("text"), jsonDuration.getInt("value"));
route.endAddress = jsonLeg.getString("end_address");
route.startAddress = jsonLeg.getString("start_address");
route.startLocation = new LatLng(jsonStartLocation.getDouble("lat"), jsonStartLocation.getDouble("lng"));
route.endLocation = new LatLng(jsonEndLocation.getDouble("lat"), jsonEndLocation.getDouble("lng"));
route.points = decodePolyLine(overview_polylineJson.getString("points"));
routes.add(route);
}
listener.onDirectionFinderSuccess(routes);
}
private List decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List decoded = new ArrayList();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.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 = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new LatLng(
lat / 100000d, lng / 100000d
));
}
return decoded;
}
}
-
Create DirectionFinderListener.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap.Modules;
import com.google.android.gms.maps.model.LatLng;
import java.util.ArrayList;
import java.util.List;
public interface DirectionFinderListener {
void onDirectionFinderStart();
void onDirectionFinderSuccess(List route);
}
-
Create Distance.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap.Modules;
public class Distance {
public String text;
public int value;
public Distance(String text, int value) {
this.text = text;
this.value = value;
}
}
-
Create Duration.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap.Modules;
public class Duration {
public String text;
public int value;
public Duration(String text, int value) {
this.text = text;
this.value = value;
}
}
- Create Route.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap.Modules;
import com.google.android.gms.maps.model.LatLng;
import java.util.List;
public class Route {
public Distance distance;
public Duration duration;
public String endAddress;
public LatLng endLocation;
public String startAddress;
public LatLng startLocation;
public List points;
}
- Create MainActivity.java and modify the code as below.
package waytofeed.wappteh.com.googleroutemap;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.support.v4.app.ActivityCompat;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
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.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import waytofeed.wappteh.com.googleroutemap.Modules.DirectionFinder;
import waytofeed.wappteh.com.googleroutemap.Modules.DirectionFinderListener;
import waytofeed.wappteh.com.googleroutemap.Modules.Route;
public class MainActivity extends FragmentActivity implements OnMapReadyCallback, DirectionFinderListener {
private GoogleMap mMap;
private Button btnFindPath;
private EditText etOrigin;
private EditText etDestination;
private List originMarkers = new ArrayList<>();
private List destinationMarkers = new ArrayList<>();
private List polylinePaths = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
btnFindPath = (Button) findViewById(R.id.btnFindPath);
etOrigin = (EditText) findViewById(R.id.etOrigin);
etDestination = (EditText) findViewById(R.id.etDestination);
btnFindPath.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendRequest();
}
});
}
@SuppressLint("NewApi")
private void sendRequest() {
String origin = etOrigin.getText().toString();
String destination = etDestination.getText().toString();
if (origin.isEmpty()) {
Toast.makeText(this, "Please enter origin address!", Toast.LENGTH_SHORT).show();
return;
}
if (destination.isEmpty()) {
Toast.makeText(this, "Please enter destination address!", Toast.LENGTH_SHORT).show();
return;
}
try {
new DirectionFinder(this, origin, destination).execute();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
LatLng hcmus = new LatLng(10.762963, 106.682394);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(hcmus, 18));
originMarkers.add(mMap.addMarker(new MarkerOptions()
.title("??i h?c Khoa h?c t? nhiên")
.position(hcmus)));
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;
}
mMap.setMyLocationEnabled(true);
}
@Override
public void onDirectionFinderStart() {
if (originMarkers != null) {
for (Marker marker : originMarkers) {
marker.remove();
}
}
if (destinationMarkers != null) {
for (Marker marker : destinationMarkers) {
marker.remove();
}
}
if (polylinePaths != null) {
for (Polyline polyline:polylinePaths ) {
polyline.remove();
}
}
}
@Override
public void onDirectionFinderSuccess(List routes) {
polylinePaths = new ArrayList<>();
originMarkers = new ArrayList<>();
destinationMarkers = new ArrayList<>();
for (Route route : routes) {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 16));
((TextView) findViewById(R.id.tvDuration)).setText(route.duration.text);
((TextView) findViewById(R.id.tvDistance)).setText(route.distance.text);
originMarkers.add(mMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.fromResource(R.drawable.start_blue))
.title(route.startAddress)
.position(route.startLocation)));
destinationMarkers.add(mMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green))
.title(route.endAddress)
.position(route.endLocation)));
PolylineOptions polylineOptions = new PolylineOptions().
geodesic(true).
color(Color.BLUE).
width(10);
for (int i = 0; i < route.points.size(); i++)
polylineOptions.add(route.points.get(i));
polylinePaths.add(mMap.addPolyline(polylineOptions));
}
}
}
- After Finally open AndroidManifest.XML and make IntroActivity as launcher activity.
xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="waytofeed.wappteh.com.googleroutemap">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_app_id"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
application>
manifest>