Add Shipping Directions Function

This commit is contained in:
phanhuuloi27
2022-06-06 21:45:33 +07:00
parent 9b09517c5e
commit 68cd0a41ea
12 changed files with 544 additions and 1 deletions
+6
View File
@@ -1,5 +1,6 @@
plugins { plugins {
id 'com.android.application' id 'com.android.application'
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
} }
android { android {
@@ -54,6 +55,11 @@ dependencies {
implementation 'com.github.jd-alexander:android-flat-button:v1.1' implementation 'com.github.jd-alexander:android-flat-button:v1.1'
implementation 'com.rengwuxian.materialedittext:library:2.1.4' implementation 'com.rengwuxian.materialedittext:library:2.1.4'
implementation 'com.jaredrummler:material-spinner:1.1.0' implementation 'com.jaredrummler:material-spinner:1.1.0'
implementation 'com.google.android.gms:play-services-maps:10.2.0'
implementation 'com.google.android.gms:play-services:10.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
@@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.waterbase.foodifyServer"> package="com.waterbase.foodifyServer">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@@ -13,6 +15,27 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.FoodifyServer" android:theme="@style/Theme.FoodifyServer"
tools:targetApi="31"> tools:targetApi="31">
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<!--
TODO: Before you run your application, you need a Google Maps API key.
To get one, follow the directions here:
https://developers.google.com/maps/documentation/android-sdk/get-api-key
Once you have your API key (it starts with "AIza"), define a new property in your
project's local.properties file (e.g. MAPS_API_KEY=Aiza...), and replace the
"YOUR_API_KEY" string in this file with "${MAPS_API_KEY}".
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyApaoTIiQj-faYEkJuSlJoTHTZFC4L8CbM" />
<activity
android:name=".TrackingOrder"
android:exported="false"
android:label="@string/title_activity_tracking_order" />
<activity <activity
android:name=".OrderStatus" android:name=".OrderStatus"
android:exported="false" /> android:exported="false" />
@@ -1,14 +1,25 @@
package com.waterbase.foodifyServer.Common; package com.waterbase.foodifyServer.Common;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import com.waterbase.foodifyServer.Model.Request;
import com.waterbase.foodifyServer.Model.User; import com.waterbase.foodifyServer.Model.User;
import com.waterbase.foodifyServer.Remote.IGeoCoordinates;
import com.waterbase.foodifyServer.Remote.RetrofitClient;
public class Common { public class Common {
public static User currentUser; public static User currentUser;
public static Request currentRequest;
public static final String UPDATE = "Cập nhật"; public static final String UPDATE = "Cập nhật";
public static final String DELETE = "Xoá"; public static final String DELETE = "Xoá";
public static final int PICK_IMAGE_REQUEST = 71; public static final int PICK_IMAGE_REQUEST = 71;
public static final String baseUrl = "https://maps.googleapis.com";
public static String coverCodeToStatus(String code){ public static String coverCodeToStatus(String code){
if(code.equals("0")) if(code.equals("0"))
return "Placed"; return "Placed";
@@ -17,4 +28,25 @@ public class Common {
else else
return "Shipped"; return "Shipped";
} }
public static IGeoCoordinates getGeoCodeService() {
return RetrofitClient.getClient(baseUrl).create(IGeoCoordinates.class);
}
public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
float scaleX = newWidth / (float)bitmap.getWidth();
float scaleY = newWidth / (float)bitmap.getHeight();
float pivotX = 0, pivotY = 0;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
} }
@@ -0,0 +1,100 @@
package com.waterbase.foodifyServer.Common;
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 DirectionJSONParser {
/**
* 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 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 decodePoly(String encoded) {
List 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;
}
}
@@ -7,6 +7,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
@@ -68,7 +69,9 @@ public class OrderStatus extends AppCompatActivity {
viewHolder.setItemClickListener(new ItemClickListener() { viewHolder.setItemClickListener(new ItemClickListener() {
@Override @Override
public void onClick(View view, int position, boolean isLongClick) { public void onClick(View view, int position, boolean isLongClick) {
Intent trackingOrder = new Intent(OrderStatus.this, TrackingOrder.class);
Common.currentRequest = model;
startActivity(trackingOrder);
} }
}); });
} }
@@ -0,0 +1,13 @@
package com.waterbase.foodifyServer.Remote;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface IGeoCoordinates {
@GET("maps/api/geocode/json")
Call<String> getGeoCode(@Query("address") String address);
@GET("maps/api/directions/json")
Call<String> getDirections(@Query("origin") String origin, @Query("destination") String destination);
}
@@ -0,0 +1,19 @@
package com.waterbase.foodifyServer.Remote;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if(retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
}
return retrofit;
}
}
@@ -0,0 +1,336 @@
package com.waterbase.foodifyServer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.loader.content.AsyncTaskLoader;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
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.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.waterbase.foodifyServer.Common.Common;
import com.waterbase.foodifyServer.Common.DirectionJSONParser;
import com.waterbase.foodifyServer.Remote.IGeoCoordinates;
import com.waterbase.foodifyServer.databinding.ActivityTrackingOrderBinding;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class TrackingOrder extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private GoogleMap mMap;
private ActivityTrackingOrderBinding binding;
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private final static int LOCATION_PERMISSION_REQUEST = 1001;
private Location mLastLocation;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private static int UPDATE_INTERVAL = 1000;
private static int FATEST_INTERVAL = 5000;
private static int DISPLACEMENT = 10;
private IGeoCoordinates mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityTrackingOrderBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
mService = Common.getGeoCodeService();
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestRuntimePermission();
} else {
if(checkPlayServices()) {
buildGoogleApiClient();
createLocationRequest();
}
}
// 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);
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private void displayLocation() {
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestRuntimePermission();
} else {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
//Add Marker in your location and move the camera
LatLng yourLocation = new LatLng(latitude, longitude);
mMap.addMarker(new MarkerOptions().position(yourLocation).title("Vị trí của bạn"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(yourLocation));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17.0f));
//After add Marker for your location, Add Marker for this Order and draw route
drawRoute(yourLocation, Common.currentRequest.getAddress());
} else {
Toast.makeText(this, "Không thể lấy được vị trí của bạn", Toast.LENGTH_SHORT).show();
}
}
}
private void drawRoute(LatLng yourLocation, String address) {
mService.getGeoCode(address).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
try {
JSONObject jsonObject = new JSONObject(response.body());
String lat = ((JSONArray)jsonObject.get("results"))
.getJSONObject(0)
.getJSONObject("geometry")
.getJSONObject("location")
.get("lat").toString();
String lng = ((JSONArray)jsonObject.get("results"))
.getJSONObject(0)
.getJSONObject("geometry")
.getJSONObject("location")
.get("lng").toString();
LatLng orderLocation = new LatLng(Double.parseDouble(lat), Double.parseDouble(lng));
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.box);
bitmap = Common.scaleBitmap(bitmap, 70, 70);
MarkerOptions marker = new MarkerOptions().icon(BitmapDescriptorFactory.fromBitmap(bitmap))
.title("Đơn hàng " + Common.currentRequest.getPhone())
.position(orderLocation);
mMap.addMarker(marker);
//draw route
mService.getDirections(yourLocation.latitude + ", " + yourLocation.longitude,
orderLocation.latitude + ", " + orderLocation.longitude)
.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
new ParserTask().execute(response.body().toString());
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resultCode != ConnectionResult.SUCCESS){
if(GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Toast.makeText(this, "This device is not support", Toast.LENGTH_SHORT).show();
finish();
}
return false;
}
return true;
}
private void requestRuntimePermission() {
ActivityCompat.requestPermissions(this, new String[]
{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
}, LOCATION_PERMISSION_REQUEST);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case LOCATION_PERMISSION_REQUEST:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
if(checkPlayServices()) {
buildGoogleApiClient();
createLocationRequest();
displayLocation();
}
}
break;
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
}
@Override
public void onLocationChanged(@NonNull Location location) {
mLastLocation = location;
displayLocation();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
displayLocation();
startLocationUpdates();
}
private void startLocationUpdates() {
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
protected void onResume() {
super.onResume();
checkPlayServices();
}
@Override
protected void onStart() {
super.onStart();
if(mGoogleApiClient != null)
mGoogleApiClient.connect();
}
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
ProgressDialog mDialog = new ProgressDialog(TrackingOrder.this);
@Override
protected void onPreExecute() {
super.onPreExecute();
mDialog.setMessage("Xin vui lòng đợi...");
mDialog.show();
}
@Override
protected List<List<HashMap<String, String>>> doInBackground(String... strings) {
JSONObject jsonObject;
List<List<HashMap<String, String>>> routes = null;
try {
jsonObject = new JSONObject(strings[0]);
DirectionJSONParser parser = new DirectionJSONParser();
routes = parser.parse(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
return routes;
}
@Override
protected void onPostExecute(List<List<HashMap<String, String>>> lists) {
mDialog.dismiss();
ArrayList points;
PolylineOptions lineOptions = null;
for(int i = 0; i < lists.size(); i++){
points = new ArrayList();
lineOptions = new PolylineOptions();
List<HashMap<String, String>> path = lists.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(12);
lineOptions.color(Color.RED);
lineOptions.geodesic(true);
}
mMap.addPolyline(lineOptions);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TrackingOrder" />
@@ -12,4 +12,5 @@
<string name="menu_home">Home</string> <string name="menu_home">Home</string>
<string name="menu_gallery">Gallery</string> <string name="menu_gallery">Gallery</string>
<string name="menu_slideshow">Slideshow</string> <string name="menu_slideshow">Slideshow</string>
<string name="title_activity_tracking_order">TrackingOrder</string>
</resources> </resources>
+1
View File
@@ -12,6 +12,7 @@ buildscript {
plugins { plugins {
id 'com.android.application' version '7.2.0' apply false id 'com.android.application' version '7.2.0' apply false
id 'com.android.library' version '7.2.0' apply false id 'com.android.library' version '7.2.0' apply false
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.0' apply false
} }
allprojects { allprojects {