From 584e7dbf6d7ab00a42e3366a68599e7de263569b Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sun, 21 Feb 2021 13:44:22 +0200 Subject: [PATCH] Implement GPX online routing, step 1 --- .../main/java/net/osmand/util/Algorithms.java | 10 + .../onlinerouting/OnlineRoutingFactory.java | 3 + .../onlinerouting/OnlineRoutingHelper.java | 21 +- .../plus/onlinerouting/VehicleType.java | 1 + .../plus/onlinerouting/engine/EngineType.java | 20 +- .../plus/onlinerouting/engine/GpxEngine.java | 57 ++++++ .../engine/GraphhopperEngine.java | 162 +-------------- .../engine/OnlineRoutingEngine.java | 94 +++------ .../plus/onlinerouting/engine/OrsEngine.java | 48 +---- .../plus/onlinerouting/engine/OsrmEngine.java | 181 +---------------- .../plus/onlinerouting/parser/GpxParser.java | 42 ++++ .../parser/GraphhopperParser.java | 165 ++++++++++++++++ .../plus/onlinerouting/parser/JSONParser.java | 77 ++++++++ .../plus/onlinerouting/parser/OrsParser.java | 52 +++++ .../plus/onlinerouting/parser/OsrmParser.java | 187 ++++++++++++++++++ .../onlinerouting/parser/ResponseParser.java | 77 ++++++++ .../ui/OnlineRoutingEngineFragment.java | 8 +- .../osmand/plus/routing/RouteProvider.java | 28 ++- 18 files changed, 778 insertions(+), 455 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java create mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index 83b7c14b44..247fc30ced 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -53,6 +53,8 @@ public class Algorithms { public static final int XML_FILE_SIGNATURE = 0x3c3f786d; public static final int OBF_FILE_SIGNATURE = 0x08029001; public static final int SQLITE_FILE_SIGNATURE = 0x53514C69; + public static final int BZIP_FILE_SIGNATURE = 0x425a; + public static final int GZIP_FILE_SIGNATURE = 0x1f8b; public static String normalizeSearchText(String s) { boolean norm = false; @@ -358,6 +360,14 @@ public class Algorithms { return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); } + public static int readSmallInt(InputStream in) throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return ((ch1 << 8) + ch2); + } + public static String capitalizeFirstLetterAndLowercase(String s) { if (s != null && s.length() > 1) { // not very efficient algorithm diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java index 4b92000847..71ea72f5e4 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.plus.onlinerouting.engine.EngineType; +import net.osmand.plus.onlinerouting.engine.GpxEngine; import net.osmand.plus.onlinerouting.engine.GraphhopperEngine; import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.onlinerouting.engine.OrsEngine; @@ -27,6 +28,8 @@ public class OnlineRoutingFactory { return new OsrmEngine(params); case ORS: return new OrsEngine(params); + case GPX: + return new GpxEngine(params); default: throw new IllegalArgumentException( "Online routing type {" + type.name() + "} not supported"); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java index de36b87449..079cfd8a12 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java @@ -9,7 +9,8 @@ import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.OsmandApplication; import net.osmand.plus.Version; import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; -import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; +import net.osmand.plus.onlinerouting.parser.ResponseParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser.OnlineRoutingResponse; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; @@ -19,12 +20,14 @@ 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.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.zip.GZIPInputStream; import static net.osmand.util.Algorithms.isEmpty; @@ -88,7 +91,8 @@ public class OnlineRoutingHelper { boolean leftSideNavigation) throws IOException, JSONException { String url = engine.getFullUrl(path); String content = makeRequest(url); - return engine.parseServerResponse(content, app, leftSideNavigation); + ResponseParser parser = engine.getResponseParser(); + return parser.parseResponse(content, app, leftSideNavigation); } @NonNull @@ -98,7 +102,7 @@ public class OnlineRoutingHelper { StringBuilder content = new StringBuilder(); BufferedReader reader; if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { - reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + reader = new BufferedReader(new InputStreamReader(getInputStream(connection))); } else { reader = new BufferedReader(new InputStreamReader(connection.getErrorStream())); } @@ -113,6 +117,17 @@ public class OnlineRoutingHelper { return content.toString(); } + private InputStream getInputStream(@NonNull HttpURLConnection connection) throws IOException { + // todo check file signature correctly +// InputStream is = connection.getInputStream(); +// int header = Algorithms.readTwoInt(is); +// boolean isGzipFile = header == Algorithms.GZIP_FILE_SIGNATURE; +// if (isGzipFile) { +// return new GZIPInputStream(connection.getInputStream()); +// } + return connection.getInputStream(); + } + public void saveEngine(@NonNull OnlineRoutingEngine engine) { deleteInaccessibleParameters(engine); String key = createEngineKeyIfNeeded(engine); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java index 9936f8efbf..494f3aa7a1 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; public class VehicleType { + private final String key; @StringRes private final int titleId; diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java index 431ad33a3d..41e10b1dd3 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -3,23 +3,35 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import net.osmand.plus.onlinerouting.parser.GpxParser; +import net.osmand.plus.onlinerouting.parser.GraphhopperParser; +import net.osmand.plus.onlinerouting.parser.OrsParser; +import net.osmand.plus.onlinerouting.parser.OsrmParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser; import net.osmand.util.Algorithms; public enum EngineType { - GRAPHHOPPER("Graphhopper"), - OSRM("OSRM"), - ORS("Openroute Service"); + GRAPHHOPPER("Graphhopper", GraphhopperParser.class), + OSRM("OSRM", OsrmParser.class), + ORS("Openroute Service", OrsParser.class), + GPX("GPX", GpxParser.class); private final String title; + private final Class parserClass; - EngineType(String title) { + EngineType(String title, Class parserClass) { this.title = title; + this.parserClass = parserClass; } public String getTitle() { return title; } + public Class getParserClass() { + return parserClass; + } + @NonNull public static EngineType getTypeByName(@Nullable String name) { if (!Algorithms.isEmpty(name)) { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java new file mode 100644 index 0000000000..557a98dc86 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -0,0 +1,57 @@ +package net.osmand.plus.onlinerouting.engine; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +import net.osmand.plus.onlinerouting.EngineParameter; +import net.osmand.plus.onlinerouting.VehicleType; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class GpxEngine extends OnlineRoutingEngine { + + public GpxEngine(@Nullable Map params) { + super(params); + } + + @NonNull + @Override + public EngineType getType() { + return EngineType.GPX; + } + + @Override + protected void makeFullUrl(@NonNull StringBuilder sb, + @NonNull List path) { + for (int i = 0; i < path.size(); i++) { + LatLon point = path.get(i); + sb.append(point.getLongitude()).append(',').append(point.getLatitude()); + if (i < path.size() - 1) { + sb.append(';'); + } + } + } + + @NonNull + @Override + public String getStandardUrl() { + return ""; // TODO will be determined in the future + } + + @Override + protected void collectAllowedVehicles(@NonNull List vehicles) { + + } + + @Override + protected void collectAllowedParameters(@NonNull Set params) { + params.add(EngineParameter.KEY); + params.add(EngineParameter.CUSTOM_NAME); + params.add(EngineParameter.NAME_INDEX); + params.add(EngineParameter.CUSTOM_URL); + } + +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java index 930ebcab8d..908973b6b4 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -3,23 +3,14 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import net.osmand.Location; import net.osmand.data.LatLon; -import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.VehicleType; -import net.osmand.plus.routing.RouteDirectionInfo; -import net.osmand.router.TurnType; -import net.osmand.util.GeoPolylineParserUtil; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; @@ -42,8 +33,13 @@ public class GraphhopperEngine extends OnlineRoutingEngine { } @Override - protected void collectAllowedParameters() { - allowParameters(EngineParameter.API_KEY); + protected void collectAllowedParameters(@NonNull Set params) { + params.add(EngineParameter.KEY); + params.add(EngineParameter.VEHICLE_KEY); + params.add(EngineParameter.CUSTOM_NAME); + params.add(EngineParameter.NAME_INDEX); + params.add(EngineParameter.CUSTOM_URL); + params.add(EngineParameter.API_KEY); } @Override @@ -81,146 +77,4 @@ public class GraphhopperEngine extends OnlineRoutingEngine { sb.append('&').append("details=").append("lanes"); } - @Nullable - @Override - public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { - String encoded = root.getString("points"); - List points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5); - if (isEmpty(points)) return null; - List route = convertRouteToLocationsList(points); - - JSONArray instructions = root.getJSONArray("instructions"); - List directions = new ArrayList<>(); - for (int i = 0; i < instructions.length(); i++) { - JSONObject instruction = instructions.getJSONObject(i); - int distance = (int) Math.round(instruction.getDouble("distance")); - String description = instruction.getString("text"); - String streetName = instruction.getString("street_name"); - int timeInSeconds = Math.round(instruction.getInt("time") / 1000f); - JSONArray interval = instruction.getJSONArray("interval"); - int startPointOffset = interval.getInt(0); - int endPointOffset = interval.getInt(1); - - float averageSpeed = (float) distance / timeInSeconds; - TurnType turnType = parseTurnType(instruction, leftSideNavigation); - RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType); - - direction.routePointOffset = startPointOffset; - direction.setDescriptionRoute(description); - direction.setStreetName(streetName); - direction.setDistance(distance); - directions.add(direction); - } - return new OnlineRoutingResponse(route, directions); - } - - @NonNull - private TurnType parseTurnType(@NonNull JSONObject instruction, - boolean leftSide) throws JSONException { - int sign = instruction.getInt("sign"); - TurnType turnType = identifyTurnType(sign, leftSide); - - if (turnType == null) { - turnType = TurnType.straight(); - } else if (turnType.isRoundAbout()) { - if (instruction.has("exit_number")) { - int exit = instruction.getInt("exit_number"); - turnType.setExitOut(exit); - } - if (instruction.has("turn_angle")) { - float angle = (float) instruction.getDouble("turn_angle"); - turnType.setTurnAngle(angle); - } - } else { - // TODO turnType.setTurnAngle() - } - - return turnType; - } - - @Nullable - public static TurnType identifyTurnType(int sign, boolean leftSide) { - Integer id = null; - - if (sign == -98) { - // an U-turn without the knowledge - // if it is a right or left U-turn - id = TurnType.TU; - - } else if (sign == -8) { - // a left U-turn - leftSide = false; - id = TurnType.TU; - - } else if (sign == -7) { - // keep left - id = TurnType.KL; - - } else if (sign == -6) { - // not yet used: leave roundabout - - } else if (sign == -3) { - // turn sharp left - id = TurnType.TSHL; - - } else if (sign == -2) { - // turn left - id = TurnType.TL; - - } else if (sign == -1) { - // turn slight left - id = TurnType.TSLL; - - } else if (sign == 0) { - // continue on street - id = TurnType.C; - - } else if (sign == 1) { - // turn slight right - id = TurnType.TSLR; - - } else if (sign == 2) { - // turn right - id = TurnType.TR; - - } else if (sign == 3) { - // turn sharp right - id = TurnType.TSHR; - - } else if (sign == 4) { - // the finish instruction before the last point - id = TurnType.C; - - } else if (sign == 5) { - // the instruction before a via point - - } else if (sign == 6) { - // the instruction before entering a roundabout - id = TurnType.RNDB; - - } else if (sign == 7) { - // keep right - id = TurnType.KR; - - } else if (sign == 8) { - // a right U-turn - id = TurnType.TRU; - } - - return id != null ? TurnType.valueOf(id, leftSide) : null; - } - - @NonNull - @Override - protected String getErrorMessageKey() { - return "message"; - } - - @NonNull - @Override - protected String getRootArrayKey() { - return "paths"; - } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index 0752282c70..119b63ee9c 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -7,22 +7,19 @@ import androidx.annotation.Nullable; import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; +import net.osmand.PlatformUtil; import net.osmand.data.LatLon; -import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.OnlineRoutingFactory; import net.osmand.plus.onlinerouting.VehicleType; -import net.osmand.plus.routing.RouteDirectionInfo; +import net.osmand.plus.onlinerouting.parser.ResponseParser; import net.osmand.plus.routing.RouteProvider; import net.osmand.util.Algorithms; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import org.apache.commons.logging.Log; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -34,19 +31,22 @@ import static net.osmand.util.Algorithms.isEmpty; public abstract class OnlineRoutingEngine implements Cloneable { + protected static final Log LOG = PlatformUtil.getLog(OnlineRoutingEngine.class); + public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_"; public final static VehicleType CUSTOM_VEHICLE = new VehicleType("", R.string.shared_string_custom); private final Map params = new HashMap<>(); private final List allowedVehicles = new ArrayList<>(); private final Set allowedParameters = new HashSet<>(); + private ResponseParser responseParser; public OnlineRoutingEngine(@Nullable Map params) { if (!isEmpty(params)) { this.params.putAll(params); } collectAllowedVehiclesInternal(); - collectAllowedParametersInternal(); + collectAllowedParameters(allowedParameters); } @NonNull @@ -100,31 +100,25 @@ public abstract class OnlineRoutingEngine implements Cloneable { @NonNull public abstract String getStandardUrl(); - public OnlineRoutingResponse parseServerResponse(@NonNull String content, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { - JSONObject root = parseRootResponseObject(content); - return root != null ? parseServerResponse(root, app, leftSideNavigation) : null; - } - - @Nullable - protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException; - - @Nullable - protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException { - JSONObject fullJSON = new JSONObject(content); - String responseArrayKey = getRootArrayKey(); - JSONArray array = null; - if (fullJSON.has(responseArrayKey)) { - array = fullJSON.getJSONArray(responseArrayKey); + @NonNull + public ResponseParser getResponseParser() { + if (responseParser == null) { + responseParser = createParser(); } - return array != null && array.length() > 0 ? array.getJSONObject(0) : null; + return responseParser; } @NonNull - protected abstract String getRootArrayKey(); + protected ResponseParser createParser() { + try { + return getType().getParserClass().newInstance(); + } catch (IllegalAccessException e) { + LOG.debug("Error when create parser: " + e.getMessage()); + } catch (InstantiationException e) { + LOG.debug("Error when create parser: " + e.getMessage()); + } + return ResponseParser.emptyParser(); + } @NonNull protected List convertRouteToLocationsList(@NonNull List route) { @@ -171,23 +165,12 @@ public abstract class OnlineRoutingEngine implements Cloneable { return Collections.unmodifiableList(allowedVehicles); } - private void collectAllowedParametersInternal() { - allowedParameters.clear(); - allowParameters(EngineParameter.KEY, EngineParameter.VEHICLE_KEY, - EngineParameter.CUSTOM_NAME, EngineParameter.NAME_INDEX, EngineParameter.CUSTOM_URL); - collectAllowedParameters(); - } - - protected abstract void collectAllowedParameters(); + protected abstract void collectAllowedParameters(@NonNull Set params); public boolean isParameterAllowed(EngineParameter key) { return allowedParameters.contains(key); } - protected void allowParameters(@NonNull EngineParameter... allowedParams) { - allowedParameters.addAll(Arrays.asList(allowedParams)); - } - @Nullable private String getSelectedVehicleName(@NonNull Context ctx) { String key = get(EngineParameter.VEHICLE_KEY); @@ -216,20 +199,6 @@ public abstract class OnlineRoutingEngine implements Cloneable { return CUSTOM_VEHICLE; } - public boolean checkServerResponse(@NonNull StringBuilder errorMessage, - @NonNull String content) throws JSONException { - JSONObject obj = new JSONObject(content); - String messageKey = getErrorMessageKey(); - if (obj.has(messageKey)) { - String message = obj.getString(messageKey); - errorMessage.append(message); - } - return obj.has(getRootArrayKey()); - } - - @NonNull - protected abstract String getErrorMessageKey(); - @NonNull @Override public Object clone() { @@ -251,21 +220,4 @@ public abstract class OnlineRoutingEngine implements Cloneable { return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis(); } - public static class OnlineRoutingResponse { - private List route; - private List directions; - - public OnlineRoutingResponse(List route, List directions) { - this.route = route; - this.directions = directions; - } - - public List getRoute() { - return route; - } - - public List getDirections() { - return directions; - } - } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java index ed9168ccf9..61f3097b04 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -3,20 +3,14 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import net.osmand.Location; import net.osmand.data.LatLon; -import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.VehicleType; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; @@ -39,8 +33,13 @@ public class OrsEngine extends OnlineRoutingEngine { } @Override - protected void collectAllowedParameters() { - allowParameters(EngineParameter.API_KEY); + protected void collectAllowedParameters(@NonNull Set params) { + params.add(EngineParameter.KEY); + params.add(EngineParameter.VEHICLE_KEY); + params.add(EngineParameter.CUSTOM_NAME); + params.add(EngineParameter.NAME_INDEX); + params.add(EngineParameter.CUSTOM_URL); + params.add(EngineParameter.API_KEY); } @Override @@ -78,35 +77,4 @@ public class OrsEngine extends OnlineRoutingEngine { } } - @Nullable - @Override - public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { - JSONArray array = root.getJSONObject("geometry").getJSONArray("coordinates"); - List points = new ArrayList<>(); - for (int i = 0; i < array.length(); i++) { - JSONArray point = array.getJSONArray(i); - double lon = Double.parseDouble(point.getString(0)); - double lat = Double.parseDouble(point.getString(1)); - points.add(new LatLon(lat, lon)); - } - if (!isEmpty(points)) { - List route = convertRouteToLocationsList(points); - new OnlineRoutingResponse(route, null); - } - return null; - } - - @NonNull - @Override - protected String getErrorMessageKey() { - return "error"; - } - - @NonNull - @Override - protected String getRootArrayKey() { - return "features"; - } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java index 4d75b2b440..1da2ed215e 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -3,28 +3,16 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import net.osmand.Location; import net.osmand.data.LatLon; -import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.VehicleType; -import net.osmand.plus.routing.RouteCalculationResult; -import net.osmand.plus.routing.RouteDirectionInfo; -import net.osmand.router.TurnType; -import net.osmand.util.GeoPolylineParserUtil; -import net.osmand.util.MapUtils; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; -import static net.osmand.util.Algorithms.objectEquals; public class OsrmEngine extends OnlineRoutingEngine { @@ -45,7 +33,12 @@ public class OsrmEngine extends OnlineRoutingEngine { } @Override - protected void collectAllowedParameters() { + protected void collectAllowedParameters(@NonNull Set params) { + params.add(EngineParameter.KEY); + params.add(EngineParameter.VEHICLE_KEY); + params.add(EngineParameter.CUSTOM_NAME); + params.add(EngineParameter.NAME_INDEX); + params.add(EngineParameter.CUSTOM_URL); } @Override @@ -74,164 +67,4 @@ public class OsrmEngine extends OnlineRoutingEngine { sb.append('&').append("steps=true"); } - @Nullable - @Override - public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { - String encodedPoints = root.getString("geometry"); - List points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5); - if (isEmpty(points)) return null; - - List route = convertRouteToLocationsList(points); - List directions = new ArrayList<>(); - int startSearchingId = 0; - JSONArray legs = root.getJSONArray("legs"); - for (int i = 0; i < legs.length(); i++) { - JSONObject leg = legs.getJSONObject(i); - if (!leg.has("steps")) continue; - - JSONArray steps = leg.getJSONArray("steps"); - for (int j = 0; j < steps.length(); j++) { - JSONObject instruction = steps.getJSONObject(j); - JSONObject maneuver = instruction.getJSONObject("maneuver"); - String maneuverType = maneuver.getString("type"); - - JSONArray location = maneuver.getJSONArray("location"); - double lon = location.getDouble(0); - double lat = location.getDouble(1); - Integer routePointOffset = getLocationIndexInList(route, startSearchingId, lat, lon); - if (routePointOffset == null) continue; - startSearchingId = routePointOffset; - - // in meters - int distance = (int) Math.round(instruction.getDouble("distance")); - // in seconds - int duration = (int) Math.round(instruction.getDouble("duration")); - - float averageSpeed = (float) distance / duration; - TurnType turnType = parseTurnType(maneuver, leftSideNavigation); - RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType); - direction.setDistance(distance); - - String streetName = instruction.getString("name"); - String description = ""; - if (!objectEquals(maneuverType, "arrive")) { - description = RouteCalculationResult.toString(turnType, app, false) + " " + streetName; - } - description = description.trim(); - - direction.setStreetName(streetName); - direction.setDescriptionRoute(description); - direction.routePointOffset = routePointOffset; - directions.add(direction); - } - } - - return new OnlineRoutingResponse(route, directions); - } - - @Nullable - private Integer getLocationIndexInList(@NonNull List locations, - int startIndex, double lat, double lon) { - for (int i = startIndex; i < locations.size(); i++) { - Location l = locations.get(i); - if (MapUtils.areLatLonEqual(l, lat, lon)) { - return i; - } - } - return null; - } - - @NonNull - private TurnType parseTurnType(@NonNull JSONObject maneuver, - boolean leftSide) throws JSONException { - TurnType turnType = null; - - String type = maneuver.getString("type"); - String modifier = null; - if (maneuver.has("modifier")) { - modifier = maneuver.getString("modifier"); - } - - if (objectEquals(type, "roundabout") - || objectEquals(type, "rotary") - || objectEquals(type, "roundabout turn")) { - if (maneuver.has("exit")) { - int exit = maneuver.getInt("exit"); - turnType = TurnType.getExitTurn(exit, 0.0f, leftSide); - } else if (modifier != null) { - // for simple roundabout turn without "exit" parameter - turnType = identifyTurnType(modifier, leftSide); - } - } else { - // for other maneuver types find TurnType - // like a basic turn into direction of the modifier - if (modifier != null) { - turnType = identifyTurnType(modifier, leftSide); - } - } - if (turnType == null) { - turnType = TurnType.straight(); - } - - int bearingBefore = maneuver.getInt("bearing_before"); - int bearingAfter = maneuver.getInt("bearing_after"); - float angle = (float) MapUtils.degreesDiff(bearingAfter, bearingBefore); - turnType.setTurnAngle(angle); - - return turnType; - } - - @Nullable - private TurnType identifyTurnType(@NonNull String modifier, - boolean leftSide) { - Integer id = null; - switch (modifier) { - case "uturn": - id = TurnType.TU; - break; - - case "sharp right": - id = TurnType.TSHR; - break; - - case "right": - id = TurnType.TR; - break; - - case "slight right": - id = TurnType.TSLR; - break; - - case "straight": - id = TurnType.C; - break; - - case "slight left": - id = TurnType.TSLL; - break; - - case "left": - id = TurnType.TL; - break; - - case "sharp left": - id = TurnType.TSHL; - break; - } - return id != null ? TurnType.valueOf(id, leftSide) : null; - } - - @NonNull - @Override - protected String getErrorMessageKey() { - return "message"; - } - - @NonNull - @Override - protected String getRootArrayKey() { - return "routes"; - } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java new file mode 100644 index 0000000000..8f5db5fde7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java @@ -0,0 +1,42 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.GPXUtilities; +import net.osmand.GPXUtilities.GPXFile; +import net.osmand.plus.OsmandApplication; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +public class GpxParser extends ResponseParser { + + @Override + @Nullable + public OnlineRoutingResponse parseResponse(@NonNull String content, + @NonNull OsmandApplication app, + boolean leftSideNavigation) { + GPXFile gpxFile = parseGpx(content); + return gpxFile != null ? new OnlineRoutingResponse(parseGpx(content)) : null; + } + + @Override + public boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) { + return parseGpx(content) != null; // TODO may be there should be another check + } + + private GPXFile parseGpx(@NonNull String content) { + InputStream gpxStream = null; + try { + gpxStream = new ByteArrayInputStream(content.getBytes("UTF-8")); + return GPXUtilities.loadGPXFile(gpxStream); + } catch (UnsupportedEncodingException e) { + LOG.debug("Error when parsing GPX from server response: " + e.getMessage()); + } + return null; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java new file mode 100644 index 0000000000..331221ad09 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java @@ -0,0 +1,165 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.routing.RouteDirectionInfo; +import net.osmand.router.TurnType; +import net.osmand.util.GeoPolylineParserUtil; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.util.Algorithms.isEmpty; + +public class GraphhopperParser extends JSONParser { + + @Nullable + protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException { + String encoded = root.getString("points"); + List points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5); + if (isEmpty(points)) return null; + List route = convertRouteToLocationsList(points); + + JSONArray instructions = root.getJSONArray("instructions"); + List directions = new ArrayList<>(); + for (int i = 0; i < instructions.length(); i++) { + JSONObject instruction = instructions.getJSONObject(i); + int distance = (int) Math.round(instruction.getDouble("distance")); + String description = instruction.getString("text"); + String streetName = instruction.getString("street_name"); + int timeInSeconds = Math.round(instruction.getInt("time") / 1000f); + JSONArray interval = instruction.getJSONArray("interval"); + int startPointOffset = interval.getInt(0); + int endPointOffset = interval.getInt(1); + + float averageSpeed = (float) distance / timeInSeconds; + TurnType turnType = parseTurnType(instruction, leftSideNavigation); + RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType); + + direction.routePointOffset = startPointOffset; + direction.setDescriptionRoute(description); + direction.setStreetName(streetName); + direction.setDistance(distance); + directions.add(direction); + } + return new OnlineRoutingResponse(route, directions); + } + + @NonNull + private TurnType parseTurnType(@NonNull JSONObject instruction, + boolean leftSide) throws JSONException { + int sign = instruction.getInt("sign"); + TurnType turnType = identifyTurnType(sign, leftSide); + + if (turnType == null) { + turnType = TurnType.straight(); + } else if (turnType.isRoundAbout()) { + if (instruction.has("exit_number")) { + int exit = instruction.getInt("exit_number"); + turnType.setExitOut(exit); + } + if (instruction.has("turn_angle")) { + float angle = (float) instruction.getDouble("turn_angle"); + turnType.setTurnAngle(angle); + } + } else { + // TODO turnType.setTurnAngle() + } + + return turnType; + } + + @Nullable + public static TurnType identifyTurnType(int sign, boolean leftSide) { + Integer id = null; + + if (sign == -98) { + // an U-turn without the knowledge + // if it is a right or left U-turn + id = TurnType.TU; + + } else if (sign == -8) { + // a left U-turn + leftSide = false; + id = TurnType.TU; + + } else if (sign == -7) { + // keep left + id = TurnType.KL; + + } else if (sign == -6) { + // not yet used: leave roundabout + + } else if (sign == -3) { + // turn sharp left + id = TurnType.TSHL; + + } else if (sign == -2) { + // turn left + id = TurnType.TL; + + } else if (sign == -1) { + // turn slight left + id = TurnType.TSLL; + + } else if (sign == 0) { + // continue on street + id = TurnType.C; + + } else if (sign == 1) { + // turn slight right + id = TurnType.TSLR; + + } else if (sign == 2) { + // turn right + id = TurnType.TR; + + } else if (sign == 3) { + // turn sharp right + id = TurnType.TSHR; + + } else if (sign == 4) { + // the finish instruction before the last point + id = TurnType.C; + + } else if (sign == 5) { + // the instruction before a via point + + } else if (sign == 6) { + // the instruction before entering a roundabout + id = TurnType.RNDB; + + } else if (sign == 7) { + // keep right + id = TurnType.KR; + + } else if (sign == 8) { + // a right U-turn + id = TurnType.TRU; + } + + return id != null ? TurnType.valueOf(id, leftSide) : null; + } + + @NonNull + @Override + protected String getErrorMessageKey() { + return "message"; + } + + @NonNull + @Override + protected String getRootArrayKey() { + return "paths"; + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java new file mode 100644 index 0000000000..b01af0c444 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java @@ -0,0 +1,77 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.GPXUtilities.WptPt; +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.routing.RouteProvider; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.util.Algorithms.isEmpty; + +public abstract class JSONParser extends ResponseParser { + + @Nullable + public OnlineRoutingResponse parseResponse(@NonNull String content, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException { + JSONObject root = parseRootResponseObject(content); + return root != null ? parseServerResponse(root, app, leftSideNavigation) : null; + } + + @Nullable + protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException { + JSONObject fullJSON = new JSONObject(content); + String key = getRootArrayKey(); + JSONArray array = null; + if (fullJSON.has(key)) { + array = fullJSON.getJSONArray(key); + } + return array != null && array.length() > 0 ? array.getJSONObject(0) : null; + } + + public boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + String messageKey = getErrorMessageKey(); + if (obj.has(messageKey)) { + String message = obj.getString(messageKey); + errorMessage.append(message); + } + return obj.has(getRootArrayKey()); + } + + @NonNull + protected List convertRouteToLocationsList(@NonNull List route) { + List result = new ArrayList<>(); + if (!isEmpty(route)) { + for (LatLon pt : route) { + WptPt wpt = new WptPt(); + wpt.lat = pt.getLatitude(); + wpt.lon = pt.getLongitude(); + result.add(RouteProvider.createLocation(wpt)); + } + } + return result; + } + + @Nullable + protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException; + + @NonNull + protected abstract String getRootArrayKey(); + + @NonNull + protected abstract String getErrorMessageKey(); +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java new file mode 100644 index 0000000000..f067baf61e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java @@ -0,0 +1,52 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.util.Algorithms.isEmpty; + +public class OrsParser extends JSONParser { + + @Nullable + @Override + public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException { + JSONArray array = root.getJSONObject("geometry").getJSONArray("coordinates"); + List points = new ArrayList<>(); + for (int i = 0; i < array.length(); i++) { + JSONArray point = array.getJSONArray(i); + double lon = Double.parseDouble(point.getString(0)); + double lat = Double.parseDouble(point.getString(1)); + points.add(new LatLon(lat, lon)); + } + if (!isEmpty(points)) { + List route = convertRouteToLocationsList(points); + new OnlineRoutingResponse(route, null); + } + return null; + } + + @NonNull + @Override + protected String getErrorMessageKey() { + return "error"; + } + + @NonNull + @Override + protected String getRootArrayKey() { + return "features"; + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java new file mode 100644 index 0000000000..8c93f1750e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java @@ -0,0 +1,187 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.routing.RouteCalculationResult; +import net.osmand.plus.routing.RouteDirectionInfo; +import net.osmand.router.TurnType; +import net.osmand.util.GeoPolylineParserUtil; +import net.osmand.util.MapUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.util.Algorithms.isEmpty; +import static net.osmand.util.Algorithms.objectEquals; + +public class OsrmParser extends JSONParser { + + @Nullable + @Override + protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException { + String encodedPoints = root.getString("geometry"); + List points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5); + if (isEmpty(points)) return null; + + List route = convertRouteToLocationsList(points); + List directions = new ArrayList<>(); + int startSearchingId = 0; + JSONArray legs = root.getJSONArray("legs"); + for (int i = 0; i < legs.length(); i++) { + JSONObject leg = legs.getJSONObject(i); + if (!leg.has("steps")) continue; + + JSONArray steps = leg.getJSONArray("steps"); + for (int j = 0; j < steps.length(); j++) { + JSONObject instruction = steps.getJSONObject(j); + JSONObject maneuver = instruction.getJSONObject("maneuver"); + String maneuverType = maneuver.getString("type"); + + JSONArray location = maneuver.getJSONArray("location"); + double lon = location.getDouble(0); + double lat = location.getDouble(1); + Integer routePointOffset = getLocationIndexInList(route, startSearchingId, lat, lon); + if (routePointOffset == null) continue; + startSearchingId = routePointOffset; + + // in meters + int distance = (int) Math.round(instruction.getDouble("distance")); + // in seconds + int duration = (int) Math.round(instruction.getDouble("duration")); + + float averageSpeed = (float) distance / duration; + TurnType turnType = parseTurnType(maneuver, leftSideNavigation); + RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType); + direction.setDistance(distance); + + String streetName = instruction.getString("name"); + String description = ""; + if (!objectEquals(maneuverType, "arrive")) { + description = RouteCalculationResult.toString(turnType, app, false) + " " + streetName; + } + description = description.trim(); + + direction.setStreetName(streetName); + direction.setDescriptionRoute(description); + direction.routePointOffset = routePointOffset; + directions.add(direction); + } + } + + return new OnlineRoutingResponse(route, directions); + } + + @Nullable + private Integer getLocationIndexInList(@NonNull List locations, + int startIndex, double lat, double lon) { + for (int i = startIndex; i < locations.size(); i++) { + Location l = locations.get(i); + if (MapUtils.areLatLonEqual(l, lat, lon)) { + return i; + } + } + return null; + } + + @NonNull + private TurnType parseTurnType(@NonNull JSONObject maneuver, + boolean leftSide) throws JSONException { + TurnType turnType = null; + + String type = maneuver.getString("type"); + String modifier = null; + if (maneuver.has("modifier")) { + modifier = maneuver.getString("modifier"); + } + + if (objectEquals(type, "roundabout") + || objectEquals(type, "rotary") + || objectEquals(type, "roundabout turn")) { + if (maneuver.has("exit")) { + int exit = maneuver.getInt("exit"); + turnType = TurnType.getExitTurn(exit, 0.0f, leftSide); + } else if (modifier != null) { + // for simple roundabout turn without "exit" parameter + turnType = identifyTurnType(modifier, leftSide); + } + } else { + // for other maneuver types find TurnType + // like a basic turn into direction of the modifier + if (modifier != null) { + turnType = identifyTurnType(modifier, leftSide); + } + } + if (turnType == null) { + turnType = TurnType.straight(); + } + + int bearingBefore = maneuver.getInt("bearing_before"); + int bearingAfter = maneuver.getInt("bearing_after"); + float angle = (float) MapUtils.degreesDiff(bearingAfter, bearingBefore); + turnType.setTurnAngle(angle); + + return turnType; + } + + @Nullable + private TurnType identifyTurnType(@NonNull String modifier, + boolean leftSide) { + Integer id = null; + switch (modifier) { + case "uturn": + id = TurnType.TU; + break; + + case "sharp right": + id = TurnType.TSHR; + break; + + case "right": + id = TurnType.TR; + break; + + case "slight right": + id = TurnType.TSLR; + break; + + case "straight": + id = TurnType.C; + break; + + case "slight left": + id = TurnType.TSLL; + break; + + case "left": + id = TurnType.TL; + break; + + case "sharp left": + id = TurnType.TSHL; + break; + } + return id != null ? TurnType.valueOf(id, leftSide) : null; + } + + @NonNull + @Override + protected String getRootArrayKey() { + return "routes"; + } + + @NonNull + @Override + protected String getErrorMessageKey() { + return "message"; + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java new file mode 100644 index 0000000000..62cf7e0f44 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java @@ -0,0 +1,77 @@ +package net.osmand.plus.onlinerouting.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.GPXUtilities.GPXFile; +import net.osmand.Location; +import net.osmand.PlatformUtil; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.routing.RouteDirectionInfo; + +import org.apache.commons.logging.Log; +import org.json.JSONException; + +import java.util.List; + +public abstract class ResponseParser { + + protected static final Log LOG = PlatformUtil.getLog(ResponseParser.class); + + @Nullable + public abstract OnlineRoutingResponse parseResponse(@NonNull String content, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException; + + public abstract boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) throws JSONException; + + public static ResponseParser emptyParser() { + return new ResponseParser() { + @Nullable + @Override + public OnlineRoutingResponse parseResponse(@NonNull String content, + @NonNull OsmandApplication app, + boolean leftSideNavigation) { + return null; + } + + @Override + public boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) { + return false; + } + }; + } + + public static class OnlineRoutingResponse { + + private List route; + private List directions; + private GPXFile gpxFile; + + // constructor for JSON responses + public OnlineRoutingResponse(List route, List directions) { + this.route = route; + this.directions = directions; + } + + // constructor for GPX responses + public OnlineRoutingResponse(GPXFile gpxFile) { + this.gpxFile = gpxFile; + } + + public List getRoute() { + return route; + } + + public List getDirections() { + return directions; + } + + public GPXFile getGpxFile() { + return gpxFile; + } + } + +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java index 008bb75852..4f626569d7 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java @@ -462,7 +462,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { boolean resultOk = false; try { String response = helper.makeRequest(exampleCard.getEditedText()); - resultOk = requestedEngine.checkServerResponse(errorMessage, response); + resultOk = requestedEngine.getResponseParser().isResultOk(errorMessage, response); } catch (IOException | JSONException e) { errorMessage.append(e.toString()); } @@ -514,6 +514,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } else { apiKeyCard.hide(); } + if (engine.isParameterAllowed(EngineParameter.VEHICLE_KEY)) { + vehicleCard.show(); + } else { + + vehicleCard.hide(); + } } else if (vehicleCard.equals(card)) { VehicleType vt = engine.getSelectedVehicleType(); diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 3f0a30c99f..0eb5a74e52 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -23,7 +23,7 @@ import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.onlinerouting.OnlineRoutingHelper; -import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; +import net.osmand.plus.onlinerouting.parser.ResponseParser.OnlineRoutingResponse; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.CommonPreference; @@ -1228,16 +1228,28 @@ public class RouteProvider { } private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException { - OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper(); - String stringKey = params.mode.getRoutingProfile(); + OsmandApplication app = params.ctx; + OnlineRoutingHelper helper = app.getOnlineRoutingHelper(); + OsmandSettings settings = app.getSettings(); + String engineKey = params.mode.getRoutingProfile(); OnlineRoutingResponse response = - helper.calculateRouteOnline(stringKey, getPathFromParams(params), params.leftSide); + helper.calculateRouteOnline(engineKey, getPathFromParams(params), params.leftSide); + if (response != null) { - params.intermediates = null; - return new RouteCalculationResult(response.getRoute(), response.getDirections(), params, null, false); - } else { - return new RouteCalculationResult("Route is empty"); + if (response.getGpxFile() != null) { + GPXRouteParamsBuilder builder = new GPXRouteParamsBuilder(response.getGpxFile(), settings); + params.gpxRoute = builder.build(app); + return calculateGpxRoute(params); + } + List route = response.getRoute(); + List directions = response.getDirections(); + if (!Algorithms.isEmpty(route) && !Algorithms.isEmpty(directions)) { + params.intermediates = null; + return new RouteCalculationResult(route, directions, params, null, false); + } } + + return new RouteCalculationResult("Route is empty"); } private static List getPathFromParams(RouteCalculationParams params) {