Merge branch 'directions-api' into develop
This commit is contained in:
@@ -26,6 +26,9 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -47,6 +50,9 @@ dependencies {
|
||||
//osm
|
||||
implementation 'org.osmdroid:osmdroid-android:6.1.8'
|
||||
|
||||
//osm bonus pack
|
||||
implementation 'com.github.MKergall:osmbonuspack:6.6.0'
|
||||
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
testImplementation 'org.mockito:mockito-core:2.7.22'
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.a1.nextlocation.fragments.HomeFragment;
|
||||
import com.a1.nextlocation.fragments.RouteFragment;
|
||||
import com.a1.nextlocation.fragments.SettingsFragment;
|
||||
import com.a1.nextlocation.fragments.StatisticFragment;
|
||||
import com.a1.nextlocation.network.ApiHandler;
|
||||
import com.a1.nextlocation.recyclerview.CouponListManager;
|
||||
import com.a1.nextlocation.recyclerview.LocationListManager;
|
||||
import com.a1.nextlocation.recyclerview.RouteListManager;
|
||||
|
||||
@@ -110,8 +110,6 @@ public class HomeFragment extends Fragment {
|
||||
|
||||
mapView.getOverlays().add(customOverlay);
|
||||
|
||||
|
||||
|
||||
// add the zoom controller
|
||||
IMapController mapController = mapView.getController();
|
||||
mapController.setZoom(15.0);
|
||||
|
||||
@@ -2,19 +2,29 @@ package com.a1.nextlocation.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.a1.nextlocation.R;
|
||||
import com.a1.nextlocation.data.Location;
|
||||
import com.a1.nextlocation.data.Route;
|
||||
import com.a1.nextlocation.json.DirectionsResult;
|
||||
import com.a1.nextlocation.network.ApiHandler;
|
||||
import com.a1.nextlocation.network.DirectionsListener;
|
||||
|
||||
public class RouteFragment extends Fragment {
|
||||
private static final String TAG = RouteFragment.class.getCanonicalName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ApiHandler.INSTANCE.addListener(this::onDirectionsAvailable);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,4 +34,21 @@ public class RouteFragment extends Fragment {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_route, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// ApiHandler.INSTANCE.getDirections(8.681436,49.41461,8.687872,49.420318);
|
||||
Route r = new Route("test");
|
||||
r.addLocation(new Location("test",8.681436,49.41461,"route",null));
|
||||
r.addLocation(new Location("test",8.687872,49.420318,"route",null));
|
||||
ApiHandler.INSTANCE.getDirections(r);
|
||||
}
|
||||
|
||||
public void onDirectionsAvailable(DirectionsResult result) {
|
||||
Log.d(TAG, "onDirectionsAvailable: got result! " + result);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
164
app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java
Normal file
164
app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java
Normal file
@@ -0,0 +1,164 @@
|
||||
package com.a1.nextlocation.json;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DirectionsResult {
|
||||
private static final String TAG = DirectionsResult.class.getCanonicalName();
|
||||
private List<DirectionsStep> steps = new ArrayList<>();
|
||||
private double distance;
|
||||
private double duration;
|
||||
private double[][] wayPointCoordinates;
|
||||
|
||||
public List<DirectionsStep> getSteps() {
|
||||
return steps;
|
||||
}
|
||||
|
||||
public void setSteps(List<DirectionsStep> steps) {
|
||||
this.steps = steps;
|
||||
}
|
||||
|
||||
public double getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public void setDistance(double distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public double getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public void addStep(DirectionsStep step) {
|
||||
this.steps.add(step);
|
||||
}
|
||||
|
||||
/**
|
||||
* parses a given json string into this object. It gets all the waypoints and steps and combines them so that every step also has the correct coordinates associated with it
|
||||
* @param json the json string to parse.
|
||||
*/
|
||||
public void parse(String json) {
|
||||
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
JsonObject feature = JsonParser.parseString(json).getAsJsonObject().get("features").getAsJsonArray().get(0).getAsJsonObject();
|
||||
JsonObject properties = feature.get("properties").getAsJsonObject();
|
||||
JsonArray wayPointCoordinates = feature.get("geometry").getAsJsonObject().getAsJsonArray("coordinates");
|
||||
this.wayPointCoordinates = new double[wayPointCoordinates.size()][2];
|
||||
|
||||
|
||||
// fill the way point coordinates list for later use
|
||||
for (int i = 0; i < wayPointCoordinates.size(); i++) {
|
||||
JsonElement j = wayPointCoordinates.get(i);
|
||||
JsonArray arr = j.getAsJsonArray();
|
||||
this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble();
|
||||
this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble();
|
||||
}
|
||||
|
||||
|
||||
JsonArray segments = properties.getAsJsonArray("segments");
|
||||
|
||||
for (JsonElement element : segments) {
|
||||
JsonObject segment = element.getAsJsonObject();
|
||||
|
||||
setDistance(segment.get("distance").getAsDouble());
|
||||
setDuration(segment.get("duration").getAsDouble());
|
||||
|
||||
JsonArray steps = segment.getAsJsonArray("steps");
|
||||
|
||||
for (JsonElement j : steps) {
|
||||
|
||||
DirectionsStep step = gson.fromJson(j,DirectionsStep.class);
|
||||
double lat;
|
||||
double longl;
|
||||
|
||||
// kinda stinky but it works
|
||||
for (int i = 0; i < 2; i++) {
|
||||
lat = this.wayPointCoordinates[step.getWay_points().get(i)][0];
|
||||
longl = this.wayPointCoordinates[step.getWay_points().get(i)][1];
|
||||
step.getWaypoints()[i] = new GeoPoint(lat,longl);
|
||||
}
|
||||
|
||||
addStep(step);
|
||||
Log.d(TAG, "parse: added step" + step);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void parseRoute(String json) {
|
||||
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
JsonArray routes = JsonParser.parseString(json).getAsJsonObject().getAsJsonArray("routes");
|
||||
for (JsonElement element : routes) {
|
||||
JsonObject route = element.getAsJsonObject();
|
||||
JsonObject summary = route.getAsJsonObject("summary");
|
||||
this.distance = summary.get("distance").getAsDouble();
|
||||
this.duration = summary.get("duration").getAsDouble();
|
||||
|
||||
JsonPrimitive geometry = route.getAsJsonPrimitive("geometry");
|
||||
JsonArray wayPointCoordinates = GeometryDecoder.decodeGeometry(geometry.getAsString(),false);
|
||||
this.wayPointCoordinates = new double[wayPointCoordinates.size()][2];
|
||||
|
||||
|
||||
// fill the way point coordinates list for later use
|
||||
for (int i = 0; i < wayPointCoordinates.size(); i++) {
|
||||
JsonElement j = wayPointCoordinates.get(i);
|
||||
JsonArray arr = j.getAsJsonArray();
|
||||
this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble();
|
||||
this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble();
|
||||
}
|
||||
|
||||
|
||||
JsonArray segments = route.getAsJsonArray("segments");
|
||||
|
||||
for (JsonElement e : segments) {
|
||||
JsonObject segment = e.getAsJsonObject();
|
||||
|
||||
setDistance(segment.get("distance").getAsDouble());
|
||||
setDuration(segment.get("duration").getAsDouble());
|
||||
|
||||
JsonArray steps = segment.getAsJsonArray("steps");
|
||||
|
||||
for (JsonElement j : steps) {
|
||||
|
||||
DirectionsStep step = gson.fromJson(j,DirectionsStep.class);
|
||||
double lat;
|
||||
double longl;
|
||||
|
||||
// kinda stinky but it works
|
||||
for (int i = 0; i < 2; i++) {
|
||||
lat = this.wayPointCoordinates[step.getWay_points().get(i)][0];
|
||||
longl = this.wayPointCoordinates[step.getWay_points().get(i)][1];
|
||||
step.getWaypoints()[i] = new GeoPoint(lat,longl);
|
||||
}
|
||||
|
||||
addStep(step);
|
||||
Log.d(TAG, "parse: added step" + step);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.a1.nextlocation.json;
|
||||
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* pojo class that holds the step object from the api response
|
||||
*/
|
||||
public class DirectionsStep {
|
||||
private double distance;
|
||||
private double duration;
|
||||
private String instruction;
|
||||
private String name;
|
||||
/**
|
||||
* these are the actual waypoints that the step refers to. The first is the beginning of the step, and the second is what it leads to.
|
||||
* The second geopoint is always the first geopoint of the next step in the list of the {@link DirectionsResult} object.
|
||||
*/
|
||||
private GeoPoint[] waypoints = new GeoPoint[2];
|
||||
/**
|
||||
* this is a list of the waypoints that are in the response, it is called way_points so it can be automatically serialized with gson
|
||||
*/
|
||||
private ArrayList<Integer> way_points;
|
||||
|
||||
public double getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public void setDistance(double distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public double getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getInstruction() {
|
||||
return instruction;
|
||||
}
|
||||
|
||||
public void setInstruction(String instruction) {
|
||||
this.instruction = instruction;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getWay_points() {
|
||||
return way_points;
|
||||
}
|
||||
|
||||
public void setWay_points(ArrayList<Integer> way_points) {
|
||||
this.way_points = way_points;
|
||||
}
|
||||
|
||||
public GeoPoint[] getWaypoints() {
|
||||
return waypoints;
|
||||
}
|
||||
|
||||
public void setWaypoints(GeoPoint[] waypoints) {
|
||||
this.waypoints = waypoints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.a1.nextlocation.json;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* source: https://github.com/GIScience/openrouteservice-docs#geometry-decoding
|
||||
*/
|
||||
public class GeometryDecoder {
|
||||
|
||||
public static JsonArray decodeGeometry(String encodedGeometry, boolean inclElevation) {
|
||||
JsonArray geometry = new JsonArray();
|
||||
int len = encodedGeometry.length();
|
||||
int index = 0;
|
||||
int lat = 0;
|
||||
int lng = 0;
|
||||
int ele = 0;
|
||||
|
||||
while (index < len) {
|
||||
int result = 1;
|
||||
int shift = 0;
|
||||
int b;
|
||||
do {
|
||||
b = encodedGeometry.charAt(index++) - 63 - 1;
|
||||
result += b << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x1f);
|
||||
lat += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
||||
|
||||
result = 1;
|
||||
shift = 0;
|
||||
do {
|
||||
b = encodedGeometry.charAt(index++) - 63 - 1;
|
||||
result += b << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x1f);
|
||||
lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
||||
|
||||
|
||||
if(inclElevation){
|
||||
result = 1;
|
||||
shift = 0;
|
||||
do {
|
||||
b = encodedGeometry.charAt(index++) - 63 - 1;
|
||||
result += b << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x1f);
|
||||
ele += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
||||
}
|
||||
|
||||
JsonArray location = new JsonArray();
|
||||
location.add(lat / 1E5);
|
||||
location.add(lng / 1E5);
|
||||
if(inclElevation){
|
||||
location.add((float) (ele / 100));
|
||||
}
|
||||
geometry.add(location);
|
||||
}
|
||||
return geometry;
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,20 @@ import android.util.Log;
|
||||
|
||||
import com.a1.nextlocation.data.Location;
|
||||
import com.a1.nextlocation.data.Route;
|
||||
import com.a1.nextlocation.json.DirectionsResult;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public enum ApiHandler {
|
||||
@@ -22,21 +28,22 @@ public enum ApiHandler {
|
||||
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||
private final String BASE_URL = "https://api.openrouteservice.org/v2/directions/";
|
||||
private final String API_KEY = "5b3ce3597851110001cf6248d4eee2099f724255918adc71cc502b2a";
|
||||
private final String DIRECTIONS_MODE = "foot_walking";
|
||||
private final String DIRECTIONS_MODE = "foot-walking";
|
||||
private List<DirectionsListener> listeners = new ArrayList<>();
|
||||
|
||||
private OkHttpClient client = new OkHttpClient();
|
||||
|
||||
public Route getDirections(Location startLocation, Location endLocation) {
|
||||
return getDirections(startLocation.getCoordinates(),endLocation.getCoordinates());
|
||||
public void getDirections(Location startLocation, Location endLocation) {
|
||||
getDirections(startLocation.getCoordinates(),endLocation.getCoordinates());
|
||||
}
|
||||
|
||||
public Route getDirections(double startLat, double startLong, double endLat, double endLong) {
|
||||
return getDirections(startLat + "," + startLong, endLat + "," + endLong);
|
||||
public void getDirections(double startLat, double startLong, double endLat, double endLong) {
|
||||
getDirections(startLat + "," + startLong, endLat + "," + endLong);
|
||||
}
|
||||
|
||||
public Route getDirections(String startLocation, String endLocation) {
|
||||
public void getDirections(String startLocation, String endLocation) {
|
||||
|
||||
String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY + "&start=" +startLocation + "&end=" + endLocation;
|
||||
AtomicReference<Route> res = null;
|
||||
Thread t = new Thread(() -> {
|
||||
|
||||
Request request = new Request.Builder().url(requestUrl).build();
|
||||
@@ -45,6 +52,14 @@ public enum ApiHandler {
|
||||
if (response.body() != null) {
|
||||
String responseString = Objects.requireNonNull(response.body()).string();
|
||||
Log.d(TAG, "getDirections: got response: " + responseString);
|
||||
|
||||
DirectionsResult result = new DirectionsResult();
|
||||
result.parse(responseString);
|
||||
Log.d(TAG, "getDirections: " + result.getSteps().size());
|
||||
|
||||
for (DirectionsListener listener : listeners) {
|
||||
listener.onDirectionsAvailable(result);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
@@ -54,12 +69,59 @@ public enum ApiHandler {
|
||||
|
||||
t.start();
|
||||
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return res.get();
|
||||
|
||||
public void addListener(DirectionsListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void getDirections(Route route) {
|
||||
// for (int i = 0; i < route.getLocations().size()-1; i+= 2) {
|
||||
// Location start = route.getLocations().get(i);
|
||||
// Location end = route.getLocations().get(i+1);
|
||||
// getDirections(start,end);
|
||||
// }
|
||||
|
||||
ArrayList<double[]> allCoords = new ArrayList<>();
|
||||
for (Location location : route.getLocations()) {
|
||||
allCoords.add(location.getCoordinatesAsDoubles());
|
||||
}
|
||||
|
||||
String body = "{\"coordinates\":" + new Gson().toJson(allCoords) + "}";
|
||||
|
||||
|
||||
String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY;
|
||||
|
||||
Thread t = new Thread(() -> {
|
||||
|
||||
RequestBody requestBody = RequestBody.create(body,JSON);
|
||||
Request request = new Request.Builder()
|
||||
.url(requestUrl)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
if (response.body() != null) {
|
||||
String responseString = Objects.requireNonNull(response.body()).string();
|
||||
Log.d(TAG, "getDirections: got response: " + responseString);
|
||||
|
||||
DirectionsResult result = new DirectionsResult();
|
||||
result.parseRoute(responseString);
|
||||
Log.d(TAG, "getDirections: " + result.getSteps().size());
|
||||
|
||||
for (DirectionsListener listener : listeners) {
|
||||
listener.onDirectionsAvailable(result);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "getDirections: caught exception: " + e.getLocalizedMessage());
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.a1.nextlocation.network;
|
||||
|
||||
import com.a1.nextlocation.data.Route;
|
||||
import com.a1.nextlocation.json.DirectionsResult;
|
||||
|
||||
public interface DirectionsListener {
|
||||
void onDirectionsAvailable(DirectionsResult result);
|
||||
}
|
||||
Reference in New Issue
Block a user