diff --git a/OsmAnd/res/layout/bottom_sheet_item_with_descr_64dp.xml b/OsmAnd/res/layout/bottom_sheet_item_with_descr_64dp.xml index 2ff6a1bf58..95091e1086 100644 --- a/OsmAnd/res/layout/bottom_sheet_item_with_descr_64dp.xml +++ b/OsmAnd/res/layout/bottom_sheet_item_with_descr_64dp.xml @@ -27,6 +27,8 @@ android:layout_weight="1" android:layout_marginLeft="@dimen/content_padding" android:layout_marginStart="@dimen/content_padding" + android:paddingTop="@dimen/content_padding_small" + android:paddingBottom="@dimen/content_padding_small" android:orientation="vertical"> + + قدم دراجة هوائية سيارة - خطأ، أعد التحقق من المعايير نسخ العنوان محرك التوجيه عبر الإنترنت محركات التوجيه عبر الإنترنت diff --git a/OsmAnd/res/values-cs/strings.xml b/OsmAnd/res/values-cs/strings.xml index 38af3fcceb..6d6b906b06 100644 --- a/OsmAnd/res/values-cs/strings.xml +++ b/OsmAnd/res/values-cs/strings.xml @@ -3960,7 +3960,6 @@ Chůze Kolo Auto - Chyba, zkontrolujte parametry Kopírovat adresu Online navigační služba Online navigační služby diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index e66df6bcd7..b216a47c7c 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -3962,7 +3962,6 @@ Zu Fuß Fahrrad Auto - Fehler, Parameter erneut prüfen Subtyp Leer lassen, wenn kein API-Schlüssel vorhanden Adresse kopieren diff --git a/OsmAnd/res/values-eo/strings.xml b/OsmAnd/res/values-eo/strings.xml index 391e96ba42..9671d14e5f 100644 --- a/OsmAnd/res/values-eo/strings.xml +++ b/OsmAnd/res/values-eo/strings.xml @@ -3960,7 +3960,6 @@ Piediranto Biciklo Aŭtomobilo - Eraro, rekontrolu parametrojn Kopii adreson Enreta navigilo Enretaj navigiloj diff --git a/OsmAnd/res/values-es-rAR/strings.xml b/OsmAnd/res/values-es-rAR/strings.xml index fd54cd500f..83700ce7cd 100644 --- a/OsmAnd/res/values-es-rAR/strings.xml +++ b/OsmAnd/res/values-es-rAR/strings.xml @@ -3963,7 +3963,6 @@ Peatón Bicicleta Automóvil - Error, vuelve a comprobar los parámetros Copiar dirección Motor de navegación en línea Motores de navegación en línea diff --git a/OsmAnd/res/values-eu/strings.xml b/OsmAnd/res/values-eu/strings.xml index ee2a825985..dced5cf049 100644 --- a/OsmAnd/res/values-eu/strings.xml +++ b/OsmAnd/res/values-eu/strings.xml @@ -3933,6 +3933,5 @@ Area honi dagokio: %1$s x %2$s Oinez Bizikleta Kotxea - Errorea, egiaztatu parametroak berriro Kopiatu helbidea \ No newline at end of file diff --git a/OsmAnd/res/values-fa/strings.xml b/OsmAnd/res/values-fa/strings.xml index 3cb0760eac..226a00cc5c 100644 --- a/OsmAnd/res/values-fa/strings.xml +++ b/OsmAnd/res/values-fa/strings.xml @@ -3953,5 +3953,4 @@ پا دوچرخه خودرو - خطا، پارامترها را بازبینی کنید \ No newline at end of file diff --git a/OsmAnd/res/values-fr/strings.xml b/OsmAnd/res/values-fr/strings.xml index 0b7dc82b1c..e5f41539c2 100644 --- a/OsmAnd/res/values-fr/strings.xml +++ b/OsmAnd/res/values-fr/strings.xml @@ -3947,7 +3947,6 @@ A pieds Vélo Automobile - Erreur, vérifiez les paramètres Ajouter un moteur de routage en ligne Modifier le moteur de routage en ligne L\'URL avec tous les paramètres sera de la forme : diff --git a/OsmAnd/res/values-gl/strings.xml b/OsmAnd/res/values-gl/strings.xml index 2e0c0053d3..5570577760 100644 --- a/OsmAnd/res/values-gl/strings.xml +++ b/OsmAnd/res/values-gl/strings.xml @@ -3968,7 +3968,6 @@ Lon %2$s Bicicleta Coche - Erro, verifica novamente os parámetros Copiar enderezo Horarios dos avisos por voz Motor de navegación en liña diff --git a/OsmAnd/res/values-hu/strings.xml b/OsmAnd/res/values-hu/strings.xml index d893dcf47e..64d40e287c 100644 --- a/OsmAnd/res/values-hu/strings.xml +++ b/OsmAnd/res/values-hu/strings.xml @@ -3954,7 +3954,6 @@ Hagyja üresen, ha nem Az összes paraméterrel rendelkező URL így néz ki: Útvonaltervezés kipróbálása - Hiba, ellenőrizze újra a paramétereket Cím másolása Online útvonaltervező Online útvonaltervezők diff --git a/OsmAnd/res/values-is/strings.xml b/OsmAnd/res/values-is/strings.xml index 3449458457..0b94e361f7 100644 --- a/OsmAnd/res/values-is/strings.xml +++ b/OsmAnd/res/values-is/strings.xml @@ -3965,6 +3965,5 @@ Gangandi Hjólandi Bíll - Villa, yfirfarðu breytur Afrita heimilisfang \ No newline at end of file diff --git a/OsmAnd/res/values-iw/strings.xml b/OsmAnd/res/values-iw/strings.xml index 44f2c8c034..7ca3bcdb8d 100644 --- a/OsmAnd/res/values-iw/strings.xml +++ b/OsmAnd/res/values-iw/strings.xml @@ -3963,7 +3963,6 @@ ברגל אופנוע מכונית - שגיאה, נא לבדוק את המשתנים מחדש העתקת כתובת מנוע ניווט מקוון מנועי ניווט מקוונים diff --git a/OsmAnd/res/values-ka/strings.xml b/OsmAnd/res/values-ka/strings.xml index 770916e3b3..330d43d2c4 100644 --- a/OsmAnd/res/values-ka/strings.xml +++ b/OsmAnd/res/values-ka/strings.xml @@ -2449,7 +2449,6 @@ OsmAndის გამოწერა დაპაუზებულია OsmAndის გამოწერა შეჩერებულია URL ყველა პარამეტრით აი ასეთი იქნება: - შეცდომა, გადაამოწმეთ პარამეტრები Mapillary-ის გამოსახულება Mapillary-ის ღილაკი ფერთა გამა diff --git a/OsmAnd/res/values-lt/strings.xml b/OsmAnd/res/values-lt/strings.xml index 65c711462f..09ee2a83fd 100644 --- a/OsmAnd/res/values-lt/strings.xml +++ b/OsmAnd/res/values-lt/strings.xml @@ -2770,7 +2770,6 @@ Tai yra puikus būdas paremti OsmAnd ir OSM, jei jie jums patinka. Patikrinti maršruto apskaičiavimą Dviratis Automobilis - Įvyko klaida, patikrinkite paametrus Kopijuoti adresą Folderiai Pasirinkite folderį diff --git a/OsmAnd/res/values-nl/strings.xml b/OsmAnd/res/values-nl/strings.xml index 04da6132ce..4420cd6987 100644 --- a/OsmAnd/res/values-nl/strings.xml +++ b/OsmAnd/res/values-nl/strings.xml @@ -3916,7 +3916,6 @@ Te voet Fiets Auto - Fout, controleer parameters opnieuw Kopieer adres Online routeplanningssysteem Online routeplanningssystemen diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index cf4852f488..840fa52189 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -3956,7 +3956,6 @@ Obliczanie trasy testowej Rower Samochód - Błąd, ponownie sprawdź parametry Skopiuj adres Jazda Stopa diff --git a/OsmAnd/res/values-pt-rBR/strings.xml b/OsmAnd/res/values-pt-rBR/strings.xml index da70b09ce8..52d578c035 100644 --- a/OsmAnd/res/values-pt-rBR/strings.xml +++ b/OsmAnd/res/values-pt-rBR/strings.xml @@ -3955,7 +3955,6 @@ Bicicleta Carro - Erro, verifique novamente os parâmetros Copiar endereço Motor de encaminhamento online Mecanismos de roteamento online diff --git a/OsmAnd/res/values-sc/strings.xml b/OsmAnd/res/values-sc/strings.xml index f5ff13cd8b..aa05e82d25 100644 --- a/OsmAnd/res/values-sc/strings.xml +++ b/OsmAnd/res/values-sc/strings.xml @@ -3957,7 +3957,6 @@ A pee Bitzicleta Màchina - Errore, torra a verificare sos paràmetros Còpia s\'indiritzu Motore de càrculu in lìnia Motores de càrculu in lìnia diff --git a/OsmAnd/res/values-sk/strings.xml b/OsmAnd/res/values-sk/strings.xml index 6d8fb45d93..81a9d73353 100644 --- a/OsmAnd/res/values-sk/strings.xml +++ b/OsmAnd/res/values-sk/strings.xml @@ -3955,7 +3955,6 @@ Chôdza Bicykel Auto - Chyba, skontrolujte parametre Kopírovať adresu Online navigačná služba Online navigačné služby diff --git a/OsmAnd/res/values-tr/strings.xml b/OsmAnd/res/values-tr/strings.xml index ee5e25124a..344183c102 100644 --- a/OsmAnd/res/values-tr/strings.xml +++ b/OsmAnd/res/values-tr/strings.xml @@ -3961,7 +3961,6 @@ Yürüme Bisiklet Araba - Hata, parametreleri tekrar gözden geçirin Adresi kopyala Çevrim içi yönlendirme motoru Çevrim içi yönlendirme motorları diff --git a/OsmAnd/res/values-uk/strings.xml b/OsmAnd/res/values-uk/strings.xml index 2738eda283..6910c9a902 100644 --- a/OsmAnd/res/values-uk/strings.xml +++ b/OsmAnd/res/values-uk/strings.xml @@ -3959,7 +3959,6 @@ Пішки Велосипед Автомобіль - Помилка, повторно перевірте параметри Копіювати адресу Мережний рушій маршрутизації Мережні рушії маршрутизації diff --git a/OsmAnd/res/values-zh-rTW/strings.xml b/OsmAnd/res/values-zh-rTW/strings.xml index 738ede85e2..0f19668c01 100644 --- a/OsmAnd/res/values-zh-rTW/strings.xml +++ b/OsmAnd/res/values-zh-rTW/strings.xml @@ -3953,7 +3953,6 @@ 步行 自行車 汽車 - 錯誤,重新檢查參數 複製地址 線上路線計算引擎 線上路線計算引擎 diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 299e7aa5b2..8605ea2189 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,21 @@ --> + The name is already exists + Server error: %1$s + MTB + Racing bike + Scooter + Truck + Small truck + HGV + Regular cycling + Road cycling + Mountain cycling + Electric cycling + Walking + Hiking + Wheelchair Show track on map Start recording Announcement time @@ -37,7 +52,6 @@ Online routing engines Online routing engine Copy address - Error, recheck parameters Car Bike Foot diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/EngineParameter.java b/OsmAnd/src/net/osmand/plus/onlinerouting/EngineParameter.java new file mode 100644 index 0000000000..fa3ccd81c7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/EngineParameter.java @@ -0,0 +1,10 @@ +package net.osmand.plus.onlinerouting; + +public enum EngineParameter { + KEY, + VEHICLE_KEY, + CUSTOM_NAME, + NAME_INDEX, + CUSTOM_URL, + API_KEY +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java deleted file mode 100644 index fe5080f14c..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.osmand.plus.onlinerouting; - -public enum EngineType { - - GRAPHHOPPER("Graphhopper", "https://graphhopper.com/api/1/route"), - OSRM("OSRM", "https://router.project-osrm.org/route/v1/"), - ORS("Openroute Service", "https://api.openrouteservice.org/v2/directions/"); - - private String title; - private String standardUrl; - - EngineType(String title, String standardUrl) { - this.title = title; - this.standardUrl = standardUrl; - } - - public String getTitle() { - return title; - } - - public String getStandardUrl() { - return standardUrl; - } -} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java deleted file mode 100644 index 3193d86d09..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java +++ /dev/null @@ -1,109 +0,0 @@ -package net.osmand.plus.onlinerouting; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import net.osmand.plus.R; -import net.osmand.util.Algorithms; - -import java.util.HashMap; -import java.util.Map; - -public class OnlineRoutingEngine { - - public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_"; - - public enum EngineParameter { - CUSTOM_NAME, - CUSTOM_URL, - API_KEY - } - - private String stringKey; - private EngineType type; - private String vehicleKey; - private Map params = new HashMap<>(); - - public OnlineRoutingEngine(@NonNull String stringKey, - @NonNull EngineType type, - @NonNull String vehicleKey, - @Nullable Map params) { - this(stringKey, type, vehicleKey); - if (!Algorithms.isEmpty(params)) { - this.params.putAll(params); - } - } - - public OnlineRoutingEngine(@NonNull String stringKey, - @NonNull EngineType type, - @NonNull String vehicleKey) { - this.stringKey = stringKey; - this.type = type; - this.vehicleKey = vehicleKey; - } - - public String getStringKey() { - return stringKey; - } - - public EngineType getType() { - return type; - } - - public String getBaseUrl() { - String customUrl = getParameter(EngineParameter.CUSTOM_URL); - if (Algorithms.isEmpty(customUrl)) { - return type.getStandardUrl(); - } - return customUrl; - } - - public String getVehicleKey() { - return vehicleKey; - } - - public Map getParams() { - return params; - } - - public String getParameter(EngineParameter paramKey) { - return params.get(paramKey.name()); - } - - public void putParameter(EngineParameter paramKey, String paramValue) { - params.put(paramKey.name(), paramValue); - } - - public String getName(@NonNull Context ctx) { - String customName = getParameter(EngineParameter.CUSTOM_NAME); - if (customName != null) { - return customName; - } else { - return getStandardName(ctx); - } - } - - private String getStandardName(@NonNull Context ctx) { - return getStandardName(ctx, type, vehicleKey); - } - - public static String getStandardName(@NonNull Context ctx, - @NonNull EngineType type, - @NonNull String vehicleKey) { - String vehicleTitle = VehicleType.toHumanString(ctx, vehicleKey); - String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_dash); - return String.format(pattern, type.getTitle(), vehicleTitle); - } - - public static OnlineRoutingEngine createNewEngine(@NonNull EngineType type, - @NonNull String vehicleKey, - @Nullable Map params) { - return new OnlineRoutingEngine(generateKey(), type, vehicleKey, params); - } - - private static String generateKey() { - return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis(); - } -} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java new file mode 100644 index 0000000000..4b92000847 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingFactory.java @@ -0,0 +1,36 @@ +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 b54746ddd6..b28d98d55f 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java @@ -1,6 +1,7 @@ package net.osmand.plus.onlinerouting; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -10,10 +11,10 @@ import net.osmand.data.LatLon; import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.OsmandApplication; import net.osmand.plus.Version; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter; +import net.osmand.plus.onlinerouting.engine.EngineType; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; -import net.osmand.util.GeoPolylineParserUtil; import org.apache.commons.logging.Log; import org.json.JSONArray; @@ -24,7 +25,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; -import java.net.URLConnection; +import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -35,14 +36,18 @@ public class OnlineRoutingHelper { private static final Log LOG = PlatformUtil.getLog(OnlineRoutingHelper.class); + private static final String ITEMS = "items"; + private static final String TYPE = "type"; + private static final String PARAMS = "params"; + private OsmandApplication app; private OsmandSettings settings; private Map cachedEngines; - public OnlineRoutingHelper(OsmandApplication app) { + public OnlineRoutingHelper(@NonNull OsmandApplication app) { this.app = app; this.settings = app.getSettings(); - loadFromSettings(); + this.cachedEngines = loadSavedEngines(); } @NonNull @@ -50,104 +55,42 @@ public class OnlineRoutingHelper { return new ArrayList<>(cachedEngines.values()); } - public OnlineRoutingEngine getEngineByKey(String stringKey) { + @NonNull + public List getEnginesExceptMentioned(@Nullable String ... excludeKeys) { + List engines = getEngines(); + if (excludeKeys != null) { + for (String key : excludeKeys) { + OnlineRoutingEngine engine = getEngineByKey(key); + engines.remove(engine); + } + } + return engines; + } + + @Nullable + public OnlineRoutingEngine getEngineByKey(@Nullable String stringKey) { return cachedEngines.get(stringKey); } + @NonNull public List calculateRouteOnline(@NonNull OnlineRoutingEngine engine, @NonNull List path) throws IOException, JSONException { - String fullUrl = createFullUrl(engine, path); - String content = makeRequest(fullUrl); - return parseResponse(engine, content); + String url = engine.getFullUrl(path); + String content = makeRequest(url); + return engine.parseServerResponse(content); } - public String createFullUrl(OnlineRoutingEngine engine, List path) { - StringBuilder sb = new StringBuilder(engine.getBaseUrl()); - String vehicle = engine.getVehicleKey(); - String apiKey = engine.getParameter(EngineParameter.API_KEY); - switch (engine.getType()) { - - case GRAPHHOPPER: - sb.append("?"); - for (LatLon point : path) { - sb.append("point=") - .append(point.getLatitude()) - .append(',') - .append(point.getLongitude()) - .append('&'); - } - sb.append("vehicle=").append(vehicle); - - if (!Algorithms.isEmpty(apiKey)) { - sb.append('&').append("key=").append(apiKey); - } - break; - - case OSRM: - sb.append(vehicle).append('/'); - 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(';'); - } - } - break; - - case ORS: - if (path.size() > 1) { - sb.append("driving-car").append('?'); // todo only for testing - if (!Algorithms.isEmpty(apiKey)) { - sb.append("api_key=").append(apiKey); - } - LatLon start = path.get(0); - LatLon end = path.get(path.size() - 1); - sb.append('&').append("start=") - .append(start.getLatitude()).append(',').append(start.getLongitude()); - sb.append('&').append("end=") - .append(end.getLatitude()).append(',').append(end.getLongitude()); - } - break; - - } - return sb.toString(); - } - - private List parseResponse(OnlineRoutingEngine engine, String content) throws JSONException { - JSONObject obj = new JSONObject(content); - - switch (engine.getType()) { - - case GRAPHHOPPER: - return GeoPolylineParserUtil.parse( - obj.getJSONArray("paths").getJSONObject(0).getString("points"), - GeoPolylineParserUtil.PRECISION_5); - - case OSRM: - return GeoPolylineParserUtil.parse( - obj.getJSONArray("routes").getJSONObject(0).getString("geometry"), - GeoPolylineParserUtil.PRECISION_5); - - case ORS: - JSONArray array = obj.getJSONArray("features").getJSONObject(0) - .getJSONObject("geometry").getJSONArray("coordinates"); - List track = new ArrayList<>(); - for (int i = 0; i < array.length(); i++) { - JSONArray point = array.getJSONArray(i); - double lat = Double.parseDouble(point.getString(0)); - double lon = Double.parseDouble(point.getString(1)); - track.add(new LatLon(lat, lon)); - } - return track; - } - return new ArrayList<>(); - } - - private String makeRequest(String url) throws IOException { - URLConnection connection = NetworkUtils.getHttpURLConnection(url); + @NonNull + public String makeRequest(@NonNull String url) throws IOException { + HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url); connection.setRequestProperty("User-Agent", Version.getFullVersion(app)); StringBuilder content = new StringBuilder(); - BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + BufferedReader reader; + if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { + reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + } else { + reader = new BufferedReader(new InputStreamReader(connection.getErrorStream())); + } String s; while ((s = reader.readLine()) != null) { content.append(s); @@ -160,32 +103,49 @@ public class OnlineRoutingHelper { } public void saveEngine(@NonNull OnlineRoutingEngine engine) { - String stringKey = engine.getStringKey(); - cachedEngines.put(stringKey, engine); - saveToSettings(); - } - - public void deleteEngine(@NonNull String stringKey) { - OnlineRoutingEngine engine = getEngineByKey(stringKey); - if (engine != null) { - deleteEngine(engine); - } + deleteInaccessibleParameters(engine); + String key = createEngineKeyIfNeeded(engine); + cachedEngines.put(key, engine); + saveCacheToSettings(); } public void deleteEngine(@NonNull OnlineRoutingEngine engine) { String stringKey = engine.getStringKey(); - if (cachedEngines.containsKey(stringKey)) { + deleteEngine(stringKey); + } + + public void deleteEngine(@Nullable String stringKey) { + if (stringKey != null) { cachedEngines.remove(stringKey); - saveToSettings(); + saveCacheToSettings(); } } - private void loadFromSettings() { + private void deleteInaccessibleParameters(@NonNull OnlineRoutingEngine engine) { + for (EngineParameter key : EngineParameter.values()) { + if (!engine.isParameterAllowed(key)) { + engine.remove(key); + } + } + } + + @NonNull + private String createEngineKeyIfNeeded(@NonNull OnlineRoutingEngine engine) { + String key = engine.get(EngineParameter.KEY); + if (Algorithms.isEmpty(key)) { + key = OnlineRoutingEngine.generateKey(); + engine.put(EngineParameter.KEY, key); + } + return key; + } + + @NonNull + private Map loadSavedEngines() { Map cachedEngines = new LinkedHashMap<>(); for (OnlineRoutingEngine engine : readFromSettings()) { cachedEngines.put(engine.getStringKey(), engine); } - this.cachedEngines = cachedEngines; + return cachedEngines; } @NonNull @@ -196,14 +156,14 @@ public class OnlineRoutingHelper { try { JSONObject json = new JSONObject(jsonString); readFromJson(json, engines); - } catch (JSONException e) { + } catch (JSONException | IllegalArgumentException e) { LOG.debug("Error when reading engines from JSON ", e); } } return engines; } - private void saveToSettings() { + private void saveCacheToSettings() { if (!Algorithms.isEmpty(cachedEngines)) { try { JSONObject json = new JSONObject(); @@ -217,38 +177,44 @@ public class OnlineRoutingHelper { } } - public static void readFromJson(JSONObject json, List engines) throws JSONException { + public static void readFromJson(@NonNull JSONObject json, + @NonNull List engines) throws JSONException { if (!json.has("items")) { return; } Gson gson = new Gson(); - Type type = new TypeToken>() { + Type typeToken = new TypeToken>() { }.getType(); - JSONArray itemsJson = json.getJSONArray("items"); + JSONArray itemsJson = json.getJSONArray(ITEMS); for (int i = 0; i < itemsJson.length(); i++) { JSONObject object = itemsJson.getJSONObject(i); - String key = object.getString("key"); - String vehicleKey = object.getString("vehicle"); - EngineType engineType = EngineType.valueOf(object.getString("type")); - String paramsString = object.getString("params"); - HashMap params = gson.fromJson(paramsString, type); - engines.add(new OnlineRoutingEngine(key, engineType, vehicleKey, params)); + if (object.has(TYPE) && object.has(PARAMS)) { + EngineType type = EngineType.getTypeByName(object.getString(TYPE)); + String paramsString = object.getString(PARAMS); + HashMap params = gson.fromJson(paramsString, typeToken); + OnlineRoutingEngine engine = OnlineRoutingFactory.createEngine(type, params); + if (!Algorithms.isEmpty(engine.getStringKey())) { + engines.add(engine); + } + } } } - public static void writeToJson(JSONObject json, List engines) throws JSONException { + public static void writeToJson(@NonNull JSONObject json, + @NonNull List engines) throws JSONException { JSONArray jsonArray = new JSONArray(); Gson gson = new Gson(); Type type = new TypeToken>() { }.getType(); for (OnlineRoutingEngine engine : engines) { + if (Algorithms.isEmpty(engine.getStringKey())) { + continue; + } JSONObject jsonObject = new JSONObject(); - jsonObject.put("key", engine.getStringKey()); - jsonObject.put("type", engine.getType().name()); - jsonObject.put("vehicle", engine.getVehicleKey()); - jsonObject.put("params", gson.toJson(engine.getParams(), type)); + jsonObject.put(TYPE, engine.getType().name()); + jsonObject.put(PARAMS, gson.toJson(engine.getParams(), type)); jsonArray.put(jsonObject); } - json.put("items", jsonArray); + json.put(ITEMS, jsonArray); } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java index 3e3fea6660..9936f8efbf 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/VehicleType.java @@ -3,48 +3,26 @@ package net.osmand.plus.onlinerouting; import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; -import net.osmand.plus.R; -import net.osmand.util.Algorithms; +public class VehicleType { + private final String key; + @StringRes + private final int titleId; -public enum VehicleType { - CAR("car", R.string.routing_engine_vehicle_type_car), - BIKE("bike", R.string.routing_engine_vehicle_type_bike), - FOOT("foot", R.string.routing_engine_vehicle_type_foot), - DRIVING("driving", R.string.routing_engine_vehicle_type_driving), - CUSTOM("", R.string.shared_string_custom); - - VehicleType(String key, int titleId) { + public VehicleType(@NonNull String key, + @StringRes int titleId) { this.key = key; this.titleId = titleId; } - private String key; - private int titleId; - + @NonNull public String getKey() { return key; } - public String getTitle(Context ctx) { + @NonNull + public String getTitle(@NonNull Context ctx) { return ctx.getString(titleId); } - - public static String toHumanString(@NonNull Context ctx, - @NonNull String key) { - VehicleType vehicleType = getVehicleByKey(key); - if (vehicleType == CUSTOM) { - return Algorithms.capitalizeFirstLetter(key); - } - return vehicleType.getTitle(ctx); - } - - public static VehicleType getVehicleByKey(String key) { - for (VehicleType v : values()) { - if (Algorithms.objectEquals(v.getKey(), key)) { - return v; - } - } - return CUSTOM; - } -} \ No newline at end of file +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java new file mode 100644 index 0000000000..431ad33a3d --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -0,0 +1,34 @@ +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"); + + private final String title; + + EngineType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + @NonNull + public static EngineType getTypeByName(@Nullable String name) { + if (!Algorithms.isEmpty(name)) { + for (EngineType type : values()) { + if (type.name().equals(name)) { + return type; + } + } + } + return values()[0]; + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java new file mode 100644 index 0000000000..d676e1e154 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -0,0 +1,95 @@ +package net.osmand.plus.onlinerouting.engine; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +import net.osmand.plus.R; +import net.osmand.plus.onlinerouting.EngineParameter; +import net.osmand.plus.onlinerouting.VehicleType; +import net.osmand.util.GeoPolylineParserUtil; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; +import java.util.Map; + +import static net.osmand.util.Algorithms.isEmpty; + +public class GraphhopperEngine extends OnlineRoutingEngine { + + public GraphhopperEngine(@Nullable Map params) { + super(params); + } + + @Override + public @NonNull EngineType getType() { + return EngineType.GRAPHHOPPER; + } + + @NonNull + @Override + public String getStandardUrl() { + return "https://graphhopper.com/api/1/route"; + } + + @Override + protected void collectAllowedParameters() { + allowParameters(EngineParameter.API_KEY); + } + + @Override + protected void collectAllowedVehicles(@NonNull List vehicles) { + vehicles.add(new VehicleType("car", R.string.routing_engine_vehicle_type_car)); + vehicles.add(new VehicleType("bike", R.string.routing_engine_vehicle_type_bike)); + vehicles.add(new VehicleType("foot", R.string.routing_engine_vehicle_type_foot)); + vehicles.add(new VehicleType("hike", R.string.routing_engine_vehicle_type_hiking)); + vehicles.add(new VehicleType("mtb", R.string.routing_engine_vehicle_type_mtb)); + vehicles.add(new VehicleType("racingbike", R.string.routing_engine_vehicle_type_racingbike)); + vehicles.add(new VehicleType("scooter", R.string.routing_engine_vehicle_type_scooter)); + vehicles.add(new VehicleType("truck", R.string.routing_engine_vehicle_type_truck)); + vehicles.add(new VehicleType("small_truck", R.string.routing_engine_vehicle_type_small_truck)); + } + + @Override + protected void makeFullUrl(@NonNull StringBuilder sb, + @NonNull List path) { + sb.append("?"); + for (LatLon point : path) { + sb.append("point=") + .append(point.getLatitude()) + .append(',') + .append(point.getLongitude()) + .append('&'); + } + String vehicle = get(EngineParameter.VEHICLE_KEY); + if (isEmpty(vehicle)) { + sb.append("vehicle=").append(vehicle); + } + String apiKey = get(EngineParameter.API_KEY); + if (isEmpty(apiKey)) { + sb.append('&').append("key=").append(apiKey); + } + } + + @NonNull + @Override + public List parseServerResponse(@NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + return GeoPolylineParserUtil.parse( + obj.getJSONArray("paths").getJSONObject(0).getString("points"), + GeoPolylineParserUtil.PRECISION_5); + } + + @Override + public boolean parseServerMessage(@NonNull StringBuilder sb, + @NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + if (obj.has("message")) { + String message = obj.getString("message"); + sb.append(message); + } + return obj.has("paths"); + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java new file mode 100644 index 0000000000..e3f2d416ce --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -0,0 +1,205 @@ +package net.osmand.plus.onlinerouting.engine; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +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.util.Algorithms; + +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static net.osmand.util.Algorithms.isEmpty; + +public abstract class OnlineRoutingEngine implements Cloneable { + + public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_"; + public static final 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<>(); + + public OnlineRoutingEngine(@Nullable Map params) { + if (!isEmpty(params)) { + this.params.putAll(params); + } + collectAllowedVehiclesInternal(); + collectAllowedParametersInternal(); + } + + @NonNull + public abstract EngineType getType(); + + @Nullable + public String getStringKey() { + return get(EngineParameter.KEY); + } + + @NonNull + public String getName(@NonNull Context ctx) { + String customName = get(EngineParameter.CUSTOM_NAME); + if (customName != null) { + return customName; + } else { + return getStandardName(ctx); + } + } + + @NonNull + private String getStandardName(@NonNull Context ctx) { + String base = getBaseName(ctx); + String index = get(EngineParameter.NAME_INDEX); + return !isEmpty(index) ? base + " " + index : base; + } + + @NonNull + public String getBaseName(@NonNull Context ctx) { + String vehicleTitle = getSelectedVehicleName(ctx); + if (isEmpty(vehicleTitle)) { + return getType().getTitle(); + } else { + String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_dash); + return String.format(pattern, getType().getTitle(), vehicleTitle); + } + } + + @NonNull + public String getBaseUrl() { + String customUrl = get(EngineParameter.CUSTOM_URL); + if (isEmpty(customUrl)) { + return getStandardUrl(); + } + return customUrl; + } + + @NonNull + public String getFullUrl(@NonNull List path) { + StringBuilder sb = new StringBuilder(getBaseUrl()); + makeFullUrl(sb, path); + return sb.toString(); + } + + protected abstract void makeFullUrl(@NonNull StringBuilder sb, + @NonNull List path); + + @NonNull + public abstract List parseServerResponse(@NonNull String content) throws JSONException; + + @NonNull + public abstract String getStandardUrl(); + + @NonNull + public Map getParams() { + return params; + } + + @Nullable + public String get(@NonNull EngineParameter key) { + return params.get(key.name()); + } + + public void put(@NonNull EngineParameter key, @NonNull String value) { + params.put(key.name(), value); + } + + public void remove(@NonNull EngineParameter key) { + params.remove(key.name()); + } + + private void collectAllowedVehiclesInternal() { + allowedVehicles.clear(); + collectAllowedVehicles(allowedVehicles); + allowedVehicles.add(CUSTOM_VEHICLE); + } + + protected abstract void collectAllowedVehicles(@NonNull List vehicles); + + @NonNull + public List getAllowedVehicles() { + 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(); + + 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); + VehicleType vt = getVehicleTypeByKey(key); + if (!vt.equals(CUSTOM_VEHICLE)) { + return vt.getTitle(ctx); + } + return key != null ? Algorithms.capitalizeFirstLetter(key) : null; + } + + @NonNull + public VehicleType getSelectedVehicleType() { + String key = get(EngineParameter.VEHICLE_KEY); + return getVehicleTypeByKey(key); + } + + @NonNull + public VehicleType getVehicleTypeByKey(@Nullable String vehicleKey) { + if (!isEmpty(vehicleKey)) { + for (VehicleType vt : allowedVehicles) { + if (Algorithms.objectEquals(vt.getKey(), vehicleKey)) { + return vt; + } + } + } + return CUSTOM_VEHICLE; + } + + public abstract boolean parseServerMessage(@NonNull StringBuilder sb, + @NonNull String content) throws JSONException; + + @NonNull + @Override + public Object clone() { + return OnlineRoutingFactory.createEngine(getType(), getParams()); + } + + @NonNull + public static String generateKey() { + return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OnlineRoutingEngine)) return false; + + OnlineRoutingEngine engine = (OnlineRoutingEngine) o; + if (getType() != engine.getType()) return false; + return Algorithms.objectEquals(getParams(), engine.getParams()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java new file mode 100644 index 0000000000..594e7e1b36 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -0,0 +1,104 @@ +package net.osmand.plus.onlinerouting.engine; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +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 static net.osmand.util.Algorithms.isEmpty; + +public class OrsEngine extends OnlineRoutingEngine { + + public OrsEngine(@Nullable Map params) { + super(params); + } + + @Override + public @NonNull EngineType getType() { + return EngineType.ORS; + } + + @NonNull + @Override + public String getStandardUrl() { + return "https://api.openrouteservice.org/v2/directions/"; + } + + @Override + protected void collectAllowedParameters() { + allowParameters(EngineParameter.API_KEY); + } + + @Override + protected void collectAllowedVehicles(@NonNull List vehicles) { + vehicles.add(new VehicleType("driving-car", R.string.routing_engine_vehicle_type_car)); + vehicles.add(new VehicleType("driving-hgv", R.string.routing_engine_vehicle_type_hgv)); + vehicles.add(new VehicleType("cycling-regular", R.string.routing_engine_vehicle_type_cycling_regular)); + vehicles.add(new VehicleType("cycling-road", R.string.routing_engine_vehicle_type_cycling_road)); + vehicles.add(new VehicleType("cycling-mountain", R.string.routing_engine_vehicle_type_cycling_mountain)); + vehicles.add(new VehicleType("cycling-electric", R.string.routing_engine_vehicle_type_cycling_electric)); + vehicles.add(new VehicleType("foot-walking", R.string.routing_engine_vehicle_type_walking)); + vehicles.add(new VehicleType("foot-hiking", R.string.routing_engine_vehicle_type_hiking)); + vehicles.add(new VehicleType("wheelchair", R.string.routing_engine_vehicle_type_wheelchair)); + } + + @Override + protected void makeFullUrl(@NonNull StringBuilder sb, + @NonNull List path) { + if (path.size() > 1) { + String vehicleKey = get(EngineParameter.VEHICLE_KEY); + if (!isEmpty(vehicleKey)) { + sb.append(vehicleKey); + } + sb.append('?'); + String apiKey = get(EngineParameter.API_KEY); + if (!isEmpty(apiKey)) { + sb.append("api_key=").append(apiKey); + } + LatLon start = path.get(0); + LatLon end = path.get(path.size() - 1); + sb.append('&').append("start=") + .append(start.getLatitude()).append(',').append(start.getLongitude()); + sb.append('&').append("end=") + .append(end.getLatitude()).append(',').append(end.getLongitude()); + } + } + + @NonNull + @Override + public List parseServerResponse(@NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + JSONArray array = obj.getJSONArray("features").getJSONObject(0) + .getJSONObject("geometry").getJSONArray("coordinates"); + List track = new ArrayList<>(); + for (int i = 0; i < array.length(); i++) { + JSONArray point = array.getJSONArray(i); + double lat = Double.parseDouble(point.getString(0)); + double lon = Double.parseDouble(point.getString(1)); + track.add(new LatLon(lat, lon)); + } + return track; + } + + @Override + public boolean parseServerMessage(@NonNull StringBuilder sb, + @NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + if (obj.has("error")) { + String message = obj.getString("error"); + sb.append(message); + } + return obj.has("features"); + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java new file mode 100644 index 0000000000..1ef9c1a622 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -0,0 +1,84 @@ +package net.osmand.plus.onlinerouting.engine; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.data.LatLon; +import net.osmand.plus.R; +import net.osmand.plus.onlinerouting.EngineParameter; +import net.osmand.plus.onlinerouting.VehicleType; +import net.osmand.util.GeoPolylineParserUtil; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; +import java.util.Map; + +import static net.osmand.util.Algorithms.isEmpty; + +public class OsrmEngine extends OnlineRoutingEngine { + + public OsrmEngine(@Nullable Map params) { + super(params); + } + + @Override + public @NonNull EngineType getType() { + return EngineType.OSRM; + } + + @NonNull + @Override + public String getStandardUrl() { + return "https://router.project-osrm.org/route/v1/"; + } + + @Override + protected void collectAllowedParameters() { } + + @Override + protected void collectAllowedVehicles(@NonNull List vehicles) { + vehicles.add(new VehicleType("car", R.string.routing_engine_vehicle_type_car)); + vehicles.add(new VehicleType("bike", R.string.routing_engine_vehicle_type_bike)); + vehicles.add(new VehicleType("foot", R.string.routing_engine_vehicle_type_foot)); + } + + @Override + protected void makeFullUrl(@NonNull StringBuilder sb, + @NonNull List path) { + String vehicleKey = get(EngineParameter.VEHICLE_KEY); + if (!isEmpty(vehicleKey)) { + sb.append(vehicleKey).append('/'); + } + 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(';'); + } + } + sb.append('?'); + sb.append("overview=full"); + } + + @NonNull + @Override + public List parseServerResponse(@NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + return GeoPolylineParserUtil.parse( + obj.getJSONArray("routes").getJSONObject(0).getString("geometry"), + GeoPolylineParserUtil.PRECISION_5); + } + + @Override + public boolean parseServerMessage(@NonNull StringBuilder sb, + @NonNull String content) throws JSONException { + JSONObject obj = new JSONObject(content); + if (obj.has("message")) { + String message = obj.getString("message"); + sb.append(message); + } + return obj.has("routes"); + } +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/ui/ExampleLocation.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/ExampleLocation.java new file mode 100644 index 0000000000..0a384002f7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/ExampleLocation.java @@ -0,0 +1,52 @@ +package net.osmand.plus.onlinerouting.ui; + +import androidx.annotation.NonNull; + +import net.osmand.data.LatLon; + +public enum ExampleLocation { + + AMSTERDAM("Amsterdam", + new LatLon(52.379189, 4.899431), + new LatLon(52.308056, 4.764167)), + + BERLIN("Berlin", + new LatLon(52.520008, 13.404954), + new LatLon(52.3666652, 13.501997992)), + + NEW_YORK("New York", + new LatLon(43.000000, -75.000000), + new LatLon(40.641766, -73.780968)), + + PARIS("Paris", + new LatLon(48.864716, 2.349014), + new LatLon(48.948437, 2.434931)); + + ExampleLocation(@NonNull String name, + @NonNull LatLon cityCenterLatLon, + @NonNull LatLon cityAirportLatLon) { + this.name = name; + this.cityCenterLatLon = cityCenterLatLon; + this.cityAirportLatLon = cityAirportLatLon; + } + + private String name; + private LatLon cityCenterLatLon; + private LatLon cityAirportLatLon; + + @NonNull + public String getName() { + return name; + } + + @NonNull + public LatLon getCityCenterLatLon() { + return cityCenterLatLon; + } + + @NonNull + public LatLon getCityAirportLatLon() { + return cityAirportLatLon; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingCard.java similarity index 82% rename from OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java rename to OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingCard.java index 888216abb3..cb40a2a192 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingCard.java @@ -1,4 +1,4 @@ -package net.osmand.plus.onlinerouting; +package net.osmand.plus.onlinerouting.ui; import android.text.Editable; import android.text.TextWatcher; @@ -10,6 +10,7 @@ import android.widget.EditText; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -42,9 +43,12 @@ public class OnlineRoutingCard extends BaseCard { private OsmandTextFieldBoxes textFieldBoxes; private EditText editText; private TextView tvHelperText; + private TextView tvErrorText; private View bottomDivider; private View button; private OnTextChangedListener onTextChangedListener; + private boolean fieldBoxHelperTextShowed; + private ApplicationMode appMode; public OnlineRoutingCard(@NonNull MapActivity mapActivity, boolean nightMode, ApplicationMode appMode) { @@ -69,6 +73,7 @@ public class OnlineRoutingCard extends BaseCard { textFieldBoxes = view.findViewById(R.id.field_box); editText = view.findViewById(R.id.edit_text); tvHelperText = view.findViewById(R.id.helper_text); + tvErrorText = view.findViewById(R.id.error_text); bottomDivider = view.findViewById(R.id.bottom_divider); button = view.findViewById(R.id.button); @@ -88,7 +93,7 @@ public class OnlineRoutingCard extends BaseCard { public void afterTextChanged(Editable s) { if (onTextChangedListener != null) { boolean editedByUser = editText.getTag() == null; - String text = editText.getText().toString(); + String text = editText.getText().toString().trim(); onTextChangedListener.onTextChanged(editedByUser, text); } } @@ -115,9 +120,9 @@ public class OnlineRoutingCard extends BaseCard { tvHeaderSubtitle.setText(subtitle); } - public void setSelectionMenu(List items, - String selectedItemTitle, - final CallbackWithObject callback) { + public void setSelectionMenu(@NonNull List items, + @NonNull String selectedItemTitle, + @NonNull final CallbackWithObject callback) { showElements(rvSelectionMenu); rvSelectionMenu.setLayoutManager( new LinearLayoutManager(app, RecyclerView.HORIZONTAL, false)); @@ -152,15 +157,31 @@ public class OnlineRoutingCard extends BaseCard { public void setFieldBoxHelperText(@NonNull String helperText) { showElements(fieldBoxContainer, tvHelperText); + fieldBoxHelperTextShowed = true; tvHelperText.setText(helperText); } + public void showFieldBoxError(@NonNull String errorText) { + showElements(fieldBoxContainer, tvErrorText); + hideElements(tvHelperText); + tvErrorText.setText(errorText); + } + + public void hideFieldBoxError() { + hideElements(tvErrorText); + if (fieldBoxHelperTextShowed) { + showElements(tvHelperText); + } + } + public void setEditedText(@NonNull String text) { - editText.setTag(""); // needed to indicate that the text was edited programmatically + showElements(fieldBoxContainer); + editText.setTag(""); // indicate that the text was edited programmatically editText.setText(text); editText.setTag(null); } + @NonNull public String getEditedText() { return editText.getText().toString(); } @@ -169,7 +190,8 @@ public class OnlineRoutingCard extends BaseCard { showElements(bottomDivider); } - public void setButton(String title, OnClickListener listener) { + public void setButton(@NonNull String title, + @NonNull OnClickListener listener) { showElements(button); button.setOnClickListener(listener); UiUtilities.setupDialogButton(nightMode, button, DialogButtonType.PRIMARY, title); @@ -199,11 +221,11 @@ public class OnlineRoutingCard extends BaseCard { AndroidUiHelper.setVisibility(View.GONE, views); } - public void setOnTextChangedListener(OnTextChangedListener onTextChangedListener) { + public void setOnTextChangedListener(@Nullable OnTextChangedListener onTextChangedListener) { this.onTextChangedListener = onTextChangedListener; } public interface OnTextChangedListener { - void onTextChanged(boolean editedByUser, String text); + void onTextChanged(boolean editedByUser, @NonNull String text); } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java similarity index 58% rename from OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java rename to OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java index 997b7fb34c..d362898275 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/ui/OnlineRoutingEngineFragment.java @@ -1,4 +1,4 @@ -package net.osmand.plus.onlinerouting; +package net.osmand.plus.onlinerouting.ui; import android.annotation.SuppressLint; import android.app.Activity; @@ -27,8 +27,6 @@ import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; -import net.osmand.AndroidNetworkUtils; -import net.osmand.AndroidNetworkUtils.OnRequestResultListener; import net.osmand.AndroidUtils; import net.osmand.CallbackWithObject; import net.osmand.data.LatLon; @@ -39,39 +37,37 @@ import net.osmand.plus.UiUtilities.DialogButtonType; 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.OnlineRoutingCard.OnTextChangedListener; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter; +import net.osmand.plus.onlinerouting.EngineParameter; +import net.osmand.plus.onlinerouting.OnlineRoutingFactory; +import net.osmand.plus.onlinerouting.OnlineRoutingHelper; +import net.osmand.plus.onlinerouting.VehicleType; +import net.osmand.plus.onlinerouting.ui.OnlineRoutingCard.OnTextChangedListener; +import net.osmand.plus.onlinerouting.engine.EngineType; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.util.Algorithms; import org.json.JSONException; -import org.json.JSONObject; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.CUSTOM_VEHICLE; + public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { public static final String TAG = OnlineRoutingEngineFragment.class.getSimpleName(); - private static final String ENGINE_NAME_KEY = "engine_name"; - private static final String ENGINE_SERVER_KEY = "engine_server"; - private static final String ENGINE_SERVER_URL_KEY = "engine_server_url"; - private static final String ENGINE_VEHICLE_TYPE_KEY = "engine_vehicle_type"; + private static final String ENGINE_TYPE_KEY = "engine_type"; private static final String ENGINE_CUSTOM_VEHICLE_KEY = "engine_custom_vehicle"; - private static final String ENGINE_API_KEY_KEY = "engine_api_key"; - private static final String INIT_ENGINE_NAME_KEY = "init_engine_name"; - private static final String INIT_ENGINE_SERVER_KEY = "init_engine_server"; - private static final String INIT_ENGINE_SERVER_URL_KEY = "init_engine_server_url"; - private static final String INIT_ENGINE_VEHICLE_TYPE_KEY = "init_engine_vehicle_type"; - private static final String INIT_ENGINE_CUSTOM_VEHICLE_KEY = "init_engine_custom_vehicle"; - private static final String INIT_ENGINE_API_KEY_KEY = "init_engine_api_key"; private static final String EXAMPLE_LOCATION_KEY = "example_location"; private static final String APP_MODE_KEY = "app_mode"; private static final String EDITED_ENGINE_KEY = "edited_engine_key"; private OsmandApplication app; + private ApplicationMode appMode; private MapActivity mapActivity; private OnlineRoutingHelper helper; @@ -83,66 +79,23 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { private OnlineRoutingCard apiKeyCard; private OnlineRoutingCard exampleCard; private View testResultsContainer; + private View saveButton; private ScrollView scrollView; private OnGlobalLayoutListener onGlobalLayout; private boolean isKeyboardShown = false; - private ApplicationMode appMode; - - private OnlineRoutingEngineObject engine; - private OnlineRoutingEngineObject initEngine; + private OnlineRoutingEngine engine; + private OnlineRoutingEngine initEngine; + private String customVehicleKey; private ExampleLocation selectedLocation; private String editedEngineKey; - private enum ExampleLocation { - - AMSTERDAM("Amsterdam", - new LatLon(52.379189, 4.899431), - new LatLon(52.308056, 4.764167)), - - BERLIN("Berlin", - new LatLon(52.520008, 13.404954), - new LatLon(52.3666652, 13.501997992)), - - NEW_YORK("New York", - new LatLon(43.000000, -75.000000), - new LatLon(40.641766, -73.780968)), - - PARIS("Paris", - new LatLon(48.864716, 2.349014), - new LatLon(48.948437, 2.434931)); - - ExampleLocation(String name, LatLon cityCenterLatLon, LatLon cityAirportLatLon) { - this.name = name; - this.cityCenterLatLon = cityCenterLatLon; - this.cityAirportLatLon = cityAirportLatLon; - } - - private String name; - private LatLon cityCenterLatLon; - private LatLon cityAirportLatLon; - - public String getName() { - return name; - } - - public LatLon getCityCenterLatLon() { - return cityCenterLatLon; - } - - public LatLon getCityAirportLatLon() { - return cityAirportLatLon; - } - } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); app = requireMyApplication(); mapActivity = getMapActivity(); helper = app.getOnlineRoutingHelper(); - engine = new OnlineRoutingEngineObject(); - initEngine = new OnlineRoutingEngineObject(); if (savedInstanceState != null) { restoreState(savedInstanceState); } else { @@ -179,10 +132,9 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { setupApiKeyCard(); setupExampleCard(); setupResultsContainer(); - addSpaceSegment(); - setupButtons(); + generateUniqueNameIfNeeded(); updateCardViews(nameCard, typeCard, vehicleCard, exampleCard); scrollView.setOnTouchListener(new View.OnTouchListener() { @@ -250,13 +202,33 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { return view; } - @Override - public void onDestroyView() { - super.onDestroyView(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayout); + private void setupToolbar(Toolbar toolbar) { + ImageView navigationIcon = toolbar.findViewById(R.id.close_button); + navigationIcon.setImageResource(R.drawable.ic_action_close); + navigationIcon.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + showExitDialog(); + } + }); + TextView title = toolbar.findViewById(R.id.toolbar_title); + toolbar.findViewById(R.id.toolbar_subtitle).setVisibility(View.GONE); + View actionBtn = toolbar.findViewById(R.id.action_button); + if (isEditingMode()) { + title.setText(getString(R.string.edit_online_routing_engine)); + ImageView ivBtn = toolbar.findViewById(R.id.action_button_icon); + ivBtn.setImageDrawable( + getIcon(R.drawable.ic_action_delete_dark, R.color.color_osm_edit_delete)); + actionBtn.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onDeleteEngine(); + dismiss(); + } + }); } else { - view.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayout); + title.setText(getString(R.string.add_online_routing_engine)); + actionBtn.setVisibility(View.GONE); } } @@ -268,9 +240,10 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { nameCard.setFieldBoxLabelText(getString(R.string.shared_string_name)); nameCard.setOnTextChangedListener(new OnTextChangedListener() { @Override - public void onTextChanged(boolean changedByUser, String text) { + public void onTextChanged(boolean changedByUser, @NonNull String text) { if (changedByUser) { - engine.customName = text; + engine.put(EngineParameter.CUSTOM_NAME, text); + checkCustomNameUnique(engine); } } }); @@ -286,14 +259,13 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { for (EngineType server : EngineType.values()) { serverItems.add(new HorizontalSelectionItem(server.getTitle(), server)); } - typeCard.setSelectionMenu(serverItems, engine.type.getTitle(), + typeCard.setSelectionMenu(serverItems, engine.getType().getTitle(), new CallbackWithObject() { @Override public boolean processResult(HorizontalSelectionItem result) { EngineType type = (EngineType) result.getObject(); - if (engine.type != type) { - engine.type = type; - updateCardViews(nameCard, typeCard, exampleCard); + if (engine.getType() != type) { + changeEngineType(type); return true; } return false; @@ -301,9 +273,9 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { }); typeCard.setOnTextChangedListener(new OnTextChangedListener() { @Override - public void onTextChanged(boolean editedByUser, String text) { + public void onTextChanged(boolean editedByUser, @NonNull String text) { if (editedByUser) { - engine.customServerUrl = text; + engine.put(EngineParameter.CUSTOM_URL, text); updateCardViews(exampleCard); } } @@ -317,37 +289,44 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { vehicleCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); vehicleCard.build(mapActivity); vehicleCard.setHeaderTitle(getString(R.string.shared_string_vehicle)); + vehicleCard.setFieldBoxLabelText(getString(R.string.shared_string_custom)); + vehicleCard.setOnTextChangedListener(new OnTextChangedListener() { + @Override + public void onTextChanged(boolean editedByUser, @NonNull String text) { + if (editedByUser) { + customVehicleKey = text; + engine.put(EngineParameter.VEHICLE_KEY, customVehicleKey); + updateCardViews(nameCard, exampleCard); + } + } + }); + vehicleCard.setEditedText(customVehicleKey); + vehicleCard.setFieldBoxHelperText(getString(R.string.shared_string_enter_param)); + vehicleCard.showDivider(); + segmentsContainer.addView(vehicleCard.getView()); + setupVehicleTypes(); + } + + private void setupVehicleTypes() { List vehicleItems = new ArrayList<>(); - for (VehicleType vehicle : VehicleType.values()) { + for (VehicleType vehicle : engine.getAllowedVehicles()) { vehicleItems.add(new HorizontalSelectionItem(vehicle.getTitle(app), vehicle)); } - vehicleCard.setSelectionMenu(vehicleItems, engine.vehicleType.getTitle(app), + vehicleCard.setSelectionMenu(vehicleItems, engine.getSelectedVehicleType().getTitle(app), new CallbackWithObject() { @Override public boolean processResult(HorizontalSelectionItem result) { VehicleType vehicle = (VehicleType) result.getObject(); - if (engine.vehicleType != vehicle) { - engine.vehicleType = vehicle; + if (!Algorithms.objectEquals(engine.getSelectedVehicleType(), vehicle)) { + String vehicleKey = vehicle.equals(CUSTOM_VEHICLE) ? customVehicleKey : vehicle.getKey(); + engine.put(EngineParameter.VEHICLE_KEY, vehicleKey); + generateUniqueNameIfNeeded(); updateCardViews(nameCard, vehicleCard, exampleCard); return true; } return false; } }); - vehicleCard.setFieldBoxLabelText(getString(R.string.shared_string_custom)); - vehicleCard.setOnTextChangedListener(new OnTextChangedListener() { - @Override - public void onTextChanged(boolean editedByUser, String text) { - if (editedByUser) { - engine.customVehicleKey = text; - updateCardViews(nameCard, exampleCard); - } - } - }); - vehicleCard.setEditedText(engine.customVehicleKey); - vehicleCard.setFieldBoxHelperText(getString(R.string.shared_string_enter_param)); - vehicleCard.showDivider(); - segmentsContainer.addView(vehicleCard.getView()); } private void setupApiKeyCard() { @@ -355,12 +334,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { apiKeyCard.build(mapActivity); apiKeyCard.setHeaderTitle(getString(R.string.shared_string_api_key)); apiKeyCard.setFieldBoxLabelText(getString(R.string.keep_it_empty_if_not)); - apiKeyCard.setEditedText(engine.apiKey); + String apiKey = engine.get(EngineParameter.API_KEY); + if (apiKey != null) { + apiKeyCard.setEditedText(apiKey); + } apiKeyCard.showDivider(); apiKeyCard.setOnTextChangedListener(new OnTextChangedListener() { @Override - public void onTextChanged(boolean editedByUser, String text) { - engine.apiKey = text; + public void onTextChanged(boolean editedByUser, @NonNull String text) { + engine.put(EngineParameter.API_KEY, text); updateCardViews(exampleCard); } }); @@ -402,87 +384,10 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { private void setupResultsContainer() { testResultsContainer = getInflater().inflate( R.layout.bottom_sheet_item_with_descr_64dp, segmentsContainer, false); - testResultsContainer.setVisibility(View.GONE); + testResultsContainer.setVisibility(View.INVISIBLE); segmentsContainer.addView(testResultsContainer); } - private void addSpaceSegment() { - int space = (int) getResources().getDimension(R.dimen.empty_state_text_button_padding_top); - View bottomSpaceView = new View(app); - bottomSpaceView.setLayoutParams( - new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, space)); - segmentsContainer.addView(bottomSpaceView); - } - - private void setupToolbar(Toolbar toolbar) { - ImageView navigationIcon = toolbar.findViewById(R.id.close_button); - navigationIcon.setImageResource(R.drawable.ic_action_close); - navigationIcon.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - showExitDialog(); - } - }); - TextView title = toolbar.findViewById(R.id.toolbar_title); - toolbar.findViewById(R.id.toolbar_subtitle).setVisibility(View.GONE); - View actionBtn = toolbar.findViewById(R.id.action_button); - if (isEditingMode()) { - title.setText(getString(R.string.edit_online_routing_engine)); - ImageView ivBtn = toolbar.findViewById(R.id.action_button_icon); - ivBtn.setImageDrawable( - getIcon(R.drawable.ic_action_delete_dark, R.color.color_osm_edit_delete)); - actionBtn.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - deleteEngine(); - dismiss(); - } - }); - } else { - title.setText(getString(R.string.add_online_routing_engine)); - actionBtn.setVisibility(View.GONE); - } - } - - private void updateCardViews(BaseCard... cardsToUpdate) { - for (BaseCard card : cardsToUpdate) { - if (nameCard.equals(card)) { - if (Algorithms.isEmpty(engine.customName)) { - String name; - if (Algorithms.isEmpty(engine.getVehicleKey())) { - name = engine.type.getTitle(); - } else { - name = OnlineRoutingEngine.getStandardName(app, engine.type, engine.getVehicleKey()); - } - nameCard.setEditedText(name); - } - - } else if (typeCard.equals(card)) { - typeCard.setHeaderSubtitle(engine.type.getTitle()); - typeCard.setEditedText(engine.getBaseUrl()); - if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) { - apiKeyCard.show(); - } else { - apiKeyCard.hide(); - } - - } else if (vehicleCard.equals(card)) { - VehicleType vt = VehicleType.getVehicleByKey(engine.getVehicleKey()); - vehicleCard.setHeaderSubtitle(vt.getTitle(app)); - if (vt == VehicleType.CUSTOM) { - vehicleCard.showFieldBox(); - vehicleCard.setEditedText(engine.getVehicleKey()); - } else { - vehicleCard.hideFieldBox(); - } - int contentPadding = getResources().getDimensionPixelSize(R.dimen.content_padding); - vehicleCard.updateBottomMarginSelectionMenu(engine.vehicleType != VehicleType.CUSTOM ? 0 : contentPadding); - } else if (exampleCard.equals(card)) { - exampleCard.setEditedText(getTestUrl()); - } - } - } - private void setupButtons() { boolean nightMode = isNightMode(); View cancelButton = view.findViewById(R.id.dismiss_button); @@ -497,172 +402,167 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { view.findViewById(R.id.buttons_divider).setVisibility(View.VISIBLE); - View saveButton = view.findViewById(R.id.right_bottom_button); + saveButton = view.findViewById(R.id.right_bottom_button); UiUtilities.setupDialogButton(nightMode, saveButton, UiUtilities.DialogButtonType.PRIMARY, R.string.shared_string_save); saveButton.setVisibility(View.VISIBLE); saveButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - saveChanges(); + onSaveEngine(); dismiss(); } }); } - private void saveChanges() { - OnlineRoutingEngine engineToSave; - if (isEditingMode()) { - engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.type, engine.getVehicleKey()); + private void changeEngineType(EngineType type) { + OnlineRoutingEngine tmp = (OnlineRoutingEngine) engine.clone(); + engine = OnlineRoutingFactory.createEngine(type, tmp.getParams()); + + // after changing the type, select the vehicle + // with the same name that was selected before + VehicleType previous = tmp.getSelectedVehicleType(); + VehicleType next = null; + for (VehicleType vt : engine.getAllowedVehicles()) { + if (Algorithms.objectEquals(previous.getTitle(app), vt.getTitle(app))) { + next = vt; + break; + } + } + String vehicleKey; + if (next != null) { + vehicleKey = next.equals(CUSTOM_VEHICLE) ? customVehicleKey : next.getKey(); } else { - engineToSave = OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null); + vehicleKey = engine.getAllowedVehicles().get(0).getKey(); } + engine.put(EngineParameter.VEHICLE_KEY, vehicleKey); - engineToSave.putParameter(EngineParameter.CUSTOM_NAME, engine.customName); - engineToSave.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl); - if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) { - engineToSave.putParameter(EngineParameter.API_KEY, engine.apiKey); + setupVehicleTypes(); + generateUniqueNameIfNeeded(); + updateCardViews(nameCard, typeCard, vehicleCard, exampleCard); + } + + private void generateUniqueNameIfNeeded() { + if (engine.get(EngineParameter.CUSTOM_NAME) == null) { + engine.remove(EngineParameter.NAME_INDEX); + if (hasNameDuplicate(engine.getName(app))) { + int index = 0; + do { + engine.put(EngineParameter.NAME_INDEX, String.valueOf(++index)); + } while (hasNameDuplicate(engine.getName(app))); + } } - - helper.saveEngine(engineToSave); } - private void deleteEngine() { - helper.deleteEngine(editedEngineKey); - } - - private String getTestUrl() { - List path = new ArrayList<>(); - path.add(selectedLocation.getCityCenterLatLon()); - path.add(selectedLocation.getCityAirportLatLon()); - OnlineRoutingEngine tmpEngine = - OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null); - tmpEngine.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl); - tmpEngine.putParameter(EngineParameter.API_KEY, engine.apiKey); - return helper.createFullUrl(tmpEngine, path); - } - - private void testEngineWork() { - final EngineType type = engine.type; - final ExampleLocation location = selectedLocation; - AndroidNetworkUtils.sendRequestAsync(app, exampleCard.getEditedText(), null, - null, false, false, new OnRequestResultListener() { - @Override - public void onResult(String response) { - boolean resultOk = false; - if (response != null) { - try { - JSONObject obj = new JSONObject(response); - - if (type == EngineType.GRAPHHOPPER) { - resultOk = obj.has("paths"); - } else if (type == EngineType.OSRM) { - resultOk = obj.has("routes"); - } else if (type == EngineType.ORS) { - resultOk = obj.has("features"); - } - } catch (JSONException e) { - - } - } - showTestResults(resultOk, location); - } - }); - } - - private void showTestResults(boolean resultOk, ExampleLocation location) { - testResultsContainer.setVisibility(View.VISIBLE); - ImageView ivImage = testResultsContainer.findViewById(R.id.icon); - TextView tvTitle = testResultsContainer.findViewById(R.id.title); - TextView tvDescription = testResultsContainer.findViewById(R.id.description); - if (resultOk) { - ivImage.setImageDrawable(getContentIcon(R.drawable.ic_action_gdirections_dark)); - tvTitle.setText(getString(R.string.shared_string_ok)); + private void checkCustomNameUnique(@NonNull OnlineRoutingEngine engine) { + if (hasNameDuplicate(engine.getName(app))) { + nameCard.showFieldBoxError(getString(R.string.message_name_is_already_exists)); + saveButton.setEnabled(false); } else { - ivImage.setImageDrawable(getContentIcon(R.drawable.ic_action_alert)); - tvTitle.setText(getString(R.string.message_error_recheck_parameters)); + nameCard.hideFieldBoxError(); + saveButton.setEnabled(true); } - tvDescription.setText(location.getName()); + } + + private boolean hasNameDuplicate(@NonNull String name) { + for (OnlineRoutingEngine engine : helper.getEnginesExceptMentioned(editedEngineKey)) { + if (Algorithms.objectEquals(engine.getName(app), name)) { + return true; + } + } + return false; + } + + private void onSaveEngine() { + if (engine != null) { + helper.saveEngine(engine); + } + } + + private void onDeleteEngine() { + helper.deleteEngine(engine); } private boolean isEditingMode() { return editedEngineKey != null; } - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - saveState(outState); + private String getTestUrl() { + List path = new ArrayList<>(); + path.add(selectedLocation.getCityCenterLatLon()); + path.add(selectedLocation.getCityAirportLatLon()); + return engine.getFullUrl(path); } - private void saveState(Bundle outState) { - outState.putString(ENGINE_NAME_KEY, engine.customName); - outState.putString(ENGINE_SERVER_KEY, engine.type.name()); - outState.putString(ENGINE_SERVER_URL_KEY, engine.customServerUrl); - outState.putString(ENGINE_VEHICLE_TYPE_KEY, engine.vehicleType.name()); - outState.putString(ENGINE_CUSTOM_VEHICLE_KEY, engine.customVehicleKey); - outState.putString(ENGINE_API_KEY_KEY, engine.apiKey); - outState.putString(INIT_ENGINE_NAME_KEY, initEngine.customName); - outState.putString(INIT_ENGINE_SERVER_KEY, initEngine.type.name()); - outState.putString(INIT_ENGINE_SERVER_URL_KEY, initEngine.customServerUrl); - outState.putString(INIT_ENGINE_VEHICLE_TYPE_KEY, initEngine.vehicleType.name()); - outState.putString(INIT_ENGINE_CUSTOM_VEHICLE_KEY, initEngine.customVehicleKey); - outState.putString(INIT_ENGINE_API_KEY_KEY, initEngine.apiKey); - outState.putString(EXAMPLE_LOCATION_KEY, selectedLocation.name()); - if (appMode != null) { - outState.putString(APP_MODE_KEY, appMode.getStringKey()); - } - outState.putString(EDITED_ENGINE_KEY, editedEngineKey); - } - - private void restoreState(Bundle savedState) { - engine.customName = savedState.getString(ENGINE_NAME_KEY); - engine.type = EngineType.valueOf(savedState.getString(ENGINE_SERVER_KEY)); - engine.customServerUrl = savedState.getString(ENGINE_SERVER_URL_KEY); - engine.vehicleType = VehicleType.valueOf(savedState.getString(ENGINE_VEHICLE_TYPE_KEY)); - engine.customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY); - engine.apiKey = savedState.getString(ENGINE_API_KEY_KEY); - initEngine.customName = savedState.getString(INIT_ENGINE_NAME_KEY); - initEngine.type = EngineType.valueOf(savedState.getString(INIT_ENGINE_SERVER_KEY)); - initEngine.customServerUrl = savedState.getString(INIT_ENGINE_SERVER_URL_KEY); - initEngine.vehicleType = VehicleType.valueOf(savedState.getString(INIT_ENGINE_VEHICLE_TYPE_KEY)); - initEngine.customVehicleKey = savedState.getString(INIT_ENGINE_CUSTOM_VEHICLE_KEY); - initEngine.apiKey = savedState.getString(INIT_ENGINE_API_KEY_KEY); - selectedLocation = ExampleLocation.valueOf(savedState.getString(EXAMPLE_LOCATION_KEY)); - appMode = ApplicationMode.valueOfStringKey(savedState.getString(APP_MODE_KEY), null); - editedEngineKey = savedState.getString(EDITED_ENGINE_KEY); - } - - private void initState() { - engine.type = EngineType.values()[0]; - engine.vehicleType = VehicleType.values()[0]; - selectedLocation = ExampleLocation.values()[0]; - - if (isEditingMode()) { - OnlineRoutingEngine editedEngine = helper.getEngineByKey(editedEngineKey); - if (editedEngine != null) { - engine.customName = editedEngine.getParameter(EngineParameter.CUSTOM_NAME); - engine.type = editedEngine.getType(); - String vehicleKey = editedEngine.getVehicleKey(); - if (vehicleKey != null) { - VehicleType vehicleType = VehicleType.getVehicleByKey(vehicleKey); - if (vehicleType == VehicleType.CUSTOM) { - engine.customVehicleKey = vehicleKey; - } - engine.vehicleType = vehicleType; + private void testEngineWork() { + final OnlineRoutingEngine requestedEngine = (OnlineRoutingEngine) engine.clone(); + final ExampleLocation location = selectedLocation; + new Thread(new Runnable() { + @Override + public void run() { + StringBuilder message = new StringBuilder(); + boolean resultOk = false; + try { + String response = helper.makeRequest(exampleCard.getEditedText()); + resultOk = requestedEngine.parseServerMessage(message, response); + } catch (IOException | JSONException e) { + message.append(e.toString()); } - engine.apiKey = editedEngine.getParameter(EngineParameter.API_KEY); + showTestResults(resultOk, message.toString(), location); } - } - engine.cloneIn(initEngine); + }).start(); } - private void dismiss() { - FragmentActivity activity = getActivity(); - if (activity != null) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (!fragmentManager.isStateSaved()) { - fragmentManager.popBackStack(); + private void showTestResults(final boolean resultOk, + final @NonNull String message, + final @NonNull ExampleLocation location) { + app.runInUIThread(new Runnable() { + @Override + public void run() { + testResultsContainer.setVisibility(View.VISIBLE); + ImageView ivImage = testResultsContainer.findViewById(R.id.icon); + TextView tvTitle = testResultsContainer.findViewById(R.id.title); + TextView tvDescription = testResultsContainer.findViewById(R.id.description); + if (resultOk) { + ivImage.setImageDrawable(getContentIcon(R.drawable.ic_action_gdirections_dark)); + tvTitle.setText(getString(R.string.shared_string_ok)); + } else { + ivImage.setImageDrawable(getContentIcon(R.drawable.ic_action_alert)); + tvTitle.setText(String.format(getString(R.string.message_server_error), message)); + } + tvDescription.setText(location.getName()); + } + }); + } + + private void updateCardViews(@NonNull BaseCard... cardsToUpdate) { + for (BaseCard card : cardsToUpdate) { + if (nameCard.equals(card)) { + if (Algorithms.isEmpty(engine.get(EngineParameter.CUSTOM_NAME))) { + nameCard.setEditedText(engine.getName(app)); + } + + } else if (typeCard.equals(card)) { + typeCard.setHeaderSubtitle(engine.getType().getTitle()); + typeCard.setEditedText(engine.getBaseUrl()); + if (engine.isParameterAllowed(EngineParameter.API_KEY)) { + apiKeyCard.show(); + } else { + apiKeyCard.hide(); + } + + } else if (vehicleCard.equals(card)) { + VehicleType vt = engine.getSelectedVehicleType(); + vehicleCard.setHeaderSubtitle(vt.getTitle(app)); + if (vt.equals(CUSTOM_VEHICLE)) { + vehicleCard.showFieldBox(); + vehicleCard.setEditedText(customVehicleKey); + } else { + vehicleCard.hideFieldBox(); + } + + } else if (exampleCard.equals(card)) { + exampleCard.setEditedText(getTestUrl()); } } } @@ -670,9 +570,6 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { public void showExitDialog() { View focus = view.findFocus(); AndroidUtils.hideSoftKeyboard(mapActivity, focus); - if (engine.customName != null && initEngine.customName == null) { - initEngine.customName = initEngine.getName(app); - } if (!engine.equals(initEngine)) { AlertDialog.Builder dismissDialog = createWarningDialog(mapActivity, R.string.shared_string_dismiss, R.string.exit_without_saving, R.string.shared_string_cancel); @@ -697,8 +594,23 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { return warningDialog; } + private void dismiss() { + FragmentActivity activity = getActivity(); + if (activity != null) { + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } + } + } + private boolean isNightMode() { - return !app.getSettings().isLightContentForMode(appMode); + return !app.getSettings().isLightContentForMode(getAppMode()); + } + + @NonNull + private ApplicationMode getAppMode() { + return appMode != null ? appMode : app.getSettings().getApplicationMode(); } @Nullable @@ -715,9 +627,83 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { return UiUtilities.getInflater(mapActivity, isNightMode()); } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + view.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayout); + } else { + view.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayout); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + saveState(outState); + } + + private void saveState(@NonNull Bundle outState) { + outState.putString(ENGINE_TYPE_KEY, engine.getType().name()); + for (EngineParameter key : EngineParameter.values()) { + String value = engine.get(key); + if (value != null) { + outState.putString(key.name(), value); + } + } + outState.putString(ENGINE_CUSTOM_VEHICLE_KEY, customVehicleKey); + outState.putString(EXAMPLE_LOCATION_KEY, selectedLocation.name()); + outState.putString(APP_MODE_KEY, getAppMode().getStringKey()); + outState.putString(EDITED_ENGINE_KEY, editedEngineKey); + } + + private void restoreState(@NonNull Bundle savedState) { + initEngine = createInitStateEngine(); + String typeKey = savedState.getString(ENGINE_TYPE_KEY); + EngineType type = EngineType.getTypeByName(typeKey); + engine = OnlineRoutingFactory.createEngine(type); + for (EngineParameter key : EngineParameter.values()) { + String value = savedState.getString(key.name()); + if (value != null) { + engine.put(key, value); + } + } + customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY); + selectedLocation = ExampleLocation.valueOf(savedState.getString(EXAMPLE_LOCATION_KEY)); + appMode = ApplicationMode.valueOfStringKey(savedState.getString(APP_MODE_KEY), null); + editedEngineKey = savedState.getString(EngineParameter.KEY.name()); + } + + private void initState() { + initEngine = createInitStateEngine(); + selectedLocation = ExampleLocation.values()[0]; + engine = (OnlineRoutingEngine) initEngine.clone(); + if (Algorithms.objectEquals(engine.getSelectedVehicleType(), CUSTOM_VEHICLE)) { + customVehicleKey = engine.get(EngineParameter.VEHICLE_KEY); + } else { + customVehicleKey = ""; + } + } + + private OnlineRoutingEngine createInitStateEngine() { + OnlineRoutingEngine engine; + OnlineRoutingEngine editedEngine = helper.getEngineByKey(editedEngineKey); + if (editedEngine != null) { + engine = (OnlineRoutingEngine) editedEngine.clone(); + } else { + engine = OnlineRoutingFactory.createEngine(EngineType.values()[0]); + String vehicle = engine.getAllowedVehicles().get(0).getKey(); + engine.put(EngineParameter.VEHICLE_KEY, vehicle); + if (editedEngineKey != null) { + engine.put(EngineParameter.KEY, editedEngineKey); + } + } + return engine; + } + public static void showInstance(@NonNull FragmentActivity activity, - @NonNull ApplicationMode appMode, - String editedEngineKey) { + @NonNull ApplicationMode appMode, + @Nullable String editedEngineKey) { FragmentManager fm = activity.getSupportFragmentManager(); if (!fm.isStateSaved() && fm.findFragmentByTag(OnlineRoutingEngineFragment.TAG) == null) { OnlineRoutingEngineFragment fragment = new OnlineRoutingEngineFragment(); @@ -728,57 +714,4 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { .addToBackStack(TAG).commitAllowingStateLoss(); } } - - private static class OnlineRoutingEngineObject { - private String customName; - private EngineType type; - private String customServerUrl; - private VehicleType vehicleType; - private String customVehicleKey; - private String apiKey; - - public String getVehicleKey() { - if (vehicleType == VehicleType.CUSTOM) { - return customVehicleKey; - } - return vehicleType.getKey(); - } - - public String getName(Context ctx) { - if (customName != null) { - return customName; - } - return OnlineRoutingEngine.getStandardName(ctx, type, getVehicleKey()); - } - - public String getBaseUrl() { - if (Algorithms.isEmpty(customServerUrl)) { - return type.getStandardUrl(); - } - return customServerUrl; - } - - public void cloneIn(OnlineRoutingEngineObject clone) { - clone.customName = customName; - clone.type = type; - clone.customServerUrl = customServerUrl; - clone.vehicleType = vehicleType; - clone.customVehicleKey = customVehicleKey; - clone.apiKey = apiKey; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - - OnlineRoutingEngineObject engine = (OnlineRoutingEngineObject) obj; - if (!Algorithms.stringsEqual(customName, engine.customName)) return false; - if (type != engine.type) return false; - if (!Algorithms.stringsEqual(getBaseUrl(), engine.getBaseUrl())) return false; - if (vehicleType != engine.vehicleType) return false; - if (!Algorithms.stringsEqual(getVehicleKey(), engine.getVehicleKey())) return false; - return Algorithms.isEmpty(apiKey) ? Algorithms.isEmpty(engine.apiKey) : Algorithms.stringsEqual(apiKey, engine.apiKey); - } - } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/OnlineRoutingEngineDataObject.java b/OsmAnd/src/net/osmand/plus/profiles/OnlineRoutingEngineDataObject.java index 46a35ea67e..fd0f593462 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/OnlineRoutingEngineDataObject.java +++ b/OsmAnd/src/net/osmand/plus/profiles/OnlineRoutingEngineDataObject.java @@ -1,12 +1,27 @@ package net.osmand.plus.profiles; +import androidx.annotation.NonNull; + import net.osmand.plus.R; public class OnlineRoutingEngineDataObject extends ProfileDataObject { + private int order; + public OnlineRoutingEngineDataObject(String name, String description, - String stringKey) { + String stringKey, + int order) { super(name, description, stringKey, R.drawable.ic_world_globe_dark, false, null); + this.order = order; + } + + @Override + public int compareTo(@NonNull ProfileDataObject profileDataObject) { + if (profileDataObject instanceof OnlineRoutingEngineDataObject) { + OnlineRoutingEngineDataObject another = (OnlineRoutingEngineDataObject) profileDataObject; + return (this.order < another.order) ? -1 : ((this.order == another.order) ? 0 : 1); + } + return 0; } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java index 28967ba2f3..6306dee9cc 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java +++ b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java @@ -5,7 +5,7 @@ import android.content.Context; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.router.GeneralRouter; @@ -56,7 +56,22 @@ public class ProfileDataUtils { Collections.sort(fileNames, new Comparator() { @Override public int compare(String s, String t1) { - return s.equals(OSMAND_NAVIGATION) ? -1 : t1.equals(OSMAND_NAVIGATION) ? 1 : s.compareToIgnoreCase(t1); + // OsmAnd navigation should be at the top of the list + if (s.equals(OSMAND_NAVIGATION)) { + return -1; + } else if (t1.equals(OSMAND_NAVIGATION)) { + return 1; + + // Online navigation should be at the bottom of the list + } else if (s.equals(ONLINE_NAVIGATION)) { + return 1; + } else if (t1.equals(ONLINE_NAVIGATION)) { + return -1; + + // Other sorted by file names + } else { + return s.compareToIgnoreCase(t1); + } } }); for (String fileName : fileNames) { @@ -71,9 +86,11 @@ public class ProfileDataUtils { public static List getOnlineRoutingProfiles(OsmandApplication app) { List objects = new ArrayList<>(); - for (OnlineRoutingEngine engine : app.getOnlineRoutingHelper().getEngines()) { + List engines = app.getOnlineRoutingHelper().getEngines(); + for (int i = 0; i < engines.size(); i++) { + OnlineRoutingEngine engine = engines.get(i); objects.add(new OnlineRoutingEngineDataObject( - engine.getName(app), engine.getBaseUrl(), engine.getStringKey())); + engine.getName(app), engine.getBaseUrl(), engine.getStringKey(), i)); } return objects; } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java index 98ca4771cc..eb97a8ae85 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java @@ -39,8 +39,9 @@ import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.helpers.FontCache; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; -import net.osmand.plus.onlinerouting.OnlineRoutingEngineFragment; +import net.osmand.plus.onlinerouting.ui.OnlineRoutingEngineFragment; import net.osmand.router.RoutingConfiguration; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -250,7 +251,7 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet { tvTitle.setText(profile.getName()); tvDescription.setText(profile.getDescription()); - boolean isSelected = setupSelected && profile.getStringKey().equals(selectedItemKey); + boolean isSelected = setupSelected && Algorithms.objectEquals(profile.getStringKey(), selectedItemKey); int iconColor; if (dialogMode == DialogMode.NAVIGATION_PROFILE) { iconColor = isSelected ? activeColorResId : iconDefaultColorResId; diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 89c17f1c2b..96017bc96c 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -2,7 +2,6 @@ package net.osmand.plus.routing; import android.content.Context; -import android.os.Build; import android.os.Bundle; import android.util.Base64; @@ -20,16 +19,14 @@ import net.osmand.binary.BinaryMapIndexReader; import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.WptLocationPoint; -import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine; import net.osmand.plus.onlinerouting.OnlineRoutingHelper; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; -import net.osmand.plus.Version; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.router.GeneralRouter; @@ -48,21 +45,16 @@ import net.osmand.router.RoutingConfiguration.Builder; import net.osmand.router.RoutingContext; import net.osmand.router.TurnType; import net.osmand.util.Algorithms; -import net.osmand.util.GeoPolylineParserUtil; import net.osmand.util.MapUtils; import org.json.JSONException; -import org.json.JSONObject; import org.xml.sax.SAXException; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.MalformedURLException; -import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1210,8 +1202,12 @@ public class RouteProvider { private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException { OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper(); String stringKey = params.mode.getRoutingProfile(); - List route = helper.calculateRouteOnline(helper.getEngineByKey(stringKey), getFullPathFromParams(params)); - if (!route.isEmpty()) { + OnlineRoutingEngine engine = helper.getEngineByKey(stringKey); + List route = null; + if (engine != null) { + route = helper.calculateRouteOnline(engine, getFullPathFromParams(params)); + } + if (!Algorithms.isEmpty(route)) { List res = new ArrayList<>(); for (LatLon pt : route) { WptPt wpt = new WptPt(); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java index 779a97d1df..cf08142393 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java @@ -7,8 +7,9 @@ import androidx.annotation.Nullable; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine; -import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter; +import net.osmand.plus.onlinerouting.EngineParameter; +import net.osmand.plus.onlinerouting.OnlineRoutingFactory; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine; import net.osmand.plus.onlinerouting.OnlineRoutingHelper; import org.json.JSONException; @@ -93,8 +94,8 @@ public class OnlineRoutingSettingsItem extends CollectionSettingsItem