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..36c0034a26 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; @@ -322,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. @@ -358,6 +378,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 @@ -537,6 +565,13 @@ public class Algorithms { } } + public static ByteArrayInputStream createByteArrayIS(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + streamCopy(in, out); + in.close(); + return new ByteArrayInputStream(out.toByteArray()); + } + @SuppressWarnings("ResultOfMethodCallIgnored") public static void updateAllExistingImgTilesToOsmandFormat(File f) { if (f.isDirectory()) { 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 4b92000847..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java +++ /dev/null @@ -1,36 +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.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); - 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..9ae8f5cb02 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java @@ -18,14 +18,20 @@ 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; 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 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 { @@ -88,7 +94,7 @@ public class OnlineRoutingHelper { boolean leftSideNavigation) throws IOException, JSONException { String url = engine.getFullUrl(path); String content = makeRequest(url); - return engine.parseServerResponse(content, app, leftSideNavigation); + return engine.parseResponse(content, app, leftSideNavigation); } @NonNull @@ -98,7 +104,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 +119,18 @@ public class OnlineRoutingHelper { return content.toString(); } + private InputStream getInputStream(@NonNull HttpURLConnection connection) throws IOException { + 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) { deleteInaccessibleParameters(engine); String key = createEngineKeyIfNeeded(engine); 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/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..5b6614691e 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -1,34 +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"); +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 new file mode 100644 index 0000000000..736d09611a --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -0,0 +1,107 @@ +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 java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +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) { + super(params); + } + + @NonNull + @Override + public OnlineRoutingEngine getType() { + return GPX_TYPE; + } + + @Override + @NonNull + public String getTitle() { + return "GPX"; + } + + @NonNull + @Override + public String getTypeName() { + return "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 ""; + } + + @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); + } + + @Override + public OnlineRoutingEngine newInstance(Map params) { + return new GpxEngine(params); + } + + @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; + 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 930ebcab8d..ae62b8c71d 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -20,10 +20,12 @@ import org.json.JSONObject; import java.util.ArrayList; 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 OnlineRoutingEngine { +public class GraphhopperEngine extends JsonOnlineRoutingEngine { public GraphhopperEngine(@Nullable Map params) { super(params); @@ -31,8 +33,20 @@ public class GraphhopperEngine extends OnlineRoutingEngine { @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 @@ -42,8 +56,18 @@ 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 + public OnlineRoutingEngine newInstance(Map params) { + return new GraphhopperEngine(params); } @Override @@ -82,10 +106,9 @@ public class GraphhopperEngine extends OnlineRoutingEngine { } @Nullable - @Override - public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { + 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; @@ -223,4 +246,5 @@ public class GraphhopperEngine extends OnlineRoutingEngine { protected String getRootArrayKey() { return "paths"; } + } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/JsonOnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/JsonOnlineRoutingEngine.java new file mode 100644 index 0000000000..dcd191da19 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/JsonOnlineRoutingEngine.java @@ -0,0 +1,82 @@ +package net.osmand.plus.onlinerouting.engine; + +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 java.util.Map; + +import static net.osmand.util.Algorithms.isEmpty; + +public abstract class JsonOnlineRoutingEngine extends OnlineRoutingEngine { + + public JsonOnlineRoutingEngine(@Nullable Map params) { + super(params); + } + + @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()); + } + + @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(); + + @NonNull + protected static 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; + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index 0752282c70..670375c0b5 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -5,24 +5,21 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import net.osmand.GPXUtilities.WptPt; +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.routing.RouteDirectionInfo; -import net.osmand.plus.routing.RouteProvider; import net.osmand.util.Algorithms; -import org.json.JSONArray; +import org.apache.commons.logging.Log; import org.json.JSONException; -import org.json.JSONObject; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -34,6 +31,8 @@ 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); @@ -46,11 +45,17 @@ public abstract class OnlineRoutingEngine implements Cloneable { this.params.putAll(params); } collectAllowedVehiclesInternal(); - collectAllowedParametersInternal(); + collectAllowedParameters(allowedParameters); } @NonNull - public abstract EngineType getType(); + public abstract OnlineRoutingEngine getType(); + + @NonNull + public abstract String getTitle(); + + @NonNull + public abstract String getTypeName(); @Nullable public String getStringKey() { @@ -100,45 +105,13 @@ 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; + public abstract OnlineRoutingResponse parseResponse(@NonNull String content, + @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); - } - return array != null && array.length() > 0 ? array.getJSONObject(0) : null; - } - - @NonNull - protected abstract String 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; - } + public abstract boolean isResultOk(@NonNull StringBuilder errorMessage, + @NonNull String content) throws JSONException; @NonNull public Map getParams() { @@ -171,23 +144,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,24 +178,10 @@ 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() { - return OnlineRoutingFactory.createEngine(getType(), getParams()); + return newInstance(getParams()); } @Override @@ -246,20 +194,30 @@ 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(); } 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; } @@ -267,5 +225,10 @@ public abstract class OnlineRoutingEngine implements Cloneable { 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 ed9168ccf9..16a5452caa 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -17,10 +17,12 @@ import org.json.JSONObject; import java.util.ArrayList; 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 OnlineRoutingEngine { +public class OrsEngine extends JsonOnlineRoutingEngine { public OrsEngine(@Nullable Map params) { super(params); @@ -28,8 +30,20 @@ public class OrsEngine extends OnlineRoutingEngine { @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 @@ -39,8 +53,18 @@ 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 + public OnlineRoutingEngine newInstance(Map params) { + return new OrsEngine(params); } @Override @@ -109,4 +133,5 @@ public class OrsEngine extends OnlineRoutingEngine { 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..20d98c0daf 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -22,20 +22,34 @@ import org.json.JSONObject; import java.util.ArrayList; 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; -public class OsrmEngine extends OnlineRoutingEngine { +public class OsrmEngine extends JsonOnlineRoutingEngine { public OsrmEngine(@Nullable Map params) { super(params); } @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 @@ -45,7 +59,17 @@ 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 + public OnlineRoutingEngine newInstance(Map params) { + return new OsrmEngine(params); } @Override @@ -76,9 +100,9 @@ public class OsrmEngine extends OnlineRoutingEngine { @Nullable @Override - public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root, - @NonNull OsmandApplication app, - boolean leftSideNavigation) throws JSONException { + 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; @@ -225,13 +249,14 @@ public class OsrmEngine extends OnlineRoutingEngine { @NonNull @Override - protected String getErrorMessageKey() { - return "message"; + protected String getRootArrayKey() { + return "routes"; } @NonNull @Override - protected String getRootArrayKey() { - return "routes"; + protected String getErrorMessageKey() { + return "message"; } + } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java index 008bb75852..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 @@ -462,7 +463,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { boolean resultOk = false; try { String response = helper.makeRequest(exampleCard.getEditedText()); - resultOk = requestedEngine.checkServerResponse(errorMessage, response); + resultOk = requestedEngine.isResultOk(errorMessage, response); } catch (IOException | JSONException e) { errorMessage.append(e.toString()); } @@ -514,6 +515,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(); @@ -609,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) { @@ -626,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); @@ -656,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) { diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 3f0a30c99f..19d0fcd3f7 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -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) {