From 584e7dbf6d7ab00a42e3366a68599e7de263569b Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sun, 21 Feb 2021 13:44:22 +0200 Subject: [PATCH 1/6] 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) { From e44f7634059159839181985319b516ced966f105 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 22 Feb 2021 13:14:10 +0200 Subject: [PATCH 2/6] Check ZIP and GZIP formats --- .../main/java/net/osmand/util/Algorithms.java | 30 +++++++++++++++++++ .../onlinerouting/OnlineRoutingHelper.java | 21 ++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) 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 247fc30ced..8954e2d61b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -324,6 +324,24 @@ public class Algorithms { return test == ZIP_FILE_SIGNATURE; } + public static boolean checkFileSignature(InputStream inputStream, int fileSignature) throws IOException { + if (inputStream == null) return false; + int firstBytes; + if (isSmallFileSignature(fileSignature)) { + firstBytes = readSmallInt(inputStream); + } else { + firstBytes = readInt(inputStream); + } + if (inputStream.markSupported()) { + inputStream.reset(); + } + return firstBytes == fileSignature; + } + + public static boolean isSmallFileSignature(int fileSignature) { + return fileSignature == BZIP_FILE_SIGNATURE || fileSignature == GZIP_FILE_SIGNATURE; + } + /** * Checks, whether the child directory is a subdirectory of the parent * directory. @@ -547,6 +565,18 @@ public class Algorithms { } } + public static ByteArrayInputStream createByteArrayIS(InputStream inputStream) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int i = 0; + while ((i = inputStream.read()) != -1) { + outputStream.write(i); + } + inputStream.close(); + + byte[] byteArray = outputStream.toByteArray(); + return new ByteArrayInputStream(byteArray); + } + @SuppressWarnings("ResultOfMethodCallIgnored") public static void updateAllExistingImgTilesToOsmandFormat(File f) { if (f.isDirectory()) { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java index 079cfd8a12..503977c7b7 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java @@ -19,6 +19,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -28,7 +29,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.zip.GZIPInputStream; +import java.util.zip.ZipInputStream; +import static net.osmand.util.Algorithms.GZIP_FILE_SIGNATURE; +import static net.osmand.util.Algorithms.ZIP_FILE_SIGNATURE; import static net.osmand.util.Algorithms.isEmpty; public class OnlineRoutingHelper { @@ -118,14 +122,15 @@ public class OnlineRoutingHelper { } 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(); + ByteArrayInputStream localIS = Algorithms.createByteArrayIS(connection.getInputStream()); + if (Algorithms.checkFileSignature(localIS, ZIP_FILE_SIGNATURE)) { + ZipInputStream zipIS = new ZipInputStream(localIS); + zipIS.getNextEntry(); // set position to reading for the first item + return zipIS; + } else if (Algorithms.checkFileSignature(localIS, GZIP_FILE_SIGNATURE)) { + return new GZIPInputStream(localIS); + } + return localIS; } public void saveEngine(@NonNull OnlineRoutingEngine engine) { From fab1df33a6561a2ff52e9d9e6dc7314a0d57f4bf Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 22 Feb 2021 13:44:49 +0200 Subject: [PATCH 3/6] Refactoring: change parser location, remove todo --- .../plus/onlinerouting/engine/EngineType.java | 21 +- .../plus/onlinerouting/engine/GpxEngine.java | 9 +- .../engine/GraphhopperEngine.java | 162 +++++++++++++++ .../engine/OnlineRoutingEngine.java | 28 +-- .../plus/onlinerouting/engine/OrsEngine.java | 49 +++++ .../plus/onlinerouting/engine/OsrmEngine.java | 184 +++++++++++++++++ .../plus/onlinerouting/parser/GpxParser.java | 2 +- .../parser/GraphhopperParser.java | 165 ---------------- .../plus/onlinerouting/parser/JSONParser.java | 24 +-- .../plus/onlinerouting/parser/OrsParser.java | 52 ----- .../plus/onlinerouting/parser/OsrmParser.java | 187 ------------------ 11 files changed, 422 insertions(+), 461 deletions(-) delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java index 41e10b1dd3..0efd91e759 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -3,35 +3,24 @@ 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", GraphhopperParser.class), - OSRM("OSRM", OsrmParser.class), - ORS("Openroute Service", OrsParser.class), - GPX("GPX", GpxParser.class); + GRAPHHOPPER("Graphhopper"), + OSRM("OSRM"), + ORS("Openroute Service"), + GPX("GPX"); private final String title; - private final Class parserClass; - EngineType(String title, Class parserClass) { + EngineType(String title) { 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 index 557a98dc86..1f6146273d 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -6,6 +6,8 @@ import androidx.annotation.Nullable; import net.osmand.data.LatLon; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.VehicleType; +import net.osmand.plus.onlinerouting.parser.GpxParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser; import java.util.List; import java.util.Map; @@ -38,7 +40,7 @@ public class GpxEngine extends OnlineRoutingEngine { @NonNull @Override public String getStandardUrl() { - return ""; // TODO will be determined in the future + return ""; } @Override @@ -54,4 +56,9 @@ public class GpxEngine extends OnlineRoutingEngine { params.add(EngineParameter.CUSTOM_URL); } + @NonNull + @Override + protected ResponseParser createParser() { + return new GpxParser(); + } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java index 908973b6b4..14852e2633 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -3,11 +3,23 @@ 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.onlinerouting.parser.JSONParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser; +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; @@ -55,6 +67,12 @@ public class GraphhopperEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("small_truck", R.string.routing_engine_vehicle_type_small_truck)); } + @NonNull + @Override + protected ResponseParser createParser() { + return new GraphhopperParser(); + } + @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -77,4 +95,148 @@ public class GraphhopperEngine extends OnlineRoutingEngine { sb.append('&').append("details=").append("lanes"); } + private static 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/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index 119b63ee9c..b2bba21ca6 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -5,8 +5,6 @@ import android.content.Context; import androidx.annotation.NonNull; 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.R; @@ -14,7 +12,6 @@ import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.OnlineRoutingFactory; import net.osmand.plus.onlinerouting.VehicleType; import net.osmand.plus.onlinerouting.parser.ResponseParser; -import net.osmand.plus.routing.RouteProvider; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -109,30 +106,7 @@ public abstract class OnlineRoutingEngine implements Cloneable { } @NonNull - 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) { - 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; - } + protected abstract ResponseParser createParser(); @NonNull public Map getParams() { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java index 61f3097b04..d80d3df3c1 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -3,11 +3,20 @@ 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.onlinerouting.parser.JSONParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser; +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; @@ -55,6 +64,12 @@ public class OrsEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("wheelchair", R.string.routing_engine_vehicle_type_wheelchair)); } + @NonNull + @Override + protected ResponseParser createParser() { + return new OrsParser(); + } + @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -77,4 +92,38 @@ public class OrsEngine extends OnlineRoutingEngine { } } + private static 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/engine/OsrmEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java index 1da2ed215e..19860ee15c 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -3,16 +3,31 @@ 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.onlinerouting.parser.JSONParser; +import net.osmand.plus.onlinerouting.parser.ResponseParser; +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 { @@ -48,6 +63,12 @@ public class OsrmEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("foot", R.string.routing_engine_vehicle_type_foot)); } + @NonNull + @Override + protected ResponseParser createParser() { + return new OsrmParser(); + } + @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -67,4 +88,167 @@ public class OsrmEngine extends OnlineRoutingEngine { sb.append('&').append("steps=true"); } + private static 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/GpxParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java index 8f5db5fde7..92621b2b3f 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java @@ -25,7 +25,7 @@ public class GpxParser extends ResponseParser { @Override public boolean isResultOk(@NonNull StringBuilder errorMessage, @NonNull String content) { - return parseGpx(content) != null; // TODO may be there should be another check + return parseGpx(content) != null; } private GPXFile parseGpx(@NonNull String content) { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java deleted file mode 100644 index 331221ad09..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java +++ /dev/null @@ -1,165 +0,0 @@ -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 index b01af0c444..e0676f68c2 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java @@ -50,8 +50,19 @@ public abstract class JSONParser extends ResponseParser { return obj.has(getRootArrayKey()); } + @Nullable + protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException; + @NonNull - protected List convertRouteToLocationsList(@NonNull List route) { + protected abstract String getRootArrayKey(); + + @NonNull + protected abstract String getErrorMessageKey(); + + @NonNull + protected static List convertRouteToLocationsList(@NonNull List route) { List result = new ArrayList<>(); if (!isEmpty(route)) { for (LatLon pt : route) { @@ -63,15 +74,4 @@ public abstract class JSONParser extends ResponseParser { } 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 deleted file mode 100644 index f067baf61e..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index 8c93f1750e..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java +++ /dev/null @@ -1,187 +0,0 @@ -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"; - } -} From 1be6bc7eea2ebb7e86996fbaac9b4674061e0d58 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 22 Feb 2021 17:04:38 +0200 Subject: [PATCH 4/6] Refactoring: inheritance instead of composition --- .../onlinerouting/OnlineRoutingHelper.java | 6 +- .../plus/onlinerouting/engine/GpxEngine.java | 34 +- .../engine/GraphhopperEngine.java | 286 ++++++++-------- .../JsonOnlineRoutingEngine.java} | 9 +- .../engine/OnlineRoutingEngine.java | 52 ++- .../plus/onlinerouting/engine/OrsEngine.java | 70 ++-- .../plus/onlinerouting/engine/OsrmEngine.java | 312 +++++++++--------- .../plus/onlinerouting/parser/GpxParser.java | 42 --- .../onlinerouting/parser/ResponseParser.java | 77 ----- .../ui/OnlineRoutingEngineFragment.java | 2 +- .../osmand/plus/routing/RouteProvider.java | 2 +- 11 files changed, 400 insertions(+), 492 deletions(-) rename OsmAnd/src/net/osmand/plus/onlinerouting/{parser/JSONParser.java => engine/JsonOnlineRoutingEngine.java} (90%) delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java index 503977c7b7..9ae8f5cb02 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java @@ -9,8 +9,7 @@ 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.parser.ResponseParser; -import net.osmand.plus.onlinerouting.parser.ResponseParser.OnlineRoutingResponse; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; @@ -95,8 +94,7 @@ public class OnlineRoutingHelper { boolean leftSideNavigation) throws IOException, JSONException { String url = engine.getFullUrl(path); String content = makeRequest(url); - ResponseParser parser = engine.getResponseParser(); - return parser.parseResponse(content, app, leftSideNavigation); + return engine.parseResponse(content, app, leftSideNavigation); } @NonNull diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java index 1f6146273d..676ea6ba48 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -3,12 +3,16 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import net.osmand.GPXUtilities; +import net.osmand.GPXUtilities.GPXFile; import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.onlinerouting.EngineParameter; import net.osmand.plus.onlinerouting.VehicleType; -import net.osmand.plus.onlinerouting.parser.GpxParser; -import net.osmand.plus.onlinerouting.parser.ResponseParser; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.List; import java.util.Map; import java.util.Set; @@ -56,9 +60,29 @@ public class GpxEngine extends OnlineRoutingEngine { params.add(EngineParameter.CUSTOM_URL); } - @NonNull @Override - protected ResponseParser createParser() { - return new GpxParser(); + @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; + } + + 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/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java index 14852e2633..68122b3bdd 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -9,8 +9,6 @@ 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.onlinerouting.parser.JSONParser; -import net.osmand.plus.onlinerouting.parser.ResponseParser; import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.router.TurnType; import net.osmand.util.GeoPolylineParserUtil; @@ -26,7 +24,7 @@ import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; -public class GraphhopperEngine extends OnlineRoutingEngine { +public class GraphhopperEngine extends JsonOnlineRoutingEngine { public GraphhopperEngine(@Nullable Map params) { super(params); @@ -67,12 +65,6 @@ public class GraphhopperEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("small_truck", R.string.routing_engine_vehicle_type_small_truck)); } - @NonNull - @Override - protected ResponseParser createParser() { - return new GraphhopperParser(); - } - @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -95,148 +87,146 @@ public class GraphhopperEngine extends OnlineRoutingEngine { sb.append('&').append("details=").append("lanes"); } - private static 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); - @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); - 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); - 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"; + 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/engine/JsonOnlineRoutingEngine.java similarity index 90% rename from OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java rename to OsmAnd/src/net/osmand/plus/onlinerouting/engine/JsonOnlineRoutingEngine.java index e0676f68c2..dcd191da19 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/JsonOnlineRoutingEngine.java @@ -1,4 +1,4 @@ -package net.osmand.plus.onlinerouting.parser; +package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -15,10 +15,15 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.List; +import java.util.Map; import static net.osmand.util.Algorithms.isEmpty; -public abstract class JSONParser extends ResponseParser { +public abstract class JsonOnlineRoutingEngine extends OnlineRoutingEngine { + + public JsonOnlineRoutingEngine(@Nullable Map params) { + super(params); + } @Nullable public OnlineRoutingResponse parseResponse(@NonNull String content, diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index b2bba21ca6..85514dec85 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -5,16 +5,20 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import net.osmand.GPXUtilities.GPXFile; +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.onlinerouting.parser.ResponseParser; +import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; +import org.json.JSONException; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +40,6 @@ public abstract class OnlineRoutingEngine implements Cloneable { 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)) { @@ -97,16 +100,13 @@ public abstract class OnlineRoutingEngine implements Cloneable { @NonNull public abstract String getStandardUrl(); - @NonNull - public ResponseParser getResponseParser() { - if (responseParser == null) { - responseParser = createParser(); - } - return responseParser; - } + @Nullable + public abstract OnlineRoutingResponse parseResponse(@NonNull String content, + @NonNull OsmandApplication app, + boolean leftSideNavigation) throws JSONException; - @NonNull - protected abstract ResponseParser createParser(); + public abstract boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) throws JSONException; @NonNull public Map getParams() { @@ -194,4 +194,34 @@ public abstract class OnlineRoutingEngine implements Cloneable { return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis(); } + 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/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java index d80d3df3c1..9a16be62ee 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -9,8 +9,6 @@ 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.onlinerouting.parser.JSONParser; -import net.osmand.plus.onlinerouting.parser.ResponseParser; import org.json.JSONArray; import org.json.JSONException; @@ -23,7 +21,7 @@ import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; -public class OrsEngine extends OnlineRoutingEngine { +public class OrsEngine extends JsonOnlineRoutingEngine { public OrsEngine(@Nullable Map params) { super(params); @@ -64,12 +62,6 @@ public class OrsEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("wheelchair", R.string.routing_engine_vehicle_type_wheelchair)); } - @NonNull - @Override - protected ResponseParser createParser() { - return new OrsParser(); - } - @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -92,38 +84,36 @@ public class OrsEngine extends OnlineRoutingEngine { } } - private static 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; + @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)); } - - @NonNull - @Override - protected String getErrorMessageKey() { - return "error"; - } - - @NonNull - @Override - protected String getRootArrayKey() { - return "features"; + 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 19860ee15c..4219204cca 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -9,8 +9,6 @@ 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.onlinerouting.parser.JSONParser; -import net.osmand.plus.onlinerouting.parser.ResponseParser; import net.osmand.plus.routing.RouteCalculationResult; import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.router.TurnType; @@ -29,7 +27,7 @@ import java.util.Set; import static net.osmand.util.Algorithms.isEmpty; import static net.osmand.util.Algorithms.objectEquals; -public class OsrmEngine extends OnlineRoutingEngine { +public class OsrmEngine extends JsonOnlineRoutingEngine { public OsrmEngine(@Nullable Map params) { super(params); @@ -63,12 +61,6 @@ public class OsrmEngine extends OnlineRoutingEngine { vehicles.add(new VehicleType("foot", R.string.routing_engine_vehicle_type_foot)); } - @NonNull - @Override - protected ResponseParser createParser() { - return new OsrmParser(); - } - @Override protected void makeFullUrl(@NonNull StringBuilder sb, @NonNull List path) { @@ -88,167 +80,165 @@ public class OsrmEngine extends OnlineRoutingEngine { sb.append('&').append("steps=true"); } - private static 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; - @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; - 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 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; - 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")); - // 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); - 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); + String streetName = instruction.getString("name"); + String description = ""; + if (!objectEquals(maneuverType, "arrive")) { + description = RouteCalculationResult.toString(turnType, app, false) + " " + streetName; } - } + description = description.trim(); - return new OnlineRoutingResponse(route, directions); + direction.setStreetName(streetName); + direction.setDescriptionRoute(description); + direction.routePointOffset = routePointOffset; + directions.add(direction); + } } - @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"; - } + 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/GpxParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java deleted file mode 100644 index 92621b2b3f..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java +++ /dev/null @@ -1,42 +0,0 @@ -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; - } - - 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/ResponseParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java deleted file mode 100644 index 62cf7e0f44..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/ResponseParser.java +++ /dev/null @@ -1,77 +0,0 @@ -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 4f626569d7..fee3d02524 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.getResponseParser().isResultOk(errorMessage, response); + resultOk = requestedEngine.isResultOk(errorMessage, response); } catch (IOException | JSONException e) { errorMessage.append(e.toString()); } diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 0eb5a74e52..19d0fcd3f7 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.parser.ResponseParser.OnlineRoutingResponse; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.CommonPreference; From cea1fa60e798f04971afad6ac89eb85014898cf9 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 22 Feb 2021 19:09:30 +0200 Subject: [PATCH 5/6] Refactoring: remove enum EngineType, use OnlineRoutingEngine constants instead --- .../onlinerouting/OnlineRoutingFactory.java | 39 ------------------- .../onlinerouting/OnlineRoutingUtils.java | 8 ++-- .../plus/onlinerouting/engine/EngineType.java | 39 ++++++++++--------- .../plus/onlinerouting/engine/GpxEngine.java | 23 ++++++++++- .../engine/GraphhopperEngine.java | 22 ++++++++++- .../engine/OnlineRoutingEngine.java | 13 +++++-- .../plus/onlinerouting/engine/OrsEngine.java | 22 ++++++++++- .../plus/onlinerouting/engine/OsrmEngine.java | 24 ++++++++++-- .../ui/OnlineRoutingEngineFragment.java | 30 +++++++------- 9 files changed, 133 insertions(+), 87 deletions(-) delete mode 100644 OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java deleted file mode 100644 index 71ea72f5e4..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.osmand.plus.onlinerouting; - -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; -import net.osmand.plus.onlinerouting.engine.OsrmEngine; - -import java.util.Map; - -public class OnlineRoutingFactory { - - public static OnlineRoutingEngine createEngine(@NonNull EngineType type) { - return createEngine(type, null); - } - - @NonNull - public static OnlineRoutingEngine createEngine(@NonNull EngineType type, - @Nullable Map params) { - switch (type) { - case GRAPHHOPPER: - return new GraphhopperEngine(params); - case OSRM: - 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/OnlineRoutingUtils.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingUtils.java index 90eb4ea83c..ce8ea65f7c 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingUtils.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingUtils.java @@ -7,8 +7,8 @@ import androidx.annotation.NonNull; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import net.osmand.plus.onlinerouting.engine.EngineType; import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; +import net.osmand.plus.onlinerouting.engine.EngineType; import net.osmand.util.Algorithms; import org.json.JSONArray; @@ -60,10 +60,10 @@ public class OnlineRoutingUtils { for (int i = 0; i < itemsJson.length(); i++) { JSONObject object = itemsJson.getJSONObject(i); if (object.has(TYPE) && object.has(PARAMS)) { - EngineType type = EngineType.getTypeByName(object.getString(TYPE)); + OnlineRoutingEngine type = EngineType.getTypeByName(object.getString(TYPE)); String paramsString = object.getString(PARAMS); HashMap params = gson.fromJson(paramsString, typeToken); - OnlineRoutingEngine engine = OnlineRoutingFactory.createEngine(type, params); + OnlineRoutingEngine engine = type.newInstance(params); if (!Algorithms.isEmpty(engine.getStringKey())) { engines.add(engine); } @@ -82,7 +82,7 @@ public class OnlineRoutingUtils { continue; } JSONObject jsonObject = new JSONObject(); - jsonObject.put(TYPE, engine.getType().name()); + jsonObject.put(TYPE, engine.getTypeName()); jsonObject.put(PARAMS, gson.toJson(engine.getParams(), type)); jsonArray.put(jsonObject); } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java index 0efd91e759..5b6614691e 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -1,35 +1,38 @@ package net.osmand.plus.onlinerouting.engine; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import net.osmand.util.Algorithms; -public enum EngineType { - GRAPHHOPPER("Graphhopper"), - OSRM("OSRM"), - ORS("Openroute Service"), - GPX("GPX"); +public class EngineType { - private final String title; + public final static OnlineRoutingEngine GRAPHHOPPER_TYPE = new GraphhopperEngine(null); + public final static OnlineRoutingEngine OSRM_TYPE = new OsrmEngine(null); + public final static OnlineRoutingEngine ORS_TYPE = new OrsEngine(null); + public final static OnlineRoutingEngine GPX_TYPE = new GpxEngine(null); - EngineType(String title) { - this.title = title; - } + private static OnlineRoutingEngine[] enginesTypes; - public String getTitle() { - return title; + public static OnlineRoutingEngine[] values() { + if (enginesTypes == null) { + enginesTypes = new OnlineRoutingEngine[]{ + GRAPHHOPPER_TYPE, + OSRM_TYPE, + ORS_TYPE, + GPX_TYPE + }; + } + return enginesTypes; } @NonNull - public static EngineType getTypeByName(@Nullable String name) { - if (!Algorithms.isEmpty(name)) { - for (EngineType type : values()) { - if (type.name().equals(name)) { - return type; - } + public static OnlineRoutingEngine getTypeByName(@NonNull String typeName) { + for (OnlineRoutingEngine type : values()) { + if (Algorithms.objectEquals(type.getTypeName(), typeName)) { + return type; } } return values()[0]; } + } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java index 676ea6ba48..eac4771ba3 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -17,6 +17,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static net.osmand.plus.onlinerouting.engine.EngineType.GPX_TYPE; + public class GpxEngine extends OnlineRoutingEngine { public GpxEngine(@Nullable Map params) { @@ -25,8 +27,20 @@ public class GpxEngine extends OnlineRoutingEngine { @NonNull @Override - public EngineType getType() { - return EngineType.GPX; + public OnlineRoutingEngine getType() { + return GPX_TYPE; + } + + @Override + @NonNull + public String getTitle() { + return "GPX"; + } + + @NonNull + @Override + public String getTypeName() { + return "GPX"; } @Override @@ -60,6 +74,11 @@ public class GpxEngine extends OnlineRoutingEngine { params.add(EngineParameter.CUSTOM_URL); } + @Override + public OnlineRoutingEngine newInstance(Map params) { + return new GpxEngine(params); + } + @Override @Nullable public OnlineRoutingResponse parseResponse(@NonNull String content, diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java index 68122b3bdd..ae62b8c71d 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static net.osmand.plus.onlinerouting.engine.EngineType.GRAPHHOPPER_TYPE; import static net.osmand.util.Algorithms.isEmpty; public class GraphhopperEngine extends JsonOnlineRoutingEngine { @@ -32,8 +33,20 @@ public class GraphhopperEngine extends JsonOnlineRoutingEngine { @NonNull @Override - public EngineType getType() { - return EngineType.GRAPHHOPPER; + public OnlineRoutingEngine getType() { + return GRAPHHOPPER_TYPE; + } + + @Override + @NonNull + public String getTitle() { + return "Graphhopper"; + } + + @NonNull + @Override + public String getTypeName() { + return "GRAPHHOPPER"; } @NonNull @@ -52,6 +65,11 @@ public class GraphhopperEngine extends JsonOnlineRoutingEngine { params.add(EngineParameter.API_KEY); } + @Override + public OnlineRoutingEngine newInstance(Map params) { + return new GraphhopperEngine(params); + } + @Override protected void collectAllowedVehicles(@NonNull List vehicles) { vehicles.add(new VehicleType("car", R.string.routing_engine_vehicle_type_car)); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index 85514dec85..670375c0b5 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -12,7 +12,6 @@ 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.util.Algorithms; @@ -50,7 +49,13 @@ public abstract class OnlineRoutingEngine implements Cloneable { } @NonNull - public abstract EngineType getType(); + public abstract OnlineRoutingEngine getType(); + + @NonNull + public abstract String getTitle(); + + @NonNull + public abstract String getTypeName(); @Nullable public String getStringKey() { @@ -176,7 +181,7 @@ public abstract class OnlineRoutingEngine implements Cloneable { @NonNull @Override public Object clone() { - return OnlineRoutingFactory.createEngine(getType(), getParams()); + return newInstance(getParams()); } @Override @@ -189,6 +194,8 @@ public abstract class OnlineRoutingEngine implements Cloneable { return Algorithms.objectEquals(getParams(), engine.getParams()); } + public abstract OnlineRoutingEngine newInstance(Map params); + @NonNull public static String generateKey() { return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis(); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java index 9a16be62ee..16a5452caa 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static net.osmand.plus.onlinerouting.engine.EngineType.ORS_TYPE; import static net.osmand.util.Algorithms.isEmpty; public class OrsEngine extends JsonOnlineRoutingEngine { @@ -29,8 +30,20 @@ public class OrsEngine extends JsonOnlineRoutingEngine { @NonNull @Override - public EngineType getType() { - return EngineType.ORS; + public OnlineRoutingEngine getType() { + return ORS_TYPE; + } + + @Override + @NonNull + public String getTitle() { + return "Openroute Service"; + } + + @NonNull + @Override + public String getTypeName() { + return "ORS"; } @NonNull @@ -49,6 +62,11 @@ public class OrsEngine extends JsonOnlineRoutingEngine { params.add(EngineParameter.API_KEY); } + @Override + public OnlineRoutingEngine newInstance(Map params) { + return new OrsEngine(params); + } + @Override protected void collectAllowedVehicles(@NonNull List vehicles) { vehicles.add(new VehicleType("driving-car", R.string.routing_engine_vehicle_type_car)); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java index 4219204cca..20d98c0daf 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static net.osmand.plus.onlinerouting.engine.EngineType.OSRM_TYPE; import static net.osmand.util.Algorithms.isEmpty; import static net.osmand.util.Algorithms.objectEquals; @@ -34,9 +35,21 @@ public class OsrmEngine extends JsonOnlineRoutingEngine { } @Override - public @NonNull - EngineType getType() { - return EngineType.OSRM; + @NonNull + public OnlineRoutingEngine getType() { + return OSRM_TYPE; + } + + @Override + @NonNull + public String getTitle() { + return "OSRM"; + } + + @NonNull + @Override + public String getTypeName() { + return "OSRM"; } @NonNull @@ -54,6 +67,11 @@ public class OsrmEngine extends JsonOnlineRoutingEngine { params.add(EngineParameter.CUSTOM_URL); } + @Override + public OnlineRoutingEngine newInstance(Map params) { + return new OsrmEngine(params); + } + @Override protected void collectAllowedVehicles(@NonNull List vehicles) { vehicles.add(new VehicleType("car", R.string.routing_engine_vehicle_type_car)); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java index fee3d02524..175e22016e 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java @@ -39,12 +39,11 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem; import net.osmand.plus.onlinerouting.EngineParameter; -import net.osmand.plus.onlinerouting.OnlineRoutingFactory; import net.osmand.plus.onlinerouting.OnlineRoutingHelper; import net.osmand.plus.onlinerouting.OnlineRoutingUtils; import net.osmand.plus.onlinerouting.VehicleType; -import net.osmand.plus.onlinerouting.engine.EngineType; import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; +import net.osmand.plus.onlinerouting.engine.EngineType; import net.osmand.plus.onlinerouting.ui.OnlineRoutingCard.OnTextChangedListener; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.settings.backend.ApplicationMode; @@ -54,7 +53,9 @@ import org.json.JSONException; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.CUSTOM_VEHICLE; @@ -201,15 +202,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { typeCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); typeCard.build(mapActivity); typeCard.setHeaderTitle(getString(R.string.shared_string_type)); - List serverItems = new ArrayList<>(); - for (EngineType server : EngineType.values()) { - serverItems.add(new HorizontalSelectionItem(server.getTitle(), server)); + List typeItems = new ArrayList<>(); + for (OnlineRoutingEngine type : EngineType.values()) { + typeItems.add(new HorizontalSelectionItem(type.getTitle(), type)); } - typeCard.setSelectionMenu(serverItems, engine.getType().getTitle(), + typeCard.setSelectionMenu(typeItems, engine.getType().getTitle(), new CallbackWithObject() { @Override public boolean processResult(HorizontalSelectionItem result) { - EngineType type = (EngineType) result.getObject(); + OnlineRoutingEngine type = (OnlineRoutingEngine) result.getObject(); if (engine.getType() != type) { changeEngineType(type); return true; @@ -366,9 +367,9 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { }); } - private void changeEngineType(EngineType type) { + private void changeEngineType(OnlineRoutingEngine type) { OnlineRoutingEngine tmp = (OnlineRoutingEngine) engine.clone(); - engine = OnlineRoutingFactory.createEngine(type, tmp.getParams()); + engine = type.newInstance(tmp.getParams()); // after changing the type, select the vehicle // with the same name that was selected before @@ -615,7 +616,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } private void saveState(@NonNull Bundle outState) { - outState.putString(ENGINE_TYPE_KEY, engine.getType().name()); + outState.putString(ENGINE_TYPE_KEY, engine.getTypeName()); for (EngineParameter key : EngineParameter.values()) { String value = engine.get(key); if (value != null) { @@ -632,14 +633,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { editedEngineKey = savedState.getString(EngineParameter.KEY.name()); initEngine = createInitStateEngine(); String typeKey = savedState.getString(ENGINE_TYPE_KEY); - EngineType type = EngineType.getTypeByName(typeKey); - engine = OnlineRoutingFactory.createEngine(type); + OnlineRoutingEngine type = EngineType.getTypeByName(typeKey); + Map params = new HashMap<>(); for (EngineParameter key : EngineParameter.values()) { String value = savedState.getString(key.name()); if (value != null) { - engine.put(key, value); + params.put(key.name(), value); } } + engine = type.newInstance(params); customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY); selectedLocation = ExampleLocation.valueOf(savedState.getString(EXAMPLE_LOCATION_KEY)); appMode = ApplicationMode.valueOfStringKey(savedState.getString(APP_MODE_KEY), null); @@ -662,7 +664,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { if (editedEngine != null) { engine = (OnlineRoutingEngine) editedEngine.clone(); } else { - engine = OnlineRoutingFactory.createEngine(EngineType.values()[0]); + engine = EngineType.values()[0].newInstance(null); String vehicle = engine.getAllowedVehicles().get(0).getKey(); engine.put(EngineParameter.VEHICLE_KEY, vehicle); if (editedEngineKey != null) { From fa353ad87ce7e38954ef8854a91036db70061ccb Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 1 Mar 2021 13:24:30 +0200 Subject: [PATCH 6/6] small fixes --- .../src/main/java/net/osmand/util/Algorithms.java | 15 +++++---------- .../plus/onlinerouting/engine/GpxEngine.java | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) 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 8954e2d61b..36c0034a26 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -565,16 +565,11 @@ public class Algorithms { } } - public static ByteArrayInputStream createByteArrayIS(InputStream inputStream) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - int i = 0; - while ((i = inputStream.read()) != -1) { - outputStream.write(i); - } - inputStream.close(); - - byte[] byteArray = outputStream.toByteArray(); - return new ByteArrayInputStream(byteArray); + public static ByteArrayInputStream createByteArrayIS(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + streamCopy(in, out); + in.close(); + return new ByteArrayInputStream(out.toByteArray()); } @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java index eac4771ba3..736d09611a 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -95,7 +95,7 @@ public class GpxEngine extends OnlineRoutingEngine { } private GPXFile parseGpx(@NonNull String content) { - InputStream gpxStream = null; + InputStream gpxStream; try { gpxStream = new ByteArrayInputStream(content.getBytes("UTF-8")); return GPXUtilities.loadGPXFile(gpxStream);