diff --git a/OsmAnd-api/src/net/osmand/aidlapi/IOsmAndAidlInterface.aidl b/OsmAnd-api/src/net/osmand/aidlapi/IOsmAndAidlInterface.aidl index ca19b48c83..92115f873b 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/IOsmAndAidlInterface.aidl +++ b/OsmAnd-api/src/net/osmand/aidlapi/IOsmAndAidlInterface.aidl @@ -92,6 +92,9 @@ import net.osmand.aidlapi.copyfile.CopyFileParams; import net.osmand.aidlapi.navigation.ANavigationUpdateParams; import net.osmand.aidlapi.navigation.ANavigationVoiceRouterMessageParams; +import net.osmand.aidlapi.navigation.ABlockedRoad; +import net.osmand.aidlapi.navigation.AddBlockedRoadParams; +import net.osmand.aidlapi.navigation.RemoveBlockedRoadParams; import net.osmand.aidlapi.contextmenu.ContextMenuButtonsParams; import net.osmand.aidlapi.contextmenu.UpdateContextMenuButtonsParams; @@ -892,4 +895,10 @@ interface IOsmAndAidlInterface { boolean selectProfile(in SelectProfileParams params); boolean getProfiles(out List profiles); + + boolean getBlockedRoads(out List blockedRoads); + + boolean addRoadBlock(in AddBlockedRoadParams params); + + boolean removeRoadBlock(in RemoveBlockedRoadParams params); } \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.aidl b/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.aidl new file mode 100644 index 0000000000..23c31596d5 --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.aidl @@ -0,0 +1,3 @@ +package net.osmand.aidlapi.navigation; + +parcelable ABlockedRoad; \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.java new file mode 100644 index 0000000000..e83f64334b --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/ABlockedRoad.java @@ -0,0 +1,85 @@ +package net.osmand.aidlapi.navigation; + +import android.os.Bundle; +import android.os.Parcel; + +import net.osmand.aidlapi.AidlParams; + +public class ABlockedRoad extends AidlParams { + + private long roadId; + private double latitude; + private double longitude; + private double direction; + private String name; + private String appModeKey; + + public ABlockedRoad(long roadId, double latitude, double longitude, double direction, String name, String appModeKey) { + this.roadId = roadId; + this.latitude = latitude; + this.longitude = longitude; + this.direction = direction; + this.name = name; + this.appModeKey = appModeKey; + } + + protected ABlockedRoad(Parcel in) { + readFromParcel(in); + } + + public static final Creator CREATOR = new Creator() { + @Override + public ABlockedRoad createFromParcel(Parcel in) { + return new ABlockedRoad(in); + } + + @Override + public ABlockedRoad[] newArray(int size) { + return new ABlockedRoad[size]; + } + }; + + public long getRoadId() { + return roadId; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public double getDirection() { + return direction; + } + + public String getName() { + return name; + } + + public String getAppModeKey() { + return appModeKey; + } + + @Override + protected void readFromBundle(Bundle bundle) { + roadId = bundle.getLong("roadId"); + latitude = bundle.getDouble("latitude"); + longitude = bundle.getDouble("longitude"); + direction = bundle.getDouble("direction"); + name = bundle.getString("name"); + appModeKey = bundle.getString("appModeKey"); + } + + @Override + public void writeToBundle(Bundle bundle) { + bundle.putLong("roadId", roadId); + bundle.putDouble("latitude", latitude); + bundle.putDouble("longitude", longitude); + bundle.putDouble("direction", direction); + bundle.putString("name", name); + bundle.putString("appModeKey", appModeKey); + } +} \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.aidl b/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.aidl new file mode 100644 index 0000000000..5eb74b0b53 --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.aidl @@ -0,0 +1,3 @@ +package net.osmand.aidlapi.navigation; + +parcelable AddBlockedRoadParams; diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.java new file mode 100644 index 0000000000..b64a9d32ce --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/AddBlockedRoadParams.java @@ -0,0 +1,46 @@ +package net.osmand.aidlapi.navigation; + +import android.os.Bundle; +import android.os.Parcel; + +import net.osmand.aidlapi.AidlParams; + +public class AddBlockedRoadParams extends AidlParams { + + private ABlockedRoad blockedRoad; + + public AddBlockedRoadParams(ABlockedRoad blockedRoad) { + this.blockedRoad = blockedRoad; + } + + public AddBlockedRoadParams(Parcel in) { + readFromParcel(in); + } + + public static final Creator CREATOR = new Creator() { + @Override + public AddBlockedRoadParams createFromParcel(Parcel in) { + return new AddBlockedRoadParams(in); + } + + @Override + public AddBlockedRoadParams[] newArray(int size) { + return new AddBlockedRoadParams[size]; + } + }; + + public ABlockedRoad getBlockedRoad() { + return blockedRoad; + } + + @Override + public void writeToBundle(Bundle bundle) { + bundle.putParcelable("blockedRoad", blockedRoad); + } + + @Override + protected void readFromBundle(Bundle bundle) { + bundle.setClassLoader(ABlockedRoad.class.getClassLoader()); + blockedRoad = bundle.getParcelable("blockedRoad"); + } +} \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateGpxParams.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateGpxParams.java index 8b4901b35e..e6fad0c1b1 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateGpxParams.java +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateGpxParams.java @@ -11,15 +11,18 @@ public class NavigateGpxParams extends AidlParams { private String data; private Uri uri; private boolean force; + private boolean needLocationPermission; - public NavigateGpxParams(String data, boolean force) { + public NavigateGpxParams(String data, boolean force, boolean needLocationPermission) { this.data = data; this.force = force; + this.needLocationPermission = needLocationPermission; } - public NavigateGpxParams(Uri uri, boolean force) { + public NavigateGpxParams(Uri uri, boolean force, boolean needLocationPermission) { this.uri = uri; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateGpxParams(Parcel in) { @@ -50,11 +53,16 @@ public class NavigateGpxParams extends AidlParams { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToBundle(Bundle bundle) { bundle.putString("data", data); bundle.putParcelable("uri", uri); bundle.putBoolean("force", force); + bundle.putBoolean("needLocationPermission", needLocationPermission); } @Override @@ -62,5 +70,6 @@ public class NavigateGpxParams extends AidlParams { data = bundle.getString("data"); uri = bundle.getParcelable("uri"); force = bundle.getBoolean("force"); + needLocationPermission = bundle.getBoolean("needLocationPermission"); } } \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateParams.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateParams.java index 6dff82b7e4..ad83489f17 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateParams.java +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateParams.java @@ -17,8 +17,10 @@ public class NavigateParams extends AidlParams { private double destLon; private boolean force; + private boolean needLocationPermission; - public NavigateParams(String startName, double startLat, double startLon, String destName, double destLat, double destLon, String profile, boolean force) { + public NavigateParams(String startName, double startLat, double startLon, String destName, double destLat, + double destLon, String profile, boolean force, boolean needLocationPermission) { this.startName = startName; this.startLat = startLat; this.startLon = startLon; @@ -27,6 +29,7 @@ public class NavigateParams extends AidlParams { this.destLon = destLon; this.profile = profile; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateParams(Parcel in) { @@ -77,6 +80,10 @@ public class NavigateParams extends AidlParams { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToBundle(Bundle bundle) { bundle.putString("startName", startName); @@ -87,6 +94,7 @@ public class NavigateParams extends AidlParams { bundle.putDouble("destLon", destLon); bundle.putString("profile", profile); bundle.putBoolean("force", force); + bundle.putBoolean("needLocationPermission", needLocationPermission); } @Override @@ -99,5 +107,6 @@ public class NavigateParams extends AidlParams { destLon = bundle.getDouble("destLon"); profile = bundle.getString("profile"); force = bundle.getBoolean("force"); + needLocationPermission = bundle.getBoolean("needLocationPermission"); } } \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateSearchParams.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateSearchParams.java index d548dab2f3..a5edc7524c 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateSearchParams.java +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/NavigateSearchParams.java @@ -17,10 +17,11 @@ public class NavigateSearchParams extends AidlParams { private double searchLon; private boolean force; + private boolean needLocationPermission; public NavigateSearchParams(String startName, double startLat, double startLon, - String searchQuery, double searchLat, double searchLon, - String profile, boolean force) { + String searchQuery, double searchLat, double searchLon, + String profile, boolean force, boolean needLocationPermission) { this.startName = startName; this.startLat = startLat; this.startLon = startLon; @@ -29,6 +30,7 @@ public class NavigateSearchParams extends AidlParams { this.searchLon = searchLon; this.profile = profile; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateSearchParams(Parcel in) { @@ -79,6 +81,10 @@ public class NavigateSearchParams extends AidlParams { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToBundle(Bundle bundle) { bundle.putString("startName", startName); @@ -89,6 +95,7 @@ public class NavigateSearchParams extends AidlParams { bundle.putBoolean("force", force); bundle.putDouble("searchLat", searchLat); bundle.putDouble("searchLon", searchLon); + bundle.putBoolean("needLocationPermission", needLocationPermission); } @Override @@ -101,5 +108,6 @@ public class NavigateSearchParams extends AidlParams { force = bundle.getBoolean("force"); searchLat = bundle.getDouble("searchLat"); searchLon = bundle.getDouble("searchLon"); + needLocationPermission = bundle.getBoolean("needLocationPermission"); } } \ No newline at end of file diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.aidl b/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.aidl new file mode 100644 index 0000000000..02c9f36f0c --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.aidl @@ -0,0 +1,3 @@ +package net.osmand.aidlapi.navigation; + +parcelable RemoveBlockedRoadParams; diff --git a/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.java b/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.java new file mode 100644 index 0000000000..1cb4e2e6a5 --- /dev/null +++ b/OsmAnd-api/src/net/osmand/aidlapi/navigation/RemoveBlockedRoadParams.java @@ -0,0 +1,46 @@ +package net.osmand.aidlapi.navigation; + +import android.os.Bundle; +import android.os.Parcel; + +import net.osmand.aidlapi.AidlParams; + +public class RemoveBlockedRoadParams extends AidlParams { + + private ABlockedRoad blockedRoad; + + public RemoveBlockedRoadParams(ABlockedRoad blockedRoad) { + this.blockedRoad = blockedRoad; + } + + public RemoveBlockedRoadParams(Parcel in) { + readFromParcel(in); + } + + public static final Creator CREATOR = new Creator() { + @Override + public RemoveBlockedRoadParams createFromParcel(Parcel in) { + return new RemoveBlockedRoadParams(in); + } + + @Override + public RemoveBlockedRoadParams[] newArray(int size) { + return new RemoveBlockedRoadParams[size]; + } + }; + + public ABlockedRoad getBlockedRoad() { + return blockedRoad; + } + + @Override + public void writeToBundle(Bundle bundle) { + bundle.putParcelable("blockedRoad", blockedRoad); + } + + @Override + protected void readFromBundle(Bundle bundle) { + bundle.setClassLoader(ABlockedRoad.class.getClassLoader()); + blockedRoad = bundle.getParcelable("blockedRoad"); + } +} \ No newline at end of file diff --git a/OsmAnd-java/OsmAnd-core-android.jar b/OsmAnd-java/OsmAnd-core-android.jar deleted file mode 100644 index e90615a1c7..0000000000 Binary files a/OsmAnd-java/OsmAnd-core-android.jar and /dev/null differ diff --git a/OsmAnd-java/OsmAnd-core.jar b/OsmAnd-java/OsmAnd-core.jar deleted file mode 100644 index 7e621009fe..0000000000 Binary files a/OsmAnd-java/OsmAnd-core.jar and /dev/null differ diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapIndexReader.java b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapIndexReader.java index 035b33d470..f0b26d09e8 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapIndexReader.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapIndexReader.java @@ -1568,6 +1568,10 @@ public class BinaryMapIndexReader { } public static SearchRequest buildSearchPoiRequest(int x, int y, String nameFilter, int sleft, int sright, int stop, int sbottom, ResultMatcher resultMatcher, ResultMatcher rawDataCollector) { + return buildSearchPoiRequest(x, y, nameFilter, sleft, sright, stop, sbottom, null, resultMatcher, null); + } + + public static SearchRequest buildSearchPoiRequest(int x, int y, String nameFilter, int sleft, int sright, int stop, int sbottom, SearchPoiTypeFilter poiTypeFilter, ResultMatcher resultMatcher, ResultMatcher rawDataCollector) { SearchRequest request = new SearchRequest(); request.x = x; request.y = y; @@ -1575,6 +1579,7 @@ public class BinaryMapIndexReader { request.right = sright; request.top = stop; request.bottom = sbottom; + request.poiTypeFilter = poiTypeFilter; request.resultMatcher = resultMatcher; request.rawDataCollector = rawDataCollector; request.nameQuery = nameFilter.trim(); diff --git a/OsmAnd/assets/bundled_assets.xml b/OsmAnd/assets/bundled_assets.xml index 9b69d7250c..d5626ac886 100644 --- a/OsmAnd/assets/bundled_assets.xml +++ b/OsmAnd/assets/bundled_assets.xml @@ -8,6 +8,7 @@ + diff --git a/OsmAnd/res/values-ar/phrases.xml b/OsmAnd/res/values-ar/phrases.xml index 5b5499949f..a369c15aab 100644 --- a/OsmAnd/res/values-ar/phrases.xml +++ b/OsmAnd/res/values-ar/phrases.xml @@ -3364,8 +3364,8 @@ الرابط أماكن لوقوف السيارات قبر - جنس المجتمع: ذكر - جنس المجتمع: أنثى + نوع المجتمع: ذكر + نوع المجتمع: أنثى لا نعم حمام القدم @@ -3659,4 +3659,17 @@ حطام سفينة حجر الشاهد القائم الروني دبابة تاريخية + بحيرة + نهر + بئر + مضخة + خزان مياه + حنفية + أعمال مياه + شيب مياه + لقاح كورونا COVID19 + يتوفر لدهم لقاح + منصة الانقاذ + صفارت إنذار + نوع المجتمع: مختلط \ No newline at end of file diff --git a/OsmAnd/res/values-ar/strings.xml b/OsmAnd/res/values-ar/strings.xml index 1b5757ad14..54a8a6f3dd 100644 --- a/OsmAnd/res/values-ar/strings.xml +++ b/OsmAnd/res/values-ar/strings.xml @@ -4005,4 +4005,5 @@ \n ملف تعريف أوسماند ملف تعريف المستخدم + عكس جميع النقاط \ No newline at end of file diff --git a/OsmAnd/res/values-de/phrases.xml b/OsmAnd/res/values-de/phrases.xml index 5fa56c8b47..e39de1583c 100644 --- a/OsmAnd/res/values-de/phrases.xml +++ b/OsmAnd/res/values-de/phrases.xml @@ -557,7 +557,7 @@ Tapezierer Staubsaugergeschäft Kleinkaufhaus - Fahrzeugkontrolle + Fahrzeugprüfstelle Fahrzeugrampe Verkaufsautomat Tierarzt @@ -1528,8 +1528,8 @@ Baden: ja Baden: nein Bootslager - Brücke Nr. - Tunnel Nr. + Bauwerksnummer + Bauwerksnummer Nr. Passagiere Fahrzeuge @@ -3889,4 +3889,16 @@ Rettungsschwimmerbasis Impfung: COVID19 Impfung + Rammbrunnen + See + Fluss + Brunnen + Angetriebene Pumpe + Wassertank + Wasserhahn + Wasserwerk + Waschplatz für Wäsche + Müllumladestation + Fahrzeugwaage + Rangerstation \ No newline at end of file diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index f8133d7c17..7ec31aa8a6 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -562,7 +562,7 @@ Sprachansagen Sprachansage Vektorkarten wurden nicht geladen - GPX-Daten konnten nicht gelesen werden + GPX-Daten konnten nicht gelesen werden. Offline-Vektorkarten Suche nach Verbindung an Haltestelle Bearbeite POI @@ -1960,7 +1960,7 @@ Relative Peilung Zeit zwischen automatischen Ansagen Magnetische Peilung - Ziel ist nicht festgelegt + Modul für Bedienungshilfen: Ziel ist nicht festgelegt OsmAnd-Live-Navigation Akkustand Karte bewegen, um die Position der Markierung zu verändern @@ -2170,7 +2170,7 @@ Karten-Overlay wurde in „%s“ geändert. Karten-Underlay wurde in „%s“ geändert. Ungültiger OLC - +\n Kurzer OLC \nBitte geben Sie einen vollständigen Code ein Gültiger vollständiger OLC @@ -3520,7 +3520,7 @@ Das importierte Profil enthält zusätzliche Daten. Klicken Sie auf \"Importieren\", um nur Profildaten zu importieren, oder wählen Sie zusätzliche Daten aus. Sie können zusätzliche Daten zum Exportieren zusammen mit dem Profil auswählen. Antarktis - Sie können alle Ihre noch nicht hochgeladenen Bearbeitungen oder OSM-Fehlermeldungen in %1$s anzeigen. Hochgeladene Punkte werden in OsmAnd nicht angezeigt. + Betrachten Sie alle Ihre noch nicht hochgeladenen Bearbeitungen oder OSM-Hinweise in %1$s. Bereits hochgeladene Änderungen werden nicht mehr angezeigt. Empfehlung: Versuchen Sie zunächst, die Bewegungserkennung über den Filter zur Mindestabstandsmessung (B) zu verwenden. Das kann zu besseren Ergebnissen führen und Sie werden weniger Daten verlieren. Sollten Ihre Tracks bei niedrigen Geschwindigkeiten ungenau bleiben, versuchen Sie hier Werte ungleich Null. Bitte beachten Sie, dass einige Messungen (einige netzwerkbasierte Methoden) möglicherweise überhaupt keine Geschwindigkeitswerte anzeigen. In diesem Fall wird nichts aufgezeichnet. Es werden nur Punkte aufgezeichnet, die mit der gewählten Mindestgenauigkeit bestimmt wurden (in Metern/Fuß, wie von Android je nach Chipsatz bereitgestellt). Die Genauigkeit beschreibt die Nähe der Messungen zur wahren Position und steht nicht unmittelbar in Bezug zur Präzision, der Streuung wiederholter Messungen. Bemerkung: Wenn das GPS unmittelbar vor einer Aufzeichnung ausgeschaltet war, kann der erste gemessene Punkt eine verminderte Genauigkeit haben, sodass wir in unserem Code vielleicht eine Sekunde oder so warten wollen, bevor ein Punkt (oder der beste von 3 aufeinanderfolgenden Punkten usw.) aufgezeichnet wird. Das ist aber noch nicht implementiert. @@ -3801,9 +3801,9 @@ Bitte geben Sie Ihre Fahrzeuglänge an. Für lange Fahrzeuge könnten einige Streckenabschnitte nicht befahrbar sein. Nächstgelegenen Zielpunkt löschen Bitte geben Sie einen Namen für das Profil an - Der aktuelle Punkt auf der Route wird gelöscht. Wenn es das Ziel ist, wird die Navigation gestoppt. + Löscht das nächste Ziel auf Ihrer Route. Wenn dies das endgültige Ziel ist, wird die Navigation gestoppt. Wikipedia-Karten herunterladen - Info über Sehenswürdigkeiten erhalten Sie bei Wikipedia. Es ist Ihr Offline-Wegweiser für die Hosentasche - aktivieren Sie einfach das Wikipedia-Modul und genießen Sie Artikel über Objekte in Ihrer Umgebung. + Holen Sie sich Informationen über Sehenswürdigkeiten aus Wikipedia, einem Offline-Reiseführer für die Hosentasche mit Artikeln über Orte und Ziele. Enduro Motorroller Rollstuhl @@ -3844,7 +3844,7 @@ Adresse hinzufügen Adresse eingeben Bilder auf Straßenebene - Sind Sie sicher, dass Sie alle Änderungen an der geplanten Route verwerfen wollen, indem Sie sie schließen\? + Sind Sie sicher, dass Sie alle Änderungen an der geplanten Route verwerfen wollen\? Routentyp davor ändern Routentyp danach ändern Davor trimmen @@ -3877,7 +3877,7 @@ Während der Navigation automatisch Track aufzeichnen Track Route Track Datei zum Folgen auswählen, oder vom Gerät importieren. - Die GPX-Aufzeichnung wird angehalten, wenn OsmAnd beendet wird (über „zuletzt verwendete Apps“). (Die Hintergrunddienst-Anzeige verschwindet aus der Android-Benachrichtigungsleiste.) + Die Track-Aufzeichnung wird angehalten, wenn OsmAnd beendet wird (über „zuletzt verwendete Apps“). (Die Hintergrunddienst-Anzeige verschwindet aus der Android-Benachrichtigungsleiste.) Aufzeichnungsintervall für die generelle Track-Aufzeichnung festlegen (wird über die Schaltfläche \'Routenaufzeichung\' auf dem Kartenbildschirm angeschaltet). Als nächstes können Sie Ihren Track mit einem Ihrer Navigationsprofile auf die nächstgelegene erlaubte Straße einrasten lassen, um diese Option zu nutzen. Track-Wegpunkt hinzufügen @@ -3913,12 +3913,12 @@ Name: A – Z Start- und Zielsymbole Vielen Dank für den Kauf von \'Höhenlinien\' - Das Abonnement wird pro ausgewähltem Zeitraum berechnet. Sie können das Abonnement jederzeit über die AppGallery kündigen. - Die Bezahlung wird Ihrem AppGallery-Konto bei der Bestätigung des Kaufs belastet. + Das Abonnement wird für den gewählten Zeitraum berechnet. Sie können es jederzeit in Ihrer AppGallery kündigen. + Ihr AppGallery-Konto wird mit der Kaufbestätigung belastet. \n -\nDas Abonnement verlängert sich automatisch, sofern es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird für den Verlängerungszeitraum (Monat / drei Monate / Jahr) nur am Verlängerungsdatum belastet. +\nDas Abonnement verlängert sich automatisch, wenn es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird erst am Verlängerungsdatum für den Verlängerungszeitraum (Monat/drei Monate/Jahr) belastet. \n -\nSie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren AppGallery-Einstellungen gehen. +\nSie können Ihre Abonnements in Ihren AppGallery-Einstellungen verwalten und kündigen. Vermeidet Fußwege Keine Fußwege Entwicklung @@ -3942,7 +3942,7 @@ Bitte warten Sie. \nDie Grafik wird nach der Neuberechnung der Route verfügbar sein. Einrichtung - ÖPNV + Verkehr Dienstleistung Reisen Sport @@ -3953,7 +3953,7 @@ Spezial Fügen Sie mindestens zwei Punkte hinzu Abonnement verwalten - Es gibt ein Problem mit Ihrem Abonnement. Tippen Sie auf die Schaltfläche, um zu den Einstellungen des Google Play Abonnements zu gelangen und Ihre Zahlungsmethode zu überprüfen. + Tippen Sie auf die Schaltfläche, um eine Zahlungsmethode auf Google Play einzurichten und Ihr Abonnement zu bestätigen. OsmAnd Live Abonnement ist abgelaufen OsmAnd Live Abonnement wurde ausgesetzt OsmAnd Live Abonnement liegt auf Eis @@ -4020,4 +4020,7 @@ Lücke Segmente verbinden Neues Segment hinzufügen + OsmAnd-Profil + Benutzerprofil + Alle Punkte umkehren \ No newline at end of file diff --git a/OsmAnd/res/values-eo/phrases.xml b/OsmAnd/res/values-eo/phrases.xml index f3ba290f90..670f41c2be 100644 --- a/OsmAnd/res/values-eo/phrases.xml +++ b/OsmAnd/res/values-eo/phrases.xml @@ -3887,4 +3887,8 @@ krano akvokondukilo puto tuba (abisena) + Pezilo por aŭtomobiloj + Oficejo de naturrezervejo + Vestaĵ-lavejo (ĉe rivero) + Stacio de rubmastrumado \ No newline at end of file diff --git a/OsmAnd/res/values-eo/strings.xml b/OsmAnd/res/values-eo/strings.xml index 563bf3a276..09a2f3363d 100644 --- a/OsmAnd/res/values-eo/strings.xml +++ b/OsmAnd/res/values-eo/strings.xml @@ -4017,4 +4017,5 @@ \n OsmAnd‑profilo Profilo de uzanto + Inversigi ĉiujn punktojn \ No newline at end of file diff --git a/OsmAnd/res/values-es-rAR/phrases.xml b/OsmAnd/res/values-es-rAR/phrases.xml index eeb3cd5c9d..7aa4610509 100644 --- a/OsmAnd/res/values-es-rAR/phrases.xml +++ b/OsmAnd/res/values-es-rAR/phrases.xml @@ -3901,4 +3901,8 @@ Canilla Planta potabilizadora Pozo entubado + Báscula puente + Estación de guardabosques + Lavadero público de ropa + Estación de transferencia de residuos \ No newline at end of file diff --git a/OsmAnd/res/values-es-rAR/strings.xml b/OsmAnd/res/values-es-rAR/strings.xml index 4618562b7e..01a7bc425a 100644 --- a/OsmAnd/res/values-es-rAR/strings.xml +++ b/OsmAnd/res/values-es-rAR/strings.xml @@ -4023,4 +4023,5 @@ \n Perfil de OsmAnd Perfil de usuario + Invertir todos los puntos \ No newline at end of file diff --git a/OsmAnd/res/values-et/phrases.xml b/OsmAnd/res/values-et/phrases.xml index 381bede727..8ef9bbe198 100644 --- a/OsmAnd/res/values-et/phrases.xml +++ b/OsmAnd/res/values-et/phrases.xml @@ -3843,4 +3843,18 @@ Ei Sireen Vetelpäästejaam + Õde + Vaktsineerimine + Vaktsineerimine: COVID19 + Puurkaev + Veevärgi ettevõte + Veekraan + Veepaak + Mootoriga veepump + Kaev + Jõgi + Järv + Mobiiliraha müügikoht + Pargivahi maja + Autokaal \ No newline at end of file diff --git a/OsmAnd/res/values-et/strings.xml b/OsmAnd/res/values-et/strings.xml index 835fad3539..ebfe9773ee 100644 --- a/OsmAnd/res/values-et/strings.xml +++ b/OsmAnd/res/values-et/strings.xml @@ -7,8 +7,8 @@ Jäta vahele lisa Sõnum - A-GPS andmed on allalaetud: %1$s - Kaartide allalaadimine + A-GPS andmed on alla laaditud: %1$s + Laadi kaarte Tere tulemast Märgi kustutamiseks Tühjendada ajalugu\? @@ -46,9 +46,9 @@ Ära enam näita Mäleta valikut Värskenda - Lae alla + Laadi alla Allalaadimine… - Alla laetud + Alla laaditud Sulge Välju Näita @@ -154,7 +154,7 @@ Lisa fotosid Mapillary vidin Lähtesta - Lae uuesti + Laadi uuesti Vale kasutajanimi Kuupäev Sisesta kasutajatunnus @@ -186,7 +186,7 @@ Link avatakse veebilehitsejas. Kuidas link avada? Loe Wikipediat ilma võrguühenduseta - Lae kõik alla + Laadi kõik alla Rakenduse taaskäivitamine Näita pilte Kaardid, mida vajad @@ -195,7 +195,7 @@ Makstud rakendus Makstud lisa Uuendus saadaval - Lae fail alla + Laadi fail alla Alusta muutmist Hangi piiramatu ligipääs Igakuised kaardiuuendused @@ -312,7 +312,7 @@ Kuva alates suurenduse tasemest Luba eramaad Lisand - Lae alla \'Künkavarjutuse ülekatte\' kaart vertikaalse varjutuse kuvamiseks. + Vertikaalse varjutuse kuvamiseks laadi alla „Künkavarjutuse ülekatte“ kaart. Paigalda \'Kõrgusjoonte\' laiendus astmestatud vertikaalsete alade kuvamiseks. Peida alates suurenduse tasemest Sorteeritud kauguse järgi @@ -513,13 +513,13 @@ Ära Tee Ainult Wi-Fi ühendusega - Lae pildid alla - Artikli pilte saab laadida alla võrguühenduseta kasutamiseks. + Laadi pildid alla + Artikli pilte saad laadida alla võrguühenduseta kasutamiseks. \nAlati saadaval menüüs \'Avasta\' → \'Valikud\'. Ainult Wi-Fi ühendusega Vali reisikiri Reisikiri - Lae pildid alla + Laadi pildid alla Vali plaan Vali sobiv toode Ostmise järel on sulle püsivalt kasutatav. @@ -528,11 +528,11 @@ Vikipeedia võrguühenduseta Ava kõik OsmAnd funktsioonid Uued Wikivoyage andmed saadaval, uuenda nautimiseks. - Lae alla Wikivoyage reisijuhid, et vaadata artikleid kohtadest üle maailma ilma internetiühenduseta. + Laadi alla Wikivoyage reisijuhid, et vaadata artikleid kohtadest üle maailma ilma internetiühenduseta. Tasuta ülemaailmne kõigi poolt täiendatav reisijuht. Tere tulemast avatud beetasse Kõrgusjooned & künkavarjutusega kaardid - Sinu järjehoidjatesse lisatud artiklite alusel on soovitatav laadida alla järgmised kaardid: + Sinu järjehoidjatesse lisatud artiklite alusel on soovitame alla laadida järgmised kaardid: Oled tühistanud oma OsmAnd Live tellimuse Uuenda tellimust kõigi funktsioonide kasutamise jätkamiseks: Hangi OsmAnd Live tellimus, et lugeda Vikipeedia ja Wikivoyage artikleid ilma võrguühenduseta. @@ -702,7 +702,7 @@ \n \nSeadista mis tahes ajal menüüst \'Seaded\' → \'Privaatsus ja turvalisus\'. Vali, millist liiki andmeid soovid jagada: - Alla laetud kaardid + Allalaaditud kaardid Külastatud ekraanid Määra, milliseid andmeid OsmAnd võib jagada. Aita meil mõista riikide ja piirkondade kaartide populaarsust. @@ -913,7 +913,7 @@ Logcati puhver Laienduse seaded Vaikimisi - Selle ala vaatlemiseks lae alla üksikasjalik %s kaart. + Selle ala vaatlemiseks laadi alla üksikasjalik %s kaart. Teisaldada OsmAnd andmefailid uude sihtkohta\? \n%1$s > %2$s %1$s • %2$s @@ -1033,7 +1033,7 @@ %1$s • %2$s %1$s, %2$s Isiklik - Allalaadimine %s + Laadin alla %s Jäme Kõrbete ja muude hõredalt asustatud piirkondade jaoks. Üksikasjalikum. Liikumisel kuvatav asukohaikoon @@ -1124,7 +1124,7 @@ Eesti Sebu Sul on vana ja kokkusobimatu Vikipeedia andmestik. Arhiveerida see\? - Laadida täiendavaid andmeid Vikipeediast (%1$s MB)\? + Kas laadime täiendavaid andmeid Vikipeediast (%1$s MB)\? Asukohateenus on välja lülitatud. Lülitada sisse\? Väldi iseseisvat logimist OsmAnd import @@ -1239,9 +1239,9 @@ Ameerika teede atlas Puuduvad v1.9 teekonna arvutuse reeglid Ära kasuta v1.9 teekonna arvutuse reegleid. - Laadida alla võrguühenduseta kaarte\? + Kas laadime alla võrguühenduseta kaarte\? Oled laadinud alla %1$s kaarti - Lae alla uus kaart + Laadi alla uus kaart Halda Kaardi keel Peatuskohad @@ -1323,7 +1323,7 @@ Kaugus Ringkäik Kõik - Laadida alla puuduvad kaardid %1$s (%2$d MB)\? + Kas laadime alla puuduvad kaardid %1$s (%2$d MB)\? Sirvi kaarti Auto Jalgratas @@ -1511,9 +1511,9 @@ Maailma aluskaart Versioon: Versiooni info, litsentsid, projekti liikmed - Allalaetud suumitasemed: %1$s + Allalaaditud suumitasemed: %1$s Aegumine (minutites): %1$s - Alla laetav: %1$s + Alla laaditav: %1$s Maksimaalne suurendus: %1$s Minimaalne suurendus: %1$s Mercatori elliptiline projektsioon @@ -1570,7 +1570,7 @@ Kasuta magnetandurit Muu %1$d faili järel - %1$d faili veel alla laadida + Veel %1$d faili on jäänud alla laadida Täisversioon Lõpeta navigeerimine Eemalda sihtpunkt @@ -1697,37 +1697,37 @@ Hääljuhised peatavad muusika esitamise. Peata muusika OsmAnd kaardid ja navigeerimine - OsmAnd (OSM automatiseeritud navigeerimisjuhised) -\n -\n OsmAnd on avatud lähtekoodiga tarkvara navigeerimisrakendus, millel on juurdepääs mitmesugustele ülemaailmsetele OpenStreetMap (OSM) andmetele. Kõiki kaardiandmeid (vektor- või paanikaarte) saab salvestada telefoni mälukaardile võrguühenduseta kasutamiseks. Pakutakse ka võrguühenduseta ja veebipõhist teekonna leidmise funktsiooni, sealhulgas pöörangupõhiseid hääljuhiseid. -\n -\n Mõned põhifunktsioonid: -\n - Täielik võrguühenduseta funktsioon (salvestage alla laetud vektor- või paanikaardid seadme mällu) -\n - Saadaval on kompaktsed võrguühenduseta vektorkaardid üle kogu maailma -\n - Riigi või piirkonna kaardid on alla laetavad otse rakendusest -\n - Võimalik on mitme kaardikihi ülekatmine, näiteks GPX või navigeerimisrajad, huvipunktid, eelistused, kõrgusjooned, ühistranspordi peatused, täiendavad kaardid kohandatava läbipaistvusega -\n - Aadresside ja kohtade (huvipunktide) otsing ilma võrguühenduseta -\n - Võrguühenduseta teekonna leidmine keskmise vahemaa jaoks -\n - Auto-, jalgratta- ja jalakäijarežiim valikuliselt: -\n - Automatiseeritud päeva/öö vaate vahetamine -\n - Kiirusest sõltuv kaardi suurendusaste -\n - Kaardi joondamine vastavalt kompassile või liikumissuunale -\n - Teekonnal juhtimine, kiiruspiirangu kuvamine, salvestatud ja kõnesünteesitud hääljuhised -\n -\n Selle tasuta OsmAnd versiooni piirangud: -\n - Kaardi allalaadimiste arv on piiratud -\n - Vikipeedia huvipunktidele puudub võrguühenduseta juurdepääs -\n + OsmAnd (OSM automatiseeritud navigeerimisjuhised) +\n +\n OsmAnd on avatud lähtekoodiga tarkvara navigeerimisrakendus, millel on juurdepääs mitmesugustele ülemaailmsetele OpenStreetMap (OSM) andmetele. Kõiki kaardiandmeid (vektor- või paanikaarte) saad salvestada telefoni mälukaardile võrguühenduseta kasutamiseks. Olemas on ka võrguühenduseta ja veebipõhised teekonna leidmise funktsioonid, sealhulgas pöörangupõhiseid hääljuhiseid. +\n +\n Mõned põhifunktsioonid: +\n - Täielik võrguühenduseta funktsioon (salvestades allalaaditud vektor- või paanikaardid seadme mällu) +\n - Saadaval on kompaktsed võrguühenduseta vektorkaardid üle kogu maailma +\n - Riigi või piirkonna kaardid on alla laaditavad otse rakendusest +\n - Võimalik on mitme kaardikihi ülekatmine, näiteks GPX või navigeerimisrajad, huvipunktid, eelistused, kõrgusjooned, ühistranspordi peatused, täiendavad kaardid kohandatava läbipaistvusega +\n - Aadresside ja kohtade (huvipunktide) otsing ilma võrguühenduseta +\n - Võrguühenduseta teekonna leidmine keskmise vahemaa jaoks +\n - Auto-, jalgratta- ja jalakäijarežiim valikuliselt: +\n - Automatiseeritud päeva/öö vaate vahetamine +\n - Kiirusest sõltuv kaardi suurendusaste +\n - Kaardi joondamine vastavalt kompassile või liikumissuunale +\n - Teekonnal juhtimine, kiiruspiirangu kuvamine, salvestatud ja kõnesünteesitud hääljuhised +\n +\n Selle tasuta OsmAnd versiooni piirangud: +\n - Kaardi allalaadimiste arv on piiratud +\n - Vikipeedia huvipunktidele puudub võrguühenduseta juurdepääs +\n \n OsmAnd on aktiivselt arendamisel ning meie projekt ja selle jätkuv edasiminek sõltub rahalisest toetusest uute funktsioonide väljatöötamiseks ja testimiseks. Palun kaalu OsmAnd+ ostmist või konkreetsete uute funktsioonide rahastamist või üldise annetuse tegemist leheküljel https://osmand.net. OsmAnd+ kaardid ja navigeerimine OsmAnd+ (OSM automatiseeritud navigeerimisjuhised) \n -\n OsmAnd+ on avatud lähtekoodiga tarkvara navigeerimisrakendus, millel on juurdepääs paljudele globaalsetele OpenStreetMap (OSM) andmetele. Kõiki kaardiandmeid (vektor- ja paanikaarte) saab salvestada telefoni mälukaardile võrguühenduseta kasutamiseks. Võimalik on nii võrguühenduseta kui ka -ühendusega teekonna leidmise funktsioon, milles on ka hääljuhiseid. +\n OsmAnd+ on avatud lähtekoodiga tarkvara navigeerimisrakendus, millel on juurdepääs paljudele globaalsetele OpenStreetMap (OSM) andmetele. Kõiki kaardiandmeid (vektor- ja paanikaarte) saad salvestada telefoni mälukaardile võrguühenduseta kasutamiseks. Võimalik on nii võrguühenduseta kui ka -ühendusega teekonna leidmise funktsioon, milles on ka hääljuhiseid. \n -\n OsmAnd+ on rakenduse tasuline versioon, mida ostes toetate projekti, rahastate uute funktsioonide arendamist ja saate kõige värskemaid uuendusi. +\n OsmAnd+ on rakenduse tasuline versioon, mida ostes toetad projekti, rahastad uute funktsioonide arendamist ja saad kõige värskemaid uuendusi. \n \n Mõned põhifunktsioonid: -\n - Täielik võrguühenduseta funktsioon (salvestage alla laetud vektor- ja paanikaardid seadme mällu) +\n - Täielik võrguühenduseta funktsioon (salvesta alla laaditud vektor- ja paanikaardid seadme mällu) \n - Saadaval on kompaktsed kogu maailma vektorkaardid (võrguühenduseta režiim) \n - Riigi või piirkonna kaartide piiramatu allalaadimine otse rakendusest \n - Võrguühenduseta Vikipeedia funktsioon (laadige Vikipeedia huvipunktid alla), sobib suurepäraselt vaatamisväärsustega tutvumiseks @@ -1832,11 +1832,11 @@ Lähtepunkt on veel määramata. Asukoht ei ole veel teada. Määra läbipaistvus (0 - läbipaistev, 255 - läbipaistmatu) - Tühistada allalaadimine\? - Põhifunktsionaalsuse pakkumiseks vajaliku aluskaardi alla laadimine on järjekorras. + Tühistame allalaadimise\? + Põhifunktsionaalsuse pakkumiseks vajaliku aluskaardi allalaadimine on järjekorras. Standardkaardid (vektor) Luba \'Internetikaardid\' lisa erinevate kaardiallikate valimiseks - Kasuta internetikaarte (lae alla ja puhverda paanid mälukaardil). + Kasuta internetikaarte (laadi alla ja puhverda paanid mälukaardil). Vali veebipõhised või puhverdatud paanikaartide allikad. Lisad Lisad @@ -1901,11 +1901,11 @@ Kui vara soovid kohale jõudmise teavitust\? Helkivad ülekatted Võrguühenduseta muutmine - Kui võrguühenduseta muutmine on kasutusel, siis muudatused salvestatakse esmalt kohalikus nutiseadmes ning laetakse üles eraldi päringuga. Muul juhul laetakse muudatused üles koheselt. + Kui võrguühenduseta muutmine on kasutusel, siis muudatused salvestatakse esmalt kohalikus nutiseadmes ning laaditakse üles eraldi päringuga. Muul juhul laaditakse muudatused üles koheselt. Üles laadimine… - {0} huvipunkti/märget üles laetud - Lae kõik üles - Lae muudatus OSM-i üles + {0} huvipunkti/märget üles laaditud + Laadi kõik üles + Laadi muudatus OSM-i üles Kustuta muudatus Asünkroonne OSM muutmine: OSM huvipunktid/märkmed salvestatud seadmes @@ -1946,7 +1946,7 @@ Salasõna Taustarežiim OsmAnd töötab taustal, ekraan välja lülitatud. - Kas laeme alla {0} fail(i)\? + Kas laadime alla {0} fail(i)\? \n{1} MB (kokku {2} MB-st) võetakse kasutusse. Läbipaistev teema Kaardivaade automaatselt keskele @@ -1981,7 +1981,7 @@ Otsi lähedusest Failinimi: Sama nimega fail on juba olemas. - %1$d / %2$d ühik(ut) üles laetud. + %1$d / %2$d ühik(ut) üles laaditud. Saada OSM-i Kuva kaardil rohkem üksikasju Lemmikpunktid kustutatud. @@ -2017,7 +2017,7 @@ Veebipõhine navigeerimine ei tööta ilma võrguühenduseta. Mittetoetatud keel Puuduvad andmed - Mine turule valitud keele alla laadimiseks\? + Kas läheme valitud keele alla laadimiseks rakendusepoodi\? Raja vastupidine suund Kasuta olemasoleva sihtkohta Mööda kogu rada @@ -2105,16 +2105,16 @@ Päikesetõus/loojang Valgusandur Päeva/öö režiim - Laadida alla {0} fail(s) ({1} MB)\? + Kas laadime alla {0} fail(i) ({1} MB)\? {0} ühik(ut) valitud - Alla laetud - Lae kaart alla + Alla laaditud + Laadi kaart alla Jätkuv kuvamine Jätkuv kuvamine pilt-pildi haaval kuvamise asemel. Valitud piirkonna joonistamine ebaõnnestus. Kasuta asukohta… - Kuvaja laetud - Kuvaja laadimine ebaõnnestus. + Visualiseerija laetud + Visualiseerija laadimine ebaõnnestus. Vektorkuvaja Vali kuvamise välimus Kuva huvipunkti veebileht @@ -2128,7 +2128,7 @@ Lähtesta transpordi otsing Salvestatud hääl Hääljuhised - Vektorkaarte ei laetud + Vektorkaarte ei laaditud GPX andmete laadimine ebaõnnestus. Võrguühenduseta vektorkaardid Otsi transporti peatuses @@ -2166,7 +2166,7 @@ Ära sirvi veebikaartide paane sellest suuremate suumitasemete korral. Veebipõhine või võrguühenduseta navigeerimisteenus. Asenda - Tänavate/hoonete laadimine… + Laadin tänavaid/hooneid… Kasuta veebipõhist navigeerimist Uuenda kaart Vali hoone @@ -2219,14 +2219,14 @@ Jaga asukohta Saada \'Väljas\' käivitab kaardi otse. - Kaart alla laetud + Kaart on allalaaditud %1$s kaart on kasutusvalmis. Kuva kaart QR kood - Maailma aluskaart (katab kogu maailma madalal suurendustasemel) puudub või on aegunud. Palun kaalu selle allalaadimist üldise ülevaate saamiseks. + Maailma aluskaart (katab kogu maailma madalal suurendustasemel) puudub või on aegunud. Üldise ülevaate saamiseks palun kaalu selle allalaadimist. Rakenduse teave OSM huvipunkt loodud - Lae üles + Laadi üles Uuenda Välja pakutud objektid Loe lisa @@ -2288,7 +2288,7 @@ Vali teed, mida soovid navigeerimise ajal vältida. Heli Vali hääljuhendamine - Vali või lae alla hääljuhendamine omas keeles. + Vali või laadi alla hääljuhendamine omas keeles. Reaalajas uuendused Saadaolevad kaardid Viimane uuendus: %s @@ -2309,7 +2309,7 @@ Huvipunktide ikoonid Vaheta omavahel lähte- ja sihkoht Vali - Eemalda alla laetud uuendused ja taasta kaardi algversioon + Eemalda allalaaditud uuendused ja taasta kaardi algversioon Lisa ajavahe Tee on kinni Eemalda @@ -2341,10 +2341,10 @@ Pole piisavalt ruumi! \n{3} MB on vajalik ajutiselt ning {1} MB püsivalt. \n(Ainult {2} MB saadaval.) - Kas laeme alla {0} fail(i)\? + Kas laadime alla {0} fail(i)\? \n{3} MB kasutatakse ajutiselt, {1} MB püsivalt. (Kokku {2} MB-st.) - Lae üles OSM märge - Lae üles anonüümselt + Laadi üles OSM märkus + Laadi üles anonüümselt Vali kaardimarker Teised markerid Kuva läbipaistev otsinguriba @@ -2407,14 +2407,14 @@ Eemalda kõik paanid Uuendada kohe kõik kaardid\? Leia minu asukoht - Jäta kaartide alla laadimine vahele + Jäta kaartide allalaadimine vahele Sul ei ole võrguühenduseta kaarte paigaldatud. Võid valida kaardi nimekirjast või kaardid hiljem alla laadida \'Menüü - %1$s\' kaudu. Vali mõni teine piirkond Kaartide otsing… - Las OsmAnd määrab sinu asukoha ja soovitab selle piirkonna jaoks alla laetavaid kaarte. + Las OsmAnd määrab sinu asukoha ja soovitab selle piirkonna jaoks alla laaditavaid kaarte. Asukohta ei leitud Internetiühendus puudub - Vajalik kaartide alla laadimiseks. + Vajalik kaartide allalaadimiseks. Asukoha otsing… Vaba ruum OsmAnd\'i andmekasutus (kaardid, rajafailid, jne.): %1$s. @@ -2423,13 +2423,13 @@ Hangi juhiseid ja avasta uusi kohti ilma internetiühenduseta Miilid/meetrid Hangi %1$s ajaks - Hangi piiramatu kaartide alla laadimine, lisades uuendused iga nädal, päev või isegi tund. + Hangi võimalus kaarte piiramatult alla laadida, lisades uuendusi kord nädalas, päevas või isegi iga tund. Piiramatud kaartide allalaadimised, uuendused ja Vikipeedia laiendus. Hangi see Tellimustasu võetakse valitud ajavahemiku kohaselt. Saad sellest Google Play kaudu igal ajal loobuda. Annetus OSM kogukonnale Osa Sinu annetusest saadetakse OSM\'i kaastöötajatele. Tellimuse hind jääb samaks. - Tellimus võimaldab uuendused igas tunnis, päevas või nädalas ja piiramatu kogu maailma kaartide alla laadimise. + Tellimus võimaldab uuendusi kord tunnis, päevas või nädalas ja piiramatu arvu terve maailma kaartide allalaadimise. Miilid/jalad Austraalia Kabiili @@ -2475,10 +2475,10 @@ Lisa veel… Välimus Peen - Lae üles huvipunkt + Laadi üles huvipunkt Linn või piirkond Lähedalasuvad Vikipeedia artiklid - Lae üles oma OSM märge anonüümselt või kasutades oma OpenStreetMap.org profiili. + Laadi üles oma OSM märge anonüümselt või kasutades oma OpenStreetMap.org profiili. Kasuta kiirteid Lubab kiirteed. Serbia (ladina) @@ -2544,20 +2544,20 @@ Täname OsmAnd tasulise versiooni ostmise eest. Parkimisvalikud Ära saada anonüümset rakenduse kasutamise statistikat - OsmAnd kogub teavet selle kohta, milliseid rakenduse osi te avate. Teie asukohta ei saadeta kunagi, ega ka midagi, mida rakendusse sisestate ega üksikasju piirkondade kohta, mida vaatate, otsite või alla laete. + OsmAnd kogub teavet selle kohta, milliseid rakenduse osi sa avad. Sinu asukohta ei saadeta kunagi, ega ka midagi, mida rakendusse sisestad ega üksikasju piirkondade kohta, mida vaatad, otsid või laadid alla. Ära kuva käivitusteateid Ära kuva rakenduse allahindlusi ega kohalike sündmuste teateid. - GPS-navigeerimine -\n • Valige võrguühenduseta (välismaal viibides rändlustasudeta) või võrgus (kiirem) vahel -\n • Hääljuhised pöörangupõhisel suunamisel juhatavad teid mööda teed (salvestatud ja sünteesitud hääled) -\n • Teekond arvutatakse sellest kõrvale kaldudes alati ümber -\n • Teeäärsed juhised, tänavanimed ja eeldatav saabumisaeg on abiks teel olles -\n • Reisi turvalisemaks muutmiseks lülitatakse päeval/öösel ekraani režiim automaatselt ümber -\n • Näidake kiiruspiiranguid ja saate selle ületamise korral meeldetuletusi -\n • Kaardi suurendustaset kohandatakse vastavalt teie kiirusele -\n • Otsige sihtkohti aadressi, liigi (nt parkimine, restoran, hotell, bensiinijaam, muuseum) või geograafiliste koordinaatide järgi -\n • Toetab teekonna vahepunkte -\n • Salvestage oma andmed või laadige üles GPX rada ja liikuge mööda seda + GPS-navigeerimine +\n • Vali võrguühenduseta (välismaal viibides rändlustasudeta) või võrgus (kiirem) vahel +\n • Hääljuhised pöörangupõhisel suunamisel juhatavad sind mööda teed (salvestatud ja sünteesitud hääled) +\n • Teekond arvutatakse sellest kõrvale kaldudes alati ümber +\n • Teeäärsed juhised, tänavanimed ja eeldatav saabumisaeg on teel olles abiks +\n • Reisi turvalisemaks muutmiseks lülitatakse päeval/öösel ekraani režiim automaatselt ümber +\n • Näitame kiiruspiiranguid ja saad selle ületamise korral meeldetuletusi +\n • Kaardi suurendustaset kohandame vastavalt sinu kiirusele +\n • Otsi sihtkohti aadressi, liigi (nt parkimine, restoran, hotell, bensiinijaam, muuseum) või geograafiliste koordinaatide järgi +\n • Toetab teekonna vahepunkte +\n • Salvesta oma andmed või laadi üles GPX rada ja liigu mööda seda \n Navigeerimine \n • Töötab võrgus (kiire) või võrguühenduseta (välismaal viibides puuduvad rändlustasud) @@ -2568,14 +2568,14 @@ \n • Otsige kohti aadressi, tüübi (nt restoran, hotell, bensiinijaam, muuseum) või geograafiliste koordinaatide järgi \n Analüüsi kaardil - Liitu meie meililistiga rakenduse allahindluste kohta teabe saamiseks ja saate veel 3 kaardi allalaadimist! + Rakenduse allahindluste kohta teabe saamiseks liitu meie postiloendiga ja saad veel 3 kaardi allalaadimist! Nupp ekraani keskkoha teekonna sihtkohaks muutmiseks; ühest varem valitud sihtkohast saab viimane vahesihtkoht. Nupp, mille vajutamine muudab ekraani keskkoha uueks teekonna sihtkohaks, asendades eelnevalt valitud sihtkoha (kui olemas). Nupp ekraani keskkoha esimeseks vahesihtkohaks muutmiseks. Nupp, mis lülitab automaatse kiirusetundliku suumimise sisse või välja. Peatatud Lülita sisse animeeritud oma asukohas kaardi panoraamimine navigeerimise ajal. - Lae alla \'Kõrgusjoonte\' kaart selles piirkonnas kasutamiseks. + Selles piirkonnas kasutamiseks laadi alla „Kõrgusjoonte“ kaart. Osta ja paigalda \'Kõrgusjoonte\' lisa astmestatud vertikaalsete alade kuvamiseks. Nupp, mis lülitab OSM märkmete kaardil kuvamise sisse või välja. Sinu sihtkoht asub eramaal. Luba kasutada erateid sellel teekonnal\? @@ -2585,7 +2585,7 @@ Tänavataseme fotod kõigile. Avasta kohti, tee kaastööd, jäädvusta maailma. Paranda foto katvust Mapillary abil Piltide filtreerimine lähetaja, kuupäeva või liigi alusel. Aktiivne ainult lähivaate suurenduse korral. - Ajakohaste andmete nägemiseks lae paanid uuesti. + Ajakohaste andmete nägemiseks laadi paanid uuesti. Salvesta salvestatud rajad kuude kaupa kaustades Salvesta salvestatud rajad salvsetamise kuu kohastes alamkataloogides (näiteks 2018-01). Keskmine @@ -2680,10 +2680,10 @@ See lisa pakub nii kõrgusjoonte ülekatte kui ka (reljeefse) künkavarjutuse kihi, mida kuvatakse OsmAnd standardkaartidel. Seda funktsionaalsust hindavad sportlased, matkajad, rändajad ja kõik teised, kes on huvitatud maastiku reljeefstruktuurist. \n \nGlobaalsed andmed (vahemikus 70 ° põhja ja 70 ° lõuna) põhinevad mõõtmistel, mille on teinud SRTM (süstiku radari topograafiamissioon) ja ASTER (täiustatud kosmose termilise kiirguse ja peegelduse radiomeeter), NASA maavaatlussatelliitide süsteemi lipulaeva Terra pardal olev pildistamisinstrument. ASTER on NASA, Jaapani majandus-, kaubandus- ja tööstusministeeriumi (METI) ja Jaapani kosmosesüsteemide (J-kosmosesüsteemid) koostöö. - See laiendus pakub nii kõrgusjoonte ülekatte kui ka (reljeefse) künkavarjutuse kihi, mida kuvatakse OsmAnd standardkaartidel. Seda funktsionaalsust hindavad sportlased, matkajad, rändajad ja kõik teised, kes on huvitatud maastiku reljeefstruktuurist. (Pange tähele, et kõrgusjoonte ja/või reljeefi andmed on eraldi, pärast laienduse aktiveerimist on saadaval täiendavald alla laetavad failid.) + See laiendus pakub nii kõrgusjoonte ülekatte kui ka (reljeefse) künkavarjutuse kihi, mida kuvatakse OsmAnd standardkaartidel. Seda funktsionaalsust hindavad sportlased, matkajad, rändajad ja kõik teised, kes on huvitatud maastiku reljeefstruktuurist. (Pange tähele, et kõrgusjoonte ja/või reljeefi andmed on eraldi, pärast laienduse aktiveerimist on saadaval täiendavad allalaaditavad failid.) \n \nGlobaalsed andmed (vahemikus 70 ° põhja ja 70 ° lõuna) põhinevad mõõtmistel, mille on teinud SRTM (süstiku radari topograafiamissioon) ja ASTER (täiustatud kosmose termilise kiirguse ja peegelduse radiomeeter), NASA maavaatlussatelliitide süsteemi lipulaeva Terra pardal olev pildistamisinstrument. ASTER on NASA, Jaapani majandus-, kaubandus- ja tööstusministeeriumi (METI) ja Jaapani kosmosesüsteemide (J-kosmosesüsteemid) koostöö. - Selle vaate aktiveerimine muudab OsmAndi kaardistiili \'Reisivaateks\'. See on reisijatele ja kutselistele autojuhtidele mõeldud eriline kõrglahutusega vaade. + Selle vaate aktiveerimine muudab OsmAndi kaardistiili „Reisivaateks“. See on reisijatele ja kutselistele autojuhtidele mõeldud eriline kõrglahutusega vaade. \n \nSee vaade pakub igal kaardi suurendamisel maksimaalse hulga kaardiandmetes saada olevaid reisiandmeid (eriti teed, rajad ja orientatsioonimärgid). \n @@ -2693,7 +2693,7 @@ \n \nSpetsiaalset kaardi allalaadimist pole vaja, vaade on loodud meie tavalistest kaartidest. \n -\nSelle vaate saab tagasi lülitada, aktiveerides selle siin uuesti või muutes vastavalt vajadusele jaotises \'Kaardi seadistamine\' \'Kaardistiil\'. +\nSelle vaate saad tagasi lülitada, aktiveerides selle siin uuesti või muutes vastavalt vajadusele jaotises „Kaardi seadistamine“ „Kaardistiil“. See lisa rikastab OsmAnd kaardi ja navigatsioonirakendust, et toota ka merekaarte paadisõiduks, purjetamiseks ja muud tüüpi veespordi jaoks. \n \nSpetsiaalne OsmAnd kaardi lisamoodul pakub kõiki merenavigatsioonimärke ja kaardisümboleid nii sisemaal kui ka rannikul navigeerimiseks. Iga navigatsioonimärgi kirjeldus sisaldab nende identifitseerimiseks vajalikke üksikasju ja tähendust (kategooria, kuju, värv, järjestus, viide jne). @@ -2732,7 +2732,7 @@ \n * Pikk puudutus punktil kirjelduse vaatamiseks ja lisamiseks. \n * Puuduta mõõtmisvidinat täpsemate tegevuste nägemiseks. Kompassi lugemiseks kasuta orientatsioonianduri asemel magnetilist andurit. - WiFi ühendus puudub. Kas kasutada allalaadimiseks praegust internetiühendust\? + WiFi ühendus puudub. Kas kasutame allalaadimiseks praegust internetiühendust\? Kuvab taustajälgimise ja navigeerimise sisselülitamise sätteid GPS-seadet perioodiliselt äratades (välja lülitatud ekraaniga). Oled kindel, et soovid sihtkoha (ja vahepealsed sihtkohad) tühjendada\? Sünkrooni salvestatud radasid ja heli- või videomärkmeid oma Dropboxi kontole. @@ -2756,45 +2756,45 @@ Optimeeri kaarti Kuva alates suurendustasemest (vajab kõrgusandmeid): Täpsema teabe saamiseks puuduta mõnda olemasolevat üksust, mitteaktiveerimiseks või kustutamiseks puuduta pikalt. Seadme praegused andmed (%1$s vaba): - Täname OsmAnd kasutamise eest. Lae piirkondlikud andmed võrguühenduseta kasutamiseks alla menüüst \'Seaded\' → \'Halda kaardifaile\', et vaadata kaarte, otsida aadresse, leida huvipunkte, ühistransporti ja palju muud. + Täname OsmAnd kasutamise eest. Laadi piirkondlikud andmed võrguühenduseta kasutamiseks alla menüüst „Seaded“ → „Halda kaardifaile“, et vaadata kaarte, otsida aadresse, leida huvipunkte, ühistransporti ja palju muud. Veebis ja vahemällu salvestatud paanikaardid - Lae alla ja halda oma seadmesse salvestatud võrguühenduseta kaardifaile. + Laadi alla ja halda oma seadmesse salvestatud võrguühenduseta kaardifaile. Veebipõhised ja paanikaardid Lisad aktiveerivad täpsemad sätted ja täiendavad funktsioonid. Vektorkaardid kuvatakse tõenäoliselt kiiremini. Mõne seadme puhul ei pruugi see hästi töötada. Vali hääl ja proovi esitades teateid: Sisseehitatud renderdamine Testi hääljuhiseid - Lae selle asukoha jaoks võrguühenduseta vektorkaart alla menüüst \'Seaded\' (\'Halda kaardifaile\') või lülitu ümber \'Veebikaardid\' lisale. + Laadi selle asukoha jaoks võrguühenduseta vektorkaart alla menüüst „Seaded“ („Halda kaardifaile“) või lülitu ümber „Veebikaardid“ lisamoodulile. GPX failide üleslaadimiseks täpsusta palun oma OSM kasutajanimi ja salasõna. Muuda kaardi suurendustaset juhtkuuli horisontaalse liigutusega. Kasuta juhtkuuli suurendustaseme juhtimiseks Valitud ala kuvamiseks pole piisavalt protsessimälu - Rakendusesisesed huvipunktide muudatused ei mõjuta alla laetud kaardifaile, muudatused salvestatakse failina seadmesse. + Rakendusesisesed huvipunktide muudatused ei mõjuta allalaaditud kaardifaile, muudatused salvestatakse failina seadmesse. Kuva ja halda seadme andmebaasis märgitud OSM huvipunkte ja märkmeid. Täpsusta veebiaadress parameetrite süntaksiga: lat={0}, lon={1}, timestamp={2}, hdop={3}, altitude={4}, speed={5}, bearing={6}. Logi rada kasutades GPX vidinat või \'Reisi salvestamise\' sätteid. Varem eksporditud lemmikuid sisaldav fail on juba olemas. Asendada see\? - Pole piisavalt vaba ruumi %1$s MB alla laadimiseks (vaba: %2$s). + Pole piisavalt vaba ruumi %1$s MB allalaadimiseks (vaba: %2$s). See seade ei toeta süsteemi teeki. Süsteemi teegi lähtestamine… Vektorite renderdamise valikud Leiti mitu seotud huvipunktide kategooriat. - Huvipunktide otsimiseks lae alla võrguühenduseta andmed. + Huvipunktide otsimiseks laadi alla võrguühenduseta andmed. Huvipunktide andmefail \'%1$s\' on üleliigne ja selle võib kustutada. Kohalikku faili huvipunktide muudatuste säilitamiseks ei leitud ega saanud ka luua. - Uute kaardifailide kasutamiseks lae alla rakenduse uus versioon. - Lae GPX failid üles OSM kogukonda, parandades seeläbi kaarte. + Uute kaardifailide kasutamiseks laadi alla rakenduse uus versioon. + Laadi GPX failid üles OSM kogukonda, parandades seeläbi kaarte. Kuva mõningaid vektorkaardi detaile (teed jne) juba madalamatel suurendustasemetel. Oled kindel, et soovid kustutada %1$d lemmikut ja %2$d lemmikute gruppi\? - Lae alla maailma põhikaart, et saada ülevaade kogu maailmast ka madalamatel suurendustasemetel. - Lae alla (\'võrguühenduseta\') andmed kaartide võrguühenduseta kasutamiseks. + Saamaks ülevaade kogu maailmast ka madalamatel suurendustasemetel, laadi alla maailma põhikaart. + Laadi alla andmed kaartide võrguühenduseta kasutamiseks. Puuduvad üksused %1$s Paigaldatud Android TTS (kõnesünteesi) mootor ei toeta valitud keelt, selle asemel kasutatakse selle eelhäälestatud TTS keelt. Kas otsida turult teist TTS-mootorit\? Selle asukoha jaoks on olemas võrguühenduseta vektorkaart. \n \nKasutamiseks aktiveeri menüü \'Menüü\' → \'Seadista kaart\' → \'Kaardiallikas…\' → \'Võrguühenduseta vektorkaardid\'. - Rakendus ei suuda alla laadida kaardikihti %1$s, uuesti paigaldamine võib aidata. + Rakendus ei suuda alla laadida kaardikihti %1$s, selle uuesti paigaldamine võib aidata. Tegevust ei saa sooritada ilma internetiühenduseta. Kasuta rasterkaarte kõigeks seda taset ületavaks. Vähim vektori suurendustase @@ -2806,16 +2806,16 @@ \n \nNavigeerimine lülitati ajutiselt ümber CloudMade võrguteenusele. Uues rakenduses toetatakse kõiki vanas paigaldatud rakenduses olevaid võrguühenduseta andmeid, kuid lemmikpunktid tuleb vanast rakendusest eksportida ja seejärel uues importida. - Hääljuhiseid ei ole saadaval, mine menüüsse \'Seaded\' → \'Navigeerimise seaded\', vali profiil → \'Hääljuhised\' ja vali või lae alla hääljuhiste pakett. + Hääljuhiseid ei ole saadaval, mine menüüsse „Seaded“ → „Navigeerimise seaded“, vali profiil → „Hääljuhised“ ja vali või laadi alla hääljuhiste pakett. Reguleeri öö- ja päevarežiimi vahetamist. Luba, et arvutada kiireim teekond või keela kütusesäästliku teekonna jaoks. - Suurendustasemel {0} lae alla {1} paani ({2} MB) - Maksimaalne eellaetav suurendustase - Seda kaarti ei saa alla laadida + Suurendustasemel {0} laadi alla {1} paani ({2} MB) + Maksimaalne eellaaditav suurendustase + Seda kaarti ei õnnestunud alla laadida Radade kaustast ei leitud ühtegi GPX faili Salvestada andmed GPX failina või importida teekonnapunktid \'Lemmikud\' hulka\? Lemmikuid sisaldavat GPX faili ei leitud asukohast {0} - Mälukaardilt ei leitud ühtegi alla laetud kaarti. + Mälukaardilt ei leitud ühtegi allalaaditud kaarti. Aitäh Yandexile liiklusinfo eest. Kasuta juhtpalli kaardi liigutamiseks. Kasuta juhtrullikut @@ -2844,11 +2844,11 @@ Mälukaardile pole juurdepääsu. \nSa ei näe kaarte ega leia asju. Mälukaart on kirjutuskaitstud. -\nNüüd on võimalik vaadata ainult eellaetud kaarti, mitte uusi alasid alla laadida. +\nNüüd on võimalik vaadata ainult eellaaditud kaarti, mitte uusi alasid alla laadida. Faili lahti pakkimine… Suundu Hiljem - Lae alla piirkondi + Laadi alla piirkondi Signaali ootel… Otsi praeguse kaardi keskkoha lähedusest Otsi lähedusest @@ -2872,7 +2872,7 @@ Kuva ühistranspordi peatused kaardil. Kuva ühistranspordi peatused OsmAnd navigeerimisrakendus - Huvipunktide andmed uuendatud (laeti {0}) + Huvipunktide andmed uuendatud (laaditi {0}) Kohalike huvipunktide loetelu uuendamine ebaõnnestus. Kaardi suurendamine võimaldab huvipunkte uuendada Linn: {0} @@ -2880,17 +2880,17 @@ Ristmik: {0} x {1} kohas {2} Lemmik Andmete üleslaadimine… - Üleslaadimine… + Laadin üles… Midagi ei leitud Otsimine… Aadressi otsimine… Võrguühenduseta otsing Vahemaa kokku %1$s, sõiduaeg %2$d h %3$d min. Mälukaardil olevale andmesalvestuskaustale pole juurdepääsu! - Laadida alla {0} - {1} \? + Kas laadime alla {0} - {1} \? Võrguühenduseta andmed {0} on juba olemas ({1}). Värskendada see ({2})\? Aadress - Saadaolevate piirkondade loetelu allalaadimine… + Laadin alla saadaolevate piirkondade loetelu… Piirkondade loendit ei õnnestunud hankida aadressilt https://osmand.net. Lemmikpunkti muudeti Lemmikpunkte pole @@ -2901,28 +2901,28 @@ Muudatuste komplekti avamine… Muudatuste komplekti sulgemine… Sõlme kinnitamine… - HP laadimine… + Laadin HP… Autoriseerimine ebaõnnestus ebaõnnestus Kohalike/ingliskeelsete nimede teisendamine… - Postiindeksite laadimine… - Tänavate laadimine… - Linnade laadimine… + Laadin postiindekseid… + Laadin tänavaid… + Laadin linnasid… HP GPX faili salvestamine ebaõnnestus. Oled kohale jõudnud. Vigased koordinaadid Tagasi kaardile - Andmete laadimine… + Laadin andmeid… Kohalike andmete lugemine… OsmAnd jooksis viimasel kasutamisel kokku. Logifail asub {0}. Palun teata probleemist ja edasta logifail. GPX faili salvestamine… Valmis Määra OSM kaastööks vajalikud OpenStreetMap.org (OSM) sätted. - Määra keel, lae alla või lae andmed uuesti. + Määra keel, laadi alla või laadi andmed uuesti. Andmed Lisaseadistused - Lae paan uuesti + Laadi paan uuesti Sihtmärk Valige kohalike ja ingliskeelsete nimede vahel. Kasuta kaartidel ingliskeelseid nimesid @@ -2941,7 +2941,7 @@ Kasuta internetti Kuva oma asukoht Kuva kaardil GPS koordinaadid - Lae alla puuduvad kaardipaanid + Laadi alla puuduvad kaardipaanid Navigeerimisrakendus Otsi Otsi @@ -2984,7 +2984,7 @@ Tegevus {0} lõpetatud. Tegevust {0} ei saanud sooritada. I/O tõrge tegevuse {0} sooritamisel. - Sõlme teavet ei laetud + Sõlme teavet ei laaditud Avatud Kommentaar Huvipunkti muutmine @@ -3018,7 +3018,7 @@ Palun anna meile teada kõigist ettepanekutest. Ei saanud üles laadida Kustuta muudatus - Üles laetud {0}/{1} + Üles laaditud {0}/{1} Proovi uuesti Viga: {0} Seadista armatuurlaud @@ -3059,7 +3059,7 @@ Allalaadimised Ainult maanteede kaarti pole vaja, sest sul on tavaline (täielik) kaart. Kas soovid selle ikkagi alla laadida\? %.1f MB - Tasuta allalaadimised ära kasutatud + Tasuta allalaadimised on ära kasutatud Kuvab järelejäänud tasuta allalaadimiste arvu. Vali, kuhu soovid kaarte ja muid andmefaile salvestada. Sisesta riigi nimi @@ -3091,7 +3091,7 @@ Kasuta armatuurlauda Kasuta menüüd %1$.1f / %2$.1f MB - Lae alla ainult WiFi kaudu + Laadi alla ainult WiFi kaudu OsmAndil puudub mälukaardi kasutamise luba Viimane kaardimuudatus: %s Iga tund @@ -3204,12 +3204,12 @@ \n • Vikipeedia sinu eelistatud keeles võib sulle linnaekskursiooni ajal palju öelda \n • Ühistranspordipeatused (buss, tramm, rong) koos liinide nimedega aitavad uues linnas navigeerida \n • Jalakäijate režiimis GPS navigeerimine loob sulle marsruudi kõnniteede abil -\n • Lae üles GPX marsruut ja järgi seda või registreeri ja jaga enda oma +\n • Laadi üles GPX marsruut ja järgi seda või salvesta ja jaga enda oma \n Panusta OSM kvaliteeti -\n • Andmevigadest teatamine -\n • Lae GPX rajad OSM keskkonda üles otse rakendusest -\n • Lisa huvipunkte ja lae need kohe üles OSM keskkonda (või hiljem internetühenduse tekkides) +\n • Teata andmevigadest +\n • Laadi GPX rajad OSM keskkonda üles otse rakendusest +\n • Lisa huvipunkte ja laadi need kohe üles OSM keskkonda (või hiljem internetühenduse tekkides) \n OsmAnd on aktiivselt arendatud avatud lähtekoodiga tarkvara. Kõik saavad rakendusse panustada, teatades vigadest, parandades tõlkeid või luues uut funktsioonaalsust. Lisaks kasutab projekt rahalisele toetuset programmerimiseks ja uute funktsioonide testimiseks. \n Ligikaudne kaardi leviala ja kvaliteet: @@ -3261,11 +3261,11 @@ \n • Valikuline kiiruse ja kõrguse kuvamine \n • Kõrgusjoonte ja künkavarjutuse kuvamine (täiendava lisa abil) Tee otse OSM kaastööd -\n • Andmevigadest teatamine -\n • Lae GPX radu OSM keskkonda otse rakendusest -\n • Lisa huvipunkte ja lae need kohe üles OSM keskkonda (või hiljem internetiühenduse tekkimisel) -\n • Valikuline reisi salvestamine ka taustrežiimis (kui seade on puhkeolekus) -\n OsmAnd on aktiivselt arendatud avatud lähtekoodiga tarkvara. Kõik saavad rakendusse panustada, teatades vigadest, parandades tõlkeid või kodeerides uusi funktsioone. Lisaks toetub projekt rahalisele toetusele koodide kodeerimiseks ja uute funktsioonide testimiseks. +\n • Teata andmevigadest +\n • Laadi GPX radu OSM keskkonda otse rakendusest +\n • Lisa huvipunkte ja laadi need kohe üles OSM keskkonda (või hiljem internetiühenduse tekkimisel) +\n • Kui soovid, siis salvesta teekonda ka taustrežiimis (kui seade on puhkeolekus) +\n OsmAnd on aktiivselt arendatud avatud lähtekoodiga tarkvara. Kõik saavad rakendusse panustada, teatades vigadest, parandades tõlkeid või kodeerides uusi funktsioone. Lisaks toetub projekt rahalisele toetusele nii programmeerimiseks kui ka uue funktsionaalsuse testimiseks. \n Ligikaudne kaardi leviala ja kvaliteet: \n • Lääne-Euroopa: **** @@ -3278,7 +3278,7 @@ \n • Lähis-Ida: ** \n • Aafrika: ** \n • Antarktika: * -\n Enamike riikide andmed üle maailma on saadaval allalaadimiseks +\n Enamike riikide andmed üle maailma on allalaadimiseks saadaval \n Afganistanist Zimbabweni, Austraaliast Ameerika Ühendriikideni. Argentina, Brasiilia, Kanada, Prantsusmaa, Saksamaa, Mehhiko, Suurbritannia, Hispaania, … \n Nimi sisaldab liiga palju suurtähti. Jätkata\? @@ -3302,8 +3302,8 @@ Nimetu asukoht Tunnel ees Tunnelid - Lae alla Vikipeedia artiklid %1$s kohta ilma võrguühenduseta lugemiseks. - Lae alla Vikipeedia andmed + Laadi alla Vikipeedia artiklid %1$s kohta ilma võrguühenduseta lugemiseks. + Laadi alla Vikipeedia andmed Vaata artiklit veebilehitsejas. see piirkond Vastava viki artikli otsing @@ -3360,7 +3360,7 @@ Kasutajanimi ja salasõna Need seaded on üldised ja rakenduvad kõikidele profiilidele OSM\'i andmete muutmine - Kõiki üleslaadimata muudatusi või OSM vigu saad vaadata menüüs %1$s. Üleslaaditud punkte OsmAnd ei kuva. + Vaata kõiki üleslaadimata muudatusi või OSM vigu saad menüüs %1$s. Juba üleslaaditud muudatusi OsmAnd ei kuva. OSM Ikooni kuvatakse vaid navigeerimise või liikumise ajal. Peatumisel näidatav ikoon. @@ -3556,7 +3556,7 @@ Nutiseadme helitugevuse nuppudega kontrollida saad kaardi suumi taset. Helitugevuse nupud toimivad suumina Palun sisestage punkti nimi - Lae alla Vikipeedia kaardid + Laadi alla Vikipeedia kaardid Hangi huviväärsuste kohta teavet Vikipeediast. See on sinu võrguühenduseta reisiraamat - lihtsalt võta kasutusele Vikipeedia lisaprogramm ja loe artikleid enda ümber asuvate objektide kohta. Kuna valitud grupp on peidetud, siis lisatud punkt ei ole kaardil nähtav. Vajadusel leiad ta „%s“ alt. Kartauto @@ -3574,7 +3574,7 @@ Toitenupp Eemalda Täiendavad kaardid - Vali kuidas sa soovid allalaetud paane salvestada. + Vali kuidas sa soovid allalaaditud paane salvestada. OsmAnd ja Mapillary Kiirtegevus Raadiuse joonlaud @@ -3653,7 +3653,7 @@ Sa võid kirjeid liigutada vaid selle kategooria piires. Kirjed Taasta kirjete vaikimisi järjekord - Puhverdatud paanid laetakse uuesti alla peale nimetatud minutite möödumist. Kui sa ei soovi uuendamist, siis jäta väli tühjaks. + Puhverdatud paanid laaaditakse uuesti alla peale nimetatud minutite möödumist. Kui sa ei soovi uuendamist, siis jäta väli tühjaks. \n \nÜks päev on 1440 minutit. \nÜks nädal on 10080 minutit. @@ -3818,7 +3818,7 @@ Lisa foto Registreeru \nOpenPlaceReviews.org saidis - Fotode allikaks on OpenPlaceReviews.org veebisait. Oma fotode üleslaadimiseks peaksid liituma selle veebisaidi kasutajaks. + Fotode allikaks on avatud andmetel põhinev OpenPlaceReviews.org veebisait. Oma fotode üleslaadimiseks peaksid liituma selle veebisaidi kasutajaks. Loo uus kasutajakonto Mul juba on kasutajakonto olemas Otsinguajalugu @@ -3838,7 +3838,7 @@ Lisa OpenPlaceReviews saiti Tavasaidi openstreetmap.org asemel kasuta OSM märkuste, huvipunktide või GPX-failide üleslaadimise katsetamiseks arendussaiti dev.openstreetmap.org. Kasuta dev.openstreetmap.org saiti - OsmAnd kuvam fotosid mitmetest allikatest: + OsmAnd kuvab fotosid mitmetest allikatest: \nOpenPlaceReviews - huvipunkti fotod; \nMapillary - tänavavaated; \nWikimedia või veeb - OpenStreetMap\'i andmetes kirjeldatud fotod. @@ -3850,4 +3850,6 @@ Tükelda pärast Tükelda enne Liida lõigud + Kasutajaprofiil + OsmAnd profiil \ No newline at end of file diff --git a/OsmAnd/res/values-fa/strings.xml b/OsmAnd/res/values-fa/strings.xml index f7493ff42e..fe55b9e35f 100644 --- a/OsmAnd/res/values-fa/strings.xml +++ b/OsmAnd/res/values-fa/strings.xml @@ -2063,7 +2063,7 @@ بازگشایی دریافت محاسبهٔ مجدد هوشمند - فقط بخش ابتدایی مسیر را مجدداً محاسبه می‌کند. برای سفرهای طولانی مفید است. + فقط بخش ابتدایی مسیر را مجدداً محاسبه می‌کند. سودمند برای سفرهای طولانی. آیا از OsmAnd راضی هستید؟ دیدگاه و بازخورد شما ارزشمند است. به این برنامه امتیاز بدهید @@ -3481,7 +3481,7 @@ اجازه می‌دهد موقعیت کنونی با استفاده از ضبط سفر هم‌رسانی شود. ردهای ضبط‌شدهٔ شما در %1$s یا در پوشهٔ OsmAnd قرار دارند. یادداشت‌های OSMای شما در %1$s قرار دارند. - می‌توانید همهٔ ویرایش‌ها یا یادداشت‌های OSMای خود را که آپلود نکرده‌اید در %1$s ببینید. نقاط آپلودشده را دیگر در OsmAnd نمی‌بینید. + همهٔ ویرایش‌ها یا یادداشت‌های OSMای آپلودنشدهٔ خود را در %1$s ببینید. تغییرات آپلودشده را دیگر نمی‌بینید. لاگ‌های جزئی برنامه را بررسی و هم‌رسانی کنید استفاده از برنامهٔ سیستم صدای شاتر دوربین @@ -3925,7 +3925,7 @@ %s فایل رد انتخاب شده است ضبط هنگامی که برنامه را از طریق برنامه‌های اخیر ببندید ضبط رد به‌طور موقت می‌ایستد. (نشانگر اجرای پس‌زمینه از نوار اعلان حذف می‌شود.) - بازهٔ زمانی برای ضبط رد را انتخاب کنید (که از طریق ابزار ضبط سفر روی نقشه فعال می‌شود). + بازهٔ زمانی برای ضبط رد را انتخاب کنید (که از طریق ابزارک ضبط سفر روی نقشه روشن می‌شود). نگه‌داشتن ضبط سفر ازسرگیری ضبط سفر اسکیت این‌لاین @@ -3933,7 +3933,7 @@ اسکوتر موتوری ویلچر رو به جلو فاصله آستانه - نمادهای ابتدا/انتها + نمادهای ابتدا و انتها راه‌های پیاده از راه‌های پیاده پرهیز می‌کند توسعه @@ -3954,15 +3954,15 @@ برای استفاده از قابلیت‌های ویرایشی، از طریق OAuth ثبت ورود کنید ثبت ورود از طریق OAuth پاک‌سازی توکن OAuth اوپن‌استریت‌مپ - ثبت خروج موفقیت‌آمیز بود + خروج ثبت شد فایل قبلاً در OsmAnd درون‌برد شده است استفاده از الگوریتم مسیریابی دومرحله‌ای A*‎ نمودار - دادهٔ %1$s فقط در جاده ارائه می‌شود. برای اینکه آن را داشته باشید با استفاده از «مسیریابی بین نقطه‌ها» مسیری محاسبه کنید. - منتظر بمانید تا مسیر دوباره محاسبه شود. -\nنمودار پس از بازمحاسبه در دسترس قرار خواهد گرفت. + دادهٔ %1$s فقط در جاده‌ها ارائه می‌شود. با استفاده از «مسیریابی بین نقطه‌ها» مسیری محاسبه کنید تا نمودارها را ببینید. + لطفاً منتظر بمانید. +\nنمودار پس از بازمحاسبهٔ مسیر فراهم می‌شود. %1$s — %2$s - دست‌کم باید دو نقطه اضافه کنید + دست‌کم دو نقطه اضافه کنید ثبت ورود در اوپن‌استریت‌مپ ثبت ورود در OpenStreetMap.org ثبت ورود از طریق اوپن‌استریت‌مپ @@ -3973,7 +3973,7 @@ حساب ثبت ورود مدیریت اشتراک - در رابطه با اشتراک شما مشکلی وجود دارد. روی دکمه کلیک کنید تا به تنظیمات اشتراک گوگل‌پلی بروید و شیوهٔ پرداخت خود را اصلاح نمایید. + روی دکمه بزنید و یک شیوهٔ پرداخت در گوگل‌پلی تنظیم کنید تا اشتراک خود را اصلاح نمایید. تاریخچهٔ نشانه‌ها ارسال فایل GPX به اوپن‌استریت‌مپ «عمومی» یا Public به این معنی است که رد به‌صورت عمومی در ردهای جی‌پی‌اس شما و لیست ردهای عمومی جی‌پی‌اس در قالب خام نمایش داده می‌شود. دادهٔ نقاط رد که از طریق API در دسترس قرار می‌گیرد، به صفحهٔ ردهای شما ارجاع نمی‌دهد. مهر زمان نقاط رد از طریق API جی‌پی‌اس‌های عمومی دست‌یافتنی نیست و نقاط رد بر اساس زمان مرتب نیستند. @@ -3987,4 +3987,23 @@ ساخت حساب جدید حساب کاربری دارم تاریخچهٔ جست‌وجو + دستگاه شما تنها %1$s فضای خالی دارد. لطفا مقادری فضا خالی کنید و یا تعداد موارد برون‌ریزی را کاهش دهید. + فضای کافی موجود نیست + گروه‌هایی را که درون‌ریزی خواهند شد را انتخاب کنید. + مواردی را که درون‌ریزی خواهند شد را انتخاب کنید. + افزودن به مپیلاری + افزودن به OpenPlaceReviews + برای امتحان کردن بارگذاری یادداشت / نقاط توجه و GPX از dev.openstreetmap.org به جای openstreetmep.org استفاده کنید. + از dev.openstreetmap.org استفاده کنید + برنامه OsmAnd عکس‌ها را از چند منبع نشان می‌دهد: +\nاز OpenPlaceReview برای عکس‌های نقاط توجه؛ +\nاز مپیلاری برای تصویر سطح خیابان؛ +\nاز وب و ویکی‌پدیا برای عکس‌های نقاط توجه متناسب با داده‌های اوپن‌استریت‌مپ. + هواپیمای سبک + اتصال بخش‌ها + "تقطیع از این جا به قبل" + تقطیع از این جا به بعد + افزودن یک بخش جدید + نمایهٔ OsmAnd + نمایهٔ کاربر \ No newline at end of file diff --git a/OsmAnd/res/values-fi/strings.xml b/OsmAnd/res/values-fi/strings.xml index 4cd281d671..026179f02c 100644 --- a/OsmAnd/res/values-fi/strings.xml +++ b/OsmAnd/res/values-fi/strings.xml @@ -305,7 +305,7 @@ Näytä vain Seuraa Valitse päämäärä ensin - Ohjeet + Reittiohjeet Avoinna Ladataan katuja/rakennuksia… Ladataan postinumeroita… @@ -390,7 +390,7 @@ Tapahtui odottamaton virhe suoritettaessa toimintoa {0}. Avoinna Tallenna nimellä - Valitse tien väriteema: + Valitse tien värimaailma: Salli GPS:n käyttö asetuksista Autotuki Muokkaa näyttöä @@ -412,7 +412,7 @@ Aikarajoitettu pysäköinti Aika rajoittamaton pysäköinti Pysäköidyn autosi sijainti. %1$s - Nouda auto kello: + Nouda ajoneuvo kello: PM AM U-Käännös @@ -488,7 +488,7 @@ Esteettömyys moodi Globaalien systeemiasetusten mukaan ZXing viivakoodinlukusovellusta ei ole asennettuna. Etsitäänkö se Google Playstä? - Tien väriteema + Tien värimaailma Näytä kohteen suunta Laske mahdollisesti epäoptimaalinen reitti pitkille matkoille Käytä aina offline editointia @@ -836,7 +836,7 @@ Maailmanlaajuiset tiedot (välillä 70 astetta pohjoista ja 70 astetta eteläist Nauhoitettu Nauhoita Ei dataa - Korkeuskäyräviivojen väripaletti + Korkeuskäyräviivojen värimaailma Miniminopeuden kirjaaminen Aseta miniminopeus kirjattavalle pisteelle. Liikkeen tunnistuksen kirjaus @@ -847,7 +847,7 @@ Maailmanlaajuiset tiedot (välillä 70 astetta pohjoista ja 70 astetta eteläist Näytä Joulupyhän KP:t\? Vaaleanruskea Tummanruskea - Korkeuskäyrien väripaletti + Korkeuskäyrien värimaailma Tienpinnan eheys Kirjoita kaupunki, osoite, KP:n nimi Muokkaa luokkia @@ -1728,7 +1728,7 @@ Maailmanlaajuiset tiedot (välillä 70 astetta pohjoista ja 70 astetta eteläist Paina ja pidä nähdäksesi kartalla Alas/Ylös: %1$s - Laske OsmAnd reitin segmentti ilman internettiä + OsmAnd reittisegmentin laskeminen ilman internettiä Laske OsmAnd reitti ensimmäiselle ja viimeiselle reitin segmentille Käytetäänkö näytettävää jälkeä suunnistuksessa\? Lisää myöhemmäksi päämääräksi @@ -2208,7 +2208,7 @@ Jos pidät OsmAndista ja OSMsta ja haluat tukea niitä, on tämä täydellinen t Kasvata haun laajuutta Muokkaa hakusanoja tai lisää haun laajuutta. Tämän toimintonappulan tökkääminen näyttää tai piilottaa OSM-huomautukset kartalla. - Väriskeema + Värimaailma Salli yksityisalueet Salli pääsy yksityisalueille. Ota käyttöön animoitu sijaintini kartan vieritys navigaation aikana. @@ -2571,6 +2571,47 @@ Jos pidät OsmAndista ja OSMsta ja haluat tukea niitä, on tämä täydellinen t Viikko Suuntima Suunnittele reitti - Viimeksi muokattu + Viimeksi muokatut Luo uusi reitti + Valitse väri + Valitse kuvake + Valitse ryhmä + Lisää kuvaus + Vain seuraava segmentti lasketaan uudelleen valitulla profiililla. + Seuraava segmentti + Kaikki seuraavat segmentit + Edellinen segmentti + Kaikki edelliset segmentit + Vain valittu segmentti lasketaan uudelleen käyttämällä valittua profiilia. + Kaikki seuraavat segmentit lasketaan uudelleen käyttämällä valittua profiilia. + Kaikki edelliset segmentit lasketaan uudelleen käyttämällä valittua profiilia. + Yhdistä segmentit + Lisää uusi segmentti + Kahdeksankulmio + Neliö + Ympyrä + Valitse muoto + Palauta oletusarvot + Kaikki profiiliasetukset palautettu oletusarvoihin. + Kaikki laajennuksen asetukset palautettu oletusarvoihin. + Sovelluksen oletus (%s) + Palauta oletus kohteiden järjestys + Näytön oletusaikakatkaisu + Järjestelmän oletus + Muokkaa profiililuetteloa + Muokkaa profiileja + Tuo profiili + Valittu profiili + Mukavuus + Matkailu + Erityinen + Urheilu + OsmAnd-latauspalvelu + Palvelu + Hätätapaus + Liikenne + Näytä julkinen liikenne + Piilota julkinen liikenne + Symbolit + Korvaa toinen kohde tällä. \ No newline at end of file diff --git a/OsmAnd/res/values-fr/strings.xml b/OsmAnd/res/values-fr/strings.xml index cc4f1eb7f8..fc753fd72b 100644 --- a/OsmAnd/res/values-fr/strings.xml +++ b/OsmAnd/res/values-fr/strings.xml @@ -3813,7 +3813,7 @@ Seuil de distance Profil de navigation Photos des rues - Voulez-vous vraiment fermer l\'itinéraire planifié sans enregistrer \? (vous perdrez vos modifications) + Souhaitez-vous vraiment ignorer toutes les modifications apportées à l\'itinéraire planifié \? Si inversion du sens Point de la trace vers lequel naviguer Enregistrer le parcours @@ -3852,7 +3852,7 @@ Reprendre l\'enregistrement du trajet Suspendre l\'enregistrement du trajet Définit la fréquence d’enregistrement des points du parcours (activable depuis le gadget \"Enregistrement\" sur la carte). - Suspend l\'enregistrement du parcours lorsque l\'application est arrêtée via Applications récentes ; les indications OsmAnd ne seront plus affichées dans la barre de notifications. + L\'enregistrement de l\'itinéraire sera suspendu si l\'application est arrêtée via Applications récentes (les indications OsmAnd ne seront plus affichées dans la barre de notifications). Tous les segments suivants seront recalculés avec le profil sélectionné. Tous les segments précédents seront recalculés avec le profil sélectionné. Tous les segments suivants @@ -3885,7 +3885,7 @@ Nom : A – Z Icônes de départ et d\'arrivée Merci pour votre achat de \'Courbes de niveaux\' - Abonnement facturé pour chaque période sélectionnée. Annulation possible à tout moment sur AppGallery. + L\'abonnement est facturé pour la période sélectionnée. Annulation possible à tout moment sur AppGallery. Éviter les trottoirs Éviter les trottoirs Développement @@ -3995,4 +3995,7 @@ Ajouter un nouveau segment « Identifiable » siginifie que la trace sera affichée publiquement dans « Mes traces GPS » ainsi que dans les listes de traces GPS publiques. Ainsi les autres utilisateurs peuvent télécharger la trace brute et l\'associer avec votre nom d\'utilisateur. Les données de points de passage horodatés fournis par l\'API GPS publique feront référence à la page d\'origine de votre trace. « Public » signifie que la trace est affichée publiquement dans vos traces GPS et dans les listes de traces GPS publiques. Les données diffusées via l\'API ne font pas référence à votre page de traces. Les horodatages des points de trace ne sont pas disponibles via l\'API GPS publique et les points de trace ne sont pas classés par ordre chronologique. + Profil OsmAnd + Profil utilisateur + Inverser tous les points \ No newline at end of file diff --git a/OsmAnd/res/values-hu/phrases.xml b/OsmAnd/res/values-hu/phrases.xml index 23b5710cb5..7c65c9a561 100644 --- a/OsmAnd/res/values-hu/phrases.xml +++ b/OsmAnd/res/values-hu/phrases.xml @@ -3878,4 +3878,16 @@ Vízimentő-támaszpont Oltóközpont: Covid19 Oltóközpont + Ranger station + Ruhamosó hely + Hulladékátrakodó + Hídmérleg + + Folyó + Kút + Motoros szivattyú + Víztartály + Csap + Vízmű + Csöves kút \ No newline at end of file diff --git a/OsmAnd/res/values-hu/strings.xml b/OsmAnd/res/values-hu/strings.xml index 875d3ad0d0..ad8a1e9fa4 100644 --- a/OsmAnd/res/values-hu/strings.xml +++ b/OsmAnd/res/values-hu/strings.xml @@ -1559,7 +1559,7 @@ galiciai észt szebuano - Régi, összeférhetetlen Wikipédia adataid vannak. Archiválod őket? + A Wikipédia-adatok régiek és inkompatbilisek. Archiválja őket\? Letölt további Wikipédia-adatokat (%1$s MB)\? spanyol (argentín) norvég bokmål @@ -1943,7 +1943,7 @@ Mágneses irány Ne tervezzen újra, ha letérsz az útvonalról Ne tervezzen újra, ha ellenkező irányba mész - Nincs beállítva célpont + Kisegítő lehetőségek bővítmény: nincs beállítva célpont Akkumulátor töltöttsége A jelölő helyének módosításához mozgasd a térképet @@ -2566,7 +2566,7 @@ Könyvjelző Teljes leírás elrejtése Teljes leírás megjelenítése - Wikipédia hivatkozás megnyitása online + Wikipédia-link megnyitása online A hivatkozás a böngészőben fog megnyílni. Wikipédia olvasása offline Összes letöltése @@ -2603,7 +2603,7 @@ Kép gyorsítótár Keresési előzmények törlése Képek letöltése - Szerezz OsmAnd Live előfizetést, hogy Wikipédia és Wikivoyage cikkeket olvashass offline. + Szerezzen OsmAnd Live előfizetést, hogy offline módon is olvashasson Wikipédia- és Wikivoyage-szócikkeket. Hogyan nyisd meg a linket? Lemondtad az OsmAnd Live előfizetésedet Előfizetés megújítása az alábbi funkciók használatának folytatásához: @@ -2640,14 +2640,14 @@ Wikivoyage szócikkek Köztes érkezési idő Köztes idő - Töltsd le %1$s Wikipédia szócikkeit offline olvasásra. + Töltse le %1$s Wikipédia szócikkeit offline olvasásra. Wikipédia adatok letöltése Szócikk megnyitása online Szócikk megtekintése böngészőben. - ez a régió + ezen régió Megfelelő szócikk keresése Szócikk nem található - Hogyan nyiss meg Wikipédia szócikkeket? + Hogyan lehet Wikipédia szócikkeket megnyitni\? Az összes funkció feloldásához szerezze be az OsmAnd Live-ot: Napi térképfrissítés korlátlan számú letöltéssel, az összes fizetős és ingyenes bővítmény, Wikipédia, Wikivoyage és sok más. Az alapértelmezett stílus módosítása a gyalogos és kerékpáros utak kontrasztosabb megjelenítése érdekében. Mapnik színeket használ. Topo stílus alapján terepen történő vezetéshez és alátétként zöld műholdképekkel történő használathoz. Vékonyabb főutak, vastagabb mezőgazdasági és erdészeti utak, ösvények, kerékpár- és más útvonalak. @@ -3422,7 +3422,7 @@ Felhasználónév és jelszó Ezek a bővítménybeállítások globálisak, és minden profilra vonatkoznak OSM-szerkesztés - Az összes még fel nem töltött szerkesztés vagy OSM-hiba megtekinthető itt: %1$s. A már feltöltött pontok nem láthatók az OsmAndban. + "A még fel nem töltött szerkesztéseket vagy OSM-hibákat megtekintheti itt: %1$s. A már feltöltött módosítások nem jelennek meg." OSM Navigáció vagy haladás közben megjelenő ikon. Álló helyzetben megjelenő ikon. @@ -3481,7 +3481,7 @@ A domborzatárnyékolás réteg sötét árnyalattal emeli ki a lejtőket, csúcsokat és a síkságokat. A lejtő réteg színezéssel jeleníti meg a terep meredekségét. Állítsa be a legkisebb és legnagyobb nagyítási szintet, amelyen a réteg megjelenjen. - További térképek szükségesek a domborzatárnyékolás térképen való megjelenítéséhez. + A domborzatárnyékolás térképen való megjelenítéséhez további térképek szükségesek. További térképek szükségesek a lejtők térképen való megjelenítéséhez. Áttetszőség Nagyítási szintek @@ -3543,8 +3543,8 @@ \n \nA használaton kívüli bővítmények kikapcsolásával elrejtheti őket a %1$s menüből. Menü elemek, Opciók - Jelölje ki a térképen megjelenő Wikipédia szócikkek nyelvét. A szócikk olvasása közben válthat valamennyi elérhető nyelv között. - Előfordulhat, hogy néhány Wikipédia szócikk nem érhető el az ön nyelvén. + Jelölje ki a térképen megjelenő Wikipédia-szócikkek nyelvét. A szócikk olvasása közben válthat valamennyi elérhető nyelv között. + Előfordulhat, hogy néhány Wikipédia-szócikk nem érhető el az ön nyelvén. Nyomvonalfájl kijelölése kantoni déli min @@ -3734,7 +3734,7 @@ Kérem, adjon nevet a pontnak Adja meg a járműve hosszát (a hosszú járművekre útvonalkorlátozások vonatkozhatnak). Legközelebbi célpont törlése - Wikipédia térképek letöltése + Wikipédia-térképek letöltése További adatokat is kijelölhet exportálásra a profillal együtt. Kiegészítő adatok átvétele Az importált profil kiegészítő adatokat is tartalmaz. Koppintson az \"Importál\" gombra kizálólag a profiladatok importálásához vagy válassza a kiegészítő adatokat. @@ -3744,8 +3744,8 @@ \nAz előfizetés automatikusan megújul, kivéve, ha azt a megújítási dátum előtt lemondja. A megújítási időszakra (hónap / 3 hónap / év) vonatkozóan a számláját csak a megújítás napján terheljük meg. \n \nAz előfizetéseket a Google Play beállításai között kezelheti és törölheti. - Törli az útvonal soron következő célpontját. Amennyiben ez a végző célpont, a navigáció megáll. - Tudjon meg többet az érdekes pontokról a Wikipédiából. Ez az Ön offline zsebútikönyve – egyszerűen kapcsolja be a Wikipédia-bővítményt, és élvezze az Ön körüli objektumokról szóló cikkeket. + Törli az útvonala következő célpontját. Ha ez a végső cél, akkor a navigáció leáll. + Az érdekes helyekről a Wikipédia segítségével tájékozódhat. Ez olyan, mint egy zsebútikönyv: helyekről és úti célokról olvashat benne. Salakmotor Robogó Kerekesszék @@ -3785,7 +3785,7 @@ Válassza ki, hogy a nyomvonalon milyen távolság- vagy időintervallumok jelzései jelenjenek meg. Ez a szűrő kiküszöböli az ismétlődő pontok rögzítését ott, ahol túl kevés tényleges mozgás történhetett, így szebb lesz a később utólag fel nem dolgozott nyomvonalak térbeli megjelenése. Felvétel vágása - Szünetelteti a nyomvonal naplózását, amikor az alkalmazást bezárják (a \'mostanában használt alkalmazások\' felületen). (Az OsmAnd háttérjelzése eltűnik az Android értesítési sávjáról.) + A nyomvonal naplózása szünetelni fog, amikor az alkalmazást (újabb alkalmazásokkal) kilövik. (Ilyenkor az OsmAnd háttérjelzése is eltűnik az Android értesítési sávjáról.) Javaslat: Először próbálja meg a mozgásérzékelést használni a legkisebb elmozdulást naplózó szűrővel (B). Ez jobb eredményeket hozhat, és kevesebb adatot veszít. Ha a nyomvonalak alacsony sebességnél továbbra is zajosak, próbálkozzon itt nullától eltérő értékekkel. Felhívjuk figyelmét, hogy egyes (hálózatalapú módszereket használó) mérőeszközök egyáltalán nem adnak sebességértéket, így ebben az esetben semmi sem fog rögzülni. Utcaszintű képek Csak az út vonala lesz elmentve, az útpontok törlődnek. @@ -3859,7 +3859,7 @@ Navigációs profil Megjegyzés a „sebesség > 0” ellenőrzéséhez: A legtöbb GPS lapkakészlet (chipset) csak akkor mutat sebességértéket, ha az algoritmus megállapítja, hogy mozgásban van. Ha nincs mozgás, akkor nem mutatnak sebességet. Ezért ebben a szűrőben a „> 0” beállítás bizonyos értelemben a GPS lapkakészlet mozgásérzékelését használja. De – még ha a rögzítés ideje alatt itt nem is szűrjük – a GPX elemzése során mégis használjuk ezt a funkciót a korrigált távolság meghatározásához, vagyis az abban a mezőben megjelenített érték a mozgás közben rögzített távolság. Csak a kijelölt szakasz lesz újraszámítva a kiválasztott profilnak megfelelően. - Biztos, hogy mentés nélkül bezárja az útvonaltervezőt\? Minden változást elvész. + Biztosan elveti az összes módosítást a tervezett útvonalon\? Válassza ki a követendő nyomvonalfájlt A felsorolt %1$s már létezik az OsmAndban. Minden korábbi szakasz @@ -3898,12 +3898,12 @@ Név: A–Z Kiindulás és érkezés ikonjai Köszönjük, hogy megvásárolta a szintvonalbővítményt (Contour lines) - Az előfizetés díja a kiválasztott időszakonként lesz kiszámítva. Bármikor törölheti az AppGallery webhelyen. - A fizetést a vásárlás visszaigazolásakor az AppGallery számlájára terheljük. + Az előfizetés a kiválasztott időszakonként kerül felszámolásra. Bármikor törölheti az AppGallery alkalmazásban. + AppGallery-fiókját a vásárlás visszaigazolása után terheljük meg. \n -\nAz előfizetés automatikusan megújul, kivéve, ha azt a megújítási dátum előtt lemondja. A megújítási időszakra (hónap / 3 hónap / év) vonatkozóan a számláját csak a megújítás napján terheljük meg. +\nAz előfizetés automatikusan meghosszabbodik, kivéve, ha a megújítási dátum előtt lemondják. A megújítási időszakra (hónap / három hónap / év) az Ön számláját csak a megújítás napján terheljük meg. \n -\nAz előfizetéseket az AppGallery beállításai között kezelheti és törölheti. +\nAz előfizetéseket az AppGallery beállításaiban kezelheti és törölheti. Gyalogutak elkerülése Gyalogutak elkerülése Fejlesztés @@ -3950,7 +3950,7 @@ Az OsmAnd-előfizetés fel van függesztve Az OsmAnd Live-előfizetés szünetel Az OsmAnd Live-előfizetés lejárt - Probléma van az előfizetésével. A fizetési mód kijavítása érdekében koppintson a gombra a Google Play előfizetési beállításaihoz történő ugráshoz. + Előfizetése kijavítása érdekében koppintson a gombra, és állítsa be a fizetési módot a Google Playen. Bejelentkezés Fiók Bejelentkezés felhasználónévvel és jelszóval @@ -4007,4 +4007,7 @@ \n • Egyéni színek támogatása a kedvenceknél és a nyomvonalak útpontjainál \n \n" + OsmAnd profil + Felhasználói profil + Összes pont megfordítása \ No newline at end of file diff --git a/OsmAnd/res/values-is/phrases.xml b/OsmAnd/res/values-is/phrases.xml index f83bcbafb9..fb51911ead 100644 --- a/OsmAnd/res/values-is/phrases.xml +++ b/OsmAnd/res/values-is/phrases.xml @@ -3610,7 +3610,7 @@ Aðgangur farartækja: hernaðarlegur Aðgangur farartækja: vöruafhending Aðgangur farartækja: skógrækt - Aðgangur bifreiða: + Aðgangur bifreiða: já Aðgangur bifreiða: einka Aðgangur bifreiða: nei Aðgangur bifreiða: áfangastaður @@ -3868,4 +3868,19 @@ Ræðismannastofnun Útibú Ræðisskrifstofa + Millifærslustöð fyrir úrgang + Aflknúin dæla + Vatnstankur + Vatnshani + Bólusetning + Landvarðastöð + Pípubrunnur + Vatnsvinnsla + Bólusetning: COVID19 + Brunnur + Vogarbrú + Stöðuvatn + Þvottaþró (þvottaaðstaða) + Á + Bækistöð öryggisvarða \ No newline at end of file diff --git a/OsmAnd/res/values-is/strings.xml b/OsmAnd/res/values-is/strings.xml index b0f780c060..a5e5e86d40 100644 --- a/OsmAnd/res/values-is/strings.xml +++ b/OsmAnd/res/values-is/strings.xml @@ -1085,7 +1085,7 @@ Nota Kalman-síu Nota segulskynjara Full útgáfa - Hafna leið + Hafna leið\? Stöðva leiðsögn Hreinsa út áfangastað Sérsníddu hvernig forritið lítur út. @@ -1384,7 +1384,7 @@ Ertu viss að þú viljir skipta út eftirlætinu %1$s? Fjarlægja valin atriði úr breytingaskránni? Breyta staðsetningu kortamerkis - Áfangastaður er ekki stilltur + Stillingaviðbót fyrir altækan aðgang: Áfangastaður er ekki stilltur Hlutfallsleg stefna Bættu við kortamerkjum á kortinu Nafnlausir notendur geta ekki: @@ -1746,7 +1746,7 @@ Stigvaxandi leit byggingar Upplýsingum um hnút var ekki hlaðið inn Snjöll endurreiknun leiðar - Endurreiknar aðeins upphafshluta leiðar. Má nota fyrir langar ferðir. + Endurreiknar aðeins upphafshluta leiðar, má nota fyrir langar ferðir. Kortið sem eingöngu er með vegum er ekki nauðsynlegt, þar sem þú ert þegar með staðlaða (fulla útgáfu) kortsins. Sækja það samt? Birta dýptarlínur og punkta. Dýptarlínur sjávar @@ -3429,7 +3429,7 @@ Rakning með netstuðningi Nákvæmni skráninga Endurreikningur leiðar - Þessar stillingar eru víðværar og eiga við um öll snið + Þessar stillingar viðbótarinnar eru víðværar og eiga við um öll snið OSM-breytingar OSM Táknið birtist þegar leiðsögn er í gangi eða á meðan verið er á ferðinni. @@ -3459,7 +3459,7 @@ Hljóð við myndatöku Heimild fékkst Veljið studda %1$s kerfisviðaukaskrá í staðinn. - Þú getur skoðað allar óinnsendar breytingar þínar eða villur í OSM í %1$s. Innsendir punktar eru ekki birtir í OsmAnd. + Þú getur skoðað allar óinnsendar breytingar þínar eða villur í OSM í %1$s. Áður innsendir punktar eru ekki lengur birtir. Aukaverkanir: Ferilinn þinn mun vanta alla þá hluta þar sem kröfur um lágmarkshraða voru ekki uppfylltar (t.d. þar sem þú ert að ýta hjólinu þínu upp bratta brekku). Að auki verða engar upplýsingar um kyrrstöður, eins og t.d. hvíldarstaði. Þetta hefur áhrif á alla greiningu eða eftirvinnslu, eins og þegar verið er að skilgreina heildarlengd ferðar, tíma á ferðinni eða meðalhraða þinn. Ábending: Reyndu fyrst að nota hreyfiskynjun í gegnum síuna sem mælis skráða lágmarkshliðrun (B), hún gæti gefið betri niðurstöður og þú tapar minna af gögnum. Ef ferlarnir þínir eru áfram loðnir við lágan hraða, skaltu prófa hér gildi sem ekki eru núll. Athugaðu að sumar mælingar gætu gefið gildi án hraða (sumar mæliaðferðir sem byggjast á netkerfum), í þeim tilfellum myndi ekkert vera skráð. Athugaðu: ef hraði > 0 skoðaðu: Flest GPS kubbasett gefa aðeins upp hraðagildi ef reikniritið ákvarðar að tækið sé á hreyfingu, en gefa ekki neitt gildi ef svo er ekki. Þar af leiðir að sé notuð stillingin > 0 í þessari síu má segja að sé verið að nota hreyfiskynjunina í GPS kubbasettinu. En jafnvel þó þetta sé ekki síað á meðan skráningu stendur, þá notum við samt þennan eiginleika í greiningu okkar á GPX-ferlinum til að ákvarða leiðrétta vegalengd, þ.e.a.s. gildið sem birtist í þeim reit er einmitt skráð vegalengd á meðan verið er á ferðinni. @@ -3788,7 +3788,7 @@ Eyða næsta markpunkti Leiðsagnarsnið Hjólastóll áfram - Náðu í upplýsingar um merka staði frá Wikipedia. Þetta er þá orðið að vasaleiðsögn án nettengingar - bara virkjaðu Wikipedia-viðbótina og njóttu þess að geta lesið um hlutina í kringum þig. + Náðu í upplýsingar um merka staði frá Wikipedia, þetta er þá orðið að vasaleiðsögn án nettengingar. Stýrðu aðdráttarstigi korts með hljóðstyrkshnöppum tækisins. Tilgreindu lengd farartækis sem leyfð er á leiðum. Ef stefna er öfug @@ -3840,7 +3840,7 @@ \n Veldu bilið þar sem merki með tíma eða vegalengd á ferlinum verða birt. Tengja við vegina - Ertu viss um að þú viljir loka leiðaskipulagningu án þess að vista\? + Ertu viss um að þú viljir henda öllum óvistuðum breytingum í skipulögðu leiðinni\? Vista sem ferilskrá Þolvik vegalengdar Skrifa feril í GPX-skrá @@ -3850,7 +3850,7 @@ Veldu hvernig þú vilt skipta upp: eftir tíma eða vegalengd. Vista sem nýja ferilskrá Veldu ferilskrá til að fylgja - Puntinum á núverandi áfangastað leiðarinnar verður eytt. Ef þetta er sjálfur áfangastaðurinn, mun leiðsögn stöðvast. + Eyðir næsta áfangastað leiðarinnar. Ef þetta er sjálfur áfangastaðurinn, mun leiðsögn stöðvast. Eyða heimilisfangi Ferlar Upphaf ferils @@ -3910,7 +3910,7 @@ Hreinsa OAuth-teikn OpenStreetMap Skráð út %s GPX-skrár valdar - Mun setja GPX-skráningu í bið þegar forritið er drepið (slökkt á því í gegnum skjáinn fyrir nýleg forrit - bakgrunnsvísir OsmAnd hverfur þar með úr tilkynningastiku Android-kerfisins.) + GPX-skráning er sett í bið þegar forritið er drepið (slökkt á því í gegnum skjáinn fyrir nýleg forrit - bakgrunnsvísir OsmAnd hverfur þar með úr tilkynningastiku Android-kerfisins.) Veldu millibil skráninga í almenna leiðarskráningu (virkjað með viðmótshlutanum \'Skráning ferðar\' á kortinu). Setja skráningu í bið Halda áfram með skráningu @@ -3929,10 +3929,10 @@ \n • Lagfærð vandamál við inn/útflutning á stillingum sniða \n \n - Bíddu eftir endurútreikningi leiðar. + Bíddu aðeins. \nGrafið verður tiltækt eftir endurútreikning. Fyrir akstur vélsleða á sérstökum vegum og slóðum. - %1$s gögn aðeins tiltæk á vegunum, þú þarft að reikna leið með “Leið milli punkta” til að fá hana. + %1$s gögn aðeins tiltæk á vegunum, þú þarft að reikna leið með “Leið milli punkta” til að sjá gröf. Skrá hefur þegar verið flutt inn í OsmAnd Bil Takk fyrir að kaupa \'Hæðarlínur\' @@ -3957,7 +3957,7 @@ Þú þarft að skrá þig inn til að geta sent inn ný atriði eða breytingar. \n \nÞú getur skráð þig inn með öruggu OAuth-aðferðinni eða notað notandanafn og lykilorð innskráningar. - Það er vandamál með áskriftina þína. Smelltu á hnappinn til að fara í stillingar Google Play áskriftarinnar og laga þar greiðslumátann. + Smelltu á hnappinn til að setja upp greiðslumáta á Google Play áskriftarinnar og laga þar áskriftina þína. Nota notandanafn og lykilorð Skrá inn á OpenStreetMap Skrá inn @@ -3969,7 +3969,7 @@ Notandaaðgangur Skrá inn á OpenStreetMap.org Vinnsluferill kortamerkja - Þú þarft að bæta við a.m.k. tveimur punktum + Bættu við a.m.k. tveimur punktum MGRS Áskrift að OsmAnd Live hefur verið sett í bið OsmAnd notar MGRS, sem er svipað og UTM-snið NATO. @@ -3988,7 +3988,7 @@ Búa til nýjan notandaaðgang Þú getur skráð þig inn með öruggu OAuth-aðferðinni eða notað notandanafn og lykilorð innskráningar. Vélbátar - Ljósmyndir eru í boði frá opna gagnaverkefninu OpenPlaceReviews.org. Til að geta sent inn myndir þarftu að skrá þig á vefsvæðinu. + Ljósmyndir eru í boði frá opna gagnaverkefninu OpenPlaceReviews.org. Til að geta sent inn myndir þarftu að skrá þig á vefsvæðinu þeirra. Gera athugasemd við OSM-minnispunkt \"Rekjanlegt\" þýðir að ferillinn birtist ekki á neinum opinberum listum, en meðhöndlaðir ferilpunktar með tímamerkjum úr ferlinum (sem ekki er hægt að tengja beint við þig) munu birtast í gögnum sem eru sótt í gegnum opinbert GPS API-forritsviðmót. Þú getur notað hæðargögn til útreikninga á hækkun/lækkun í ferðunum þínum @@ -4013,4 +4013,20 @@ Veldu þau gögn sem á að flytja út í skrána. Veldu mynd Mistókst að senda inn mynd, reyndu aftur síðar + • Bætt við möguleika á að flytja út og inn öll gögn, þar með talið stillingar, tilföng, staðir +\n +\n • Skipulagning leiða: gröf ferilbúta með leið, bætt við möguleika á að búa til og breyta mörgum ferilbútum +\n +\n • Bætt við OAuth-auðkenningarleið fyrir OpenStreetMap, endurbætt viðmót valglugga í OSM +\n +\n • Stuðningur við sérsniðna liti í eftirlætum og ferilpunktum +\n +\n + Sameina búta + Skipta upp á eftir + Bæta við nýjum bút + Skipta upp á undan + Notandasnið + Snúa við öllum punktum + OsmAnd-snið \ No newline at end of file diff --git a/OsmAnd/res/values-iw/phrases.xml b/OsmAnd/res/values-iw/phrases.xml index d23f018e7c..ba49e0a35e 100644 --- a/OsmAnd/res/values-iw/phrases.xml +++ b/OsmAnd/res/values-iw/phrases.xml @@ -2174,4 +2174,71 @@ לוח זמנים כוורת דבורים חנות אגוזים + תת־קרקעי + רחוב + חנייה + נתיב + ירוק + מדרכה + קיבולת זרימה של ברז כיבוי + שירותים לאזרח + ויזות למהגרים + קונסוליה + שגרירות + לוח זמנים + מילוי מי שתייה + חץ + רטט + לחץ + + + + + + + + + + + + + + + + + + + + + טרוליבוס + מונית שירות + אוטובוס + פני השטח: שלג + פני השטח: מלח + סדרת פיצוצים + תאריך הפיצוץ (UTC) + סוג פיצוץ: תת־ימי + סוג פיצוץ: תת־קרקעי + ניקוי אופניים: אין + ניקוי + כלים לתיקון עצמי של אופניים: אין + כלים לתיקון עצמי + משאבת אופניים: אין + משאבה + השכרת אופניים: לא + השכרה + תיקון אופניים: לא + תיקון + קמעונאות אופניים: לא + קמעונאי + עם חנות + מעקב: יש + פריט היסטורי + רכבת תחתית + מעבורת + פוניקולר + מונורייל + רכבת קלה + רכבת + חשמלית \ No newline at end of file diff --git a/OsmAnd/res/values-iw/strings.xml b/OsmAnd/res/values-iw/strings.xml index fdcadfd9f0..4b135e2e34 100644 --- a/OsmAnd/res/values-iw/strings.xml +++ b/OsmAnd/res/values-iw/strings.xml @@ -3561,7 +3561,7 @@ מעויני ריבועי מזערי - ניתן לצפות בכל העריכות או בתקלות ב־OSM שטרם הועלו תחת %1$s. נקודות שהועלו לא מופיעות ב־OsmAnd. + ניתן לצפות בכל העריכות או בתקלות ב־OSM שטרם הועלו תחת %1$s. שינויים שהועלו לא יופיעו עוד. מפת הצללה עם צבעי הצללה כהים כדי להדגיש מדרונות, פסגות ועמקים. מתומן הערות ה־OSM שלך הן תחת %1$s. @@ -3800,7 +3800,7 @@ נא לספק את אורך כלי הרכב שלך, מגבלות מסלול מסוימות עשויות לחול על כלי רכב ארוכים. מחיקת נקודת היעד הקרובה ביותר נא לספק שם לנקודה - נקודת היעד הנוכחית במסלול תימחק. אם זה יהיה היעד, הניווט ייעצר. + מוחק את נקודת היעד הבאה במסלול שלך. אם זו נקודת היעד, הניווט ייפסק. הורדת מפות ויקיפדיה קבלת מידע על נקודות עניין מוויקיפדיה. מדריך הכיס הפרטי שלך - עליך פשוט להפעיל את התוסף של ויקיפדיה וליהנות מערכים על מה שסביבך. אופנוע שטח @@ -3877,7 +3877,7 @@ רק קו המסלול יישמר, נקודות הדרך תימחקנה. שם קובץ %s קובצי מסלול נבחרו - רישום ה־GPX יושהה כאשר היישומון ייסגר (דרך היישומונים האחרונים). (התראות הרקע של OsmAnd תיעלמנה מסרגל ההודעות של Android.) + תיעוד המסלול יושהה כאשר היישומון ייסגר (דרך היישומונים האחרונים). (התראות הרקע של OsmAnd תיעלמנה מסרגל ההודעות של Android.) להשהות הקלטת מסלול להמשיך בהקלטת המסלול בררת המחדל של המערכת @@ -3914,11 +3914,11 @@ הימנעות משבילי הולכי רגל הימנעות משבילי הולכי רגל המינוי חויב לתקופה הנבחרת. ניתן לבטל דרך ה־AppGallery בכל עת. - התשלום יחויב דרך חשבון ה־AppGallery שלך עם אישור הרכישה. + חשבון ה־AppGallery שלך יחויב עם אישור הרכישה. \n -\nהמינוי מתחדש אוטומטי אלא אם כן בוטל בטרם תאריך החידוש. החשבון שלך יחויב על תקופת החידוש (חודש/שלושה חודשים/שנה) רק בתאריך החידוש. +\nתוקף המינוי מתארך אוטומטי אלא אם כן בוטל בטרם תאריך החידוש. החשבון שלך יחויב על תקופת החידוש (חודש/שלושה חודשים/שנה) רק בתאריך החידוש. \n -\nניתן לנהל ולבטל את המינויים שלך דרך ההגדרות ב־AppGallery שלך. +\nניתן לנהל ולבטל את המינויים שלך בהגדרות ב־AppGallery שלך. מה חדש פיתוח נתוני זמן אמת של OsmAnd @@ -4018,4 +4018,7 @@ \n • תמיכה בצבעים מותאמים אישית למועדפים ולנקודות דרך במסלול \n \n + פרופיל + פרופיל + להפוך את כל \ No newline at end of file diff --git a/OsmAnd/res/values-nb/strings.xml b/OsmAnd/res/values-nb/strings.xml index 89b718abcd..aa5dcb1a44 100644 --- a/OsmAnd/res/values-nb/strings.xml +++ b/OsmAnd/res/values-nb/strings.xml @@ -2904,7 +2904,7 @@ Veityper Gå av på Sitt på stoppet - Vis/skjul GPX-spor + Vis/skjul spor Knapp for å vise eller skjule valgte spor på kartet. Skjul spor Vis spor @@ -2945,9 +2945,9 @@ Fast dekke Betong Brostein - Rustikk brostein + Naturlig brostein Steinbelagt - Småstein + Rullestein Stein Metall Tre @@ -3031,15 +3031,15 @@ Tillat OsmAnd å samle inn og behandle anonym programbruksdata. Ingen data om din plassering, eller om plasseringer du ser på kartet blir samlet inn. \n \nDu kan alltid endre ditt valg i \"Innstillinger\" → \"Personvern og sikkerhet\". - Velg hvilken data du ønsker å dele: + Velg typen data du vil dele: Nedlastede kart Besøkte skjermer Definer hvilken data du ønsker å dele med OsmAnd. - Hjelp oss å forstå hvilke kart over hvilke regioner og land som er mest populære. - Hjelp oss å fastslå popularitet for OsmAnd-funksjoner. - Trykk \"Tillat\" hvis du samtykker du til vår %1$s + Hjelp oss å forstå hvilke land- og regionkart som er mest populære. + Hjelp oss å forstå hvilke OsmAnd-funksjoner som er mest populære. + Trykk \"Tillat\" hvis du er enig med vår %1$s Personvern og sikkerhet - Velg data til deling + Velg hvilke data du deler Nei takk Tillat Profilnavn @@ -3048,8 +3048,8 @@ Hest Helikopter Du kan legge til din egen endrede versjon av filen routing.xml til i ..osmand/routing - Skikjøring - Skikjøring + Stå på ski + Ski Vis kompasslinjal Skjul kompasslinjal Velg ikon @@ -3103,10 +3103,10 @@ Terreng Sett opp profil Antall overganger - Pendlebuss - Tunnelbane + Skyttelbuss + T-bane Baser din egendefinerte profil på en av de forvalgte programprofilene, dette definerer grunnleggende oppsett, som forvalg synliget for miniprogrammer, enheter for hastighet og distanse. Dette er de forvalgte programprofilene, sammen med eksempler på egentilpassede profiler de kan utvides til: - Alle typer offentlig transport + Offentlige transporttyper Endre kartforstørrelse ved å rulle hjulet opp og ned. Escape tar deg tilbake til WunderLINQ-programmet. Legg til minst ett element i listen i hurtighandlingsinnstillingene Bakker for alpin skisport og tilgang til skiheiser. @@ -3125,8 +3125,8 @@ Minimumshastighet Maksimumshastighet Standardhastighet - Endre forvalgte hastighetsinnstillinger - Sett min/maks -hastighet + Endre standardhastighetsinnstillinger + Still inn min/maks-hastighet Ny profil Krasj OsmAnd krasjet tidligere. Hjelp til å forbedre OsmAnd ved å dele feilmeldingen. @@ -3157,11 +3157,11 @@ Scooter Vannrett nøyaktighet: %1$s, loddrett: %2$s Vannrett nøyaktighet: %s - Profil beholder sine egne innstillinger - Velg kartinnstillinger for profilen - Velg skjerminnstillinger for profilen + Profilen beholder sine egne innstillinger + Velg kartalternativer for profilen + Velg skjermalternativer for profilen Velg navigeringsinnstillinger for profilen - Angi øvre grense for endringer + Bestem det maksimale antall overganger Eksterne inndataenheter Velg en enhet for ekstern kontroll, som f.eks. tastatur eller WunderLINQ. Tastatur @@ -3309,10 +3309,10 @@ Overgang Spor lagret Tomt filnavn - Vekk for sving + Slå på skjermen ved sving Juster hvor lenge skjermen skal forbli påslått. Bruk nærhetssensor - Vift hånden din over toppen av skjermen for å skru den på under navigasjon. + Å bevege hånden over skjermen vil slå den på. Klasse 1 Klasse 2 Klasse 3 @@ -3939,4 +3939,5 @@ Logg inn på OpenStreetMap.org OsmAnd-profil Brukerprofil + Bedøm \ No newline at end of file diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index 9e18f5c096..f3ca626e16 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -1941,7 +1941,7 @@ Cienki Średni Gruby - Nie ustalono celu + Wtyczka ułatwień dostępu: nie ustawiono miejsca docelowego Utrzymywanie trasy po zboczeniu z niej Brak ponownego przeliczania trasy po zjechaniu z trasy. Orientacja magnetyczna @@ -3791,9 +3791,9 @@ Usuń najbliższy punkt docelowy Steruj poziomem powiększenia mapy za pomocą przycisków głośności na urządzeniu. Podaj nazwę punktu - Bieżący punkt docelowy na trasie zostanie usunięty. Jeśli będzie to miejsce docelowe, nawigacja zostanie zatrzymana. + Usuwa następny cel na trasie. Jeśli jest to miejsce docelowe, nawigacja zostanie zatrzymana. Pobierz mapy Wikipedii - Uzyskaj informacje o interesujących miejscach z Wikipedii. Jest to kieszonkowy przewodnik offline - wystarczy włączyć wtyczkę Wikipedii i cieszyć się artykułami o obiektach wokół ciebie. + Uzyskaj informacje o ciekawych miejscach z Wikipedii, kieszonkowego przewodnika offline zawierającego artykuły o miejscach i celach. Motocykl Enduro Skuter Określ długość pojazdu dozwoloną na trasach. @@ -3839,7 +3839,7 @@ Wybierz sposób łączenia punktów, za pomocą linii prostej, lub oblicz trasę między nimi w sposób określony poniżej. Następnie przyciągnij trasę do najbliższej dozwolonej drogi za pomocą jednego z profili nawigacji, aby skorzystać z tej opcji. Zdjęcia z poziomu ulicy - Czy na pewno chcesz odrzucić wszystkie zmiany w zaplanowanej trasie, zamykając ją\? + Czy na pewno chcesz odrzucić wszystkie zmiany w zaplanowanej trasie\? W przypadku odwrotnego kierunku Przejdź z mojej lokalizacji na trasę Sportowy wózek inwalidzki @@ -3912,7 +3912,7 @@ Co nowego Ikony startu i końca Dziękujemy za zakup \"Linii konturowych\" - Subskrypcja naliczona za wybrany okres. Anuluj ją w AppGallery w dowolnym momencie. + Subskrypcja jest naliczana za wybrany okres. Anuluj go w AppGallery w dowolnym momencie. Płatność zostanie pobrana z konta AppGallery po potwierdzeniu zakupu. \n \nSubskrypcja jest automatycznie odnawiana, chyba że zostanie anulowana przed datą odnowienia. Twoje konto zostanie obciążone opłatą za okres odnowienia (miesiąc/trzy miesiące/rok) tylko w dniu odnowienia. @@ -3937,7 +3937,7 @@ MGRS Użyj 2-fazowego algorytmu routingu A * Wykres - %1$s dane dostępne tylko na drogach, aby je uzyskać, musisz obliczyć trasę za pomocą opcji „Trasa między punktami”. + %1$s dane dostępne tylko na drogach, oblicz trasę, korzystając z opcji „Trasa między punktami”, aby wyświetlić wykresy. Proszę czekać. \nWykres będzie dostępny po ponownym obliczeniu trasy. Mapy lokalne @@ -3956,7 +3956,7 @@ Subskrypcja OsmAnd Live została wstrzymana Do jazdy skuterem śnieżnym z wyznaczonymi drogami i torami. Dodaj co najmniej dwa punkty - Wystąpił problem z Twoją subskrypcją. Naciśnij przycisk, aby przejść do ustawień subskrypcji Google Play i naprawić metodę płatności. + Stuknij przycisk, aby skonfigurować metodę płatności w Google Play i naprawić subskrypcję. Subskrypcja OsmAnd Live jest wstrzymana Login Zaloguj się do OpenStreetMap @@ -4021,4 +4021,7 @@ \n• Obsługa niestandardowych kolorów dla ulubionych i śledzenia punktów trasy \n \n + Profil OsmAnd + Profil użytkownika + Odwróć wszystkie punkty \ No newline at end of file diff --git a/OsmAnd/res/values-pt-rBR/phrases.xml b/OsmAnd/res/values-pt-rBR/phrases.xml index 466eae1657..cea52cd7ef 100644 --- a/OsmAnd/res/values-pt-rBR/phrases.xml +++ b/OsmAnd/res/values-pt-rBR/phrases.xml @@ -3894,4 +3894,7 @@ Toque Estação de tratamento de água Bem embalado + Balança + Posto de guarda florestal + Estação de transferência de resíduos \ No newline at end of file diff --git a/OsmAnd/res/values-pt-rBR/strings.xml b/OsmAnd/res/values-pt-rBR/strings.xml index 331af6bd93..af7e266361 100644 --- a/OsmAnd/res/values-pt-rBR/strings.xml +++ b/OsmAnd/res/values-pt-rBR/strings.xml @@ -4013,4 +4013,5 @@ Adicionar novo segmento Perfil do OsmAnd Perfil de usuário + Reverter todos os pontos \ No newline at end of file diff --git a/OsmAnd/res/values-pt/phrases.xml b/OsmAnd/res/values-pt/phrases.xml index 97cf62dc34..f523f432af 100644 --- a/OsmAnd/res/values-pt/phrases.xml +++ b/OsmAnd/res/values-pt/phrases.xml @@ -3871,4 +3871,11 @@ Base de salva-vidas Vacinação: COVID19 Vacinação + Estação de transferência de resíduos + Ponte de peso + Lago + Rio + Tanque de água + Torneira + Estação de tratamento de água \ No newline at end of file diff --git a/OsmAnd/res/values-ru/phrases.xml b/OsmAnd/res/values-ru/phrases.xml index 1430becd00..1cdda217e1 100644 --- a/OsmAnd/res/values-ru/phrases.xml +++ b/OsmAnd/res/values-ru/phrases.xml @@ -3881,4 +3881,9 @@ Нажмите Водозабор Трубчатый колодец + Мобильный платёжный офис + Весовая платформа + Умывальник + Станция перекачки отходов + Станция рейнджеров \ No newline at end of file diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index 8ca4200ddd..c7dbab21d9 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -1819,7 +1819,7 @@ Предельная высота Укажите высоту транспортного средства для учёта при построении маршрута. Умный пересчёт маршрута - Пересчитывается только начальная часть маршрута. Может использоваться для дальних поездок. + Пересчитывается только начальная часть маршрута. Полезно для дальних поездок. Удалить правки OSM Выключено Раскраска по сетевой принадлежности @@ -2169,7 +2169,7 @@ Предотвращает пересчёт маршрута после того, как вы из него вышли. Не пересчитывать маршрут при обратном направлении движения Предотвращает автоматический пересчёт маршрута при обратном направлении движения. - Пункт назначения не задан + Плагин специальных возможностей: пункт назначения не задан Озвучивать направление Индицировать звуком направление на целевую точку. Тактильная индикация направления @@ -3505,7 +3505,7 @@ Имя пользователя и пароль Эти настройки плагина применяются ко всем профилям Редактирование OSM - Здесь отображаются ваши правки и ошибки OSM, ещё не отправленные в %1$s. Отправленные точки не будут отображаться. + Здесь отображаются ваши правки и ошибки OSM, ещё не отправленные в %1$s. Отправленные изменения не отображаются. OSM Значок, отображаемый во время навигации или движения. Значок, отображаемый в состоянии покоя. @@ -3905,7 +3905,7 @@ Спасибо за покупку \'Контурных линий\' Избегать пешеходных дорожек Избегать пешеходных дорожек - Подписка взимается за выбранный период. Отмените её в AppGallery в любое время. + Подписка оплачивается за выбранный период. Отмените её в AppGallery в любое время. Оплата будет снята с вашей учётной записи AppGallery при подтверждении покупки. \n \nПодписка продлевается автоматически, если она не будет отменена до даты продления. С вашего счёта будет взиматься плата за период продления (месяц/три месяца/год) только в дату продления. @@ -3941,7 +3941,7 @@ MGRS OsmAnd использует MGRS, который похож на формат UTM NATO. Развитие местного общественного транспорта - Нужно добавить не менее двух точек + Добавьте не менее двух точек Данные %1$s доступны только для дорог, нужно рассчитать маршрут с помощью «Маршрут между точками». Вводите теги через запятую. Перейти на расчёт маршрутов общественного транспорта с помощью Java (safe) @@ -3974,7 +3974,7 @@ OsmAnd показывает фотографии из нескольких источников: \nOpenPlaceReviews — фотогорафии POI; \nMapillary — изображения улиц; -\nWeb / Wikimedia — фотографии POI, указанные в данных OpenStreetMap. +\nWeb / Wikimedia — фотографии POI по данным OpenStreetMap. Ресурсы Примерный размер файла Требуется для импорта @@ -3985,10 +3985,10 @@ Выберите импортируемые элементы. Использовать dev.openstreetmap.org Можно войти в систему с помощью безопасного метода OAuth или используя свои имя пользователя и пароль. - Возникла проблема с подпиской. Нажмите кнопку, чтобы перейти к настройкам подписки Google Play и исправить способ оплаты. + Нажмите кнопку, чтобы перейти к настройкам подписки Google Play и исправить способ оплаты. Комментировать заметку OSM Переключиться на использование dev.openstreetmap.org вместо openstreetmap.org для тестирования отправки заметок OSM / POI / GPX. - Фотографии предоставлены проектом открытых данных OpenPlaceReviews.org. Чтобы отправить свои фотографии, необходимо зарегистрироваться на сайте. + Фотографии предоставлены проектом открытых данных OpenPlaceReviews.org. Чтобы отправить свои фотографии, необходимо зарегистрироваться на этом сайте. Невозможно отправить изображение, попробуйте позже Выбор изображения Каяк @@ -3999,4 +3999,6 @@ Объединить сегменты Разделить до Разделить после + Профиль пользователя + Профиль OsmAnd \ No newline at end of file diff --git a/OsmAnd/res/values-sc/phrases.xml b/OsmAnd/res/values-sc/phrases.xml index 0aeaf1f00b..939dd49e0c 100644 --- a/OsmAnd/res/values-sc/phrases.xml +++ b/OsmAnd/res/values-sc/phrases.xml @@ -3890,4 +3890,8 @@ Isceta Òperas idràulicas Putzu a tubu + Bilàntzia a ponte + Istatzione de sos rangers + Sabunadòrgiu + Istatzione de tramudòngiu de s\'arga \ No newline at end of file diff --git a/OsmAnd/res/values-sc/strings.xml b/OsmAnd/res/values-sc/strings.xml index 68e3956fb4..44d5d37f94 100644 --- a/OsmAnd/res/values-sc/strings.xml +++ b/OsmAnd/res/values-sc/strings.xml @@ -4013,4 +4013,7 @@ \n • Suportu pro colores personalizados pro sos preferidos e sos puntos de coladòrgiu de sas rastas \n \n + Profilu de OsmAnd + Profilu de s\'impreadore + Fùrria totu sos puntos \ No newline at end of file diff --git a/OsmAnd/res/values-sk/strings.xml b/OsmAnd/res/values-sk/strings.xml index 3a606aac2e..422e385aca 100644 --- a/OsmAnd/res/values-sk/strings.xml +++ b/OsmAnd/res/values-sk/strings.xml @@ -4016,4 +4016,7 @@ \n• Podpora vlastných farieb pre obľúbené položky a sledovanie trasových bodov \n \n + Profil OsmAnd + Profil používateľa + Otočiť všetky body \ No newline at end of file diff --git a/OsmAnd/res/values-tr/strings.xml b/OsmAnd/res/values-tr/strings.xml index b018a39601..4be2bd1df1 100644 --- a/OsmAnd/res/values-tr/strings.xml +++ b/OsmAnd/res/values-tr/strings.xml @@ -3973,4 +3973,5 @@ \n OsmAnd profili Kullanıcı profili + Tüm noktaları tersine çevir \ No newline at end of file diff --git a/OsmAnd/res/values-uk/phrases.xml b/OsmAnd/res/values-uk/phrases.xml index 2454d78d33..6991f87786 100644 --- a/OsmAnd/res/values-uk/phrases.xml +++ b/OsmAnd/res/values-uk/phrases.xml @@ -3882,4 +3882,8 @@ Резервуар для води Озеро Річка + Лісництво + Автомобільні ваги + Громадська пральня + Станція перевезення відходів \ No newline at end of file diff --git a/OsmAnd/res/values-uk/strings.xml b/OsmAnd/res/values-uk/strings.xml index 9ac26b675a..0ea2ee3374 100644 --- a/OsmAnd/res/values-uk/strings.xml +++ b/OsmAnd/res/values-uk/strings.xml @@ -4012,4 +4012,7 @@ \n• Підтримка власних кольорів закладок та маршрутних точок треку \n \n + Профіль OsmAnd + Профіль користувача + Повернути назад всі точки \ No newline at end of file diff --git a/OsmAnd/res/values-zh-rTW/phrases.xml b/OsmAnd/res/values-zh-rTW/phrases.xml index 3a13797bd1..e675bb2d0b 100644 --- a/OsmAnd/res/values-zh-rTW/phrases.xml +++ b/OsmAnd/res/values-zh-rTW/phrases.xml @@ -3893,4 +3893,8 @@ 點擊 自來水廠 管井 + 地磅 + 護林員站 + 公共洗衣區 + 垃圾站 \ No newline at end of file diff --git a/OsmAnd/res/values-zh-rTW/strings.xml b/OsmAnd/res/values-zh-rTW/strings.xml index 990ccc8531..dfbbb9bb93 100644 --- a/OsmAnd/res/values-zh-rTW/strings.xml +++ b/OsmAnd/res/values-zh-rTW/strings.xml @@ -4013,4 +4013,5 @@ \n OsmAnd 設定檔 使用者設定檔 + 反轉所有點 \ No newline at end of file diff --git a/OsmAnd/res/values/phrases.xml b/OsmAnd/res/values/phrases.xml index 055ed90025..28c17c4a5d 100644 --- a/OsmAnd/res/values/phrases.xml +++ b/OsmAnd/res/values/phrases.xml @@ -4318,4 +4318,13 @@ Well River Lake + + Ranger station + Weightbridge + + Waste transfer station + + Lavoir + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 56d61d25ff..c6b833deac 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,9 @@ Thx - Hardy --> + Last used + Select the profile, that will be used on application start. + Reverse all points • Added option to export and import all data including settings, resources, my places\n\n • Plan Route: graphs for track segments with route, and added the ability to create and edit multiple track segments\n\n diff --git a/OsmAnd/res/xml/global_settings.xml b/OsmAnd/res/xml/global_settings.xml index 5f2fef7d02..7ba1dce420 100644 --- a/OsmAnd/res/xml/global_settings.xml +++ b/OsmAnd/res/xml/global_settings.xml @@ -4,9 +4,10 @@ xmlns:tools="http://schemas.android.com/tools" android:title="@string/osmand_settings"> - diff --git a/OsmAnd/src/net/osmand/access/AccessibilityPlugin.java b/OsmAnd/src/net/osmand/access/AccessibilityPlugin.java index eb806a5a33..fefc2d9dda 100644 --- a/OsmAnd/src/net/osmand/access/AccessibilityPlugin.java +++ b/OsmAnd/src/net/osmand/access/AccessibilityPlugin.java @@ -56,7 +56,7 @@ public class AccessibilityPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.osmand_accessibility_description); } diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java index 6b9bb29dea..acc5677352 100644 --- a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java +++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java @@ -43,6 +43,7 @@ import net.osmand.aidl.tiles.ASqliteDbFile; import net.osmand.aidlapi.customization.AProfile; import net.osmand.aidlapi.info.AppInfoParams; import net.osmand.aidlapi.map.ALatLon; +import net.osmand.aidlapi.navigation.ABlockedRoad; import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; @@ -62,6 +63,7 @@ import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.audionotes.AudioVideoNotesPlugin; import net.osmand.plus.dialogs.GpxAppearanceAdapter; +import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.helpers.ColorDialogs; import net.osmand.plus.helpers.ExternalApiHelper; import net.osmand.plus.helpers.LockHelper; @@ -78,6 +80,7 @@ import net.osmand.plus.routing.IRoutingDataUpdateListener; import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.routing.VoiceRouter; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; @@ -138,8 +141,11 @@ import static net.osmand.aidlapi.OsmandAidlConstants.COPY_FILE_UNSUPPORTED_FILE_ import static net.osmand.aidlapi.OsmandAidlConstants.COPY_FILE_WRITE_LOCK_ERROR; import static net.osmand.aidlapi.OsmandAidlConstants.OK_RESPONSE; import static net.osmand.plus.FavouritesDbHelper.FILE_TO_SAVE; +import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_ANGLE; import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_LANES; import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_NAME; +import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_POSSIBLY_LEFT; +import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_POSSIBLY_RIGHT; import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DIRECTION_TURN; import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_DISTANCE; import static net.osmand.plus.helpers.ExternalApiHelper.PARAM_NT_IMMINENT; @@ -177,6 +183,7 @@ public class OsmandAidlApi { private static final String AIDL_DATA = "aidl_data"; private static final String AIDL_URI = "aidl_uri"; private static final String AIDL_FORCE = "aidl_force"; + private static final String AIDL_LOCATION_PERMISSION = "aidl_location_permission"; private static final String AIDL_SEARCH_QUERY = "aidl_search_query"; private static final String AIDL_SEARCH_LAT = "aidl_search_lat"; private static final String AIDL_SEARCH_LON = "aidl_search_lon"; @@ -208,7 +215,7 @@ public class OsmandAidlApi { private static final ApplicationMode DEFAULT_PROFILE = ApplicationMode.CAR; - private static final ApplicationMode[] VALID_PROFILES = new ApplicationMode[]{ + private static final ApplicationMode[] VALID_PROFILES = new ApplicationMode[] { ApplicationMode.CAR, ApplicationMode.BICYCLE, ApplicationMode.PEDESTRIAN @@ -287,7 +294,7 @@ public class OsmandAidlApi { } private void initOsmandTelegram() { - String[] packages = new String[]{"net.osmand.telegram", "net.osmand.telegram.debug"}; + String[] packages = new String[] {"net.osmand.telegram", "net.osmand.telegram.debug"}; Intent intent = new Intent("net.osmand.telegram.InitApp"); for (String pack : packages) { intent.setComponent(new ComponentName(pack, "net.osmand.telegram.InitAppBroadcastReceiver")); @@ -601,6 +608,7 @@ public class OsmandAidlApi { final RoutingHelper routingHelper = app.getRoutingHelper(); boolean force = intent.getBooleanExtra(AIDL_FORCE, true); + final boolean locationPermission = intent.getBooleanExtra(AIDL_LOCATION_PERMISSION, false); if (routingHelper.isFollowingMode() && !force) { mapActivity.getMapActions().stopNavigationActionConfirm(new DialogInterface.OnDismissListener() { @@ -608,12 +616,12 @@ public class OsmandAidlApi { public void onDismiss(DialogInterface dialog) { MapActivity mapActivity = mapActivityRef.get(); if (mapActivity != null && !routingHelper.isFollowingMode()) { - ExternalApiHelper.startNavigation(mapActivity, start, startDesc, dest, destDesc, profile); + ExternalApiHelper.startNavigation(mapActivity, start, startDesc, dest, destDesc, profile, locationPermission); } } }); } else { - ExternalApiHelper.startNavigation(mapActivity, start, startDesc, dest, destDesc, profile); + ExternalApiHelper.startNavigation(mapActivity, start, startDesc, dest, destDesc, profile, locationPermission); } } } @@ -667,6 +675,7 @@ public class OsmandAidlApi { if (searchLocation != null) { final RoutingHelper routingHelper = app.getRoutingHelper(); boolean force = intent.getBooleanExtra(AIDL_FORCE, true); + final boolean locationPermission = intent.getBooleanExtra(AIDL_LOCATION_PERMISSION, false); if (routingHelper.isFollowingMode() && !force) { mapActivity.getMapActions().stopNavigationActionConfirm(new DialogInterface.OnDismissListener() { @@ -674,12 +683,14 @@ public class OsmandAidlApi { public void onDismiss(DialogInterface dialog) { MapActivity mapActivity = mapActivityRef.get(); if (mapActivity != null && !routingHelper.isFollowingMode()) { - ExternalApiHelper.searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, false); + ExternalApiHelper.searchAndNavigate(mapActivity, searchLocation, start, + startDesc, profile, searchQuery, false, locationPermission); } } }); } else { - ExternalApiHelper.searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, false); + ExternalApiHelper.searchAndNavigate(mapActivity, searchLocation, start, + startDesc, profile, searchQuery, false, locationPermission); } } } @@ -698,7 +709,8 @@ public class OsmandAidlApi { GPXFile gpx = loadGpxFileFromIntent(mapActivity, intent); if (gpx != null) { boolean force = intent.getBooleanExtra(AIDL_FORCE, false); - ExternalApiHelper.saveAndNavigateGpx(mapActivity, gpx, force); + boolean locationPermission = intent.getBooleanExtra(AIDL_LOCATION_PERMISSION, false); + ExternalApiHelper.saveAndNavigateGpx(mapActivity, gpx, force, locationPermission); } } } @@ -1652,8 +1664,8 @@ public class OsmandAidlApi { } boolean navigate(String startName, double startLat, double startLon, - String destName, double destLat, double destLon, - String profile, boolean force) { + String destName, double destLat, double destLon, + String profile, boolean force, boolean requestLocationPermission) { Intent intent = new Intent(); intent.setAction(AIDL_NAVIGATE); intent.putExtra(AIDL_START_NAME, startName); @@ -1664,13 +1676,14 @@ public class OsmandAidlApi { intent.putExtra(AIDL_DEST_LON, destLon); intent.putExtra(AIDL_PROFILE, profile); intent.putExtra(AIDL_FORCE, force); + intent.putExtra(AIDL_LOCATION_PERMISSION, requestLocationPermission); app.sendBroadcast(intent); return true; } boolean navigateSearch(String startName, double startLat, double startLon, - String searchQuery, double searchLat, double searchLon, - String profile, boolean force) { + String searchQuery, double searchLat, double searchLon, + String profile, boolean force, boolean requestLocationPermission) { Intent intent = new Intent(); intent.setAction(AIDL_NAVIGATE_SEARCH); intent.putExtra(AIDL_START_NAME, startName); @@ -1681,6 +1694,7 @@ public class OsmandAidlApi { intent.putExtra(AIDL_SEARCH_LON, searchLon); intent.putExtra(AIDL_PROFILE, profile); intent.putExtra(AIDL_FORCE, force); + intent.putExtra(AIDL_LOCATION_PERMISSION, requestLocationPermission); app.sendBroadcast(intent); return true; } @@ -1720,12 +1734,13 @@ public class OsmandAidlApi { return true; } - boolean navigateGpx(String data, Uri uri, boolean force) { + boolean navigateGpx(String data, Uri uri, boolean force, boolean requestLocationPermission) { Intent intent = new Intent(); intent.setAction(AIDL_NAVIGATE_GPX); intent.putExtra(AIDL_DATA, data); intent.putExtra(AIDL_URI, uri); intent.putExtra(AIDL_FORCE, force); + intent.putExtra(AIDL_LOCATION_PERMISSION, requestLocationPermission); app.sendBroadcast(intent); return true; } @@ -1789,8 +1804,11 @@ public class OsmandAidlApi { if (ni.directionInfo != null && ni.directionInfo.getTurnType() != null) { TurnType tt = ni.directionInfo.getTurnType(); RouteDirectionInfo a = ni.directionInfo; - bundle.putString(prefix + PARAM_NT_DIRECTION_NAME, RoutingHelper.formatStreetName(a.getStreetName(), a.getRef(), a.getDestinationName(), "")); + bundle.putString(prefix + PARAM_NT_DIRECTION_NAME, RoutingHelperUtils.formatStreetName(a.getStreetName(), a.getRef(), a.getDestinationName(), "")); bundle.putString(prefix + PARAM_NT_DIRECTION_TURN, tt.toXmlString()); + bundle.putFloat(prefix + PARAM_NT_DIRECTION_ANGLE, tt.getTurnAngle()); + bundle.putBoolean(prefix + PARAM_NT_DIRECTION_POSSIBLY_LEFT, tt.isPossibleLeftTurn()); + bundle.putBoolean(prefix + PARAM_NT_DIRECTION_POSSIBLY_RIGHT, tt.isPossibleRightTurn()); if (tt.getLanes() != null) { bundle.putString(prefix + PARAM_NT_DIRECTION_LANES, Arrays.toString(tt.getLanes())); } @@ -1798,7 +1816,7 @@ public class OsmandAidlApi { } boolean search(final String searchQuery, final int searchType, final double latitude, final double longitude, - final int radiusLevel, final int totalLimit, final SearchCompleteCallback callback) { + final int radiusLevel, final int totalLimit, final SearchCompleteCallback callback) { if (Algorithms.isEmpty(searchQuery) || latitude == 0 || longitude == 0 || callback == null) { return false; } @@ -2167,7 +2185,7 @@ public class OsmandAidlApi { } boolean getBitmapForGpx(final Uri gpxUri, final float density, final int widthPixels, - final int heightPixels, final int color, final GpxBitmapCreatedCallback callback) { + final int heightPixels, final int color, final GpxBitmapCreatedCallback callback) { if (gpxUri == null || callback == null) { return false; } @@ -2368,6 +2386,25 @@ public class OsmandAidlApi { return true; } + public boolean getBlockedRoads(List blockedRoads) { + Map impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads(); + for (AvoidRoadInfo info : impassableRoads.values()) { + blockedRoads.add(new ABlockedRoad(info.id, info.latitude, info.longitude, info.direction, info.name, info.appModeKey)); + } + return true; + } + + public boolean addRoadBlock(ABlockedRoad road) { + LatLon latLon = new LatLon(road.getLatitude(), road.getLongitude()); + app.getAvoidSpecificRoads().addImpassableRoad(null, latLon, false, false, road.getAppModeKey()); + return true; + } + + public boolean removeRoadBlock(ABlockedRoad road) { + app.getAvoidSpecificRoads().removeImpassableRoad(new LatLon(road.getLatitude(), road.getLongitude())); + return true; + } + private static class FileCopyInfo { long startTime; long lastAccessTime; diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java index 99e888973f..2760dbe1d0 100644 --- a/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java +++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java @@ -44,6 +44,7 @@ import net.osmand.aidl.gpx.RemoveGpxParams; import net.osmand.aidl.gpx.ShowGpxParams; import net.osmand.aidl.gpx.StartGpxRecordingParams; import net.osmand.aidl.gpx.StopGpxRecordingParams; +import net.osmand.aidl.lock.SetLockStateParams; import net.osmand.aidl.map.ALatLon; import net.osmand.aidl.map.SetMapLocationParams; import net.osmand.aidl.maplayer.AddMapLayerParams; @@ -85,10 +86,9 @@ import net.osmand.aidl.quickaction.QuickActionParams; import net.osmand.aidl.search.SearchParams; import net.osmand.aidl.search.SearchResult; import net.osmand.aidl.tiles.ASqliteDbFile; -import net.osmand.aidl.lock.SetLockStateParams; import net.osmand.data.LatLon; -import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -736,7 +736,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener { return params != null && api != null && api.navigate( params.getStartName(), params.getStartLat(), params.getStartLon(), params.getDestName(), params.getDestLat(), params.getDestLon(), - params.getProfile(), params.isForce()); + params.getProfile(), params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -747,7 +747,8 @@ public class OsmandAidlService extends Service implements AidlCallbackListener { public boolean navigateGpx(NavigateGpxParams params) { try { OsmandAidlApi api = getApi("navigateGpx"); - return params != null && api != null && api.navigateGpx(params.getData(), params.getUri(), params.isForce()); + return params != null && api != null && api.navigateGpx(params.getData(), params.getUri(), + params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -857,7 +858,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener { return params != null && api != null && api.navigateSearch( params.getStartName(), params.getStartLat(), params.getStartLon(), params.getSearchQuery(), params.getSearchLat(), params.getSearchLon(), - params.getProfile(), params.isForce()); + params.getProfile(), params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -1328,6 +1329,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener { return false; } } + @Override public boolean setLockState(SetLockStateParams params) { try { diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlServiceV2.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlServiceV2.java index 9943257c03..5fa2f75421 100644 --- a/OsmAnd/src/net/osmand/aidl/OsmandAidlServiceV2.java +++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlServiceV2.java @@ -73,13 +73,16 @@ import net.osmand.aidlapi.navdrawer.NavDrawerFooterParams; import net.osmand.aidlapi.navdrawer.NavDrawerHeaderParams; import net.osmand.aidlapi.navdrawer.NavDrawerItem; import net.osmand.aidlapi.navdrawer.SetNavDrawerItemsParams; +import net.osmand.aidlapi.navigation.ABlockedRoad; import net.osmand.aidlapi.navigation.ANavigationUpdateParams; import net.osmand.aidlapi.navigation.ANavigationVoiceRouterMessageParams; +import net.osmand.aidlapi.navigation.AddBlockedRoadParams; import net.osmand.aidlapi.navigation.MuteNavigationParams; import net.osmand.aidlapi.navigation.NavigateGpxParams; import net.osmand.aidlapi.navigation.NavigateParams; import net.osmand.aidlapi.navigation.NavigateSearchParams; import net.osmand.aidlapi.navigation.PauseNavigationParams; +import net.osmand.aidlapi.navigation.RemoveBlockedRoadParams; import net.osmand.aidlapi.navigation.ResumeNavigationParams; import net.osmand.aidlapi.navigation.StopNavigationParams; import net.osmand.aidlapi.navigation.UnmuteNavigationParams; @@ -693,7 +696,7 @@ public class OsmandAidlServiceV2 extends Service implements AidlCallbackListener return params != null && api != null && api.navigate( params.getStartName(), params.getStartLat(), params.getStartLon(), params.getDestName(), params.getDestLat(), params.getDestLon(), - params.getProfile(), params.isForce()); + params.getProfile(), params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -704,7 +707,8 @@ public class OsmandAidlServiceV2 extends Service implements AidlCallbackListener public boolean navigateGpx(NavigateGpxParams params) { try { OsmandAidlApi api = getApi("navigateGpx"); - return params != null && api != null && api.navigateGpx(params.getData(), params.getUri(), params.isForce()); + return params != null && api != null && api.navigateGpx(params.getData(), params.getUri(), + params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -814,7 +818,7 @@ public class OsmandAidlServiceV2 extends Service implements AidlCallbackListener return params != null && api != null && api.navigateSearch( params.getStartName(), params.getStartLat(), params.getStartLon(), params.getSearchQuery(), params.getSearchLat(), params.getSearchLon(), - params.getProfile(), params.isForce()); + params.getProfile(), params.isForce(), params.isNeedLocationPermission()); } catch (Exception e) { handleException(e); return false; @@ -1396,6 +1400,49 @@ public class OsmandAidlServiceV2 extends Service implements AidlCallbackListener return false; } } + + @Override + public boolean getBlockedRoads(List blockedRoads) { + try { + OsmandAidlApi api = getApi("getBlockedRoads"); + return api != null && api.getBlockedRoads(blockedRoads); + } catch (Exception e) { + handleException(e); + return false; + } + } + + @Override + public boolean addRoadBlock(AddBlockedRoadParams params) { + try { + OsmandAidlApi api = getApi("addRoadBlock"); + if (params != null && api != null) { + ABlockedRoad road = params.getBlockedRoad(); + if (road != null) { + return api.addRoadBlock(road); + } + } + } catch (Exception e) { + handleException(e); + } + return false; + } + + @Override + public boolean removeRoadBlock(RemoveBlockedRoadParams params) { + try { + OsmandAidlApi api = getApi("removeRoadBlock"); + if (params != null && api != null) { + ABlockedRoad road = params.getBlockedRoad(); + if (road != null) { + return api.removeRoadBlock(road); + } + } + } catch (Exception e) { + handleException(e); + } + return false; + } }; private void setCustomization(OsmandAidlApi api, CustomizationInfoParams params) { diff --git a/OsmAnd/src/net/osmand/aidl/navigation/NavigateGpxParams.java b/OsmAnd/src/net/osmand/aidl/navigation/NavigateGpxParams.java index 6e8fb8efe7..0944c1a5f9 100644 --- a/OsmAnd/src/net/osmand/aidl/navigation/NavigateGpxParams.java +++ b/OsmAnd/src/net/osmand/aidl/navigation/NavigateGpxParams.java @@ -9,15 +9,18 @@ public class NavigateGpxParams implements Parcelable { private String data; private Uri uri; private boolean force; + private boolean needLocationPermission; - public NavigateGpxParams(String data, boolean force) { + public NavigateGpxParams(String data, boolean force, boolean needLocationPermission) { this.data = data; this.force = force; + this.needLocationPermission = needLocationPermission; } - public NavigateGpxParams(Uri uri, boolean force) { + public NavigateGpxParams(Uri uri, boolean force, boolean needLocationPermission) { this.uri = uri; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateGpxParams(Parcel in) { @@ -48,22 +51,27 @@ public class NavigateGpxParams implements Parcelable { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToParcel(Parcel out, int flags) { out.writeString(data); out.writeParcelable(uri, flags); out.writeByte((byte) (force ? 1 : 0)); + out.writeByte((byte) (needLocationPermission ? 1 : 0)); } private void readFromParcel(Parcel in) { data = in.readString(); uri = in.readParcelable(Uri.class.getClassLoader()); force = in.readByte() != 0; + needLocationPermission = in.readByte() != 0; } @Override public int describeContents() { return 0; } - } diff --git a/OsmAnd/src/net/osmand/aidl/navigation/NavigateParams.java b/OsmAnd/src/net/osmand/aidl/navigation/NavigateParams.java index 8b0bdeb1eb..ce3b7ae0e6 100644 --- a/OsmAnd/src/net/osmand/aidl/navigation/NavigateParams.java +++ b/OsmAnd/src/net/osmand/aidl/navigation/NavigateParams.java @@ -13,8 +13,10 @@ public class NavigateParams implements Parcelable { private double destLon; private String profile; private boolean force; + private boolean needLocationPermission; - public NavigateParams(String startName, double startLat, double startLon, String destName, double destLat, double destLon, String profile, boolean force) { + public NavigateParams(String startName, double startLat, double startLon, String destName, double destLat, + double destLon, String profile, boolean force, boolean needLocationPermission) { this.startName = startName; this.startLat = startLat; this.startLon = startLon; @@ -23,6 +25,7 @@ public class NavigateParams implements Parcelable { this.destLon = destLon; this.profile = profile; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateParams(Parcel in) { @@ -73,6 +76,10 @@ public class NavigateParams implements Parcelable { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToParcel(Parcel out, int flags) { out.writeString(startName); @@ -83,6 +90,7 @@ public class NavigateParams implements Parcelable { out.writeDouble(destLon); out.writeString(profile); out.writeByte((byte) (force ? 1 : 0)); + out.writeByte((byte) (needLocationPermission ? 1 : 0)); } private void readFromParcel(Parcel in) { @@ -94,11 +102,11 @@ public class NavigateParams implements Parcelable { destLon = in.readDouble(); profile = in.readString(); force = in.readByte() != 0; + needLocationPermission = in.readByte() != 0; } @Override public int describeContents() { return 0; } - } diff --git a/OsmAnd/src/net/osmand/aidl/navigation/NavigateSearchParams.java b/OsmAnd/src/net/osmand/aidl/navigation/NavigateSearchParams.java index b092bcd4eb..8fc9ccea18 100644 --- a/OsmAnd/src/net/osmand/aidl/navigation/NavigateSearchParams.java +++ b/OsmAnd/src/net/osmand/aidl/navigation/NavigateSearchParams.java @@ -13,10 +13,11 @@ public class NavigateSearchParams implements Parcelable { private double searchLon; private String profile; private boolean force; + private boolean needLocationPermission; public NavigateSearchParams(String startName, double startLat, double startLon, String searchQuery, double searchLat, double searchLon, - String profile, boolean force) { + String profile, boolean force, boolean needLocationPermission) { this.startName = startName; this.startLat = startLat; this.startLon = startLon; @@ -25,6 +26,7 @@ public class NavigateSearchParams implements Parcelable { this.searchLon = searchLon; this.profile = profile; this.force = force; + this.needLocationPermission = needLocationPermission; } public NavigateSearchParams(Parcel in) { @@ -75,6 +77,10 @@ public class NavigateSearchParams implements Parcelable { return force; } + public boolean isNeedLocationPermission() { + return needLocationPermission; + } + @Override public void writeToParcel(Parcel out, int flags) { out.writeString(startName); @@ -85,6 +91,7 @@ public class NavigateSearchParams implements Parcelable { out.writeByte((byte) (force ? 1 : 0)); out.writeDouble(searchLat); out.writeDouble(searchLon); + out.writeByte((byte) (needLocationPermission ? 1 : 0)); } private void readFromParcel(Parcel in) { @@ -96,11 +103,11 @@ public class NavigateSearchParams implements Parcelable { force = in.readByte() != 0; searchLat = in.readDouble(); searchLon = in.readDouble(); + needLocationPermission = in.readByte() != 0; } @Override public int describeContents() { return 0; } - } diff --git a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java index c465ce2f77..2d35556d84 100644 --- a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java +++ b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java @@ -39,7 +39,7 @@ import net.osmand.data.LatLon; import net.osmand.data.QuadPoint; import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.routing.RoutingHelper; -import net.osmand.plus.routing.RoutingHelper.RouteSegmentSearchResult; +import net.osmand.plus.routing.RouteSegmentSearchResult; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.router.RouteSegmentResult; @@ -154,7 +154,7 @@ public class OsmAndLocationProvider implements SensorEventListener { startLocation.setTime(ms); } RouteSegmentSearchResult searchResult = - RoutingHelper.searchRouteSegment(currentLocation.getLatitude(), currentLocation.getLongitude(), -1, roads); + RouteSegmentSearchResult.searchRouteSegment(currentLocation.getLatitude(), currentLocation.getLongitude(), -1, roads); if (searchResult != null) { currentRoad = searchResult.getRoadIndex(); currentSegment = searchResult.getSegmentIndex(); diff --git a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java index 4221ffa308..2d46b63fd1 100644 --- a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java +++ b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java @@ -12,6 +12,7 @@ import net.osmand.data.PointDescription; import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.routing.RouteProvider.RouteService; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener; import net.osmand.plus.settings.backend.OsmandSettings; @@ -444,7 +445,7 @@ public class TargetPointsHelper { Location lastKnownLocation = ctx.getLocationProvider().getLastKnownLocation(); LatLon latLon = lastKnownLocation != null ? new LatLon(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()) : null; - routingHelper.checkAndUpdateStartLocation(latLon); + RoutingHelperUtils.checkAndUpdateStartLocation(ctx, latLon); setMyLocationPoint(latLon, false, null); } } diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index 313fa6b917..02a61a8219 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -126,7 +126,7 @@ import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu; import net.osmand.plus.routepreparationmenu.MapRouteInfoMenuFragment; import net.osmand.plus.routing.IRouteInformationListener; import net.osmand.plus.routing.RoutingHelper; -import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback; +import net.osmand.plus.routing.RouteCalculationProgressCallback; import net.osmand.plus.routing.TransportRoutingHelper.TransportRouteCalculationProgressCallback; import net.osmand.plus.search.QuickSearchDialogFragment; import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab; @@ -553,7 +553,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven allowPrivate.setModeValue(mode, true); } } - getRoutingHelper().recalculateRouteDueToSettingsChange(); + getRoutingHelper().onSettingsChanged(true); } }); dlg.setNegativeButton(R.string.shared_string_no, null); @@ -1195,6 +1195,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven mapView.fitRectToMap(qr.left, qr.right, qr.top, qr.bottom, (int) qr.width(), (int) qr.height(), 0); getMapLayers().getContextMenuLayer().enterAddGpxPointMode(newGpxPoint); } else if (toShow instanceof GpxData) { + hideContextAndRouteInfoMenues(); + GpxData gpxData = (GpxData) toShow; QuadRect qr = gpxData.getRect(); mapView.fitRectToMap(qr.left, qr.right, qr.top, qr.bottom, (int) qr.width(), (int) qr.height(), 0); diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index ed97a3669e..1eca37b058 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -63,6 +63,7 @@ import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet; import net.osmand.plus.monitoring.OsmandMonitoringPlugin; import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment; +import net.osmand.plus.profiles.ProfileDataUtils; import net.osmand.plus.profiles.RoutingProfileDataObject; import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu; import net.osmand.plus.routepreparationmenu.WaypointsFragment; @@ -121,7 +122,6 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_S import static net.osmand.plus.ContextMenuAdapter.PROFILES_CHOSEN_PROFILE_TAG; import static net.osmand.plus.ContextMenuAdapter.PROFILES_CONTROL_BUTTON_TAG; import static net.osmand.plus.ContextMenuAdapter.PROFILES_NORMAL_PROFILE_TAG; -import static net.osmand.plus.settings.fragments.NavigationFragment.getRoutingProfiles; public class MapActivityActions implements DialogProvider { @@ -737,7 +737,7 @@ public class MapActivityActions implements DialogProvider { String modeDescription; - Map profilesObjects = getRoutingProfiles(app); + Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app); for (final ApplicationMode appMode : activeModes) { if (appMode.isCustomProfile()) { modeDescription = getProfileDescription(app, appMode, profilesObjects, getString(R.string.profile_type_user_string)); @@ -1046,7 +1046,7 @@ public class MapActivityActions implements DialogProvider { //switch profile button ApplicationMode currentMode = app.getSettings().APPLICATION_MODE.get(); String modeDescription; - Map profilesObjects = getRoutingProfiles(app); + Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app); if (currentMode.isCustomProfile()) { modeDescription = getProfileDescription(app, currentMode, profilesObjects, getString(R.string.profile_type_user_string)); } else { diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java index c42e4de8aa..b7f15624b4 100644 --- a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java @@ -581,7 +581,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.audionotes_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java index 9c6c6c2e7e..fa66a5c91a 100644 --- a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java +++ b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java @@ -25,6 +25,7 @@ import net.osmand.plus.dashboard.DashboardOnMap; import net.osmand.plus.mapcontextmenu.MapContextMenu; import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.views.AnimateDraggingMapThread; import net.osmand.plus.views.OsmandMapTileView; @@ -175,7 +176,7 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc locationProvider = location.getProvider(); if (settings.DRIVING_REGION_AUTOMATIC.get() && !drivingRegionUpdated && !app.isApplicationInitializing()) { drivingRegionUpdated = true; - app.getRoutingHelper().checkAndUpdateStartLocation(location); + RoutingHelperUtils.checkAndUpdateStartLocation(app, location); } } if (mapView != null) { diff --git a/OsmAnd/src/net/osmand/plus/development/OsmandDevelopmentPlugin.java b/OsmAnd/src/net/osmand/plus/development/OsmandDevelopmentPlugin.java index e5d7b3e11d..10997d0f07 100644 --- a/OsmAnd/src/net/osmand/plus/development/OsmandDevelopmentPlugin.java +++ b/OsmAnd/src/net/osmand/plus/development/OsmandDevelopmentPlugin.java @@ -37,7 +37,7 @@ public class OsmandDevelopmentPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.osmand_development_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/dialogs/PluginInstalledBottomSheetDialog.java b/OsmAnd/src/net/osmand/plus/dialogs/PluginInstalledBottomSheetDialog.java index 0ef7154d2b..db9422859a 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/PluginInstalledBottomSheetDialog.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/PluginInstalledBottomSheetDialog.java @@ -15,6 +15,7 @@ import androidx.fragment.app.FragmentManager; import net.osmand.AndroidUtils; import net.osmand.PlatformUtil; +import net.osmand.plus.profiles.ProfileDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; @@ -33,7 +34,6 @@ import net.osmand.plus.download.DownloadValidationManager; import net.osmand.plus.download.IndexItem; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.FontCache; -import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.plus.widgets.style.CustomTypefaceSpan; import org.apache.commons.logging.Log; @@ -221,7 +221,7 @@ public class PluginInstalledBottomSheetDialog extends MenuBottomSheetDialogFragm final BottomSheetItemWithCompoundButton[] appModeItem = new BottomSheetItemWithCompoundButton[1]; appModeItem[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder() .setChecked(ApplicationMode.values(app).contains(mode)) - .setDescription(BaseSettingsFragment.getAppModeDescription(app, mode)) + .setDescription(ProfileDataUtils.getAppModeDescription(app, mode)) .setTitle(mode.toHumanString()) .setIcon(getActiveIcon(mode.getIconRes())) .setLayoutId(R.layout.bottom_sheet_item_with_descr_and_switch_56dp) diff --git a/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java b/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java index 22e0607c7f..bfb0ff75b1 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java +++ b/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java @@ -26,15 +26,15 @@ import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadPoint; import net.osmand.data.RotatedTileBox; -import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.mapcontextmenu.MapContextMenu; -import net.osmand.plus.routing.RoutingHelper; -import net.osmand.plus.routing.RoutingHelper.RouteSegmentSearchResult; +import net.osmand.plus.routing.RouteSegmentSearchResult; +import net.osmand.plus.routing.RoutingHelperUtils; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.views.layers.ContextMenuLayer; import net.osmand.router.RouteSegmentResult; import net.osmand.router.RoutingConfiguration; @@ -59,7 +59,7 @@ public class AvoidSpecificRoads { loadImpassableRoads(); } - public void loadImpassableRoads(){ + public void loadImpassableRoads() { for (AvoidRoadInfo avoidRoadInfo : app.getSettings().getImpassableRoadPoints()) { impassableRoads.put(new LatLon(avoidRoadInfo.latitude, avoidRoadInfo.longitude), avoidRoadInfo); } @@ -150,7 +150,7 @@ public class AvoidSpecificRoads { if (obj != null) { String locale = app.getSettings().MAP_PREFERRED_LOCALE.get(); boolean transliterate = app.getSettings().MAP_TRANSLITERATE_NAMES.get(); - String name = RoutingHelper.formatStreetName( + String name = RoutingHelperUtils.formatStreetName( obj.getName(locale, transliterate), obj.getRef(locale, transliterate, true), obj.getDestinationName(locale, transliterate, true), @@ -164,10 +164,7 @@ public class AvoidSpecificRoads { } private void recalculateRoute() { - RoutingHelper rh = app.getRoutingHelper(); - if (rh.isRouteCalculated() || rh.isRouteBeingCalculated()) { - rh.recalculateRouteDueToSettingsChange(); - } + app.getRoutingHelper().onSettingsChanged(); } public void removeImpassableRoad(LatLon latLon) { @@ -244,7 +241,7 @@ public class AvoidSpecificRoads { RotatedTileBox tb = mapActivity.getMapView().getCurrentRotatedTileBox().copy(); float maxDistPx = MAX_AVOID_ROUTE_SEARCH_RADIUS_DP * tb.getDensity(); RouteSegmentSearchResult searchResult = - RoutingHelper.searchRouteSegment(loc.getLatitude(), loc.getLongitude(), maxDistPx / tb.getPixDensity(), roads); + RouteSegmentSearchResult.searchRouteSegment(loc.getLatitude(), loc.getLongitude(), maxDistPx / tb.getPixDensity(), roads); if (searchResult != null) { QuadPoint point = searchResult.getPoint(); LatLon newLoc = new LatLon(MapUtils.get31LatitudeY((int) point.y), MapUtils.get31LongitudeX((int) point.x)); @@ -390,7 +387,14 @@ public class AvoidSpecificRoads { if (avoidRoadInfo == null) { avoidRoadInfo = new AvoidRoadInfo(); } - avoidRoadInfo.id = object != null ? object.id : 0; + if (object != null) { + avoidRoadInfo.id = object.id; +// avoidRoadInfo.direction = object.directionRoute(0, true); + avoidRoadInfo.direction = Double.NaN; + } else { + avoidRoadInfo.id = 0; + avoidRoadInfo.direction = Double.NaN; + } avoidRoadInfo.latitude = lat; avoidRoadInfo.longitude = lon; avoidRoadInfo.appModeKey = appModeKey; @@ -400,6 +404,7 @@ public class AvoidSpecificRoads { public static class AvoidRoadInfo { public long id; + public double direction = Double.NaN; public double latitude; public double longitude; public String name; diff --git a/OsmAnd/src/net/osmand/plus/helpers/ExternalApiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/ExternalApiHelper.java index 57d6039145..23c65ac932 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/ExternalApiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/ExternalApiHelper.java @@ -30,6 +30,7 @@ import net.osmand.data.PointDescription; import net.osmand.plus.FavouritesDbHelper; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; +import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; @@ -46,6 +47,7 @@ import net.osmand.plus.quickaction.QuickActionRegistry; import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.search.listitems.QuickSearchListItem; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.track.SaveGpxAsyncTask; @@ -129,6 +131,7 @@ public class ExternalApiHelper { public static final String PARAM_URI = "uri"; public static final String PARAM_DATA = "data"; public static final String PARAM_FORCE = "force"; + public static final String PARAM_LOCATION_PERMISSION = "location_permission"; public static final String PARAM_START_NAME = "start_name"; public static final String PARAM_DEST_NAME = "dest_name"; @@ -151,6 +154,9 @@ public class ExternalApiHelper { public static final String PARAM_NT_DIRECTION_NAME = "turn_name"; public static final String PARAM_NT_DIRECTION_TURN = "turn_type"; public static final String PARAM_NT_DIRECTION_LANES = "turn_lanes"; + public static final String PARAM_NT_DIRECTION_ANGLE = "turn_angle"; + public static final String PARAM_NT_DIRECTION_POSSIBLY_LEFT = "turn_possibly_left"; + public static final String PARAM_NT_DIRECTION_POSSIBLY_RIGHT = "turn_possibly_right"; public static final String PARAM_CLOSE_AFTER_COMMAND = "close_after_command"; @@ -237,7 +243,8 @@ public class ExternalApiHelper { if (gpx != null) { if (navigate) { boolean force = uri.getBooleanQueryParameter(PARAM_FORCE, false); - saveAndNavigateGpx(mapActivity, gpx, force); + boolean locationPermission = uri.getBooleanQueryParameter(PARAM_LOCATION_PERMISSION, false); + saveAndNavigateGpx(mapActivity, gpx, force, locationPermission); } else { app.getSelectedGpxHelper().setGpxFileToDisplay(gpx); } @@ -289,6 +296,7 @@ public class ExternalApiHelper { final PointDescription destDesc = new PointDescription(PointDescription.POINT_TYPE_LOCATION, destName); boolean force = uri.getBooleanQueryParameter(PARAM_FORCE, false); + final boolean locationPermission = uri.getBooleanQueryParameter(PARAM_LOCATION_PERMISSION, false); final RoutingHelper routingHelper = app.getRoutingHelper(); if (routingHelper.isFollowingMode() && !force) { @@ -297,12 +305,12 @@ public class ExternalApiHelper { @Override public void onDismiss(DialogInterface dialog) { if (!routingHelper.isFollowingMode()) { - startNavigation(mapActivity, start, startDesc, dest, destDesc, profile); + startNavigation(mapActivity, start, startDesc, dest, destDesc, profile, locationPermission); } } }); } else { - startNavigation(mapActivity, start, startDesc, dest, destDesc, profile); + startNavigation(mapActivity, start, startDesc, dest, destDesc, profile, locationPermission); } } @@ -348,6 +356,7 @@ public class ExternalApiHelper { resultCode = RESULT_CODE_ERROR_SEARCH_LOCATION_UNDEFINED; } else { boolean force = uri.getBooleanQueryParameter(PARAM_FORCE, false); + final boolean locationPermission = uri.getBooleanQueryParameter(PARAM_LOCATION_PERMISSION, false); final RoutingHelper routingHelper = app.getRoutingHelper(); if (routingHelper.isFollowingMode() && !force) { @@ -356,12 +365,12 @@ public class ExternalApiHelper { @Override public void onDismiss(DialogInterface dialog) { if (!routingHelper.isFollowingMode()) { - searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, showSearchResults); + searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, showSearchResults, locationPermission); } } }); } else { - searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, showSearchResults); + searchAndNavigate(mapActivity, searchLocation, start, startDesc, profile, searchQuery, showSearchResults, locationPermission); } resultCode = Activity.RESULT_OK; } @@ -629,7 +638,8 @@ public class ExternalApiHelper { return null; } - public static void saveAndNavigateGpx(MapActivity mapActivity, final GPXFile gpxFile, final boolean force) { + public static void saveAndNavigateGpx(MapActivity mapActivity, final GPXFile gpxFile, + final boolean force, final boolean checkLocationPermission) { final WeakReference mapActivityRef = new WeakReference<>(mapActivity); if (Algorithms.isEmpty(gpxFile.path)) { @@ -670,12 +680,12 @@ public class ExternalApiHelper { public void onDismiss(DialogInterface dialog) { MapActivity mapActivity = mapActivityRef.get(); if (mapActivity != null && !routingHelper.isFollowingMode()) { - ExternalApiHelper.startNavigation(mapActivity, gpxFile); + ExternalApiHelper.startNavigation(mapActivity, gpxFile, checkLocationPermission); } } }); } else { - startNavigation(mapActivity, gpxFile); + startNavigation(mapActivity, gpxFile, checkLocationPermission); } } } @@ -688,8 +698,11 @@ public class ExternalApiHelper { if (ni.directionInfo != null && ni.directionInfo.getTurnType() != null) { TurnType tt = ni.directionInfo.getTurnType(); RouteDirectionInfo a = ni.directionInfo; - result.putExtra(prefix + PARAM_NT_DIRECTION_NAME, RoutingHelper.formatStreetName(a.getStreetName(), a.getRef(), a.getDestinationName(), "")); + result.putExtra(prefix + PARAM_NT_DIRECTION_NAME, RoutingHelperUtils.formatStreetName(a.getStreetName(), a.getRef(), a.getDestinationName(), "")); result.putExtra(prefix + PARAM_NT_DIRECTION_TURN, tt.toXmlString()); + result.putExtra(prefix + PARAM_NT_DIRECTION_ANGLE, tt.getTurnAngle()); + result.putExtra(prefix + PARAM_NT_DIRECTION_POSSIBLY_LEFT, tt.isPossibleLeftTurn()); + result.putExtra(prefix + PARAM_NT_DIRECTION_POSSIBLY_RIGHT, tt.isPossibleRightTurn()); if (tt.getLanes() != null) { result.putExtra(prefix + PARAM_NT_DIRECTION_LANES, Arrays.toString(tt.getLanes())); } @@ -705,23 +718,22 @@ public class ExternalApiHelper { mapContextMenu.show(new LatLon(lat, lon), pointDescription, object); } - static public void startNavigation(MapActivity mapActivity, - @NonNull GPXFile gpx) { - startNavigation(mapActivity, gpx, null, null, null, null, null); + static public void startNavigation(MapActivity mapActivity, @NonNull GPXFile gpx, boolean checkLocationPermission) { + startNavigation(mapActivity, gpx, null, null, null, null, null, checkLocationPermission); } static public void startNavigation(MapActivity mapActivity, @Nullable LatLon from, @Nullable PointDescription fromDesc, @Nullable LatLon to, @Nullable PointDescription toDesc, - @NonNull ApplicationMode mode) { - startNavigation(mapActivity, null, from, fromDesc, to, toDesc, mode); + @NonNull ApplicationMode mode, boolean checkLocationPermission) { + startNavigation(mapActivity, null, from, fromDesc, to, toDesc, mode, checkLocationPermission); } static private void startNavigation(MapActivity mapActivity, GPXFile gpx, LatLon from, PointDescription fromDesc, LatLon to, PointDescription toDesc, - ApplicationMode mode) { + ApplicationMode mode, boolean checkLocationPermission) { OsmandApplication app = mapActivity.getMyApplication(); RoutingHelper routingHelper = app.getRoutingHelper(); if (gpx == null) { @@ -745,12 +757,15 @@ public class ExternalApiHelper { app.getRoutingHelper().notifyIfRouteIsCalculated(); routingHelper.setCurrentLocation(app.getLocationProvider().getLastKnownLocation(), false); } + if (checkLocationPermission) { + OsmAndLocationProvider.requestFineLocationPermissionIfNeeded(mapActivity); + } } static public void searchAndNavigate(@NonNull MapActivity mapActivity, @NonNull final LatLon searchLocation, @Nullable final LatLon from, @Nullable final PointDescription fromDesc, @NonNull final ApplicationMode mode, @NonNull final String searchQuery, - final boolean showSearchResults) { + final boolean showSearchResults, final boolean checkLocationPermission) { final WeakReference mapActivityRef = new WeakReference<>(mapActivity); OsmandApplication app = mapActivity.getMyApplication(); @@ -791,7 +806,7 @@ public class ExternalApiHelper { LatLon to = new LatLon(res.getLatitude(), res.getLongitude()); PointDescription toDesc = new PointDescription( PointDescription.POINT_TYPE_TARGET, res.getLocalName() + ", " + res.getLocalTypeName()); - startNavigation(mapActivity, from, fromDesc, to, toDesc, mode); + startNavigation(mapActivity, from, fromDesc, to, toDesc, mode, checkLocationPermission); } else { mapActivity.getMyApplication().showToastMessage(mapActivity.getString(R.string.search_nothing_found)); } diff --git a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java index 19cd646ecb..8d0d8210c1 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java @@ -39,15 +39,17 @@ import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** + * */ public class WaypointDialogHelper { private MapActivity mapActivity; private OsmandApplication app; private WaypointHelper waypointHelper; - private List helperCallbacks= new ArrayList<>(); + private List helperCallbacks = new ArrayList<>(); private boolean flat; private List deletedPoints; @@ -242,8 +244,8 @@ public class WaypointDialogHelper { // switch start & finish public static void switchStartAndFinish(TargetPointsHelper targetPointsHelper, TargetPoint finish, - Activity ctx, TargetPoint start, OsmandApplication app, - WaypointDialogHelper helper) { + Activity ctx, TargetPoint start, OsmandApplication app, + WaypointDialogHelper helper) { if (finish == null) { app.showShortToastMessage(R.string.mark_final_location_first); } else { @@ -263,6 +265,20 @@ public class WaypointDialogHelper { } } + public static void reverseAllPoints(OsmandApplication app, Activity ctx, + WaypointDialogHelper helper) { + TargetPointsHelper targets = app.getTargetPointsHelper(); + if (!targets.getAllPoints().isEmpty()) { + List points = targets.getAllPoints(); + Collections.reverse(points); + TargetPoint start = points.get(0); + targets.setStartPoint(start.point, false, start.getOriginalPointDescription()); + points.remove(start); + targets.reorderAllTargetPoints(points, true); + updateControls(ctx, helper); + } + } + public static void updateControls(Activity ctx, WaypointDialogHelper helper) { if (helper != null && helper.helperCallbacks != null) { for (WaypointDialogHelperCallback callback : helper.helperCallbacks) { @@ -278,7 +294,7 @@ public class WaypointDialogHelper { } public static void replaceStartWithFirstIntermediate(TargetPointsHelper targetPointsHelper, Activity ctx, - WaypointDialogHelper helper) { + WaypointDialogHelper helper) { List intermediatePoints = targetPointsHelper.getIntermediatePointsWithTarget(); TargetPoint firstIntermediate = intermediatePoints.remove(0); targetPointsHelper.setStartPoint(new LatLon(firstIntermediate.getLatitude(), @@ -443,7 +459,8 @@ public class WaypointDialogHelper { @Override public void createMenuItems(Bundle savedInstanceState) { items.add(new TitleItem(getString(R.string.shared_string_options))); - + final OsmandApplication app = requiredMyApplication(); + final TargetPointsHelper targetsHelper = app.getTargetPointsHelper(); BaseBottomSheetItem sortDoorToDoorItem = new SimpleBottomSheetItem.Builder() .setIcon(getContentIcon(R.drawable.ic_action_sort_door_to_door)) .setTitle(getString(R.string.intermediate_items_sort_by_distance)) @@ -491,6 +508,30 @@ public class WaypointDialogHelper { .create(); items.add(reorderStartAndFinishItem); + BaseBottomSheetItem reorderAllItems = new SimpleBottomSheetItem.Builder() + .setIcon(getContentIcon(R.drawable.ic_action_sort_reverse_order)) + .setTitle(getString(R.string.reverse_all_points)) + .setLayoutId(R.layout.bottom_sheet_item_simple) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + WaypointDialogHelper.reverseAllPoints( + app, + mapActivity, + mapActivity.getDashboard().getWaypointDialogHelper() + ); + } + dismiss(); + } + }) + .create(); + int intermediateSize = targetsHelper.getIntermediatePoints().size(); + if (intermediateSize > 2) { + items.add(reorderAllItems); + } + items.add(new DividerHalfItem(getContext())); final BaseBottomSheetItem[] addWaypointItem = new BaseBottomSheetItem[1]; diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/ImpassibleRoadsMenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/ImpassibleRoadsMenuController.java index b4779f1d27..450d89f093 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/ImpassibleRoadsMenuController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/ImpassibleRoadsMenuController.java @@ -31,10 +31,7 @@ public class ImpassibleRoadsMenuController extends MenuController { if (activity != null) { app.getAvoidSpecificRoads().removeImpassableRoad( ImpassibleRoadsMenuController.this.avoidRoadInfo); - RoutingHelper rh = app.getRoutingHelper(); - if (rh.isRouteCalculated() || rh.isRouteBeingCalculated()) { - rh.recalculateRouteDueToSettingsChange(); - } + app.getRoutingHelper().onSettingsChanged(); activity.getContextMenu().close(); } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/RoutePreferencesMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/RoutePreferencesMenu.java index 65656cec79..005433cbe2 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/RoutePreferencesMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/RoutePreferencesMenu.java @@ -137,7 +137,7 @@ public class RoutePreferencesMenu { LocalRoutingParameter rp = group.getRoutingParameters().get(i); rp.setSelected(settings, i == position); } - mapActivity.getRoutingHelper().recalculateRouteDueToSettingsChange(); + mapActivity.getRoutingHelper().onSettingsChanged(true); updateParameters(); } } @@ -366,7 +366,7 @@ public class RoutePreferencesMenu { app.getTargetPointsHelper().updateRouteAndRefresh(true); updateSpinnerItems(gpxSpinner); updateParameters(); - mapActivity.getRoutingHelper().recalculateRouteDueToSettingsChange(); + mapActivity.getRoutingHelper().onSettingsChanged(true); return true; } }, app.getDaynightHelper().isNightModeForMapControls()); @@ -389,7 +389,7 @@ public class RoutePreferencesMenu { if (mapActivity.getRoutingHelper().getCurrentGPXRoute() != null) { mapActivity.getRoutingHelper().setGpxParams(null); settings.FOLLOW_THE_GPX_ROUTE.set(null); - mapActivity.getRoutingHelper().recalculateRouteDueToSettingsChange(); + mapActivity.getRoutingHelper().onSettingsChanged(true); } updateParameters(); return true; diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java index 7883e2c5f0..770f973592 100644 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java @@ -83,7 +83,7 @@ public class MapillaryPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.plugin_mapillary_descr); } diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/MarkersPlanRouteContext.java b/OsmAnd/src/net/osmand/plus/mapmarkers/MarkersPlanRouteContext.java index 622fa39542..2060140d3d 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/MarkersPlanRouteContext.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/MarkersPlanRouteContext.java @@ -4,6 +4,7 @@ import android.util.Pair; import net.osmand.Location; import net.osmand.data.LatLon; +import net.osmand.plus.routing.RouteCalculationProgressCallback; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; @@ -127,7 +128,7 @@ public class MarkersPlanRouteContext { findPairsToCalculate(points); RoutingHelper routingHelper = app.getRoutingHelper(); if (!snapToRoadPairsToCalculate.isEmpty() && !routingHelper.isRouteBeingCalculated()) { - routingHelper.startRouteCalculationThread(getParams(), true, true); + routingHelper.startRouteCalculationThread(getParams()); app.runInUIThread(new Runnable() { @Override public void run() { @@ -217,7 +218,7 @@ public class MarkersPlanRouteContext { params.mode = snappedMode; params.ctx = app; params.calculationProgress = calculationProgress = new RouteCalculationProgress(); - params.calculationProgressCallback = new RoutingHelper.RouteCalculationProgressCallback() { + params.calculationProgressCallback = new RouteCalculationProgressCallback() { @Override public void start() { @@ -265,7 +266,7 @@ public class MarkersPlanRouteContext { } }); if (!snapToRoadPairsToCalculate.isEmpty()) { - app.getRoutingHelper().startRouteCalculationThread(getParams(), true, true); + app.getRoutingHelper().startRouteCalculationThread(getParams()); } else { app.runInUIThread(new Runnable() { @Override diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index 6d1522de1d..f4f2bd3da9 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -20,7 +20,7 @@ import net.osmand.plus.routing.RouteCalculationParams; import net.osmand.plus.routing.RouteCalculationParams.RouteCalculationResultListener; import net.osmand.plus.routing.RouteCalculationResult; import net.osmand.plus.routing.RoutingHelper; -import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback; +import net.osmand.plus.routing.RouteCalculationProgressCallback; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.router.RouteCalculationProgress; import net.osmand.router.RouteExporter; @@ -673,7 +673,7 @@ public class MeasurementEditingContext { if (progressListener != null && !routingHelper.isRouteBeingCalculated()) { RouteCalculationParams params = getParams(true); if (params != null) { - routingHelper.startRouteCalculationThread(params, true, true); + routingHelper.startRouteCalculationThread(params); application.runInUIThread(new Runnable() { @Override public void run() { @@ -1063,7 +1063,7 @@ public class MeasurementEditingContext { progressListener.refresh(); RouteCalculationParams params = getParams(false); if (params != null) { - application.getRoutingHelper().startRouteCalculationThread(params, true, true); + application.getRoutingHelper().startRouteCalculationThread(params); } else { progressListener.hideProgressBar(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java index c54dd93a08..e3987d903c 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java @@ -70,13 +70,14 @@ import net.osmand.plus.measurementtool.command.MovePointCommand; import net.osmand.plus.measurementtool.command.RemovePointCommand; import net.osmand.plus.measurementtool.command.ReorderPointCommand; import net.osmand.plus.measurementtool.command.ReversePointsCommand; -import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet; -import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DialogMode; import net.osmand.plus.measurementtool.command.SplitPointsCommand; +import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet; +import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.OnAppModeConfiguredCallback; +import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DialogMode; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.views.layers.MapControlsLayer; +import net.osmand.plus.views.layers.MapControlsLayer.MapControlsThemeInfoProvider; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarView; @@ -108,8 +109,8 @@ import static net.osmand.plus.measurementtool.command.ClearPointsCommand.ClearCo public class MeasurementToolFragment extends BaseOsmAndFragment implements RouteBetweenPointsFragmentListener, OptionsFragmentListener, GpxApproximationFragmentListener, SelectedPointFragmentListener, - SaveAsNewTrackFragmentListener, MapControlsLayer.MapControlsThemeInfoProvider, - RouteOptionsBottomSheet.OnAppModeConfiguredCallback{ + SaveAsNewTrackFragmentListener, MapControlsThemeInfoProvider, + OnAppModeConfiguredCallback { public static final String TAG = MeasurementToolFragment.class.getSimpleName(); public static final String TAPS_DISABLED_KEY = "taps_disabled_key"; @@ -179,7 +180,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route return mainView.getHeight(); } - public boolean shouldShowXAxisPoints () { + public boolean shouldShowXAxisPoints() { return false; } } @@ -546,7 +547,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (savedInstanceState == null) { if (fileName != null) { addNewGpxData(getGpxFile(fileName)); - } else if (editingCtx.isApproximationNeeded()) { + } else if (editingCtx.isApproximationNeeded() && isFollowTrackMode()) { enterApproximationMode(mapActivity); } } else { @@ -929,7 +930,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (isFollowTrackMode()) { mapActivity.getMapActions().setGPXRouteParams(gpx); app.getTargetPointsHelper().updateRouteAndRefresh(true); - app.getRoutingHelper().recalculateRouteDueToSettingsChange(); + app.getRoutingHelper().onSettingsChanged(true); } else { mapActivity.getMapActions().stopNavigationActionConfirm(null , new Runnable() { @Override diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index 7429caadd6..16c60911df 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -117,7 +117,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.record_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/notifications/NavigationNotification.java b/OsmAnd/src/net/osmand/plus/notifications/NavigationNotification.java index d0632d812a..63c17ceece 100644 --- a/OsmAnd/src/net/osmand/plus/notifications/NavigationNotification.java +++ b/OsmAnd/src/net/osmand/plus/notifications/NavigationNotification.java @@ -17,6 +17,7 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat.BigTextStyle; import androidx.core.app.NotificationCompat.Builder; +import net.osmand.Location; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; @@ -77,7 +78,7 @@ public class NavigationNotification extends OsmandNotification { RoutingHelper routingHelper = app.getRoutingHelper(); routingHelper.setRoutePlanningMode(false); routingHelper.setFollowingMode(true); - routingHelper.setCurrentLocation(app.getLocationProvider().getLastKnownLocation(), false); + routingHelper.setCurrentLocation(getLastKnownLocation(), false); } }, new IntentFilter(OSMAND_RESUME_NAVIGATION_SERVICE_ACTION)); @@ -136,10 +137,15 @@ public class NavigationNotification extends OsmandNotification { if (service != null && (service.getUsedBy() & USED_BY_NAVIGATION) != 0) { color = app.getResources().getColor(R.color.osmand_orange); - String distanceStr = OsmAndFormatter.getFormattedDistance(app.getRoutingHelper().getLeftDistance(), app); - String timeStr = OsmAndFormatter.getFormattedDuration(app.getRoutingHelper().getLeftTime(), app); + String distanceStr = OsmAndFormatter.getFormattedDistance(routingHelper.getLeftDistance(), app); + String timeStr = OsmAndFormatter.getFormattedDuration(routingHelper.getLeftTime(), app); String etaStr = SimpleDateFormat.getTimeInstance(DateFormat.SHORT) - .format(new Date(System.currentTimeMillis() + app.getRoutingHelper().getLeftTime() * 1000)); + .format(new Date(System.currentTimeMillis() + routingHelper.getLeftTime() * 1000)); + String speedStr = null; + Location location = getLastKnownLocation(); + if (location != null && location.hasSpeed()) { + speedStr = OsmAndFormatter.getFormattedSpeed(location.getSpeed(), app); + } TurnType turnType = null; boolean deviatedFromRoute; @@ -199,9 +205,12 @@ public class NavigationNotification extends OsmandNotification { notificationText.append("\n"); } } - - notificationText.append(distanceStr).append(" • ").append(timeStr).append(" • ").append(etaStr); - + notificationText.append(distanceStr) + .append(" • ").append(timeStr) + .append(" • ").append(etaStr); + if (speedStr != null) { + notificationText.append(" • ").append(speedStr); + } } else { notificationTitle = app.getString(R.string.shared_string_navigation); String error = routingHelper.getLastRouteCalcErrorShort(); @@ -211,7 +220,6 @@ public class NavigationNotification extends OsmandNotification { notificationText.append(error); } } - } else if (routingHelper.isRoutePlanningMode() && routingHelper.isPauseNavigation()) { ongoing = false; notificationTitle = app.getString(R.string.shared_string_navigation); @@ -266,6 +274,10 @@ public class NavigationNotification extends OsmandNotification { } } + private Location getLastKnownLocation() { + return app.getLocationProvider().getLastKnownLocation(); + } + public Bitmap drawableToBitmap(Drawable drawable) { int height = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_height); int width = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_width); diff --git a/OsmAnd/src/net/osmand/plus/openseamapsplugin/NauticalMapsPlugin.java b/OsmAnd/src/net/osmand/plus/openseamapsplugin/NauticalMapsPlugin.java index 7eb775c3a4..2db924aea3 100644 --- a/OsmAnd/src/net/osmand/plus/openseamapsplugin/NauticalMapsPlugin.java +++ b/OsmAnd/src/net/osmand/plus/openseamapsplugin/NauticalMapsPlugin.java @@ -42,7 +42,7 @@ public class NauticalMapsPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(net.osmand.plus.R.string.plugin_nautical_descr); } diff --git a/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java b/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java index 90da6cc65d..a9a3262216 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java @@ -378,7 +378,7 @@ public class OsmEditingPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.osm_editing_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java b/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java index 464e719a49..26a9a6d0a7 100644 --- a/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java +++ b/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java @@ -168,7 +168,7 @@ public class ParkingPositionPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.osmand_parking_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/profiles/ConfigureProfileMenuAdapter.java b/OsmAnd/src/net/osmand/plus/profiles/ConfigureProfileMenuAdapter.java index 23189180a0..a2e024f860 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/ConfigureProfileMenuAdapter.java +++ b/OsmAnd/src/net/osmand/plus/profiles/ConfigureProfileMenuAdapter.java @@ -16,7 +16,6 @@ import net.osmand.PlatformUtil; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -105,7 +104,7 @@ public class ConfigureProfileMenuAdapter extends AbstractProfileMenuAdapter { private String name; @@ -62,4 +63,5 @@ public class ProfileDataObject implements Comparable { public int compareTo(@NonNull ProfileDataObject another) { return this.name.compareToIgnoreCase(another.name); } + } diff --git a/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java new file mode 100644 index 0000000000..4cbc9b1940 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java @@ -0,0 +1,136 @@ +package net.osmand.plus.profiles; + +import android.content.Context; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.R; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.router.GeneralRouter; +import net.osmand.router.RoutingConfiguration; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ProfileDataUtils { + + public static final String OSMAND_NAVIGATION = "osmand_navigation"; + + public static List getDataObjects(OsmandApplication app, + List appModes) { + List profiles = new ArrayList<>(); + for (ApplicationMode mode : appModes) { + String description = mode.getDescription(); + if (Algorithms.isEmpty(description)) { + description = getAppModeDescription(app, mode); + } + profiles.add(new ProfileDataObject(mode.toHumanString(), description, + mode.getStringKey(), mode.getIconRes(), false, mode.getIconColorInfo())); + } + return profiles; + } + + public static String getAppModeDescription(Context ctx, ApplicationMode mode) { + String description; + if (mode.isCustomProfile()) { + description = ctx.getString(R.string.profile_type_user_string); + } else { + description = ctx.getString(R.string.profile_type_osmand_string); + } + + return description; + } + + public static List getSortedRoutingProfiles(OsmandApplication app) { + List result = new ArrayList<>(); + Map> routingProfilesByFileNames = getRoutingProfilesByFileNames(app); + List fileNames = new ArrayList<>(routingProfilesByFileNames.keySet()); + 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); + } + }); + for (String fileName : fileNames) { + List routingProfilesFromFile = routingProfilesByFileNames.get(fileName); + if (routingProfilesFromFile != null) { + Collections.sort(routingProfilesFromFile); + result.addAll(routingProfilesFromFile); + } + } + return result; + } + + public static Map> getRoutingProfilesByFileNames(OsmandApplication app) { + Map> result = new HashMap<>(); + for (final RoutingProfileDataObject profile : getRoutingProfiles(app).values()) { + String fileName = profile.getFileName() != null ? profile.getFileName() : OSMAND_NAVIGATION; + if (result.containsKey(fileName)) { + result.get(fileName).add(profile); + } else { + result.put(fileName, new ArrayList() { + { add(profile); } + }); + } + } + return result; + } + + public static Map getRoutingProfiles(OsmandApplication context) { + Map profilesObjects = new HashMap<>(); + profilesObjects.put(RoutingProfileDataObject.RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), new RoutingProfileDataObject( + RoutingProfileDataObject.RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), + context.getString(RoutingProfileDataObject.RoutingProfilesResources.STRAIGHT_LINE_MODE.getStringRes()), + context.getString(R.string.special_routing_type), + RoutingProfileDataObject.RoutingProfilesResources.STRAIGHT_LINE_MODE.getIconRes(), + false, null)); + profilesObjects.put(RoutingProfileDataObject.RoutingProfilesResources.DIRECT_TO_MODE.name(), new RoutingProfileDataObject( + RoutingProfileDataObject.RoutingProfilesResources.DIRECT_TO_MODE.name(), + context.getString(RoutingProfileDataObject.RoutingProfilesResources.DIRECT_TO_MODE.getStringRes()), + context.getString(R.string.special_routing_type), + RoutingProfileDataObject.RoutingProfilesResources.DIRECT_TO_MODE.getIconRes(), + false, null)); + if (context.getBRouterService() != null) { + profilesObjects.put(RoutingProfileDataObject.RoutingProfilesResources.BROUTER_MODE.name(), new RoutingProfileDataObject( + RoutingProfileDataObject.RoutingProfilesResources.BROUTER_MODE.name(), + context.getString(RoutingProfileDataObject.RoutingProfilesResources.BROUTER_MODE.getStringRes()), + context.getString(R.string.third_party_routing_type), + RoutingProfileDataObject.RoutingProfilesResources.BROUTER_MODE.getIconRes(), + false, null)); + } + + List disabledRouterNames = OsmandPlugin.getDisabledRouterNames(); + for (RoutingConfiguration.Builder builder : context.getAllRoutingConfigs()) { + collectRoutingProfilesFromConfig(context, builder, profilesObjects, disabledRouterNames); + } + return profilesObjects; + } + + private static void collectRoutingProfilesFromConfig(OsmandApplication app, RoutingConfiguration.Builder builder, + Map profilesObjects, List disabledRouterNames) { + for (Map.Entry entry : builder.getAllRouters().entrySet()) { + String routerKey = entry.getKey(); + GeneralRouter router = entry.getValue(); + if (!routerKey.equals("geocoding") && !disabledRouterNames.contains(router.getFilename())) { + int iconRes = R.drawable.ic_action_gdirections_dark; + String name = router.getProfileName(); + String description = app.getString(R.string.osmand_default_routing); + String fileName = router.getFilename(); + if (!Algorithms.isEmpty(fileName)) { + description = fileName; + } else if (RoutingProfileDataObject.RoutingProfilesResources.isRpValue(name.toUpperCase())) { + iconRes = RoutingProfileDataObject.RoutingProfilesResources.valueOf(name.toUpperCase()).getIconRes(); + name = app.getString(RoutingProfileDataObject.RoutingProfilesResources.valueOf(name.toUpperCase()).getStringRes()); + } + profilesObjects.put(routerKey, new RoutingProfileDataObject(routerKey, name, description, + iconRes, false, fileName)); + } + } + } + +} diff --git a/OsmAnd/src/net/osmand/plus/profiles/RoutingProfileDataObject.java b/OsmAnd/src/net/osmand/plus/profiles/RoutingProfileDataObject.java index 3cd3c74293..ab808de360 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/RoutingProfileDataObject.java +++ b/OsmAnd/src/net/osmand/plus/profiles/RoutingProfileDataObject.java @@ -59,4 +59,5 @@ public class RoutingProfileDataObject extends ProfileDataObject { return rpValues.contains(value); } } + } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectMultipleProfilesBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectMultipleProfilesBottomSheet.java index 23068084d8..7687f3386b 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectMultipleProfilesBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectMultipleProfilesBottomSheet.java @@ -19,7 +19,7 @@ import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; -import net.osmand.plus.settings.fragments.NavigationFragment; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; import java.util.ArrayList; @@ -54,7 +54,8 @@ public class SelectMultipleProfilesBottomSheet extends BasePreferenceBottomSheet private void refreshProfiles(OsmandApplication app) { profiles.clear(); - profiles.addAll(NavigationFragment.getBaseProfiles(app, true)); + List appModes = ApplicationMode.allPossibleValues(); + profiles.addAll(ProfileDataUtils.getDataObjects(app, appModes)); for (ProfileDataObject profile : profiles) { String key = profile.getStringKey(); profile.setSelected(selectedProfiles.contains(key)); diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java similarity index 62% rename from OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheetDialogFragment.java rename to OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java index 743c9897ad..eaf99b9503 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java @@ -2,8 +2,12 @@ package net.osmand.plus.profiles; import android.app.Activity; import android.content.Context; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; @@ -15,6 +19,8 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -28,10 +34,10 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; +import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; -import net.osmand.plus.settings.fragments.MainSettingsFragment; -import net.osmand.plus.settings.fragments.NavigationFragment; -import net.osmand.plus.settings.fragments.ProfileAppearanceFragment; +import net.osmand.plus.helpers.FontCache; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; import net.osmand.router.RoutingConfiguration; @@ -42,35 +48,36 @@ import java.util.List; import static net.osmand.plus.importfiles.ImportHelper.ImportType.ROUTING; -public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottomSheet { +public class SelectProfileBottomSheet extends BasePreferenceBottomSheet { - private static final Log LOG = PlatformUtil - .getLog(SelectProfileBottomSheetDialogFragment.class); - public static final String TAG = "SelectProfileBottomSheetDialogFragment"; + private static final Log LOG = PlatformUtil.getLog(SelectProfileBottomSheet.class); + public static final String TAG = "SelectProfileBottomSheet"; public final static String DIALOG_TYPE = "dialog_type"; - public final static String TYPE_BASE_APP_PROFILE = "base_profiles"; - public final static String TYPE_NAV_PROFILE = "routing_profiles"; public final static String SELECTED_KEY = "selected_base"; public final static String PROFILE_KEY_ARG = "profile_key_arg"; + public final static String USE_LAST_PROFILE_ARG = "use_last_profile_arg"; public final static String IS_PROFILE_IMPORTED_ARG = "is_profile_imported_arg"; - String type; - - private SelectProfileListener listener; - + private DialogMode dialogMode; private final List profiles = new ArrayList<>(); - private String selectedItemKey; + public enum DialogMode { + BASE_PROFILE, + NAVIGATION_PROFILE, + DEFAULT_PROFILE + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OsmandApplication app = getMyApplication(); Bundle args = getArguments(); if (args != null && args.get(DIALOG_TYPE) != null) { - type = args.getString(DIALOG_TYPE); + String dialogModeName = args.getString(DIALOG_TYPE); + dialogMode = DialogMode.valueOf(dialogModeName); selectedItemKey = args.getString(SELECTED_KEY, null); refreshProfiles(app); } @@ -91,12 +98,12 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom @Override public void createMenuItems(Bundle savedInstanceState) { OsmandApplication app = requiredMyApplication(); - + View bottomSpaceView = new View(app); int space = (int) getResources().getDimension(R.dimen.empty_state_text_button_padding_top); bottomSpaceView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, space)); - - if (type.equals(TYPE_BASE_APP_PROFILE)) { + + if (dialogMode == DialogMode.BASE_PROFILE) { items.add(new TitleItem(getString(R.string.select_base_profile_dialog_title))); items.add(new LongDescriptionItem(getString(R.string.select_base_profile_dialog_message))); for (int i = 0; i < profiles.size(); i++) { @@ -138,7 +145,7 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom .setCustomView(bottomSpaceView) .create());*/ - } else if (type.equals(TYPE_NAV_PROFILE)) { + } else if (dialogMode == DialogMode.NAVIGATION_PROFILE) { items.add(new TitleItem(getString(R.string.select_nav_profile_dialog_title))); items.add(new LongDescriptionItem(getString(R.string.select_nav_profile_dialog_message))); for (int i = 0; i < profiles.size(); i++) { @@ -146,11 +153,11 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom boolean showBottomDivider = false; if (i < profiles.size() - 1) { RoutingProfileDataObject nextProfile = (RoutingProfileDataObject) profiles.get(i + 1); - if (profile.getFileName() == null) { - showBottomDivider = nextProfile.getFileName() != null; - } else { - showBottomDivider = !profile.getFileName().equals(nextProfile.getFileName()); - } + if (profile.getFileName() == null) { + showBottomDivider = nextProfile.getFileName() != null; + } else { + showBottomDivider = !profile.getFileName().equals(nextProfile.getFileName()); + } } addProfileItem(profile, showBottomDivider); } @@ -175,15 +182,44 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom items.add(new BaseBottomSheetItem.Builder() .setCustomView(bottomSpaceView) .create()); + } else if (dialogMode == DialogMode.DEFAULT_PROFILE) { + items.add(new TitleItem(getString(R.string.settings_preset))); + items.add(new LongDescriptionItem(getString(R.string.profile_by_default_description))); + + boolean useLastAppModeByDefault = app.getSettings().USE_LAST_APPLICATION_MODE_BY_DEFAULT.get(); + addCheckableItem(R.string.shared_string_last_used, useLastAppModeByDefault, new OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putBoolean(USE_LAST_PROFILE_ARG, true); + Fragment target = getTargetFragment(); + if (target instanceof OnSelectProfileCallback) { + ((OnSelectProfileCallback) target).onProfileSelected(args); + } + dismiss(); + } + }); + + items.add(new SimpleDividerItem(app)); + for (int i = 0; i < profiles.size(); i++) { + ProfileDataObject profile = profiles.get(i); + addProfileItem(profile, false, !useLastAppModeByDefault); + } } } - + private void addProfileItem(final ProfileDataObject profile, boolean showBottomDivider) { + addProfileItem(profile, showBottomDivider, true); + } + + private void addProfileItem(final ProfileDataObject profile, + boolean showBottomDivider, + boolean setupSelected) { OsmandApplication app = requiredMyApplication(); - + int activeColorResId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; int iconDefaultColorResId = nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light; - + View itemView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.bottom_sheet_item_with_descr_and_radio_btn, null); TextView tvTitle = itemView.findViewById(R.id.title); TextView tvDescription = itemView.findViewById(R.id.description); @@ -193,13 +229,13 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom tvTitle.setText(profile.getName()); tvDescription.setText(profile.getDescription()); - - boolean isSelected = profile.getStringKey().equals(selectedItemKey); + + boolean isSelected = setupSelected && profile.getStringKey().equals(selectedItemKey); int iconColor; - if (type.equals(TYPE_BASE_APP_PROFILE)) { - iconColor = profile.getIconColor(nightMode); - } else { + if (dialogMode == DialogMode.NAVIGATION_PROFILE) { iconColor = isSelected ? activeColorResId : iconDefaultColorResId; + } else { + iconColor = profile.getIconColor(nightMode); } Drawable drawableIcon = app.getUIUtilities().getIcon(profile.getIconRes(), iconColor); @@ -213,28 +249,56 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom .setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - if (listener == null) { - getListener(); - } Bundle args = new Bundle(); args.putString(PROFILE_KEY_ARG, profile.getStringKey()); - listener.onSelectedType(args); + Fragment target = getTargetFragment(); + if (target instanceof OnSelectProfileCallback) { + ((OnSelectProfileCallback) target).onProfileSelected(args); + } dismiss(); } }) .create()); } - + + private void addCheckableItem(int titleId, + boolean isSelected, + OnClickListener listener) { + OsmandApplication app = requiredMyApplication(); + View itemView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.bottom_sheet_item_with_descr_and_radio_btn, null); + + itemView.findViewById(R.id.icon).setVisibility(View.GONE); + itemView.findViewById(R.id.description).setVisibility(View.GONE); + itemView.findViewById(R.id.divider_bottom).setVisibility(View.GONE); + + Typeface typeface = FontCache.getRobotoMedium(app); + String title = getString(titleId); + SpannableString spannable = UiUtilities.createCustomFontSpannable(typeface, title, title, title); + int activeColor = ContextCompat.getColor(app, getActiveColorId()); + ForegroundColorSpan colorSpan = new ForegroundColorSpan(activeColor); + spannable.setSpan(colorSpan, 0, title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ((TextView) itemView.findViewById(R.id.title)).setText(spannable); + + CompoundButton compoundButton = itemView.findViewById(R.id.compound_button); + compoundButton.setChecked(isSelected); + UiUtilities.setupCompoundButton(compoundButton, nightMode, UiUtilities.CompoundButtonType.GLOBAL); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(itemView) + .setOnClickListener(listener) + .create()); + } + private void addButtonItem(int titleId, int iconId, OnClickListener listener) { OsmandApplication app = requiredMyApplication(); Context themedCtx = UiUtilities.getThemedContext(app, nightMode); - + int activeColorResId = AndroidUtils.resolveAttribute(themedCtx, R.attr.active_color_basic); - + View buttonView = View.inflate(themedCtx, R.layout.bottom_sheet_item_preference_btn, null); TextView tvTitle = buttonView.findViewById(R.id.title); - tvTitle.setText(app.getString(titleId)); - + tvTitle.setText(getString(titleId)); + ImageView ivIcon = buttonView.findViewById(R.id.icon); ivIcon.setImageDrawable(app.getUIUtilities().getIcon(iconId, activeColorResId)); @@ -244,18 +308,6 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom .create()); } - private void refreshProfiles(OsmandApplication app) { - profiles.clear(); - if (type.equals(TYPE_NAV_PROFILE)) { - profiles.addAll(NavigationFragment.getSortedRoutingProfiles(app)); - } else if (type.equals(TYPE_BASE_APP_PROFILE)) { - profiles.addAll(NavigationFragment.getBaseProfiles(app)); - } else { - LOG.error("Check data type!"); - dismiss(); - } - } - private void refreshView() { Activity activity = getActivity(); View mainView = getView(); @@ -275,28 +327,25 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom } } - private void getListener() { - FragmentActivity activity = getActivity(); - if (activity != null) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - NavigationFragment navigationFragment = (NavigationFragment) fragmentManager.findFragmentByTag(NavigationFragment.class.getName()); - ProfileAppearanceFragment profileAppearanceFragment = (ProfileAppearanceFragment) fragmentManager.findFragmentByTag(ProfileAppearanceFragment.TAG); - MainSettingsFragment mainSettingsFragment = (MainSettingsFragment) fragmentManager.findFragmentByTag(MainSettingsFragment.TAG); + private void refreshProfiles(OsmandApplication app) { + profiles.clear(); + switch (dialogMode) { + case BASE_PROFILE: + List appModes = new ArrayList<>(ApplicationMode.allPossibleValues()); + appModes.remove(ApplicationMode.DEFAULT); + profiles.addAll(ProfileDataUtils.getDataObjects(app, appModes)); + break; - if (navigationFragment != null) { - listener = navigationFragment.getNavProfileListener(); - } else if (profileAppearanceFragment != null) { - listener = profileAppearanceFragment.getParentProfileListener(); - } else if (mainSettingsFragment != null) { - listener = mainSettingsFragment.getParentProfileListener(); - } + case NAVIGATION_PROFILE: + profiles.addAll(ProfileDataUtils.getSortedRoutingProfiles(app)); + break; + + case DEFAULT_PROFILE: + profiles.addAll(ProfileDataUtils.getDataObjects(app, ApplicationMode.values(app))); + break; } } - public interface SelectProfileListener { - void onSelectedType(Bundle args); - } - @Nullable private MapActivity getMapActivity() { Activity activity = getActivity(); @@ -305,4 +354,23 @@ public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottom } return null; } + + public static void showInstance(@NonNull FragmentActivity activity, + @NonNull DialogMode dialogMode, + @Nullable Fragment target, + String selectedItemKey, + boolean usedOnMap) { + SelectProfileBottomSheet fragment = new SelectProfileBottomSheet(); + Bundle args = new Bundle(); + args.putString(DIALOG_TYPE, dialogMode.name()); + args.putString(SELECTED_KEY, selectedItemKey); + fragment.setArguments(args); + fragment.setUsedOnMap(usedOnMap); + fragment.setTargetFragment(target, 0); + fragment.show(activity.getSupportFragmentManager(), TAG); + } + + public interface OnSelectProfileCallback { + void onProfileSelected(Bundle args); + } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileMenuAdapter.java b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileMenuAdapter.java index 684479fc6f..205f608c9a 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileMenuAdapter.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileMenuAdapter.java @@ -19,7 +19,6 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; -import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -99,7 +98,7 @@ public class SelectProfileMenuAdapter extends AbstractProfileMenuAdapter objects = new ArrayList<>(); + for (OsmandMapLayer layer : mapView.getLayers()) { + if (layer instanceof IContextMenuProvider) { + objects.clear(); + IContextMenuProvider provider = (IContextMenuProvider) layer; + provider.collectObjectsFromPoint(point, tileBox, objects, true); + for (Object o : objects) { + if (provider.isObjectClickable(o)) { + latLon = provider.getObjectLocation(o); + } + } + } + } + return latLon; + } + private void choosePointTypeAction(MapActivity mapActivity, LatLon latLon, PointType pointType, PointDescription pd, String address) { OsmandApplication app = getApp(); FavouritesDbHelper favorites = app.getFavorites(); @@ -862,7 +886,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener } routingHelper.setAppMode(next); app.initVoiceCommandPlayer(mapActivity, next, true, null, false, false, true); - routingHelper.recalculateRouteDueToSettingsChange(); + routingHelper.onSettingsChanged(true); } } @@ -1279,7 +1303,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener if (mapActivity != null) { OsmandApplication app = mapActivity.getMyApplication(); app.getAvoidSpecificRoads().removeImpassableRoad(avoidRoadInfo); - app.getRoutingHelper().recalculateRouteDueToSettingsChange(); + app.getRoutingHelper().onSettingsChanged(true); if (app.getAvoidSpecificRoads().getImpassableRoads().isEmpty() && getAvoidedParameters(app).isEmpty()) { mode.parameters.remove(parameter); } @@ -1312,7 +1336,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener CommonPreference preference = settings.getCustomRoutingBooleanProperty(routingParameter.getId(), routingParameter.getDefaultBoolean()); preference.setModeValue(app.getRoutingHelper().getAppMode(), false); avoidedParameters.remove(routingParameter); - app.getRoutingHelper().recalculateRouteDueToSettingsChange(); + app.getRoutingHelper().onSettingsChanged(true); if (app.getAvoidSpecificRoads().getImpassableRoads().isEmpty() && avoidedParameters.isEmpty()) { mode.parameters.remove(parameter); } @@ -2411,7 +2435,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener } } else if (routingHelper.isRouteCalculated()) { RouteCalculationResult result = routingHelper.getRoute(); - QuadRect routeRect = routingHelper.getRouteRect(result); + QuadRect routeRect = RoutingHelperUtils.getRouteRect(app, result); if (routeRect != null) { rect = routeRect; } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java index 461f947592..c7ebb4ce99 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java @@ -101,7 +101,8 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment { DIRECTIONS(), PLAN_ROUTE(MuteSoundRoutingParameter.class, RouteSimulationItem.class, - GpxLocalRoutingParameter.class); + GpxLocalRoutingParameter.class, + ShowAlongTheRouteItem.class); private final Class[] excludeParameters; @@ -399,7 +400,7 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment { boolean enabled = !settings.ENABLE_TIME_CONDITIONAL_ROUTING.getModeValue(applicationMode); settings.ENABLE_TIME_CONDITIONAL_ROUTING.setModeValue(applicationMode, enabled); timeConditionalRoutingItem[0].setChecked(enabled); - app.getRoutingHelper().recalculateRouteDueToSettingsChange(); + app.getRoutingHelper().onSettingsChanged(true); } }) .create(); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RoutingOptionsHelper.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RoutingOptionsHelper.java index d34144cbdc..1c54c1b4d2 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RoutingOptionsHelper.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RoutingOptionsHelper.java @@ -230,7 +230,7 @@ public class RoutingOptionsHelper { if (rp instanceof OtherLocalRoutingParameter) { updateGpxRoutingParameter((OtherLocalRoutingParameter) rp); } - routingHelper.recalculateRouteDueToSettingsChange(); + routingHelper.onSettingsChanged(true); } public void updateGpxRoutingParameter(OtherLocalRoutingParameter gpxParam) { @@ -377,7 +377,7 @@ public class RoutingOptionsHelper { LocalRoutingParameter rp = group.getRoutingParameters().get(i); rp.setSelected(settings, i == position); } - mapActivity.getRoutingHelper().recalculateRouteDueToSettingsChange(); + mapActivity.getRoutingHelper().onSettingsChanged(true); if (listener != null) { listener.onClick(); } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/MapMarkersCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/MapMarkersCard.java index 6367a1df9a..6e18fb0521 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/MapMarkersCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/MapMarkersCard.java @@ -108,7 +108,7 @@ public class MapMarkersCard extends BaseCard { public void onClick(View v) { LatLon point = new LatLon(marker.getLatitude(), marker.getLongitude()); app.getTargetPointsHelper().navigateToPoint(point, true, -1, marker.getPointDescription(mapActivity)); - app.getRoutingHelper().recalculateRouteDueToSettingsChange(); + app.getRoutingHelper().onSettingsChanged(true); } }); if (i > 0) { diff --git a/OsmAnd/src/net/osmand/plus/routing/CurrentStreetName.java b/OsmAnd/src/net/osmand/plus/routing/CurrentStreetName.java new file mode 100644 index 0000000000..c984fb9119 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routing/CurrentStreetName.java @@ -0,0 +1,87 @@ +package net.osmand.plus.routing; + +import androidx.annotation.NonNull; + +import net.osmand.Location; +import net.osmand.binary.RouteDataObject; +import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.router.RouteSegmentResult; +import net.osmand.router.TurnType; +import net.osmand.util.Algorithms; + +public class CurrentStreetName { + public String text; + public TurnType turnType; + public boolean showMarker; // turn type has priority over showMarker + public RouteDataObject shieldObject; + public String exitRef; + + @NonNull + private static String getRouteSegmentStreetName(@NonNull RoutingHelper routingHelper, @NonNull RouteSegmentResult rs, boolean includeRef) { + OsmandSettings settings = routingHelper.getSettings(); + String nm = rs.getObject().getName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()); + String rf = rs.getObject().getRef(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection()); + String dn = rs.getObject().getDestinationName(settings.MAP_PREFERRED_LOCALE.get(), + settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection()); + return RoutingHelperUtils.formatStreetName(nm, includeRef ? rf : null, dn, "»"); + } + + @NonNull + public static CurrentStreetName getCurrentName(@NonNull RoutingHelper routingHelper, @NonNull NextDirectionInfo n) { + CurrentStreetName streetName = new CurrentStreetName(); + Location l = routingHelper.getLastFixedLocation(); + float speed = 0; + if (l != null && l.hasSpeed()) { + speed = l.getSpeed(); + } + boolean isSet = false; + // 1. turn is imminent + if (n.distanceTo > 0 && n.directionInfo != null && !n.directionInfo.getTurnType().isSkipToSpeak() && + routingHelper.getVoiceRouter().isDistanceLess(speed, n.distanceTo, routingHelper.getVoiceRouter().PREPARE_DISTANCE * 0.75f)) { + String nm = n.directionInfo.getStreetName(); + String rf = n.directionInfo.getRef(); + String dn = n.directionInfo.getDestinationName(); + isSet = !(Algorithms.isEmpty(nm) && Algorithms.isEmpty(rf) && Algorithms.isEmpty(dn)); + streetName.text = RoutingHelperUtils.formatStreetName(nm, null, dn, "»"); + streetName.turnType = n.directionInfo.getTurnType(); + streetName.shieldObject = n.directionInfo.getRouteDataObject(); + if (streetName.turnType == null) { + streetName.turnType = TurnType.valueOf(TurnType.C, false); + } + if (n.directionInfo.getExitInfo() != null) { + streetName.exitRef = n.directionInfo.getExitInfo().getRef(); + if (!Algorithms.isEmpty(n.directionInfo.getExitInfo().getExitStreetName())) { + streetName.text = n.directionInfo.getExitInfo().getExitStreetName(); + } + } + } + // 2. display current road street name + if (!isSet) { + RouteSegmentResult rs = routingHelper.getCurrentSegmentResult(); + if (rs != null) { + streetName.text = getRouteSegmentStreetName(routingHelper, rs, false); + if (Algorithms.isEmpty(streetName.text)) { + isSet = !Algorithms.isEmpty(getRouteSegmentStreetName(routingHelper, rs, true)); + } else { + isSet = true; + } + streetName.showMarker = true; + streetName.shieldObject = rs.getObject(); + } + } + // 3. display next road street name if this one empty + if (!isSet) { + RouteSegmentResult rs = routingHelper.getNextStreetSegmentResult(); + if (rs != null) { + streetName.text = getRouteSegmentStreetName(routingHelper, rs, false); + streetName.turnType = TurnType.valueOf(TurnType.C, false); + streetName.shieldObject = rs.getObject(); + } + } + if (streetName.turnType == null) { + streetName.showMarker = true; + } + return streetName; + } +} diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationParams.java b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationParams.java index fbc361c4d5..7b38b5c91a 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationParams.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationParams.java @@ -5,7 +5,6 @@ import net.osmand.data.LatLon; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.routing.RouteProvider.GPXRouteParams; -import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback; import net.osmand.router.RouteCalculationProgress; import java.util.List; diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationProgressCallback.java b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationProgressCallback.java new file mode 100644 index 0000000000..a0649ba109 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationProgressCallback.java @@ -0,0 +1,12 @@ +package net.osmand.plus.routing; + +public interface RouteCalculationProgressCallback { + + void start(); + + void updateProgress(int progress); + + void requestPrivateAccessRouting(); + + void finish(); +} diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java index a6dcc20fca..e6efcc321f 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java @@ -435,7 +435,7 @@ public class RouteCalculationResult { } } - String description = toString(turn, ctx, false) + " " + RoutingHelper.formatStreetName(info.getStreetName(), + String description = toString(turn, ctx, false) + " " + RoutingHelperUtils.formatStreetName(info.getStreetName(), info.getRef(), info.getDestinationName(), ctx.getString(R.string.towards)); description = description.trim(); String[] pointNames = s.getObject().getPointNames(s.getStartPointIndex()); diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteRecalculationHelper.java b/OsmAnd/src/net/osmand/plus/routing/RouteRecalculationHelper.java new file mode 100644 index 0000000000..175003fe18 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routing/RouteRecalculationHelper.java @@ -0,0 +1,406 @@ +package net.osmand.plus.routing; + +import androidx.annotation.NonNull; + +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.router.RouteCalculationProgress; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static net.osmand.plus.notifications.OsmandNotification.NotificationType.NAVIGATION; + +class RouteRecalculationHelper { + + private static final int RECALCULATE_THRESHOLD_COUNT_CAUSING_FULL_RECALCULATE = 3; + private static final int RECALCULATE_THRESHOLD_CAUSING_FULL_RECALCULATE_INTERVAL = 2 * 60 * 1000; + + private final OsmandApplication app; + private final RoutingHelper routingHelper; + + private final ExecutorService executor = new RouteRecalculationExecutor(); + private final Map, RouteRecalculationTask> tasksMap = new LinkedHashMap<>(); + private RouteRecalculationTask lastTask; + + private long lastTimeEvaluatedRoute = 0; + private String lastRouteCalcError; + private String lastRouteCalcErrorShort; + private long recalculateCountInInterval = 0; + private int evalWaitInterval = 0; + + private RouteCalculationProgressCallback progressRoute; + + RouteRecalculationHelper(@NonNull RoutingHelper routingHelper) { + this.routingHelper = routingHelper; + this.app = routingHelper.getApplication(); + } + + String getLastRouteCalcError() { + return lastRouteCalcError; + } + + String getLastRouteCalcErrorShort() { + return lastRouteCalcErrorShort; + } + + void setProgressBar(RouteCalculationProgressCallback progressRoute) { + this.progressRoute = progressRoute; + } + + boolean isRouteBeingCalculated() { + synchronized (routingHelper) { + for (Future future : tasksMap.keySet()) { + if (!future.isDone()) { + return true; + } + } + } + return false; + } + + void resetEvalWaitInterval() { + evalWaitInterval = 0; + } + + void stopCalculation() { + synchronized (routingHelper) { + for (Entry, RouteRecalculationTask> taskFuture : tasksMap.entrySet()) { + taskFuture.getValue().stopCalculation(); + taskFuture.getKey().cancel(false); + } + } + } + + void stopCalculationIfParamsNotChanged() { + synchronized (routingHelper) { + boolean hasPendingTasks = tasksMap.isEmpty(); + for (Entry, RouteRecalculationTask> taskFuture : tasksMap.entrySet()) { + RouteRecalculationTask task = taskFuture.getValue(); + if (!task.isParamsChanged()) { + taskFuture.getKey().cancel(false); + task.stopCalculation(); + } + } + if (hasPendingTasks) { + if (isFollowingMode()) { + getVoiceRouter().announceBackOnRoute(); + } + } + } + } + + private OsmandSettings getSettings() { + return routingHelper.getSettings(); + } + + private ApplicationMode getAppMode() { + return routingHelper.getAppMode(); + } + + private boolean isFollowingMode() { + return routingHelper.isFollowingMode(); + } + + private VoiceRouter getVoiceRouter() { + return routingHelper.getVoiceRouter(); + } + + private Location getLastFixedLocation() { + return routingHelper.getLastFixedLocation(); + } + + private boolean isDeviatedFromRoute() { + return routingHelper.isDeviatedFromRoute(); + } + + private Location getLastProjection() { + return routingHelper.getLastProjection(); + } + + private void setNewRoute(RouteCalculationResult prevRoute, final RouteCalculationResult res, Location start) { + final boolean newRoute = !prevRoute.isCalculated(); + if (isFollowingMode()) { + Location lastFixedLocation = getLastFixedLocation(); + if (lastFixedLocation != null) { + start = lastFixedLocation; + } + // try remove false route-recalculated prompts by checking direction to second route node + boolean wrongMovementDirection = false; + List routeNodes = res.getImmutableAllLocations(); + if (routeNodes != null && !routeNodes.isEmpty()) { + int newCurrentRoute = RoutingHelperUtils.lookAheadFindMinOrthogonalDistance(start, routeNodes, res.currentRoute, 15); + if (newCurrentRoute + 1 < routeNodes.size()) { + // This check is valid for Online/GPX services (offline routing is aware of route direction) + wrongMovementDirection = RoutingHelperUtils.checkWrongMovementDirection(start, routeNodes.get(newCurrentRoute + 1)); + // set/reset evalWaitInterval only if new route is in forward direction + if (wrongMovementDirection) { + evalWaitInterval = 3000; + } else { + evalWaitInterval = Math.max(3000, evalWaitInterval * 3 / 2); + evalWaitInterval = Math.min(evalWaitInterval, 120000); + } + + } + } + // trigger voice prompt only if new route is in forward direction + // If route is in wrong direction after one more setLocation it will be recalculated + if (!wrongMovementDirection || newRoute) { + getVoiceRouter().newRouteIsCalculated(newRoute); + } + } + app.getWaypointHelper().setNewRoute(res); + routingHelper.newRouteCalculated(newRoute, res); + } + + void startRouteCalculationThread(RouteCalculationParams params, boolean paramsChanged, boolean updateProgress) { + synchronized (routingHelper) { + getSettings().LAST_ROUTE_APPLICATION_MODE.set(getAppMode()); + RouteRecalculationTask newTask = new RouteRecalculationTask(this, params, paramsChanged); + lastTask = newTask; + startProgress(params); + if (updateProgress) { + updateProgress(params); + } + Future future = executor.submit(newTask); + tasksMap.put(future, newTask); + } + } + + public void recalculateRouteInBackground(final Location start, final LatLon end, final List intermediates, + final RouteProvider.GPXRouteParamsBuilder gpxRoute, final RouteCalculationResult previousRoute, boolean paramsChanged, boolean onlyStartPointChanged) { + if (start == null || end == null) { + return; + } + // do not evaluate very often + if ((!isRouteBeingCalculated() && System.currentTimeMillis() - lastTimeEvaluatedRoute > evalWaitInterval) + || paramsChanged || !onlyStartPointChanged) { + if (System.currentTimeMillis() - lastTimeEvaluatedRoute < RECALCULATE_THRESHOLD_CAUSING_FULL_RECALCULATE_INTERVAL) { + recalculateCountInInterval++; + } + ApplicationMode mode = getAppMode(); + final RouteCalculationParams params = new RouteCalculationParams(); + params.start = start; + params.end = end; + params.intermediates = intermediates; + params.gpxRoute = gpxRoute == null ? null : gpxRoute.build(app); + params.onlyStartPointChanged = onlyStartPointChanged; + if (recalculateCountInInterval < RECALCULATE_THRESHOLD_COUNT_CAUSING_FULL_RECALCULATE + || (gpxRoute != null && gpxRoute.isPassWholeRoute() && isDeviatedFromRoute())) { + params.previousToRecalculate = previousRoute; + } else { + recalculateCountInInterval = 0; + } + params.leftSide = getSettings().DRIVING_REGION.get().leftHandDriving; + params.fast = getSettings().FAST_ROUTE_MODE.getModeValue(mode); + params.mode = mode; + params.ctx = app; + boolean updateProgress = false; + if (params.mode.getRouteService() == RouteProvider.RouteService.OSMAND) { + params.calculationProgress = new RouteCalculationProgress(); + updateProgress = true; + } else { + params.resultListener = new RouteCalculationParams.RouteCalculationResultListener() { + @Override + public void onRouteCalculated(RouteCalculationResult route) { + app.runInUIThread(new Runnable() { + + @Override + public void run() { + finishProgress(params); + } + }); + } + }; + } + if (getLastProjection() != null) { + params.currentLocation = getLastFixedLocation(); + } + startRouteCalculationThread(params, paramsChanged, updateProgress); + } + } + + void startProgress(final RouteCalculationParams params) { + if (params.calculationProgressCallback != null) { + params.calculationProgressCallback.start(); + } else if (progressRoute != null) { + progressRoute.start(); + } + } + + void updateProgress(final RouteCalculationParams params) { + final RouteCalculationProgressCallback progressRoute; + if (params.calculationProgressCallback != null) { + progressRoute = params.calculationProgressCallback; + } else { + progressRoute = this.progressRoute; + } + if (progressRoute != null) { + app.runInUIThread(new Runnable() { + + @Override + public void run() { + RouteCalculationProgress calculationProgress = params.calculationProgress; + if (isRouteBeingCalculated()) { + if (lastTask != null && lastTask.params == params) { + progressRoute.updateProgress((int) calculationProgress.getLinearProgress()); + if (calculationProgress.requestPrivateAccessRouting) { + progressRoute.requestPrivateAccessRouting(); + } + updateProgress(params); + } + } else { + if (calculationProgress.requestPrivateAccessRouting) { + progressRoute.requestPrivateAccessRouting(); + } + progressRoute.finish(); + } + } + }, 300); + } + } + + void finishProgress(RouteCalculationParams params) { + final RouteCalculationProgressCallback progressRoute; + if (params.calculationProgressCallback != null) { + progressRoute = params.calculationProgressCallback; + } else { + progressRoute = this.progressRoute; + } + if (progressRoute != null) { + progressRoute.finish(); + } + } + + private static class RouteRecalculationTask implements Runnable { + + private final RouteRecalculationHelper routingThreadHelper; + private final RoutingHelper routingHelper; + private final RouteCalculationParams params; + private final boolean paramsChanged; + + String routeCalcError; + String routeCalcErrorShort; + int evalWaitInterval = 0; + + public RouteRecalculationTask(@NonNull RouteRecalculationHelper routingThreadHelper, + @NonNull RouteCalculationParams params, boolean paramsChanged) { + this.routingThreadHelper = routingThreadHelper; + this.routingHelper = routingThreadHelper.routingHelper; + this.params = params; + this.paramsChanged = paramsChanged; + if (params.calculationProgress == null) { + params.calculationProgress = new RouteCalculationProgress(); + } + } + + public boolean isParamsChanged() { + return paramsChanged; + } + + public void stopCalculation() { + params.calculationProgress.isCancelled = true; + } + + private OsmandSettings getSettings() { + return routingHelper.getSettings(); + } + + private void showMessage(final String msg) { + final OsmandApplication app = routingHelper.getApplication(); + app.runInUIThread(new Runnable() { + @Override + public void run() { + app.showToastMessage(msg); + } + }); + } + + @Override + public void run() { + RouteProvider provider = routingHelper.getProvider(); + OsmandSettings settings = getSettings(); + RouteCalculationResult res = provider.calculateRouteImpl(params); + if (params.calculationProgress.isCancelled) { + return; + } + final boolean onlineSourceWithoutInternet = !res.isCalculated() && + params.mode.getRouteService().isOnline() && !settings.isInternetConnectionAvailable(); + if (onlineSourceWithoutInternet && settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()) { + if (params.previousToRecalculate != null && params.previousToRecalculate.isCalculated()) { + res = provider.recalculatePartOfflineRoute(res, params); + } + } + RouteCalculationResult prev = routingHelper.getRoute(); + synchronized (routingHelper) { + if (res.isCalculated()) { + if (!params.inSnapToRoadMode && !params.inPublicTransportMode) { + routingHelper.setRoute(res); + routingHelper.updateOriginalRoute(); + } + if (params.resultListener != null) { + params.resultListener.onRouteCalculated(res); + } + } else { + evalWaitInterval = Math.max(3000, routingThreadHelper.evalWaitInterval * 3 / 2); // for Issue #3899 + evalWaitInterval = Math.min(evalWaitInterval, 120000); + } + } + OsmandApplication app = routingHelper.getApplication(); + if (res.isCalculated()) { + if (!params.inSnapToRoadMode && !params.inPublicTransportMode) { + routingThreadHelper.setNewRoute(prev, res, params.start); + } + } else if (onlineSourceWithoutInternet) { + routeCalcError = app.getString(R.string.error_calculating_route) + + ":\n" + app.getString(R.string.internet_connection_required_for_online_route); + routeCalcErrorShort = app.getString(R.string.error_calculating_route); + showMessage(routeCalcError); + } else { + if (res.getErrorMessage() != null) { + routeCalcError = app.getString(R.string.error_calculating_route) + ":\n" + res.getErrorMessage(); + routeCalcErrorShort = app.getString(R.string.error_calculating_route); + } else { + routeCalcError = app.getString(R.string.empty_route_calculated); + routeCalcErrorShort = app.getString(R.string.empty_route_calculated); + } + showMessage(routeCalcError); + } + app.getNotificationHelper().refreshNotification(NAVIGATION); + } + } + + private class RouteRecalculationExecutor extends ThreadPoolExecutor { + + public RouteRecalculationExecutor() { + super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); + } + + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + RouteRecalculationTask task = null; + synchronized (routingHelper) { + if (r instanceof Future) { + task = tasksMap.remove(r); + } + } + if (t == null && task != null) { + evalWaitInterval = task.evalWaitInterval; + lastRouteCalcError = task.routeCalcError; + lastRouteCalcErrorShort = task.routeCalcErrorShort; + } + lastTimeEvaluatedRoute = System.currentTimeMillis(); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteSegmentSearchResult.java b/OsmAnd/src/net/osmand/plus/routing/RouteSegmentSearchResult.java new file mode 100644 index 0000000000..dcecfa69be --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routing/RouteSegmentSearchResult.java @@ -0,0 +1,59 @@ +package net.osmand.plus.routing; + +import net.osmand.binary.RouteDataObject; +import net.osmand.data.QuadPoint; +import net.osmand.router.RouteSegmentResult; +import net.osmand.util.MapUtils; + +import java.util.List; + +public class RouteSegmentSearchResult { + private final int roadIndex; + private final int segmentIndex; + private final QuadPoint point; + + RouteSegmentSearchResult(int roadIndex, int segmentIndex, QuadPoint point) { + this.roadIndex = roadIndex; + this.segmentIndex = segmentIndex; + this.point = point; + } + + public int getRoadIndex() { + return roadIndex; + } + + public int getSegmentIndex() { + return segmentIndex; + } + + public QuadPoint getPoint() { + return point; + } + + public static RouteSegmentSearchResult searchRouteSegment(double latitude, double longitude, double maxDist, List roads) { + int roadIndex = -1; + int segmentIndex = -1; + QuadPoint point = null; + int px = MapUtils.get31TileNumberX(longitude); + int py = MapUtils.get31TileNumberY(latitude); + double dist = maxDist < 0 ? 1000 : maxDist; + for (int i = 0; i < roads.size(); i++) { + RouteSegmentResult road = roads.get(i); + int startPointIndex = Math.min(road.getStartPointIndex(), road.getEndPointIndex()); + int endPointIndex = Math.max(road.getEndPointIndex(), road.getStartPointIndex()); + RouteDataObject obj = road.getObject(); + for (int j = startPointIndex + 1; j <= endPointIndex; j++) { + QuadPoint proj = MapUtils.getProjectionPoint31(px, py, obj.getPoint31XTile(j - 1), obj.getPoint31YTile(j - 1), + obj.getPoint31XTile(j), obj.getPoint31YTile(j)); + double dd = MapUtils.squareRootDist31((int) proj.x, (int) proj.y, px, py); + if (dd < dist) { + dist = dd; + roadIndex = i; + segmentIndex = j; + point = proj; + } + } + } + return roadIndex != -1 ? new RouteSegmentSearchResult(roadIndex, segmentIndex, point) : null; + } +} diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java index 49b8babdc8..e080f7b3bd 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java @@ -1,8 +1,6 @@ package net.osmand.plus.routing; - import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import net.osmand.GPXUtilities.GPXFile; import net.osmand.Location; @@ -10,10 +8,7 @@ import net.osmand.LocationsHolder; import net.osmand.PlatformUtil; import net.osmand.ResultMatcher; import net.osmand.ValueHolder; -import net.osmand.binary.RouteDataObject; import net.osmand.data.LatLon; -import net.osmand.data.QuadPoint; -import net.osmand.data.QuadRect; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; @@ -21,7 +16,6 @@ import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; -import net.osmand.plus.helpers.enums.MetricsConstants; import net.osmand.plus.notifications.OsmandNotification.NotificationType; import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder; @@ -30,13 +24,10 @@ import net.osmand.plus.routing.RouteProvider.RoutingEnvironment; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener; import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.router.RouteCalculationProgress; import net.osmand.router.RouteExporter; import net.osmand.router.RoutePlannerFrontEnd.GpxPoint; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import net.osmand.router.RouteSegmentResult; -import net.osmand.router.TurnType; -import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.io.IOException; @@ -46,25 +37,25 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import static net.osmand.plus.notifications.OsmandNotification.NotificationType.NAVIGATION; - public class RoutingHelper { private static final org.apache.commons.logging.Log log = PlatformUtil.getLog(RoutingHelper.class); - private static final float POSITION_TOLERANCE = 60; - private static final int CACHE_RADIUS = 100000; public static final float ALLOWED_DEVIATION = 2; // This should be correlated with RoutingHelper.updateCurrentRouteStatus ( when processed turn now is not announced) - private static int DEFAULT_GPS_TOLERANCE = 12; + private static final int DEFAULT_GPS_TOLERANCE = 12; public static int GPS_TOLERANCE = DEFAULT_GPS_TOLERANCE; public static float ARRIVAL_DISTANCE_FACTOR = 1; private List> listeners = new LinkedList<>(); private List> updateListeners = new LinkedList<>(); - private OsmandApplication app; - private TransportRoutingHelper transportRoutingHelper; + private final OsmandApplication app; + private OsmandSettings settings; + private final RouteProvider provider; + private final VoiceRouter voiceRouter; + private final RouteRecalculationHelper routeRecalculationHelper; + private final TransportRoutingHelper transportRoutingHelper; private boolean isFollowingMode = false; private boolean isRoutePlanningMode = false; @@ -81,33 +72,15 @@ public class RoutingHelper { private RouteCalculationResult originalRoute = null; - private static final int RECALCULATE_THRESHOLD_COUNT_CAUSING_FULL_RECALCULATE = 3; - private static final int RECALCULATE_THRESHOLD_CAUSING_FULL_RECALCULATE_INTERVAL = 2*60*1000; - private Thread currentRunningJob; - private long lastTimeEvaluatedRoute = 0; - private String lastRouteCalcError; - private String lastRouteCalcErrorShort; - private long recalculateCountInInterval = 0; - private int evalWaitInterval = 0; - private boolean waitingNextJob; private boolean routeWasFinished; private ApplicationMode mode; - private OsmandSettings settings; - - private RouteProvider provider; - private VoiceRouter voiceRouter; private static boolean isDeviatedFromRoute = false; private long deviateFromRouteDetected = 0; //private long wrongMovementDetected = 0; private boolean voiceRouterStopped = false; - private RouteCalculationProgressCallback progressRoute; - -// private ProgressBar progress; -// private Handler progressHandler; - public boolean isDeviatedFromRoute() { return isDeviatedFromRoute; } @@ -116,11 +89,12 @@ public class RoutingHelper { return routeWasFinished; } - public RoutingHelper(OsmandApplication context){ + public RoutingHelper(OsmandApplication context) { this.app = context; settings = context.getSettings(); voiceRouter = new VoiceRouter(this); provider = new RouteProvider(); + routeRecalculationHelper = new RouteRecalculationHelper(this); transportRoutingHelper = context.getTransportRoutingHelper(); transportRoutingHelper.setRoutingHelper(this); setAppMode(settings.APPLICATION_MODE.get()); @@ -134,6 +108,26 @@ public class RoutingHelper { app.getAppCustomization().addListener(customizationListener); } + RouteProvider getProvider() { + return provider; + } + + void resetRouteWasFinished() { + routeWasFinished = false; + } + + void setRoute(RouteCalculationResult route) { + this.route = route; + } + + long getDeviateFromRouteDetected() { + return deviateFromRouteDetected; + } + + void setDeviateFromRouteDetected(long deviateFromRouteDetected) { + this.deviateFromRouteDetected = deviateFromRouteDetected; + } + public TransportRoutingHelper getTransportRoutingHelper() { return transportRoutingHelper; } @@ -147,11 +141,11 @@ public class RoutingHelper { } public String getLastRouteCalcError() { - return lastRouteCalcError; + return routeRecalculationHelper.getLastRouteCalcError(); } public String getLastRouteCalcErrorShort() { - return lastRouteCalcErrorShort; + return routeRecalculationHelper.getLastRouteCalcErrorShort(); } public void setPauseNavigation(boolean b) { @@ -195,8 +189,8 @@ public class RoutingHelper { this.isRoutePlanningMode = isRoutePlanningMode; } - public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, List intermediatePoints, Location currentLocation){ - checkAndUpdateStartLocation(currentLocation); + public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, List intermediatePoints, Location currentLocation) { + RoutingHelperUtils.checkAndUpdateStartLocation(app, currentLocation); RouteCalculationResult previousRoute = route; clearCurrentRoute(finalLocation, intermediatePoints); // to update route @@ -206,17 +200,17 @@ public class RoutingHelper { public synchronized void clearCurrentRoute(LatLon newFinalLocation, List newIntermediatePoints) { route = new RouteCalculationResult(""); isDeviatedFromRoute = false; - evalWaitInterval = 0; + routeRecalculationHelper.resetEvalWaitInterval(); originalRoute = null; app.getWaypointHelper().setNewRoute(route); app.runInUIThread(new Runnable() { @Override public void run() { Iterator> it = listeners.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { WeakReference ref = it.next(); IRouteInformationListener l = ref.get(); - if(l == null) { + if (l == null) { it.remove(); } else { l.routeWasCancelled(); @@ -226,9 +220,7 @@ public class RoutingHelper { }); this.finalLocation = newFinalLocation; this.intermediatePoints = newIntermediatePoints; - if(currentRunningJob instanceof RouteRecalculationThread) { - ((RouteRecalculationThread) currentRunningJob).stopCalculation(); - } + routeRecalculationHelper.stopCalculation(); if (newFinalLocation == null) { settings.FOLLOW_THE_ROUTE.set(false); settings.FOLLOW_THE_GPX_ROUTE.set(null); @@ -245,10 +237,10 @@ public class RoutingHelper { @Override public void run() { Iterator> it = listeners.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { WeakReference ref = it.next(); IRouteInformationListener l = ref.get(); - if(l == null) { + if (l == null) { it.remove(); } else { l.routeWasFinished(); @@ -258,11 +250,38 @@ public class RoutingHelper { }); } + void newRouteCalculated(final boolean newRoute, final RouteCalculationResult res) { + app.runInUIThread(new Runnable() { + @Override + public void run() { + ValueHolder showToast = new ValueHolder<>(); + showToast.value = true; + Iterator> it = listeners.iterator(); + while (it.hasNext()) { + WeakReference ref = it.next(); + IRouteInformationListener l = ref.get(); + if (l == null) { + it.remove(); + } else { + l.newRouteIsCalculated(newRoute, showToast); + } + } + if (showToast.value && newRoute && OsmandPlugin.isDevelopment()) { + String msg = app.getString(R.string.new_route_calculated_dist_dbg, + OsmAndFormatter.getFormattedDistance(res.getWholeDistance(), app), + ((int) res.getRoutingTime()) + " sec", + res.getCalculateTime(), res.getVisitedSegments(), res.getLoadedTiles()); + app.showToastMessage(msg); + } + } + }); + } + public GPXRouteParamsBuilder getCurrentGPXRoute() { return currentGPXRoute; } - public boolean isCurrentGPXRouteV2() { + public boolean isCurrentGPXRouteV2() { return currentGPXRoute != null && RouteExporter.OSMAND_ROUTER_V2.equals(currentGPXRoute.getFile().author); } @@ -274,7 +293,7 @@ public class RoutingHelper { return route.getImmutableAllLocations(); } - public void setAppMode(ApplicationMode mode){ + public void setAppMode(ApplicationMode mode) { this.mode = mode; ARRIVAL_DISTANCE_FACTOR = Math.max(settings.ARRIVAL_DISTANCE_FACTOR.getModeValue(mode), 0.1f); GPS_TOLERANCE = (int) (DEFAULT_GPS_TOLERANCE * ARRIVAL_DISTANCE_FACTOR); @@ -288,27 +307,12 @@ public class RoutingHelper { public LatLon getFinalLocation() { return finalLocation; } - public void checkAndUpdateStartLocation(Location nextStartLocation) { - if (nextStartLocation != null) { - checkAndUpdateStartLocation(new LatLon(nextStartLocation.getLatitude(), nextStartLocation.getLongitude())); - } - } - - public void checkAndUpdateStartLocation(LatLon newStartLocation) { - if (newStartLocation != null) { - LatLon lastStartLocation = app.getSettings().getLastStartPoint(); - if (lastStartLocation == null || MapUtils.getDistance(newStartLocation, lastStartLocation) > CACHE_RADIUS) { - app.getMapViewTrackingUtilities().detectDrivingRegion(newStartLocation); - app.getSettings().setLastStartPoint(newStartLocation); - } - } - } public List getIntermediatePoints() { return intermediatePoints; } - public boolean isRouteCalculated(){ + public boolean isRouteCalculated() { return route.isCalculated(); } @@ -316,7 +320,7 @@ public class RoutingHelper { return voiceRouter; } - public Location getLastProjection(){ + public Location getLastProjection() { return lastProjection; } @@ -333,8 +337,8 @@ public class RoutingHelper { } private List> updateListenersList( - List> copyList, - IRoutingDataUpdateListener listener, boolean isNewListener) { + List> copyList, + IRoutingDataUpdateListener listener, boolean isNewListener) { Iterator> it = copyList.iterator(); while (it.hasNext()) { WeakReference ref = it.next(); @@ -349,18 +353,18 @@ public class RoutingHelper { return copyList; } - public void addListener(IRouteInformationListener l){ + public void addListener(IRouteInformationListener l) { listeners = updateInformationListeners(new ArrayList<>(listeners), l, true); transportRoutingHelper.addListener(l); } - public void removeListener(IRouteInformationListener lt){ + public void removeListener(IRouteInformationListener lt) { listeners = updateInformationListeners(new ArrayList<>(listeners), lt, false); } private List> updateInformationListeners( - List> copyList, - IRouteInformationListener listener, boolean isNewListener) { + List> copyList, + IRouteInformationListener listener, boolean isNewListener) { Iterator> it = copyList.iterator(); while (it.hasNext()) { WeakReference ref = it.next(); @@ -382,7 +386,7 @@ public class RoutingHelper { app.getTargetPointsHelper().setMyLocationPoint( new LatLon(currentLocation.getLatitude(), currentLocation.getLongitude()), false, null); } - if(isFollowingMode() || (settings.getPointToStart() == null && isRoutePlanningMode) || + if (isFollowingMode() || (settings.getPointToStart() == null && isRoutePlanningMode) || app.getLocationProvider().getLocationSimulation().isRouteAnimating()) { setCurrentLocation(currentLocation, false); } @@ -392,43 +396,18 @@ public class RoutingHelper { return setCurrentLocation(currentLocation, returnUpdatedLocation, route, false); } - public double getRouteDeviation(){ + public double getRouteDeviation() { if (route == null || - route.getImmutableAllDirections().size() < 2 || - route.currentRoute == 0){ + route.getImmutableAllDirections().size() < 2 || + route.currentRoute == 0) { return 0; } List routeNodes = route.getImmutableAllLocations(); - return getOrthogonalDistance(lastFixedLocation, routeNodes.get(route.currentRoute -1), routeNodes.get(route.currentRoute)); - } - - - public static float getDefaultAllowedDeviation(OsmandSettings settings, ApplicationMode mode, float posTolerance) { - if (settings.DISABLE_OFFROUTE_RECALC.getModeValue(mode)) { - return -1.0f; - } else if (mode.getRouteService() == RouteService.DIRECT_TO) { - return -1.0f; - } else if (mode.getRouteService() == RouteService.STRAIGHT) { - MetricsConstants mc = settings.METRIC_SYSTEM.getModeValue(mode); - if (mc == MetricsConstants.KILOMETERS_AND_METERS || mc == MetricsConstants.MILES_AND_METERS) { - return 500.f; - } else { - // 1/4 mile - return 482.f; - } - } - return posTolerance * ALLOWED_DEVIATION; - } - - public static float getPosTolerance(float accuracy) { - if(accuracy > 0) { - return POSITION_TOLERANCE / 2 + accuracy; - } - return POSITION_TOLERANCE; + return RoutingHelperUtils.getOrthogonalDistance(lastFixedLocation, routeNodes.get(route.currentRoute - 1), routeNodes.get(route.currentRoute)); } private Location setCurrentLocation(Location currentLocation, boolean returnUpdatedLocation, - RouteCalculationResult previousRoute, boolean targetPointsChanged) { + RouteCalculationResult previousRoute, boolean targetPointsChanged) { Location locationProjection = currentLocation; if (isPublicTransportMode() && currentLocation != null && finalLocation != null && (targetPointsChanged || transportRoutingHelper.getStartLocation() == null)) { @@ -442,14 +421,14 @@ public class RoutingHelper { isDeviatedFromRoute = false; return locationProjection; } - float posTolerance = getPosTolerance(currentLocation.hasAccuracy() ? currentLocation.getAccuracy() : 0); + float posTolerance = RoutingHelperUtils.getPosTolerance(currentLocation.hasAccuracy() ? currentLocation.getAccuracy() : 0); boolean calculateRoute = false; synchronized (this) { isDeviatedFromRoute = false; double distOrth = 0; // 0. Route empty or needs to be extended? Then re-calculate route. - if(route.isEmpty()) { + if (route.isEmpty()) { calculateRoute = true; } else { // 1. Update current route position status according to latest received location @@ -461,13 +440,13 @@ public class RoutingHelper { int currentRoute = route.currentRoute; double allowableDeviation = route.getRouteRecalcDistance(); if (allowableDeviation == 0) { - allowableDeviation = getDefaultAllowedDeviation(settings, route.getAppMode(), posTolerance); + allowableDeviation = RoutingHelperUtils.getDefaultAllowedDeviation(settings, route.getAppMode(), posTolerance); } // 2. Analyze if we need to recalculate route // >100m off current route (sideways) or parameter (for Straight line) if (currentRoute > 0 && allowableDeviation > 0) { - distOrth = getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); + distOrth = RoutingHelperUtils.getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); if (distOrth > allowableDeviation) { log.info("Recalculate route, because correlation : " + distOrth); //$NON-NLS-1$ isDeviatedFromRoute = true; @@ -478,7 +457,7 @@ public class RoutingHelper { Location next = route.getNextRouteLocation(); boolean isStraight = route.getRouteService() == RouteService.DIRECT_TO || route.getRouteService() == RouteService.STRAIGHT; - boolean wrongMovementDirection = checkWrongMovementDirection(currentLocation, next); + boolean wrongMovementDirection = RoutingHelperUtils.checkWrongMovementDirection(currentLocation, next); if ((allowableDeviation > 0 && wrongMovementDirection && !isStraight && (currentLocation.distanceTo(routeNodes.get(currentRoute)) > allowableDeviation)) && !settings.DISABLE_WRONG_DIRECTION_RECALC.get()) { log.info("Recalculate route, because wrong movement direction: " + currentLocation.distanceTo(routeNodes.get(currentRoute))); //$NON-NLS-1$ @@ -486,7 +465,7 @@ public class RoutingHelper { calculateRoute = true; } // 4. Identify if UTurn is needed - if (identifyUTurnIsNeeded(currentLocation, posTolerance)) { + if (RoutingHelperUtils.identifyUTurnIsNeeded(this, currentLocation, posTolerance)) { isDeviatedFromRoute = true; } // 5. Update Voice router @@ -509,7 +488,7 @@ public class RoutingHelper { if (currentRoute > 0) { locationProjection = new Location(currentLocation); Location nextLocation = routeNodes.get(currentRoute); - LatLon project = getProject(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); + LatLon project = RoutingHelperUtils.getProject(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); locationProjection.setLatitude(project.getLatitude()); locationProjection.setLongitude(project.getLongitude()); @@ -523,76 +502,39 @@ public class RoutingHelper { } if (calculateRoute) { - recalculateRouteInBackground(currentLocation, finalLocation, intermediatePoints, currentGPXRoute, + routeRecalculationHelper.recalculateRouteInBackground(currentLocation, finalLocation, intermediatePoints, currentGPXRoute, previousRoute.isCalculated() ? previousRoute : null, false, !targetPointsChanged); } else { - Thread job = currentRunningJob; - if(job instanceof RouteRecalculationThread) { - RouteRecalculationThread thread = (RouteRecalculationThread) job; - if(!thread.isParamsChanged()) { - thread.stopCalculation(); - } - if (isFollowingMode){ - voiceRouter.announceBackOnRoute(); - } - } + routeRecalculationHelper.stopCalculationIfParamsNotChanged(); } double projectDist = mode != null && mode.hasFastSpeed() ? posTolerance : posTolerance / 2; - if(returnUpdatedLocation && locationProjection != null && currentLocation.distanceTo(locationProjection) < projectDist) { + if (returnUpdatedLocation && locationProjection != null && currentLocation.distanceTo(locationProjection) < projectDist) { return locationProjection; } else { return currentLocation; } } - private static double getOrthogonalDistance(Location loc, Location from, Location to) { - return MapUtils.getOrthogonalDistance(loc.getLatitude(), - loc.getLongitude(), from.getLatitude(), from.getLongitude(), - to.getLatitude(), to.getLongitude()); - } - - private static LatLon getProject(Location loc, Location from, Location to) { - return MapUtils.getProjection(loc.getLatitude(), - loc.getLongitude(), from.getLatitude(), from.getLongitude(), - to.getLatitude(), to.getLongitude()); - } - - private static int lookAheadFindMinOrthogonalDistance(Location currentLocation, List routeNodes, int currentRoute, int iterations) { - double newDist; - double dist = Double.POSITIVE_INFINITY; - int index = currentRoute; - while (iterations > 0 && currentRoute + 1 < routeNodes.size()) { - newDist = getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute), routeNodes.get(currentRoute + 1)); - if (newDist < dist) { - index = currentRoute; - dist = newDist; - } - currentRoute++; - iterations--; - } - return index; - } - private boolean updateCurrentRouteStatus(Location currentLocation, double posTolerance) { List routeNodes = route.getImmutableAllLocations(); int currentRoute = route.currentRoute; // 1. Try to proceed to next point using orthogonal distance (finding minimum orthogonal dist) while (currentRoute + 1 < routeNodes.size()) { double dist = currentLocation.distanceTo(routeNodes.get(currentRoute)); - if(currentRoute > 0) { - dist = getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute - 1), + if (currentRoute > 0) { + dist = RoutingHelperUtils.getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); } boolean processed = false; // if we are still too far try to proceed many points // if not then look ahead only 3 in order to catch sharp turns boolean longDistance = dist >= 250; - int newCurrentRoute = lookAheadFindMinOrthogonalDistance(currentLocation, routeNodes, currentRoute, longDistance ? 15 : 8); - double newDist = getOrthogonalDistance(currentLocation, routeNodes.get(newCurrentRoute), + int newCurrentRoute = RoutingHelperUtils.lookAheadFindMinOrthogonalDistance(currentLocation, routeNodes, currentRoute, longDistance ? 15 : 8); + double newDist = RoutingHelperUtils.getOrthogonalDistance(currentLocation, routeNodes.get(newCurrentRoute), routeNodes.get(newCurrentRoute + 1)); - if(longDistance) { - if(newDist < dist) { + if (longDistance) { + if (newDist < dist) { if (log.isDebugEnabled()) { log.debug("Processed by distance : (new) " + newDist + " (old) " + dist); //$NON-NLS-1$//$NON-NLS-2$ } @@ -644,32 +586,32 @@ public class RoutingHelper { } // 2. check if intermediate found - if(route.getIntermediatePointsToPass() > 0 - && route.getDistanceToNextIntermediate(lastFixedLocation) < getArrivalDistance() * 2f && !isRoutePlanningMode) { + if (route.getIntermediatePointsToPass() > 0 + && route.getDistanceToNextIntermediate(lastFixedLocation) < RoutingHelperUtils.getArrivalDistance(mode, settings) * 2f && !isRoutePlanningMode) { showMessage(app.getString(R.string.arrived_at_intermediate_point)); route.passIntermediatePoint(); TargetPointsHelper targets = app.getTargetPointsHelper(); String name = ""; - if(intermediatePoints != null && !intermediatePoints.isEmpty()) { + if (intermediatePoints != null && !intermediatePoints.isEmpty()) { LatLon rm = intermediatePoints.remove(0); List ll = targets.getIntermediatePointsNavigation(); int ind = -1; - for(int i = 0; i < ll.size(); i++) { - if(ll.get(i).point != null && MapUtils.getDistance(ll.get(i).point, rm) < 5) { + for (int i = 0; i < ll.size(); i++) { + if (ll.get(i).point != null && MapUtils.getDistance(ll.get(i).point, rm) < 5) { name = ll.get(i).getOnlyName(); ind = i; break; } } - if(ind >= 0) { + if (ind >= 0) { targets.removeWayPoint(false, ind); } } - if(isFollowingMode) { + if (isFollowingMode) { voiceRouter.arrivedIntermediatePoint(name); } // double check - while(intermediatePoints != null && route.getIntermediatePointsToPass() < intermediatePoints.size()) { + while (intermediatePoints != null && route.getIntermediatePointsToPass() < intermediatePoints.size()) { intermediatePoints.remove(0); } } @@ -677,13 +619,13 @@ public class RoutingHelper { // 3. check if destination found Location lastPoint = routeNodes.get(routeNodes.size() - 1); if (currentRoute > routeNodes.size() - 3 - && currentLocation.distanceTo(lastPoint) < getArrivalDistance() + && currentLocation.distanceTo(lastPoint) < RoutingHelperUtils.getArrivalDistance(mode, settings) && !isRoutePlanningMode) { //showMessage(app.getString(R.string.arrived_at_destination)); TargetPointsHelper targets = app.getTargetPointsHelper(); TargetPoint tp = targets.getPointToNavigate(); String description = tp == null ? "" : tp.getOnlyName(); - if(isFollowingMode) { + if (isFollowingMode) { voiceRouter.arrivedDestinationPoint(description); } boolean onDestinationReached = OsmandPlugin.onDestinationReached(); @@ -717,7 +659,7 @@ public class RoutingHelper { } } - if(nextPoint > 0) { + if (nextPoint > 0) { Location next = routeNodes.get(nextPoint); Location prev = routeNodes.get(nextPoint - 1); float bearing = prev.bearingTo(next); @@ -725,14 +667,14 @@ public class RoutingHelper { double bearingPrev = Math.abs(MapUtils.degreesDiff(bearing, currentLocation.bearingTo(prev))); while (true) { Location mp = MapUtils.calculateMidPoint(prev, next); - if(mp.distanceTo(next) <= 100) { + if (mp.distanceTo(next) <= 100) { break; } double bearingMid = Math.abs(MapUtils.degreesDiff(bearing, currentLocation.bearingTo(mp))); - if(bearingPrev < ANGLE_TO_DECLINE) { + if (bearingPrev < ANGLE_TO_DECLINE) { next = mp; bearingTo = bearingMid; - } else if(bearingTo < ANGLE_TO_DECLINE){ + } else if (bearingTo < ANGLE_TO_DECLINE) { prev = mp; bearingPrev = bearingMid; } else { @@ -746,140 +688,7 @@ public class RoutingHelper { return false; } - private float getArrivalDistance() { - ApplicationMode m = mode == null ? settings.getApplicationMode() : mode; - float defaultSpeed = Math.max(0.3f, m.getDefaultSpeed()); - - /// Used to be: car - 90 m, bicycle - 50 m, pedestrian - 20 m - // return ((float)settings.getApplicationMode().getArrivalDistance()) * settings.ARRIVAL_DISTANCE_FACTOR.getModeValue(m); - // GPS_TOLERANCE - 12 m - // 5 seconds: car - 80 m @ 50 kmh, bicyle - 45 m @ 25 km/h, bicyle - 25 m @ 10 km/h, pedestrian - 18 m @ 4 km/h, - return GPS_TOLERANCE + defaultSpeed * 5 * ARRIVAL_DISTANCE_FACTOR; - } - - - private boolean identifyUTurnIsNeeded(Location currentLocation, double posTolerance) { - if (finalLocation == null || currentLocation == null || !route.isCalculated() || isPublicTransportMode()) { - return false; - } - boolean isOffRoute = false; - if (currentLocation.hasBearing()) { - float bearingMotion = currentLocation.getBearing() ; - Location nextRoutePosition = route.getNextRouteLocation(); - float bearingToRoute = currentLocation.bearingTo(nextRoutePosition); - double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); - // 7. Check if you left the route and an unscheduled U-turn would bring you back (also Issue 863) - // This prompt is an interim advice and does only sound if a new route in forward direction could not be found in x seconds - if (Math.abs(diff) > 135f) { - float d = currentLocation.distanceTo(nextRoutePosition); - // 60m tolerance to allow for GPS inaccuracy - if (d > posTolerance) { - // require x sec continuous since first detection - if (deviateFromRouteDetected == 0) { - deviateFromRouteDetected = System.currentTimeMillis(); - } else if ((System.currentTimeMillis() - deviateFromRouteDetected > 10000)) { - isOffRoute = true; - //log.info("bearingMotion is opposite to bearingRoute"); //$NON-NLS-1$ - } - } - } else { - deviateFromRouteDetected = 0; - } - } - return isOffRoute; - } - - /** - * Wrong movement direction is considered when between - * current location bearing (determines by 2 last fixed position or provided) - * and bearing from currentLocation to next (current) point - * the difference is more than 60 degrees - */ - public boolean checkWrongMovementDirection(Location currentLocation, Location nextRouteLocation) { - // measuring without bearing could be really error prone (with last fixed location) - // this code has an effect on route recalculation which should be detected without mistakes - if (currentLocation.hasBearing() && nextRouteLocation != null) { - float bearingMotion = currentLocation.getBearing(); - float bearingToRoute = currentLocation.bearingTo(nextRouteLocation); - double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); - if (Math.abs(diff) > 60f) { - // require delay interval since first detection, to avoid false positive - //but leave out for now, as late detection is worse than false positive (it may reset voice router then cause bogus turn and u-turn prompting) - //if (wrongMovementDetected == 0) { - // wrongMovementDetected = System.currentTimeMillis(); - //} else if ((System.currentTimeMillis() - wrongMovementDetected > 500)) { - return true; - //} - } else { - //wrongMovementDetected = 0; - return false; - } - } - //wrongMovementDetected = 0; - return false; - } - - private void setNewRoute(RouteCalculationResult prevRoute, final RouteCalculationResult res, Location start){ - final boolean newRoute = !prevRoute.isCalculated(); - if (isFollowingMode) { - if(lastFixedLocation != null) { - start = lastFixedLocation; - } - // try remove false route-recalculated prompts by checking direction to second route node - boolean wrongMovementDirection = false; - List routeNodes = res.getImmutableAllLocations(); - if (routeNodes != null && !routeNodes.isEmpty()) { - int newCurrentRoute = lookAheadFindMinOrthogonalDistance(start, routeNodes, res.currentRoute, 15); - if (newCurrentRoute + 1 < routeNodes.size()) { - // This check is valid for Online/GPX services (offline routing is aware of route direction) - wrongMovementDirection = checkWrongMovementDirection(start, routeNodes.get(newCurrentRoute + 1)); - // set/reset evalWaitInterval only if new route is in forward direction - if (wrongMovementDirection) { - evalWaitInterval = 3000; - } else { - evalWaitInterval = Math.max(3000, evalWaitInterval * 3 / 2); - evalWaitInterval = Math.min(evalWaitInterval, 120000); - } - - } - } - - - // trigger voice prompt only if new route is in forward direction - // If route is in wrong direction after one more setLocation it will be recalculated - if (!wrongMovementDirection || newRoute) { - voiceRouter.newRouteIsCalculated(newRoute); - } - } - app.getWaypointHelper().setNewRoute(res); - - app.runInUIThread(new Runnable() { - @Override - public void run() { - ValueHolder showToast = new ValueHolder<>(); - showToast.value = true; - Iterator> it = listeners.iterator(); - while (it.hasNext()) { - WeakReference ref = it.next(); - IRouteInformationListener l = ref.get(); - if (l == null) { - it.remove(); - } else { - l.newRouteIsCalculated(newRoute, showToast); - } - } - if (showToast.value && newRoute && OsmandPlugin.isDevelopment()) { - String msg = app.getString(R.string.new_route_calculated_dist_dbg, - OsmAndFormatter.getFormattedDistance(res.getWholeDistance(), app), - ((int)res.getRoutingTime()) + " sec", - res.getCalculateTime(), res.getVisitedSegments(), res.getLoadedTiles()); - app.showToastMessage(msg); - } - } - }); - } - - public int getLeftDistance(){ + public int getLeftDistance() { return route.getDistanceToFinish(lastFixedLocation); } @@ -899,7 +708,7 @@ public class RoutingHelper { return settings; } - public String getGeneralRouteInformation(){ + public String getGeneralRouteInformation() { int dist = getLeftDistance(); int hours = getLeftTime() / (60 * 60); int minutes = (getLeftTime() / 60) % 60; @@ -907,14 +716,14 @@ public class RoutingHelper { hours, minutes); } - public Location getLocationFromRouteDirection(RouteDirectionInfo i){ + public Location getLocationFromRouteDirection(RouteDirectionInfo i) { return route.getLocationFromRouteDirection(i); } - public synchronized NextDirectionInfo getNextRouteDirectionInfo(NextDirectionInfo info, boolean toSpeak){ + public synchronized NextDirectionInfo getNextRouteDirectionInfo(NextDirectionInfo info, boolean toSpeak) { NextDirectionInfo i = route.getNextRouteDirectionInfo(info, lastProjection, toSpeak); - if(i != null) { - i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastProjection); + if (i != null) { + i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastProjection); } return i; } @@ -923,257 +732,46 @@ public class RoutingHelper { return route.getCurrentMaxSpeed(); } - - public static String formatStreetName(String name, String ref, String destination, String towards) { - String formattedStreetName = ""; - if (ref != null && ref.length() > 0) { - formattedStreetName = ref; - } - if (name != null && name.length() > 0) { - if (formattedStreetName.length() > 0) { - formattedStreetName = formattedStreetName + " "; - } - formattedStreetName = formattedStreetName + name; - } - if (destination != null && destination.length() > 0) { - if (formattedStreetName.length() > 0) { - formattedStreetName = formattedStreetName + " "; - } - formattedStreetName = formattedStreetName + towards + " " + destination; - } - return formattedStreetName.replace(";", ", "); - - } - - - public static class CurrentStreetName { - public String text; - public TurnType turnType; - public boolean showMarker; // turn type has priority over showMarker - public RouteDataObject shieldObject; - public String exitRef; - } - - public synchronized CurrentStreetName getCurrentName(NextDirectionInfo n){ - CurrentStreetName streetName = new CurrentStreetName(); - Location l = lastFixedLocation; - float speed = 0; - if (l != null && l.hasSpeed()) { - speed = l.getSpeed(); - } - boolean isSet = false; - // 1. turn is imminent - if (n.distanceTo > 0 && n.directionInfo != null && !n.directionInfo.getTurnType().isSkipToSpeak() && - voiceRouter.isDistanceLess(speed, n.distanceTo, voiceRouter.PREPARE_DISTANCE * 0.75f)) { - String nm = n.directionInfo.getStreetName(); - String rf = n.directionInfo.getRef(); - String dn = n.directionInfo.getDestinationName(); - isSet = !(Algorithms.isEmpty(nm) && Algorithms.isEmpty(rf) && Algorithms.isEmpty(dn)); - streetName.text = formatStreetName(nm, null, dn, "»"); - streetName.turnType = n.directionInfo.getTurnType(); - streetName.shieldObject = n.directionInfo.getRouteDataObject(); - if (streetName.turnType == null) { - streetName.turnType = TurnType.valueOf(TurnType.C, false); - } - if (n.directionInfo.getExitInfo() != null) { - streetName.exitRef = n.directionInfo.getExitInfo().getRef(); - if (!Algorithms.isEmpty(n.directionInfo.getExitInfo().getExitStreetName())) { - streetName.text = n.directionInfo.getExitInfo().getExitStreetName(); - } - } - } - // 2. display current road street name - if (!isSet) { - RouteSegmentResult rs = getCurrentSegmentResult(); - if (rs != null) { - streetName.text = getRouteSegmentStreetName(rs, false); - if (Algorithms.isEmpty(streetName.text)) { - isSet = !Algorithms.isEmpty(getRouteSegmentStreetName(rs, true)); - } else { - isSet = true; - } - streetName.showMarker = true; - streetName.shieldObject = rs.getObject(); - } - } - // 3. display next road street name if this one empty - if (!isSet) { - RouteSegmentResult rs = getNextStreetSegmentResult(); - if (rs != null) { - streetName.text = getRouteSegmentStreetName(rs, false); - streetName.turnType = TurnType.valueOf(TurnType.C, false); - streetName.shieldObject = rs.getObject(); - } - } - if (streetName.turnType == null) { - streetName.showMarker = true; - } - return streetName; - } - - private String getRouteSegmentStreetName(RouteSegmentResult rs, boolean includeRef) { - String nm = rs.getObject().getName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()); - String rf = rs.getObject().getRef(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection()); - String dn = rs.getObject().getDestinationName(settings.MAP_PREFERRED_LOCALE.get(), - settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection()); - return formatStreetName(nm, includeRef ? rf : null, dn, "»"); + @NonNull + public synchronized CurrentStreetName getCurrentName(NextDirectionInfo n) { + return CurrentStreetName.getCurrentName(this, n); } public RouteSegmentResult getCurrentSegmentResult() { - return route.getCurrentSegmentResult(); - } + return route.getCurrentSegmentResult(); + } public RouteSegmentResult getNextStreetSegmentResult() { return route.getNextStreetSegmentResult(); } - public List getUpcomingTunnel(float distToStart) { - return route.getUpcomingTunnel(distToStart); - } + public List getUpcomingTunnel(float distToStart) { + return route.getUpcomingTunnel(distToStart); + } - public synchronized NextDirectionInfo getNextRouteDirectionInfoAfter(NextDirectionInfo previous, NextDirectionInfo to, boolean toSpeak){ + public synchronized NextDirectionInfo getNextRouteDirectionInfoAfter(NextDirectionInfo previous, NextDirectionInfo to, boolean toSpeak) { NextDirectionInfo i = route.getNextRouteDirectionInfoAfter(previous, to, toSpeak); - if(i != null) { - i.imminent = voiceRouter.calculateImminent(i.distanceTo, null); + if (i != null) { + i.imminent = voiceRouter.calculateImminent(i.distanceTo, null); } return i; } - public List getRouteDirections(){ + public List getRouteDirections() { return route.getRouteDirections(); } - @Nullable - public QuadRect getRouteRect(@NonNull RouteCalculationResult result) { - QuadRect rect = new QuadRect(0, 0, 0, 0); - Location lt = getLastProjection(); - if (lt == null) { - lt = app.getTargetPointsHelper().getPointToStartLocation(); - } - if (lt == null) { - lt = app.getLocationProvider().getLastKnownLocation(); - } - if (lt != null) { - MapUtils.insetLatLonRect(rect, lt.getLatitude(), lt.getLongitude()); - } - List list = result.getImmutableAllLocations(); - for (Location l : list) { - MapUtils.insetLatLonRect(rect, l.getLatitude(), l.getLongitude()); - } - List targetPoints = app.getTargetPointsHelper().getIntermediatePointsWithTarget(); - for (TargetPoint l : targetPoints) { - MapUtils.insetLatLonRect(rect, l.getLatitude(), l.getLongitude()); - } - - return rect.left == 0 && rect.right == 0 ? null : rect; + public void onSettingsChanged() { + onSettingsChanged(false); } - private class RouteRecalculationThread extends Thread { - - private final RouteCalculationParams params; - private boolean paramsChanged; - private Thread prevRunningJob; - - public RouteRecalculationThread(String name, RouteCalculationParams params, boolean paramsChanged) { - super(name); - this.params = params; - this.paramsChanged = paramsChanged; - if(params.calculationProgress == null) { - params.calculationProgress = new RouteCalculationProgress(); - } - } - - public boolean isParamsChanged() { - return paramsChanged; - } - - public void stopCalculation(){ - params.calculationProgress.isCancelled = true; - } - - - @Override - public void run() { - synchronized (RoutingHelper.this) { - routeWasFinished = false; - currentRunningJob = this; - waitingNextJob = prevRunningJob != null; - } - if(prevRunningJob != null) { - while(prevRunningJob.isAlive()){ - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - synchronized (RoutingHelper.this) { - currentRunningJob = this; - waitingNextJob = false; - } - } - lastRouteCalcError = null; - lastRouteCalcErrorShort = null; - RouteCalculationResult res = provider.calculateRouteImpl(params); - if (params.calculationProgress.isCancelled) { - synchronized (RoutingHelper.this) { - currentRunningJob = null; - } - return; - } - final boolean onlineSourceWithoutInternet = !res.isCalculated() && - params.mode.getRouteService().isOnline() && !settings.isInternetConnectionAvailable(); - if (onlineSourceWithoutInternet && settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()) { - if (params.previousToRecalculate != null && params.previousToRecalculate.isCalculated()) { - res = provider.recalculatePartOfflineRoute(res, params); - } - } - RouteCalculationResult prev = route; - synchronized (RoutingHelper.this) { - if (res.isCalculated()) { - if (!params.inSnapToRoadMode && !params.inPublicTransportMode) { - route = res; - updateOriginalRoute(); - } - if (params.resultListener != null) { - params.resultListener.onRouteCalculated(res); - } - } else { - evalWaitInterval = Math.max(3000, evalWaitInterval * 3 / 2); // for Issue #3899 - evalWaitInterval = Math.min(evalWaitInterval, 120000); - } - currentRunningJob = null; - } - if(res.isCalculated()){ - if (!params.inSnapToRoadMode && !params.inPublicTransportMode) { - setNewRoute(prev, res, params.start); - } - } else if (onlineSourceWithoutInternet) { - lastRouteCalcError = app.getString(R.string.error_calculating_route) - + ":\n" + app.getString(R.string.internet_connection_required_for_online_route); - lastRouteCalcErrorShort = app.getString(R.string.error_calculating_route); - showMessage(lastRouteCalcError); //$NON-NLS-1$ - } else { - if (res.getErrorMessage() != null) { - lastRouteCalcError = app.getString(R.string.error_calculating_route) + ":\n" + res.getErrorMessage(); - lastRouteCalcErrorShort = app.getString(R.string.error_calculating_route); - showMessage(lastRouteCalcError); //$NON-NLS-1$ - } else { - lastRouteCalcError = app.getString(R.string.empty_route_calculated); - lastRouteCalcErrorShort = app.getString(R.string.empty_route_calculated); - showMessage(lastRouteCalcError); - } - } - app.getNotificationHelper().refreshNotification(NAVIGATION); - lastTimeEvaluatedRoute = System.currentTimeMillis(); - } - - public void setWaitPrevJob(Thread prevRunningJob) { - this.prevRunningJob = prevRunningJob; + public void onSettingsChanged(boolean forceRouteRecalculation) { + if (forceRouteRecalculation || isRouteCalculated() || isRouteBeingCalculated()) { + recalculateRouteDueToSettingsChange(); } } - public void recalculateRouteDueToSettingsChange() { + private void recalculateRouteDueToSettingsChange() { clearCurrentRoute(finalLocation, intermediatePoints); if (isPublicTransportMode()) { Location start = lastFixedLocation; @@ -1186,140 +784,19 @@ public class RoutingHelper { transportRoutingHelper.recalculateRouteDueToSettingsChange(); } } else { - recalculateRouteInBackground(lastFixedLocation, finalLocation, intermediatePoints, currentGPXRoute, route, true, false); + routeRecalculationHelper.recalculateRouteInBackground(lastFixedLocation, finalLocation, + intermediatePoints, currentGPXRoute, route, true, false); } } - private void recalculateRouteInBackground(final Location start, final LatLon end, final List intermediates, - final GPXRouteParamsBuilder gpxRoute, final RouteCalculationResult previousRoute, boolean paramsChanged, boolean onlyStartPointChanged){ - if (start == null || end == null) { - return; - } - // do not evaluate very often - if ((currentRunningJob == null && System.currentTimeMillis() - lastTimeEvaluatedRoute > evalWaitInterval) - || paramsChanged || !onlyStartPointChanged) { - if(System.currentTimeMillis() - lastTimeEvaluatedRoute < RECALCULATE_THRESHOLD_CAUSING_FULL_RECALCULATE_INTERVAL) { - recalculateCountInInterval ++; - } - final RouteCalculationParams params = new RouteCalculationParams(); - params.start = start; - params.end = end; - params.intermediates = intermediates; - params.gpxRoute = gpxRoute == null ? null : gpxRoute.build(app); - params.onlyStartPointChanged = onlyStartPointChanged; - if (recalculateCountInInterval < RECALCULATE_THRESHOLD_COUNT_CAUSING_FULL_RECALCULATE - || (gpxRoute != null && gpxRoute.isPassWholeRoute() && isDeviatedFromRoute)) { - params.previousToRecalculate = previousRoute; - } else { - recalculateCountInInterval = 0; - } - params.leftSide = settings.DRIVING_REGION.get().leftHandDriving; - params.fast = settings.FAST_ROUTE_MODE.getModeValue(mode); - params.mode = mode; - params.ctx = app; - boolean updateProgress = false; - if (params.mode.getRouteService() == RouteService.OSMAND) { - params.calculationProgress = new RouteCalculationProgress(); - updateProgress = true; - } else { - params.resultListener = new RouteCalculationParams.RouteCalculationResultListener() { - @Override - public void onRouteCalculated(RouteCalculationResult route) { - app.runInUIThread(new Runnable() { - - @Override - public void run() { - finishProgress(params); - } - }); - } - }; - } - if (lastProjection != null) { - params.currentLocation = lastFixedLocation; - } - startRouteCalculationThread(params, paramsChanged, updateProgress); - } - } - - private void updateOriginalRoute() { + void updateOriginalRoute() { if (originalRoute == null) { originalRoute = route; } } - public void startRouteCalculationThread(RouteCalculationParams params, boolean paramsChanged, boolean updateProgress) { - synchronized (this) { - final Thread prevRunningJob = currentRunningJob; - getSettings().LAST_ROUTE_APPLICATION_MODE.set(getAppMode()); - RouteRecalculationThread newThread = new RouteRecalculationThread( - "Calculating route", params, paramsChanged); //$NON-NLS-1$ - currentRunningJob = newThread; - startProgress(params); - if (updateProgress) { - updateProgress(params); - } - if (prevRunningJob != null) { - newThread.setWaitPrevJob(prevRunningJob); - } - currentRunningJob.start(); - } - } - - private void startProgress(final RouteCalculationParams params) { - if (params.calculationProgressCallback != null) { - params.calculationProgressCallback.start(); - } else if (progressRoute != null) { - progressRoute.start(); - } - } - - private void updateProgress(final RouteCalculationParams params) { - final RouteCalculationProgressCallback progressRoute; - if (params.calculationProgressCallback != null) { - progressRoute = params.calculationProgressCallback; - } else { - progressRoute = this.progressRoute; - } - if (progressRoute != null ) { - app.runInUIThread(new Runnable() { - - @Override - public void run() { - RouteCalculationProgress calculationProgress = params.calculationProgress; - if (isRouteBeingCalculated()) { - Thread t = currentRunningJob; - if(t instanceof RouteRecalculationThread && ((RouteRecalculationThread) t).params != params) { - // different calculation started - return; - } else { - progressRoute.updateProgress((int) calculationProgress.getLinearProgress()); - if (calculationProgress.requestPrivateAccessRouting) { - progressRoute.requestPrivateAccessRouting(); - } - updateProgress(params); - } - } else { - if (calculationProgress.requestPrivateAccessRouting) { - progressRoute.requestPrivateAccessRouting(); - } - progressRoute.finish(); - } - } - }, 300); - } - } - - private void finishProgress(RouteCalculationParams params) { - final RouteCalculationProgressCallback progressRoute; - if (params.calculationProgressCallback != null) { - progressRoute = params.calculationProgressCallback; - } else { - progressRoute = this.progressRoute; - } - if (progressRoute != null ) { - progressRoute.finish(); - } + public void startRouteCalculationThread(RouteCalculationParams params) { + routeRecalculationHelper.startRouteCalculationThread(params, true, true); } public static void applyApplicationSettings(RouteCalculationParams params, OsmandSettings settings, ApplicationMode mode) { @@ -1328,18 +805,7 @@ public class RoutingHelper { } public void setProgressBar(RouteCalculationProgressCallback progressRoute) { - this.progressRoute = progressRoute; - } - - public interface RouteCalculationProgressCallback { - - void start(); - - void updateProgress(int progress); - - void requestPrivateAccessRouting(); - - void finish(); + routeRecalculationHelper.setProgressBar(progressRoute); } public boolean isPublicTransportMode() { @@ -1355,10 +821,10 @@ public class RoutingHelper { } public boolean isRouteBeingCalculated() { - return currentRunningJob instanceof RouteRecalculationThread || waitingNextJob; + return routeRecalculationHelper.isRouteBeingCalculated(); } - private void showMessage(final String msg){ + private void showMessage(final String msg) { app.runInUIThread(new Runnable() { @Override public void run() { @@ -1367,8 +833,6 @@ public class RoutingHelper { }); } - - // NEVER returns null @NonNull public RouteCalculationResult getRoute() { return route; @@ -1396,58 +860,7 @@ public class RoutingHelper { public void notifyIfRouteIsCalculated() { if (route.isCalculated()) { - voiceRouter.newRouteIsCalculated(true) ; + voiceRouter.newRouteIsCalculated(true); } } - - public static class RouteSegmentSearchResult { - private int roadIndex; - private int segmentIndex; - private QuadPoint point; - - private RouteSegmentSearchResult(int roadIndex, int segmentIndex, QuadPoint point) { - this.roadIndex = roadIndex; - this.segmentIndex = segmentIndex; - this.point = point; - } - - public int getRoadIndex() { - return roadIndex; - } - - public int getSegmentIndex() { - return segmentIndex; - } - - public QuadPoint getPoint() { - return point; - } - } - - public static RouteSegmentSearchResult searchRouteSegment(double latitude, double longitude, double maxDist, List roads) { - int roadIndex = -1; - int segmentIndex = -1; - QuadPoint point = null; - int px = MapUtils.get31TileNumberX(longitude); - int py = MapUtils.get31TileNumberY(latitude); - double dist = maxDist < 0 ? 1000 : maxDist; - for (int i = 0; i < roads.size(); i++) { - RouteSegmentResult road = roads.get(i); - int startPointIndex = road.getStartPointIndex() < road.getEndPointIndex() ? road.getStartPointIndex() : road.getEndPointIndex(); - int endPointIndex = road.getEndPointIndex() > road.getStartPointIndex() ? road.getEndPointIndex() : road.getStartPointIndex(); - RouteDataObject obj = road.getObject(); - for (int j = startPointIndex + 1; j <= endPointIndex; j++) { - QuadPoint proj = MapUtils.getProjectionPoint31(px, py, obj.getPoint31XTile(j - 1), obj.getPoint31YTile(j - 1), - obj.getPoint31XTile(j), obj.getPoint31YTile(j)); - double dd = MapUtils.squareRootDist31((int) proj.x, (int) proj.y, px, py); - if (dd < dist) { - dist = dd; - roadIndex = i; - segmentIndex = j; - point = proj; - } - } - } - return roadIndex != -1 ? new RouteSegmentSearchResult(roadIndex, segmentIndex, point) : null; - } } diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelperUtils.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelperUtils.java new file mode 100644 index 0000000000..c696c13585 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelperUtils.java @@ -0,0 +1,210 @@ +package net.osmand.plus.routing; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.data.QuadRect; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.TargetPointsHelper; +import net.osmand.plus.helpers.enums.MetricsConstants; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.util.MapUtils; + +import java.util.List; + +public class RoutingHelperUtils { + + private static final float POSITION_TOLERANCE = 60; + private static final int CACHE_RADIUS = 100000; + + @NonNull + public static String formatStreetName(String name, String ref, String destination, String towards) { + String formattedStreetName = ""; + if (ref != null && ref.length() > 0) { + formattedStreetName = ref; + } + if (name != null && name.length() > 0) { + if (formattedStreetName.length() > 0) { + formattedStreetName = formattedStreetName + " "; + } + formattedStreetName = formattedStreetName + name; + } + if (destination != null && destination.length() > 0) { + if (formattedStreetName.length() > 0) { + formattedStreetName = formattedStreetName + " "; + } + formattedStreetName = formattedStreetName + towards + " " + destination; + } + return formattedStreetName.replace(";", ", "); + } + + @Nullable + public static QuadRect getRouteRect(@NonNull OsmandApplication app, @NonNull RouteCalculationResult result) { + QuadRect rect = new QuadRect(0, 0, 0, 0); + Location lt = app.getRoutingHelper().getLastProjection(); + if (lt == null) { + lt = app.getTargetPointsHelper().getPointToStartLocation(); + } + if (lt == null) { + lt = app.getLocationProvider().getLastKnownLocation(); + } + if (lt != null) { + MapUtils.insetLatLonRect(rect, lt.getLatitude(), lt.getLongitude()); + } + List list = result.getImmutableAllLocations(); + for (Location l : list) { + MapUtils.insetLatLonRect(rect, l.getLatitude(), l.getLongitude()); + } + List targetPoints = app.getTargetPointsHelper().getIntermediatePointsWithTarget(); + for (TargetPointsHelper.TargetPoint l : targetPoints) { + MapUtils.insetLatLonRect(rect, l.getLatitude(), l.getLongitude()); + } + + return rect.left == 0 && rect.right == 0 ? null : rect; + } + + static LatLon getProject(Location loc, Location from, Location to) { + return MapUtils.getProjection(loc.getLatitude(), + loc.getLongitude(), from.getLatitude(), from.getLongitude(), + to.getLatitude(), to.getLongitude()); + } + + static double getOrthogonalDistance(Location loc, Location from, Location to) { + return MapUtils.getOrthogonalDistance(loc.getLatitude(), + loc.getLongitude(), from.getLatitude(), from.getLongitude(), + to.getLatitude(), to.getLongitude()); + } + + static int lookAheadFindMinOrthogonalDistance(Location currentLocation, List routeNodes, int currentRoute, int iterations) { + double newDist; + double dist = Double.POSITIVE_INFINITY; + int index = currentRoute; + while (iterations > 0 && currentRoute + 1 < routeNodes.size()) { + newDist = getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute), routeNodes.get(currentRoute + 1)); + if (newDist < dist) { + index = currentRoute; + dist = newDist; + } + currentRoute++; + iterations--; + } + return index; + } + + public static float getPosTolerance(float accuracy) { + if (accuracy > 0) { + return POSITION_TOLERANCE / 2 + accuracy; + } + return POSITION_TOLERANCE; + } + + public static float getDefaultAllowedDeviation(OsmandSettings settings, ApplicationMode mode, float posTolerance) { + if (settings.DISABLE_OFFROUTE_RECALC.getModeValue(mode)) { + return -1.0f; + } else if (mode.getRouteService() == RouteProvider.RouteService.DIRECT_TO) { + return -1.0f; + } else if (mode.getRouteService() == RouteProvider.RouteService.STRAIGHT) { + MetricsConstants mc = settings.METRIC_SYSTEM.getModeValue(mode); + if (mc == MetricsConstants.KILOMETERS_AND_METERS || mc == MetricsConstants.MILES_AND_METERS) { + return 500.f; + } else { + // 1/4 mile + return 482.f; + } + } + return posTolerance * RoutingHelper.ALLOWED_DEVIATION; + } + + /** + * Wrong movement direction is considered when between + * current location bearing (determines by 2 last fixed position or provided) + * and bearing from currentLocation to next (current) point + * the difference is more than 60 degrees + */ + public static boolean checkWrongMovementDirection(Location currentLocation, Location nextRouteLocation) { + // measuring without bearing could be really error prone (with last fixed location) + // this code has an effect on route recalculation which should be detected without mistakes + if (currentLocation.hasBearing() && nextRouteLocation != null) { + float bearingMotion = currentLocation.getBearing(); + float bearingToRoute = currentLocation.bearingTo(nextRouteLocation); + double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); + if (Math.abs(diff) > 60f) { + // require delay interval since first detection, to avoid false positive + //but leave out for now, as late detection is worse than false positive (it may reset voice router then cause bogus turn and u-turn prompting) + //if (wrongMovementDetected == 0) { + // wrongMovementDetected = System.currentTimeMillis(); + //} else if ((System.currentTimeMillis() - wrongMovementDetected > 500)) { + return true; + //} + } else { + //wrongMovementDetected = 0; + return false; + } + } + //wrongMovementDetected = 0; + return false; + } + + static boolean identifyUTurnIsNeeded(@NonNull RoutingHelper routingHelper, @NonNull Location currentLocation, double posTolerance) { + RouteCalculationResult route = routingHelper.getRoute(); + if (routingHelper.getFinalLocation() == null || currentLocation == null || !route.isCalculated() || routingHelper.isPublicTransportMode()) { + return false; + } + boolean isOffRoute = false; + if (currentLocation.hasBearing()) { + float bearingMotion = currentLocation.getBearing(); + Location nextRoutePosition = route.getNextRouteLocation(); + float bearingToRoute = currentLocation.bearingTo(nextRoutePosition); + double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); + // 7. Check if you left the route and an unscheduled U-turn would bring you back (also Issue 863) + // This prompt is an interim advice and does only sound if a new route in forward direction could not be found in x seconds + if (Math.abs(diff) > 135f) { + float d = currentLocation.distanceTo(nextRoutePosition); + // 60m tolerance to allow for GPS inaccuracy + if (d > posTolerance) { + // require x sec continuous since first detection + long deviateFromRouteDetected = routingHelper.getDeviateFromRouteDetected(); + if (deviateFromRouteDetected == 0) { + routingHelper.setDeviateFromRouteDetected(System.currentTimeMillis()); + } else if ((System.currentTimeMillis() - deviateFromRouteDetected > 10000)) { + isOffRoute = true; + //log.info("bearingMotion is opposite to bearingRoute"); //$NON-NLS-1$ + } + } + } else { + routingHelper.setDeviateFromRouteDetected(0); + } + } + return isOffRoute; + } + + static float getArrivalDistance(ApplicationMode mode, OsmandSettings settings) { + ApplicationMode m = mode == null ? settings.getApplicationMode() : mode; + float defaultSpeed = Math.max(0.3f, m.getDefaultSpeed()); + + /// Used to be: car - 90 m, bicycle - 50 m, pedestrian - 20 m + // return ((float)settings.getApplicationMode().getArrivalDistance()) * settings.ARRIVAL_DISTANCE_FACTOR.getModeValue(m); + // GPS_TOLERANCE - 12 m + // 5 seconds: car - 80 m @ 50 kmh, bicyle - 45 m @ 25 km/h, bicyle - 25 m @ 10 km/h, pedestrian - 18 m @ 4 km/h, + return RoutingHelper.GPS_TOLERANCE + defaultSpeed * 5 * RoutingHelper.ARRIVAL_DISTANCE_FACTOR; + } + + public static void checkAndUpdateStartLocation(@NonNull OsmandApplication app, LatLon newStartLocation) { + if (newStartLocation != null) { + LatLon lastStartLocation = app.getSettings().getLastStartPoint(); + if (lastStartLocation == null || MapUtils.getDistance(newStartLocation, lastStartLocation) > CACHE_RADIUS) { + app.getMapViewTrackingUtilities().detectDrivingRegion(newStartLocation); + app.getSettings().setLastStartPoint(newStartLocation); + } + } + } + + public static void checkAndUpdateStartLocation(@NonNull OsmandApplication app, Location nextStartLocation) { + if (nextStartLocation != null) { + checkAndUpdateStartLocation(app, new LatLon(nextStartLocation.getLatitude(), nextStartLocation.getLongitude())); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java index 4fa70f4c9f..08da774f27 100644 --- a/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java @@ -13,38 +13,42 @@ import net.osmand.binary.BinaryMapIndexReader; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.osm.edit.Node; -import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; -import net.osmand.plus.settings.backend.CommonPreference; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.routing.RouteCalculationParams.RouteCalculationResultListener; import net.osmand.plus.routing.RouteProvider.RouteService; -import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.router.GeneralRouter; - +import net.osmand.router.NativeTransportRoutingResult; import net.osmand.router.RouteCalculationProgress; import net.osmand.router.RoutingConfiguration; import net.osmand.router.TransportRoutePlanner; -import net.osmand.router.TransportRouteResult; import net.osmand.router.TransportRoutePlanner.TransportRouteResultSegment; -import net.osmand.router.TransportRoutingContext; +import net.osmand.router.TransportRouteResult; import net.osmand.router.TransportRoutingConfiguration; -import net.osmand.router.NativeTransportRoutingResult; +import net.osmand.router.TransportRoutingContext; import net.osmand.util.MapUtils; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.TreeMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import static net.osmand.plus.notifications.OsmandNotification.NotificationType.NAVIGATION; @@ -54,10 +58,14 @@ public class TransportRoutingHelper { private List> listeners = new LinkedList<>(); - private OsmandApplication app; + private final OsmandApplication app; private ApplicationMode applicationMode = ApplicationMode.PUBLIC_TRANSPORT; private RoutingHelper routingHelper; + private final ExecutorService executor = new RouteRecalculationExecutor(); + private final Map, RouteRecalculationTask> tasksMap = new LinkedHashMap<>(); + private RouteRecalculationTask lastTask; + private List routes; private Map, RouteCalculationResult> walkingRouteSegments; private int currentRoute = -1; @@ -65,11 +73,9 @@ public class TransportRoutingHelper { private LatLon startLocation; private LatLon endLocation; - private Thread currentRunningJob; private String lastRouteCalcError; private String lastRouteCalcErrorShort; private long lastTimeEvaluatedRoute = 0; - private boolean waitingNextJob; private TransportRouteCalculationProgressCallback progressRoute; @@ -171,16 +177,16 @@ public class TransportRoutingHelper { this.currentRoute = currentRoute; } - public void addListener(IRouteInformationListener l){ + public void addListener(IRouteInformationListener l) { listeners.add(new WeakReference<>(l)); } - public boolean removeListener(IRouteInformationListener lt){ + public boolean removeListener(IRouteInformationListener lt) { Iterator> it = listeners.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { WeakReference ref = it.next(); IRouteInformationListener l = ref.get(); - if(l == null || lt == l) { + if (l == null || lt == l) { it.remove(); return true; } @@ -213,18 +219,14 @@ public class TransportRoutingHelper { private void startRouteCalculationThread(TransportRouteCalculationParams params) { synchronized (this) { - final Thread prevRunningJob = currentRunningJob; app.getSettings().LAST_ROUTE_APPLICATION_MODE.set(routingHelper.getAppMode()); - RouteRecalculationThread newThread = - new RouteRecalculationThread("Calculating public transport route", params, - app.getSettings().SAFE_MODE.get() ? null : NativeOsmandLibrary.getLoadedLibrary()); - currentRunningJob = newThread; + RouteRecalculationTask newTask = new RouteRecalculationTask(this, params, + app.getSettings().SAFE_MODE.get() ? null : NativeOsmandLibrary.getLoadedLibrary()); + lastTask = newTask; startProgress(params); updateProgress(params); - if (prevRunningJob != null) { - newThread.setWaitPrevJob(prevRunningJob); - } - currentRunningJob.start(); + Future future = executor.submit(newTask); + tasksMap.put(future, newTask); } } @@ -251,10 +253,7 @@ public class TransportRoutingHelper { if (isRouteBeingCalculated()) { float pr = calculationProgress.getLinearProgress(); progressRoute.updateProgress((int) pr); - Thread t = currentRunningJob; - if (t instanceof RouteRecalculationThread && ((RouteRecalculationThread) t).params != params) { - // different calculation started - } else { + if (lastTask != null && lastTask.params == params) { updateProgress(params); } } else { @@ -269,7 +268,23 @@ public class TransportRoutingHelper { } public boolean isRouteBeingCalculated() { - return currentRunningJob instanceof RouteRecalculationThread || waitingNextJob; + synchronized (this) { + for (Future future : tasksMap.keySet()) { + if (!future.isDone()) { + return true; + } + } + } + return false; + } + + private void stopCalculation() { + synchronized (this) { + for (Map.Entry, RouteRecalculationTask> taskFuture : tasksMap.entrySet()) { + taskFuture.getValue().stopCalculation(); + taskFuture.getKey().cancel(false); + } + } } private void setNewRoute(final List res) { @@ -323,9 +338,7 @@ public class TransportRoutingHelper { } }); this.endLocation = newFinalLocation; - if (currentRunningJob instanceof RouteRecalculationThread) { - ((RouteRecalculationThread) currentRunningJob).stopCalculation(); - } + stopCalculation(); } private void setCurrentLocation(LatLon currentLocation) { @@ -336,15 +349,6 @@ public class TransportRoutingHelper { recalculateRouteInBackground(currentLocation, endLocation); } - private void showMessage(final String msg) { - app.runInUIThread(new Runnable() { - @Override - public void run() { - app.showToastMessage(msg); - } - }); - } - @Nullable public QuadRect getTransportRouteRect(@NonNull TransportRouteResult result) { TransportRoutingHelper transportRoutingHelper = app.getTransportRoutingHelper(); @@ -404,7 +408,7 @@ public class TransportRoutingHelper { } } - private class WalkingRouteSegment { + private static class WalkingRouteSegment { TransportRouteResultSegment s1; TransportRouteResultSegment s2; LatLon start; @@ -437,18 +441,24 @@ public class TransportRoutingHelper { } } - private class RouteRecalculationThread extends Thread { + private static class RouteRecalculationTask implements Runnable { + private final TransportRoutingHelper transportRoutingHelper; + private final RoutingHelper routingHelper; private final TransportRouteCalculationParams params; - private Thread prevRunningJob; private final Queue walkingSegmentsToCalculate = new ConcurrentLinkedQueue<>(); private Map, RouteCalculationResult> walkingRouteSegments = new HashMap<>(); private boolean walkingSegmentsCalculated; - private NativeLibrary lib; + private final NativeLibrary lib; - public RouteRecalculationThread(String name, TransportRouteCalculationParams params, NativeLibrary library) { - super(name); + String routeCalcError; + String routeCalcErrorShort; + + public RouteRecalculationTask(@NonNull TransportRoutingHelper transportRoutingHelper, + @NonNull TransportRouteCalculationParams params, @Nullable NativeLibrary library) { + this.transportRoutingHelper = transportRoutingHelper; + this.routingHelper = transportRoutingHelper.routingHelper; this.params = params; this.lib = library; if (params.calculationProgress == null) { @@ -460,9 +470,9 @@ public class TransportRoutingHelper { params.calculationProgress.isCancelled = true; } - /** * TODO Check if native lib available and calculate route there. + * * @param params * @return * @throws IOException @@ -474,18 +484,18 @@ public class TransportRoutingHelper { BinaryMapIndexReader[] files = params.ctx.getResourceManager().getTransportRoutingMapFiles(); params.params.clear(); OsmandSettings settings = params.ctx.getSettings(); - for(Map.Entry e : config.getRouter(params.mode.getRoutingProfile()).getParameters().entrySet()){ + for (Map.Entry e : config.getRouter(params.mode.getRoutingProfile()).getParameters().entrySet()) { String key = e.getKey(); GeneralRouter.RoutingParameter pr = e.getValue(); String vl; - if(pr.getType() == GeneralRouter.RoutingParameterType.BOOLEAN) { + if (pr.getType() == GeneralRouter.RoutingParameterType.BOOLEAN) { CommonPreference pref = settings.getCustomRoutingBooleanProperty(key, pr.getDefaultBoolean()); Boolean bool = pref.getModeValue(params.mode); vl = bool ? "true" : null; } else { vl = settings.getCustomRoutingProperty(key, "").getModeValue(params.mode); } - if(vl != null && vl.length() > 0) { + if (vl != null && vl.length() > 0) { params.params.put(key, vl); } } @@ -493,7 +503,7 @@ public class TransportRoutingHelper { TransportRoutingConfiguration cfg = new TransportRoutingConfiguration(prouter, params.params); TransportRoutingContext ctx = new TransportRoutingContext(cfg, library, files); - ctx.calculationProgress = params.calculationProgress; + ctx.calculationProgress = params.calculationProgress; if (ctx.library != null && !settings.PT_SAFE_MODE.get()) { NativeTransportRoutingResult[] nativeRes = library.runNativePTRouting( MapUtils.get31TileNumberX(params.start.getLongitude()), @@ -510,7 +520,6 @@ public class TransportRoutingHelper { @Nullable private RouteCalculationParams getWalkingRouteParams() { - ApplicationMode walkingMode = ApplicationMode.PEDESTRIAN; final WalkingRouteSegment walkingRouteSegment = walkingSegmentsToCalculate.poll(); @@ -518,13 +527,14 @@ public class TransportRoutingHelper { return null; } + OsmandApplication app = routingHelper.getApplication(); Location start = new Location(""); start.setLatitude(walkingRouteSegment.start.getLatitude()); start.setLongitude(walkingRouteSegment.start.getLongitude()); LatLon end = new LatLon(walkingRouteSegment.end.getLatitude(), walkingRouteSegment.end.getLongitude()); final float currentDistanceFromBegin = - RouteRecalculationThread.this.params.calculationProgress.distanceFromBegin + + RouteRecalculationTask.this.params.calculationProgress.distanceFromBegin + (walkingRouteSegment.s1 != null ? (float) walkingRouteSegment.s1.getTravelDist() : 0); final RouteCalculationParams params = new RouteCalculationParams(); @@ -548,8 +558,8 @@ public class TransportRoutingHelper { float p = Math.max(params.calculationProgress.distanceFromBegin, params.calculationProgress.distanceFromEnd); - RouteRecalculationThread.this.params.calculationProgress.distanceFromBegin = - Math.max(RouteRecalculationThread.this.params.calculationProgress.distanceFromBegin, currentDistanceFromBegin + p); + RouteRecalculationTask.this.params.calculationProgress.distanceFromBegin = + Math.max(RouteRecalculationTask.this.params.calculationProgress.distanceFromBegin, currentDistanceFromBegin + p); } @Override @@ -564,7 +574,7 @@ public class TransportRoutingHelper { updateProgress(0); RouteCalculationParams walkingRouteParams = getWalkingRouteParams(); if (walkingRouteParams != null) { - routingHelper.startRouteCalculationThread(walkingRouteParams, true, true); + routingHelper.startRouteCalculationThread(walkingRouteParams); } } } @@ -572,7 +582,7 @@ public class TransportRoutingHelper { params.resultListener = new RouteCalculationResultListener() { @Override public void onRouteCalculated(RouteCalculationResult route) { - RouteRecalculationThread.this.walkingRouteSegments.put(new Pair<>(walkingRouteSegment.s1, walkingRouteSegment.s2), route); + RouteRecalculationTask.this.walkingRouteSegments.put(new Pair<>(walkingRouteSegment.s1, walkingRouteSegment.s2), route); } }; @@ -603,7 +613,7 @@ public class TransportRoutingHelper { } RouteCalculationParams walkingRouteParams = getWalkingRouteParams(); if (walkingRouteParams != null) { - routingHelper.startRouteCalculationThread(walkingRouteParams, true, true); + routingHelper.startRouteCalculationThread(walkingRouteParams); // wait until all segments calculated while (!walkingSegmentsCalculated) { try { @@ -620,26 +630,18 @@ public class TransportRoutingHelper { } } + private void showMessage(final String msg) { + final OsmandApplication app = routingHelper.getApplication(); + app.runInUIThread(new Runnable() { + @Override + public void run() { + app.showToastMessage(msg); + } + }); + } + @Override public void run() { - synchronized (TransportRoutingHelper.this) { - currentRunningJob = this; - waitingNextJob = prevRunningJob != null; - } - if (prevRunningJob != null) { - while (prevRunningJob.isAlive()) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // ignore - } - } - synchronized (TransportRoutingHelper.this) { - currentRunningJob = this; - waitingNextJob = false; - } - } - List res = null; String error = null; try { @@ -652,38 +654,52 @@ public class TransportRoutingHelper { log.error(e); } if (params.calculationProgress.isCancelled) { - synchronized (TransportRoutingHelper.this) { - currentRunningJob = null; - } return; } - synchronized (TransportRoutingHelper.this) { - routes = res; - TransportRoutingHelper.this.walkingRouteSegments = walkingRouteSegments; + synchronized (transportRoutingHelper) { + transportRoutingHelper.routes = res; + transportRoutingHelper.walkingRouteSegments = walkingRouteSegments; if (res != null) { if (params.resultListener != null) { params.resultListener.onRouteCalculated(res); } } - currentRunningJob = null; } + OsmandApplication app = routingHelper.getApplication(); if (res != null) { - setNewRoute(res); + transportRoutingHelper.setNewRoute(res); } else if (error != null) { - lastRouteCalcError = app.getString(R.string.error_calculating_route) + ":\n" + error; - lastRouteCalcErrorShort = app.getString(R.string.error_calculating_route); - showMessage(lastRouteCalcError); + routeCalcError = app.getString(R.string.error_calculating_route) + ":\n" + error; + routeCalcErrorShort = app.getString(R.string.error_calculating_route); + showMessage(routeCalcError); } else { - lastRouteCalcError = app.getString(R.string.empty_route_calculated); - lastRouteCalcErrorShort = app.getString(R.string.empty_route_calculated); - showMessage(lastRouteCalcError); + routeCalcError = app.getString(R.string.empty_route_calculated); + routeCalcErrorShort = app.getString(R.string.empty_route_calculated); + showMessage(routeCalcError); } app.getNotificationHelper().refreshNotification(NAVIGATION); - lastTimeEvaluatedRoute = System.currentTimeMillis(); + } + } + + private class RouteRecalculationExecutor extends ThreadPoolExecutor { + + public RouteRecalculationExecutor() { + super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); } - public void setWaitPrevJob(Thread prevRunningJob) { - this.prevRunningJob = prevRunningJob; + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + RouteRecalculationTask task = null; + synchronized (TransportRoutingHelper.this) { + if (r instanceof Future) { + task = tasksMap.remove(r); + } + } + if (t == null && task != null) { + lastRouteCalcError = task.routeCalcError; + lastRouteCalcErrorShort = task.routeCalcErrorShort; + } + lastTimeEvaluatedRoute = System.currentTimeMillis(); } } } diff --git a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java index 4358938079..86523b6a49 100644 --- a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java +++ b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java @@ -530,7 +530,7 @@ public class VoiceRouter { } if (currentStatus == STATUS_UNKNOWN) { - // Play "Continue for ..." if (1) after route calculation no other prompt is due, or (2) after a turn if next turn is more than PREPARE_LONG_DISTANCE away + // Play "Continue for ..." if (1) after route calculation if no other prompt is due, or (2) after a turn if next turn is more than PREPARE_LONG_DISTANCE away if ((playGoAheadDist == -1) || (dist > PREPARE_LONG_DISTANCE)) { playGoAheadDist = dist - 3 * TURN_NOW_DISTANCE; } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java b/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java index 9f112b498e..9a5cdb7d79 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java @@ -92,6 +92,14 @@ public class ApplicationMode { .icon(R.drawable.ic_action_pedestrian_dark) .description(R.string.base_profile_descr_pedestrian).reg(); + public static final ApplicationMode TRUCK = create(ApplicationMode.CAR, R.string.app_mode_truck, "truck") + .icon(R.drawable.ic_action_truck_dark) + .description(R.string.app_mode_truck).reg(); + + public static final ApplicationMode MOTORCYCLE = create(ApplicationMode.CAR, R.string.app_mode_motorcycle, "motorcycle") + .icon(R.drawable.ic_action_motorcycle_dark) + .description(R.string.app_mode_motorcycle).reg(); + public static final ApplicationMode PUBLIC_TRANSPORT = createBase(R.string.app_mode_public_transport, "public_transport") .icon(R.drawable.ic_action_bus_dark) .description(R.string.base_profile_descr_public_transport).reg(); @@ -108,14 +116,6 @@ public class ApplicationMode { .icon(R.drawable.ic_action_skiing) .description(R.string.base_profile_descr_ski).reg(); - public static final ApplicationMode TRUCK = create(ApplicationMode.CAR, R.string.app_mode_truck, "truck") - .icon(R.drawable.ic_action_truck_dark) - .description(R.string.app_mode_truck).reg(); - - public static final ApplicationMode MOTORCYCLE = create(ApplicationMode.CAR, R.string.app_mode_motorcycle, "motorcycle") - .icon(R.drawable.ic_action_motorcycle_dark) - .description(R.string.app_mode_motorcycle).reg(); - public static List values(OsmandApplication app) { if (customizationListener == null) { customizationListener = new OsmAndAppCustomization.OsmAndAppCustomizationListener() { @@ -512,6 +512,14 @@ public class ApplicationMode { mode.app = app; mode.updateAppModeIcon(); } + if (app.getSettings().APP_MODE_ORDER.isSetForMode(PEDESTRIAN)) { + if (!app.getSettings().APP_MODE_ORDER.isSetForMode(TRUCK)) { + TRUCK.setOrder(PEDESTRIAN.getOrder() + 1); + } + if (!app.getSettings().APP_MODE_ORDER.isSetForMode(MOTORCYCLE)) { + MOTORCYCLE.setOrder(PEDESTRIAN.getOrder() + 1); + } + } } private static void initCustomModes(OsmandApplication app) { @@ -606,7 +614,7 @@ public class ApplicationMode { return gson.toJson(toModeBean()); } - public ApplicationModeBean toModeBean(){ + public ApplicationModeBean toModeBean() { ApplicationModeBean mb = new ApplicationModeBean(); mb.stringKey = stringKey; mb.userProfileName = getUserProfileName(); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/ImpassableRoadsStorage.java b/OsmAnd/src/net/osmand/plus/settings/backend/ImpassableRoadsStorage.java index 80242478e5..25586ef35a 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/ImpassableRoadsStorage.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/ImpassableRoadsStorage.java @@ -12,6 +12,7 @@ import java.util.StringTokenizer; class ImpassableRoadsStorage extends SettingsMapPointsStorage { protected String roadsIdsKey; + protected String directionsKey; protected String appModeKey; public ImpassableRoadsStorage(OsmandSettings osmandSettings) { @@ -19,6 +20,7 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { pointsKey = OsmandSettings.IMPASSABLE_ROAD_POINTS; descriptionsKey = OsmandSettings.IMPASSABLE_ROADS_DESCRIPTIONS; roadsIdsKey = OsmandSettings.IMPASSABLE_ROADS_IDS; + directionsKey = OsmandSettings.IMPASSABLE_ROADS_DIRECTIONS; appModeKey = OsmandSettings.IMPASSABLE_ROADS_APP_MODE_KEYS; } @@ -37,6 +39,21 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { return list; } + public List getDirections(int size) { + List list = new ArrayList<>(); + String directions = getSettingsAPI().getString(getOsmandSettings().getGlobalPreferences(), directionsKey, ""); + if (directions.trim().length() > 0) { + StringTokenizer tok = new StringTokenizer(directions, ","); + while (tok.hasMoreTokens() && list.size() <= size) { + list.add(Double.parseDouble(tok.nextToken())); + } + } + while (list.size() < size) { + list.add(0.0); + } + return list; + } + public List getAppModeKeys(int size) { List list = new ArrayList<>(); String roadIds = getSettingsAPI().getString(getOsmandSettings().getGlobalPreferences(), appModeKey, ""); @@ -55,6 +72,7 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { public List getImpassableRoadsInfo() { List points = getPoints(); List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); @@ -68,6 +86,7 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { avoidRoadInfo.id = roadIds.get(i); avoidRoadInfo.latitude = latLon.getLatitude(); avoidRoadInfo.longitude = latLon.getLongitude(); + avoidRoadInfo.direction = directions.get(i); avoidRoadInfo.name = description.getName(); avoidRoadInfo.appModeKey = appModeKeys.get(i); avoidRoadsInfo.add(avoidRoadInfo); @@ -79,15 +98,17 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { public boolean addImpassableRoadInfo(AvoidRoadInfo avoidRoadInfo) { List points = getPoints(); List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); roadIds.add(0, avoidRoadInfo.id); + directions.add(0, avoidRoadInfo.direction); points.add(0, new LatLon(avoidRoadInfo.latitude, avoidRoadInfo.longitude)); appModeKeys.add(0, avoidRoadInfo.appModeKey); descriptions.add(0, PointDescription.serializeToString(new PointDescription("", avoidRoadInfo.name))); - return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys); + return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys, directions); } public boolean updateImpassableRoadInfo(AvoidRoadInfo avoidRoadInfo) { @@ -96,13 +117,15 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { int index = points.indexOf(new LatLon(avoidRoadInfo.latitude, avoidRoadInfo.longitude)); if (index != -1) { List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); roadIds.set(index, avoidRoadInfo.id); + directions.set(index, avoidRoadInfo.direction); appModeKeys.set(index, avoidRoadInfo.appModeKey); descriptions.set(index, PointDescription.serializeToString(new PointDescription("", avoidRoadInfo.name))); - return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys); + return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys, directions); } return false; } @@ -111,15 +134,17 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { public boolean deletePoint(int index) { List points = getPoints(); List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); if (index < points.size()) { points.remove(index); roadIds.remove(index); + directions.remove(index); appModeKeys.remove(index); descriptions.remove(index); - return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys); + return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys, directions); } return false; } @@ -128,6 +153,7 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { public boolean deletePoint(LatLon latLon) { List points = getPoints(); List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); @@ -135,9 +161,10 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { if (index != -1) { points.remove(index); roadIds.remove(index); + directions.remove(index); appModeKeys.remove(index); descriptions.remove(index); - return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys); + return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys, directions); } return false; } @@ -146,21 +173,23 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { public boolean movePoint(LatLon latLonEx, LatLon latLonNew) { List points = getPoints(); List roadIds = getRoadIds(points.size()); + List directions = getDirections(points.size()); List appModeKeys = getAppModeKeys(points.size()); List descriptions = getPointDescriptions(points.size()); int i = points.indexOf(latLonEx); if (i != -1) { points.set(i, latLonNew); - return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys); + return saveAvoidRoadData(points, descriptions, roadIds, appModeKeys, directions); } else { return false; } } - public boolean saveAvoidRoadData(List points, List descriptions, - List roadIds, List appModeKeys) { - return savePoints(points, descriptions) && saveRoadIds(roadIds) && saveAppModeKeys(appModeKeys); + public boolean saveAvoidRoadData(List points, List descriptions, List roadIds, + List appModeKeys, List directions) { + return savePoints(points, descriptions) && saveRoadIds(roadIds) + && saveAppModeKeys(appModeKeys) && saveDirections(directions); } public boolean saveRoadIds(List roadIds) { @@ -177,6 +206,20 @@ class ImpassableRoadsStorage extends SettingsMapPointsStorage { .commit(); } + public boolean saveDirections(List directions) { + StringBuilder stringBuilder = new StringBuilder(); + Iterator iterator = directions.iterator(); + while (iterator.hasNext()) { + stringBuilder.append(iterator.next()); + if (iterator.hasNext()) { + stringBuilder.append(","); + } + } + return getSettingsAPI().edit(getOsmandSettings().getGlobalPreferences()) + .putString(directionsKey, stringBuilder.toString()) + .commit(); + } + public boolean saveAppModeKeys(List appModeKeys) { StringBuilder stringBuilder = new StringBuilder(); Iterator iterator = appModeKeys.iterator(); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index e5fa9065cd..31c081ae23 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -425,6 +425,7 @@ public class OsmandSettings { if (valueSaved) { currentMode = val; profilePreferences = getProfilePreferences(currentMode); + LAST_USED_APPLICATION_MODE.set(currentMode.getStringKey()); fireEvent(oldMode); } @@ -735,11 +736,20 @@ public class OsmandSettings { public final OsmandPreference LAST_FAV_CATEGORY_ENTERED = new StringPreference(this, "last_fav_category", "").makeGlobal(); + public final OsmandPreference USE_LAST_APPLICATION_MODE_BY_DEFAULT = new BooleanPreference(this, "use_last_application_mode_by_default", false).makeGlobal().makeShared(); + + public final OsmandPreference LAST_USED_APPLICATION_MODE = new StringPreference(this, "last_used_application_mode", ApplicationMode.DEFAULT.getStringKey()).makeGlobal().makeShared(); + public final OsmandPreference DEFAULT_APPLICATION_MODE = new CommonPreference(this, "default_application_mode_string", ApplicationMode.DEFAULT) { @Override protected ApplicationMode getValue(Object prefs, ApplicationMode defaultValue) { - String key = settingsAPI.getString(prefs, getId(), defaultValue.getStringKey()); + String key; + if (USE_LAST_APPLICATION_MODE_BY_DEFAULT.get()) { + key = LAST_USED_APPLICATION_MODE.get(); + } else { + key = settingsAPI.getString(prefs, getId(), defaultValue.getStringKey()); + } return ApplicationMode.valueOfStringKey(key, defaultValue); } @@ -978,7 +988,16 @@ public class OsmandSettings { ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.SKI, "ski"); } - public final CommonPreference ROUTE_SERVICE = new EnumStringPreference<>(this, "route_service", RouteService.OSMAND, RouteService.values()).makeProfile().cache(); + public final CommonPreference ROUTE_SERVICE = new EnumStringPreference(this, "route_service", RouteService.OSMAND, RouteService.values()) { + @Override + public RouteService getModeValue(ApplicationMode mode) { + if (mode == ApplicationMode.DEFAULT) { + return RouteService.STRAIGHT; + } else { + return super.getModeValue(mode); + } + } + }.makeProfile().cache(); { ROUTE_SERVICE.setModeDefaultValue(ApplicationMode.DEFAULT, RouteService.STRAIGHT); @@ -2097,6 +2116,7 @@ public class OsmandSettings { public static final String IMPASSABLE_ROAD_POINTS = "impassable_road_points"; public static final String IMPASSABLE_ROADS_DESCRIPTIONS = "impassable_roads_descriptions"; public static final String IMPASSABLE_ROADS_IDS = "impassable_roads_ids"; + public static final String IMPASSABLE_ROADS_DIRECTIONS = "impassable_roads_directions"; public static final String IMPASSABLE_ROADS_APP_MODE_KEYS = "impassable_roads_app_mode_keys"; public void backupPointToStart() { diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/AvoidRoadsSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/AvoidRoadsSettingsItem.java index 6507ab874e..a65a60b2d7 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/AvoidRoadsSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/AvoidRoadsSettingsItem.java @@ -9,6 +9,7 @@ import net.osmand.data.LatLon; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.helpers.AvoidSpecificRoads; +import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; @@ -19,16 +20,16 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.List; -public class AvoidRoadsSettingsItem extends CollectionSettingsItem { +public class AvoidRoadsSettingsItem extends CollectionSettingsItem { private OsmandSettings settings; private AvoidSpecificRoads specificRoads; - public AvoidRoadsSettingsItem(@NonNull OsmandApplication app, @NonNull List items) { + public AvoidRoadsSettingsItem(@NonNull OsmandApplication app, @NonNull List items) { super(app, null, items); } - public AvoidRoadsSettingsItem(@NonNull OsmandApplication app, @Nullable AvoidRoadsSettingsItem baseItem, @NonNull List items) { + public AvoidRoadsSettingsItem(@NonNull OsmandApplication app, @Nullable AvoidRoadsSettingsItem baseItem, @NonNull List items) { super(app, baseItem, items); } @@ -64,16 +65,16 @@ public class AvoidRoadsSettingsItem extends CollectionSettingsItem newItems = getNewItems(); + List newItems = getNewItems(); if (!newItems.isEmpty() || !duplicateItems.isEmpty()) { appliedItems = new ArrayList<>(newItems); - for (AvoidSpecificRoads.AvoidRoadInfo duplicate : duplicateItems) { + for (AvoidRoadInfo duplicate : duplicateItems) { LatLon latLon = new LatLon(duplicate.latitude, duplicate.longitude); if (settings.removeImpassableRoad(latLon)) { settings.addImpassableRoad(duplicate); } } - for (AvoidSpecificRoads.AvoidRoadInfo avoidRoad : appliedItems) { + for (AvoidRoadInfo avoidRoad : appliedItems) { settings.addImpassableRoad(avoidRoad); } specificRoads.loadImpassableRoads(); @@ -82,8 +83,8 @@ public class AvoidRoadsSettingsItem extends CollectionSettingsItem getPreferredLocaleIdsAndValues(Context ctx) { // See language list and statistics at: https://hosted.weblate.org/projects/osmand/main/ // Hardy maintenance 2016-05-29: diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java index 05a2b94d2f..f7ae122851 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java @@ -20,8 +20,10 @@ import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.AndroidUiHelper; -import net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment; -import net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.SelectProfileListener; +import net.osmand.plus.profiles.ProfileDataUtils; +import net.osmand.plus.profiles.SelectProfileBottomSheet; +import net.osmand.plus.profiles.SelectProfileBottomSheet.DialogMode; +import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.backup.SettingsItem; import net.osmand.plus.settings.backend.backup.SettingsItemType; @@ -33,12 +35,10 @@ import java.util.List; import java.util.Set; import static net.osmand.plus.importfiles.ImportHelper.ImportType.SETTINGS; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.DIALOG_TYPE; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.IS_PROFILE_IMPORTED_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.PROFILE_KEY_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.TYPE_BASE_APP_PROFILE; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG; -public class MainSettingsFragment extends BaseSettingsFragment { +public class MainSettingsFragment extends BaseSettingsFragment implements OnSelectProfileCallback{ public static final String TAG = MainSettingsFragment.class.getName(); @@ -52,7 +52,6 @@ public class MainSettingsFragment extends BaseSettingsFragment { private List allAppModes; private Set availableAppModes; - private SelectProfileListener selectProfileListener = null; @Override public void onCreate(Bundle savedInstanceState) { @@ -119,15 +118,9 @@ public class MainSettingsFragment extends BaseSettingsFragment { ApplicationMode.valueOfStringKey(prefId, null)); return true; } else if (CREATE_PROFILE.equals(prefId)) { - final SelectProfileBottomSheetDialogFragment dialog = new SelectProfileBottomSheetDialogFragment(); - Bundle bundle = new Bundle(); - bundle.putString(DIALOG_TYPE, TYPE_BASE_APP_PROFILE); - dialog.setArguments(bundle); - dialog.setUsedOnMap(false); - dialog.setAppMode(getSelectedAppMode()); if (getActivity() != null) { - getActivity().getSupportFragmentManager().beginTransaction() - .add(dialog, "select_base_profile").commitAllowingStateLoss(); + SelectProfileBottomSheet.showInstance(getActivity(), + DialogMode.BASE_PROFILE, this, null, false); } } else if (IMPORT_PROFILE.equals(prefId)) { final MapActivity mapActivity = getMapActivity(); @@ -162,7 +155,7 @@ public class MainSettingsFragment extends BaseSettingsFragment { private void setupConfigureProfilePref() { ApplicationMode selectedMode = app.getSettings().APPLICATION_MODE.get(); String title = selectedMode.toHumanString(); - String profileType = getAppModeDescription(getContext(), selectedMode); + String profileType = ProfileDataUtils.getAppModeDescription(getContext(), selectedMode); Preference configureProfile = findPreference(CONFIGURE_PROFILE); configureProfile.setIcon(getAppProfilesIcon(selectedMode, true)); configureProfile.setTitle(title); @@ -200,7 +193,7 @@ public class MainSettingsFragment extends BaseSettingsFragment { pref.setIcon(getAppProfilesIcon(applicationMode, isAppProfileEnabled)); pref.setTitle(applicationMode.toHumanString()); - pref.setSummary(getAppModeDescription(getContext(), applicationMode)); + pref.setSummary(ProfileDataUtils.getAppModeDescription(getContext(), applicationMode)); pref.setChecked(isAppProfileEnabled); pref.setLayoutResource(R.layout.preference_with_descr_dialog_and_switch); pref.setFragment(ConfigureProfileFragment.class.getName()); @@ -222,30 +215,23 @@ public class MainSettingsFragment extends BaseSettingsFragment { : getIcon(iconResId, isNightMode() ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light); } - public SelectProfileListener getParentProfileListener() { - if (selectProfileListener == null) { - selectProfileListener = new SelectProfileListener() { - @Override - public void onSelectedType(Bundle args) { - FragmentActivity activity = getActivity(); - if (activity != null) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (fragmentManager != null) { - String profileKey = args.getString(PROFILE_KEY_ARG); - boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG); - ProfileAppearanceFragment.showInstance(activity, SettingsScreenType.PROFILE_APPEARANCE, - profileKey, imported); - } - } - } - }; - } - return selectProfileListener; - } - @Override public void onPause() { updateRouteInfoMenu(); super.onPause(); } + + @Override + public void onProfileSelected(Bundle args) { + FragmentActivity activity = getActivity(); + if (activity != null) { + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (fragmentManager != null) { + String profileKey = args.getString(PROFILE_KEY_ARG); + boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG); + ProfileAppearanceFragment.showInstance(activity, SettingsScreenType.PROFILE_APPEARANCE, + profileKey, imported); + } + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java index 47b8270066..0720dc7714 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java @@ -10,51 +10,38 @@ import androidx.preference.Preference; import androidx.preference.SwitchPreferenceCompat; import net.osmand.plus.measurementtool.MeasurementToolFragment; +import net.osmand.plus.profiles.ProfileDataUtils; import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet; import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DialogMode; import net.osmand.plus.settings.backend.ApplicationMode; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.profiles.ProfileDataObject; import net.osmand.plus.profiles.RoutingProfileDataObject; import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources; -import net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment; +import net.osmand.plus.profiles.SelectProfileBottomSheet; +import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback; import net.osmand.plus.routing.RouteProvider; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; -import net.osmand.router.GeneralRouter; -import net.osmand.router.RoutingConfiguration; import net.osmand.util.Algorithms; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.DIALOG_TYPE; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.IS_PROFILE_IMPORTED_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.PROFILE_KEY_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.SELECTED_KEY; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.TYPE_NAV_PROFILE; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG; import static net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DIALOG_MODE_KEY; -public class NavigationFragment extends BaseSettingsFragment { +public class NavigationFragment extends BaseSettingsFragment implements OnSelectProfileCallback { public static final String TAG = NavigationFragment.class.getSimpleName(); public static final String NAVIGATION_TYPE = "navigation_type"; - public static final String OSMAND_NAVIGATION = "osmand_navigation"; - private SelectProfileBottomSheetDialogFragment.SelectProfileListener navTypeListener; private Map routingProfileDataObjects; private Preference navigationType; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - routingProfileDataObjects = getRoutingProfiles(app); + routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app); setupOnBackPressedCallback(); } @@ -134,38 +121,17 @@ public class NavigationFragment extends BaseSettingsFragment { @Override public boolean onPreferenceClick(Preference preference) { if (preference.getKey().equals(NAVIGATION_TYPE)) { - final SelectProfileBottomSheetDialogFragment dialog = new SelectProfileBottomSheetDialogFragment(); - Bundle bundle = new Bundle(); - if (getSelectedAppMode() != null) { - bundle.putString(SELECTED_KEY, getSelectedAppMode().getRoutingProfile()); - } - bundle.putString(DIALOG_TYPE, TYPE_NAV_PROFILE); - dialog.setArguments(bundle); - dialog.setUsedOnMap(false); - dialog.setAppMode(getSelectedAppMode()); + String routingProfileKey = + getSelectedAppMode() != null ? getSelectedAppMode().getRoutingProfile() : null; if (getActivity() != null) { - getActivity().getSupportFragmentManager().beginTransaction() - .add(dialog, "select_nav_type").commitAllowingStateLoss(); + SelectProfileBottomSheet.showInstance( + getActivity(), SelectProfileBottomSheet.DialogMode.NAVIGATION_PROFILE, + this, routingProfileKey, false); } } return false; } - public SelectProfileBottomSheetDialogFragment.SelectProfileListener getNavProfileListener() { - if (navTypeListener == null) { - navTypeListener = new SelectProfileBottomSheetDialogFragment.SelectProfileListener() { - @Override - public void onSelectedType(Bundle args) { - if (args.getBoolean(IS_PROFILE_IMPORTED_ARG)) { - routingProfileDataObjects = getRoutingProfiles(app); - } - updateRoutingProfile(args.getString(PROFILE_KEY_ARG)); - } - }; - } - return navTypeListener; - } - void updateRoutingProfile(String profileKey) { RoutingProfileDataObject selectedRoutingProfileDataObject = routingProfileDataObjects.get(profileKey); if (profileKey == null || selectedRoutingProfileDataObject == null) { @@ -193,112 +159,6 @@ public class NavigationFragment extends BaseSettingsFragment { appMode.setRoutingProfile(profileKey); } - public static List getSortedRoutingProfiles(OsmandApplication app) { - List result = new ArrayList<>(); - Map> routingProfilesByFileNames = getRoutingProfilesByFileNames(app); - List fileNames = new ArrayList<>(routingProfilesByFileNames.keySet()); - 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); - } - }); - for (String fileName : fileNames) { - List routingProfilesFromFile = routingProfilesByFileNames.get(fileName); - if (routingProfilesFromFile != null) { - Collections.sort(routingProfilesFromFile); - result.addAll(routingProfilesFromFile); - } - } - return result; - } - - public static Map> getRoutingProfilesByFileNames(OsmandApplication app) { - Map> result = new HashMap<>(); - for (final RoutingProfileDataObject profile : getRoutingProfiles(app).values()) { - String fileName = profile.getFileName() != null ? profile.getFileName() : OSMAND_NAVIGATION; - if (result.containsKey(fileName)) { - result.get(fileName).add(profile); - } else { - result.put(fileName, new ArrayList() { - { add(profile); } - }); - } - } - return result; - } - - public static Map getRoutingProfiles(OsmandApplication context) { - Map profilesObjects = new HashMap<>(); - profilesObjects.put(RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), new RoutingProfileDataObject( - RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), - context.getString(RoutingProfilesResources.STRAIGHT_LINE_MODE.getStringRes()), - context.getString(R.string.special_routing_type), - RoutingProfilesResources.STRAIGHT_LINE_MODE.getIconRes(), - false, null)); - profilesObjects.put(RoutingProfilesResources.DIRECT_TO_MODE.name(), new RoutingProfileDataObject( - RoutingProfilesResources.DIRECT_TO_MODE.name(), - context.getString(RoutingProfilesResources.DIRECT_TO_MODE.getStringRes()), - context.getString(R.string.special_routing_type), - RoutingProfilesResources.DIRECT_TO_MODE.getIconRes(), - false, null)); - if (context.getBRouterService() != null) { - profilesObjects.put(RoutingProfilesResources.BROUTER_MODE.name(), new RoutingProfileDataObject( - RoutingProfilesResources.BROUTER_MODE.name(), - context.getString(RoutingProfilesResources.BROUTER_MODE.getStringRes()), - context.getString(R.string.third_party_routing_type), - RoutingProfilesResources.BROUTER_MODE.getIconRes(), - false, null)); - } - - List disabledRouterNames = OsmandPlugin.getDisabledRouterNames(); - for (RoutingConfiguration.Builder builder : context.getAllRoutingConfigs()) { - collectRoutingProfilesFromConfig(context, builder, profilesObjects, disabledRouterNames); - } - return profilesObjects; - } - - private static void collectRoutingProfilesFromConfig(OsmandApplication app, RoutingConfiguration.Builder builder, - Map profilesObjects, List disabledRouterNames) { - for (Map.Entry entry : builder.getAllRouters().entrySet()) { - String routerKey = entry.getKey(); - GeneralRouter router = entry.getValue(); - if (!routerKey.equals("geocoding") && !disabledRouterNames.contains(router.getFilename())) { - int iconRes = R.drawable.ic_action_gdirections_dark; - String name = router.getProfileName(); - String description = app.getString(R.string.osmand_default_routing); - String fileName = router.getFilename(); - if (!Algorithms.isEmpty(fileName)) { - description = fileName; - } else if (RoutingProfilesResources.isRpValue(name.toUpperCase())) { - iconRes = RoutingProfilesResources.valueOf(name.toUpperCase()).getIconRes(); - name = app.getString(RoutingProfilesResources.valueOf(name.toUpperCase()).getStringRes()); - } - profilesObjects.put(routerKey, new RoutingProfileDataObject(routerKey, name, description, - iconRes, false, fileName)); - } - } - } - - public static List getBaseProfiles(OsmandApplication app) { - return getBaseProfiles(app, false); - } - - public static List getBaseProfiles(OsmandApplication app, boolean includeBrowseMap) { - List profiles = new ArrayList<>(); - for (ApplicationMode mode : ApplicationMode.allPossibleValues()) { - if (mode != ApplicationMode.DEFAULT || includeBrowseMap) { - String description = mode.getDescription(); - if (Algorithms.isEmpty(description)) { - description = getAppModeDescription(app, mode); - } - profiles.add(new ProfileDataObject(mode.toHumanString(), description, - mode.getStringKey(), mode.getIconRes(), false, mode.getIconColorInfo())); - } - } - return profiles; - } - private void setupVehicleParametersPref() { Preference vehicleParameters = findPreference("vehicle_parameters"); int iconRes = getSelectedAppMode().getIconRes(); @@ -311,4 +171,12 @@ public class NavigationFragment extends BaseSettingsFragment { mapActivity.getMapRouteInfoMenu().updateMenu(); } } + + @Override + public void onProfileSelected(Bundle args) { + if (args.getBoolean(IS_PROFILE_IMPORTED_ARG)) { + routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app); + } + updateRoutingProfile(args.getString(PROFILE_KEY_ARG)); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java index 2a15433f26..6913770773 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java @@ -51,7 +51,9 @@ import net.osmand.plus.profiles.LocationIcon; import net.osmand.plus.profiles.NavigationIcon; import net.osmand.plus.profiles.ProfileIconColors; import net.osmand.plus.profiles.ProfileIcons; -import net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment; +import net.osmand.plus.profiles.SelectProfileBottomSheet; +import net.osmand.plus.profiles.SelectProfileBottomSheet.DialogMode; +import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback; import net.osmand.plus.routing.RouteProvider; import net.osmand.plus.widgets.FlowLayout; import net.osmand.plus.widgets.OsmandTextFieldBoxes; @@ -64,13 +66,10 @@ import java.util.ArrayList; import java.util.Collections; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.DIALOG_TYPE; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.IS_PROFILE_IMPORTED_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.PROFILE_KEY_ARG; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.SELECTED_KEY; -import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.TYPE_BASE_APP_PROFILE; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG; +import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG; -public class ProfileAppearanceFragment extends BaseSettingsFragment { +public class ProfileAppearanceFragment extends BaseSettingsFragment implements OnSelectProfileCallback { private static final Log LOG = PlatformUtil.getLog(ProfileAppearanceFragment.class); @@ -98,7 +97,6 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { private static final String IS_BASE_PROFILE_IMPORTED = "is_base_profile_imported"; private static final String IS_NEW_PROFILE_KEY = "is_new_profile_key"; - private SelectProfileBottomSheetDialogFragment.SelectProfileListener parentProfileListener; private SettingsHelper.SettingsExportListener exportListener; private ProgressDialog progress; @@ -400,18 +398,12 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { public void onClick(View v) { if (isNewProfile) { hideKeyboard(); - final SelectProfileBottomSheetDialogFragment fragment = new SelectProfileBottomSheetDialogFragment(); - Bundle bundle = new Bundle(); - fragment.setUsedOnMap(false); - fragment.setAppMode(getSelectedAppMode()); - if (changedProfile.parent != null) { - bundle.putString(SELECTED_KEY, changedProfile.parent.getStringKey()); - } - bundle.putString(DIALOG_TYPE, TYPE_BASE_APP_PROFILE); - fragment.setArguments(bundle); + String selectedAppModeKey = + changedProfile.parent != null ? changedProfile.parent.getStringKey() : null; if (getActivity() != null) { - getActivity().getSupportFragmentManager().beginTransaction() - .add(fragment, "select_nav_type").commitAllowingStateLoss(); + SelectProfileBottomSheet.showInstance( + getActivity(), DialogMode.BASE_PROFILE, ProfileAppearanceFragment.this, + selectedAppModeKey, false); } } } @@ -709,20 +701,6 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { } } - public SelectProfileBottomSheetDialogFragment.SelectProfileListener getParentProfileListener() { - if (parentProfileListener == null) { - parentProfileListener = new SelectProfileBottomSheetDialogFragment.SelectProfileListener() { - @Override - public void onSelectedType(Bundle args) { - String profileKey = args.getString(PROFILE_KEY_ARG); - boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG); - updateParentProfile(profileKey, imported); - } - }; - } - return parentProfileListener; - } - private SettingsHelper.SettingsExportListener getSettingsExportListener() { if (exportListener == null) { exportListener = new SettingsHelper.SettingsExportListener() { @@ -953,6 +931,13 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { } } + @Override + public void onProfileSelected(Bundle args) { + String profileKey = args.getString(PROFILE_KEY_ARG); + boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG); + updateParentProfile(profileKey, imported); + } + public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType, @Nullable String appMode, boolean imported) { try { Fragment fragment = Fragment.instantiate(activity, screenType.fragmentName); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java index 00f0960dfe..88e2a4f957 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java @@ -33,6 +33,7 @@ import net.osmand.plus.UiUtilities; import net.osmand.plus.Version; import net.osmand.plus.routing.RouteProvider; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.BooleanPreference; import net.osmand.plus.settings.backend.CommonPreference; @@ -432,8 +433,8 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP mode.setStrAngle(angleValue[0]); updateAllSettings(); RoutingHelper routingHelper = app.getRoutingHelper(); - if (mode.equals(routingHelper.getAppMode()) && (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated())) { - routingHelper.recalculateRouteDueToSettingsChange(); + if (mode.equals(routingHelper.getAppMode())) { + routingHelper.onSettingsChanged(); } } }); @@ -481,7 +482,7 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP float allowedValue = settings.ROUTE_RECALCULATION_DISTANCE.getModeValue(appMode); boolean enabled = allowedValue != DISABLE_MODE; if (allowedValue <= 0) { - allowedValue = RoutingHelper.getDefaultAllowedDeviation(settings, appMode, RoutingHelper.getPosTolerance(0)); + allowedValue = RoutingHelperUtils.getDefaultAllowedDeviation(settings, appMode, RoutingHelperUtils.getPosTolerance(0)); } String summary = String.format(getString(R.string.ltr_or_rtl_combine_via_bold_point), enabled ? getString(R.string.shared_string_enabled) : getString(R.string.shared_string_disabled), @@ -644,9 +645,8 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP private static void recalculateRoute(OsmandApplication app, ApplicationMode mode) { RoutingHelper routingHelper = app.getRoutingHelper(); - if (mode.equals(routingHelper.getAppMode()) - && (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated())) { - routingHelper.recalculateRouteDueToSettingsChange(); + if (mode.equals(routingHelper.getAppMode())) { + routingHelper.onSettingsChanged(); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java index 738c44de35..a70dbca171 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java @@ -194,9 +194,8 @@ public class VehicleParametersFragment extends BaseSettingsFragment implements O private void recalculateRoute() { RoutingHelper routingHelper = app.getRoutingHelper(); - if (getSelectedAppMode().equals(routingHelper.getAppMode()) - && (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated())) { - routingHelper.recalculateRouteDueToSettingsChange(); + if (getSelectedAppMode().equals(routingHelper.getAppMode())) { + routingHelper.onSettingsChanged(); } } @@ -269,8 +268,8 @@ public class VehicleParametersFragment extends BaseSettingsFragment implements O mode.setMaxSpeed(maxValue[0] / ratio[0]); } RoutingHelper routingHelper = app.getRoutingHelper(); - if (mode.equals(routingHelper.getAppMode()) && (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated())) { - routingHelper.recalculateRouteDueToSettingsChange(); + if (mode.equals(routingHelper.getAppMode())) { + routingHelper.onSettingsChanged(); } } }); @@ -284,8 +283,8 @@ public class VehicleParametersFragment extends BaseSettingsFragment implements O mode.setMaxSpeed(0f); } RoutingHelper routingHelper = app.getRoutingHelper(); - if (mode.equals(routingHelper.getAppMode()) && (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated())) { - routingHelper.recalculateRouteDueToSettingsChange(); + if (mode.equals(routingHelper.getAppMode())) { + routingHelper.onSettingsChanged(); } } }); diff --git a/OsmAnd/src/net/osmand/plus/skimapsplugin/SkiMapsPlugin.java b/OsmAnd/src/net/osmand/plus/skimapsplugin/SkiMapsPlugin.java index 413b4d9c36..6fab6a62d5 100644 --- a/OsmAnd/src/net/osmand/plus/skimapsplugin/SkiMapsPlugin.java +++ b/OsmAnd/src/net/osmand/plus/skimapsplugin/SkiMapsPlugin.java @@ -21,7 +21,7 @@ public class SkiMapsPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(net.osmand.plus.R.string.plugin_ski_descr); } diff --git a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java index a8dc02135b..b6f22610e0 100644 --- a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java +++ b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java @@ -119,7 +119,7 @@ public class SRTMPlugin extends OsmandPlugin { } @Override - public String getDescription() { + public CharSequence getDescription() { return app.getString(R.string.srtm_plugin_description); } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/MapControlsLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/MapControlsLayer.java index e7cc9b4466..f73a504dfb 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/MapControlsLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/MapControlsLayer.java @@ -497,7 +497,7 @@ public class MapControlsLayer extends OsmandMapLayer { if (object instanceof SelectedGpxPoint && !((SelectedGpxPoint) object).getSelectedGpxFile().isShowCurrentTrack()) { GPXFile gpxFile = ((SelectedGpxPoint) object).getSelectedGpxFile().getGpxFile(); mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(gpxFile, null, null, true, true, MenuState.HEADER_ONLY); - routingHelper.recalculateRouteDueToSettingsChange(); + routingHelper.onSettingsChanged(true); menu.close(); } else { if (routingHelper.isFollowingMode() || routingHelper.isRoutePlanningMode()) { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java index d8101b487d..fca0ae429e 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java @@ -49,6 +49,8 @@ import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmAndLocationProvider.GPSInfo; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.routing.CurrentStreetName; +import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; @@ -933,7 +935,7 @@ public class MapInfoWidgetsFactory { public boolean updateInfo(DrawSettings d) { - RoutingHelper.CurrentStreetName streetName = null; + CurrentStreetName streetName = null; boolean showClosestWaypointFirstInAddress = true; if (routingHelper != null && routingHelper.isRouteCalculated() && !routingHelper.isDeviatedFromRoute()) { if (routingHelper.isFollowingMode()) { @@ -953,11 +955,11 @@ public class MapInfoWidgetsFactory { } } else if (map.getMapViewTrackingUtilities().isMapLinkedToLocation() && settings.SHOW_STREET_NAME.get()) { - streetName = new RoutingHelper.CurrentStreetName(); + streetName = new CurrentStreetName(); RouteDataObject rt = locationProvider.getLastKnownRouteSegment(); if (rt != null) { Location lastKnownLocation = locationProvider.getLastKnownLocation(); - streetName.text = RoutingHelper.formatStreetName( + streetName.text = RoutingHelperUtils.formatStreetName( rt.getName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()), rt.getRef(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rt.bearingVsRouteDirection(lastKnownLocation)), rt.getDestinationName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rt.bearingVsRouteDirection(lastKnownLocation)), diff --git a/OsmAnd/src/net/osmand/plus/wikipedia/WikipediaDialogFragment.java b/OsmAnd/src/net/osmand/plus/wikipedia/WikipediaDialogFragment.java index 2e917881e4..3f2114327c 100644 --- a/OsmAnd/src/net/osmand/plus/wikipedia/WikipediaDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/wikipedia/WikipediaDialogFragment.java @@ -13,6 +13,7 @@ import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.webkit.WebSettings; @@ -67,7 +68,7 @@ public class WikipediaDialogFragment extends WikiArticleBaseDialogFragment { this.lang = lang; } - @SuppressLint("SetJavaScriptEnabled") + @SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"}) @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -120,7 +121,25 @@ public class WikipediaDialogFragment extends WikiArticleBaseDialogFragment { selectedLangTv.setBackgroundResource(nightMode ? R.drawable.wikipedia_select_lang_bg_dark_n : R.drawable.wikipedia_select_lang_bg_light_n); - contentWebView = (WebView) mainView.findViewById(R.id.content_web_view); + contentWebView = mainView.findViewById(R.id.content_web_view); + contentWebView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: + case MotionEvent.ACTION_MOVE: + readFullArticleButton.setVisibility(View.GONE); + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_UP: + readFullArticleButton.setVisibility(View.VISIBLE); + break; + } + return false; + } + }); + WebSettings webSettings = contentWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setTextZoom((int) (getResources().getConfiguration().fontScale * 100f)); diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelDbHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelDbHelper.java index 378f0a6a70..d50d05e42b 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelDbHelper.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelDbHelper.java @@ -99,13 +99,13 @@ public class TravelDbHelper implements TravelHelper { private final OsmandApplication application; private TravelLocalDataHelper localDataHelper; - private Collator collator; + private final Collator collator; private SQLiteConnection connection = null; private File selectedTravelBook = null; private List existingTravelBooks = new ArrayList<>(); - private List popularArticles = new ArrayList(); + private List popularArticles = new ArrayList<>(); public TravelDbHelper(OsmandApplication application) { @@ -126,6 +126,7 @@ public class TravelDbHelper implements TravelHelper { return false; } + @Override public TravelLocalDataHelper getBookmarksHelper() { return localDataHelper; } @@ -135,6 +136,7 @@ public class TravelDbHelper implements TravelHelper { return selectedTravelBook != null; } + @Override public void initializeDataOnAppStartup() { List files = getPossibleFiles(); String travelBook = application.getSettings().SELECTED_TRAVEL_BOOK.get(); @@ -168,12 +170,14 @@ public class TravelDbHelper implements TravelHelper { return null; } + @Override public void initializeDataToDisplay() { localDataHelper.refreshCachedData(); loadPopularArticles(); } + @Override public String getSelectedTravelBookName() { if (selectedTravelBook != null) { return selectedTravelBook.getName(); @@ -210,8 +214,9 @@ public class TravelDbHelper implements TravelHelper { } } + @Override @NonNull - public List search(final String searchQuery) { + public List search(@NonNull String searchQuery) { List res = new ArrayList<>(); SQLiteConnection conn = openConnection(); String[] queries = searchQuery.replace('_', ' ').replace('/', ' ').split(" "); @@ -260,6 +265,7 @@ public class TravelDbHelper implements TravelHelper { return list; } + @Override @NonNull public List getPopularArticles() { return popularArticles; @@ -270,7 +276,7 @@ public class TravelDbHelper implements TravelHelper { String language = application.getLanguage(); SQLiteConnection conn = openConnection(); if (conn == null) { - popularArticles = new ArrayList(); + popularArticles = new ArrayList<>(); return popularArticles; } String LANG_WHERE = " WHERE " + ARTICLES_COL_LANG + " = '" + language + "'"; @@ -376,7 +382,7 @@ public class TravelDbHelper implements TravelHelper { return res; } - private void sortSearchResults(final String searchQuery, List list) { + private void sortSearchResults(@NonNull final String searchQuery, @NonNull List list) { Collections.sort(list, new Comparator() { @Override public int compare(WikivoyageSearchResult o1, WikivoyageSearchResult o2) { @@ -444,8 +450,9 @@ public class TravelDbHelper implements TravelHelper { } @NonNull + @Override public LinkedHashMap> getNavigationMap( - final TravelArticle article) { + @NonNull final TravelArticle article) { String lang = article.getLang(); String title = article.getTitle(); if (TextUtils.isEmpty(lang) || TextUtils.isEmpty(title)) { @@ -533,8 +540,9 @@ public class TravelDbHelper implements TravelHelper { return res; } + @Override @Nullable - public TravelArticle getArticleById(String routeId, String lang) { + public TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang) { TravelArticle res = null; SQLiteConnection conn = openConnection(); if (conn != null && !Algorithms.isEmpty(routeId)) { @@ -550,8 +558,9 @@ public class TravelDbHelper implements TravelHelper { return res; } + @Override @Nullable - public TravelArticle getArticleByTitle(String title, String lang) { + public TravelArticle getArticleByTitle(@NonNull String title, @NonNull String lang) { TravelArticle res = null; SQLiteConnection conn = openConnection(); if (conn != null) { @@ -567,7 +576,9 @@ public class TravelDbHelper implements TravelHelper { return res; } - public String getArticleId(String title, String lang) { + @NonNull + @Override + public String getArticleId(@NonNull String title, @NonNull String lang) { String res = ""; SQLiteConnection conn = openConnection(); if (conn != null) { @@ -585,7 +596,8 @@ public class TravelDbHelper implements TravelHelper { } @NonNull - public ArrayList getArticleLangs(String routeId) { + @Override + public ArrayList getArticleLangs(@NonNull String routeId) { ArrayList res = new ArrayList<>(); SQLiteConnection conn = openConnection(); if (conn != null) { @@ -652,12 +664,16 @@ public class TravelDbHelper implements TravelHelper { return nm.substring(0, nm.indexOf('.')).replace('_', ' '); } - public String getGPXName(TravelArticle article) { + @NonNull + @Override + public String getGPXName(@NonNull final TravelArticle article) { return article.getTitle().replace('/', '_').replace('\'', '_') .replace('\"', '_') + IndexConstants.GPX_FILE_EXT; } - public File createGpxFile(TravelArticle article) { + @NonNull + @Override + public File createGpxFile(@NonNull final TravelArticle article) { final GPXFile gpx = article.getGpxFile(); File file = application.getAppPath(IndexConstants.GPX_TRAVEL_DIR + getGPXName(article)); if (!file.exists()) { diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelHelper.java index 6ff6cf914b..b55c398817 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelHelper.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelHelper.java @@ -19,26 +19,31 @@ public interface TravelHelper { boolean isAnyTravelBookPresent(); @NonNull - List search(final String searchQuery); + List search(@NonNull String searchQuery); @NonNull List getPopularArticles(); - Map> getNavigationMap( - final TravelArticle article); + @NonNull + Map> getNavigationMap(@NonNull final TravelArticle article); @Nullable - TravelArticle getArticleById(String routeId, String lang); + TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang); - TravelArticle getArticleByTitle(String title, String lang); + @Nullable + TravelArticle getArticleByTitle(@NonNull String title, @NonNull String lang); - String getArticleId(String title, String lang); + @NonNull + String getArticleId(@NonNull String title, @NonNull String lang); - ArrayList getArticleLangs(String routeId); + @NonNull + ArrayList getArticleLangs(@NonNull String routeId); - String getGPXName(TravelArticle article); + @NonNull + String getGPXName(@NonNull final TravelArticle article); - File createGpxFile(TravelArticle article); + @NonNull + File createGpxFile(@NonNull final TravelArticle article); // TODO: this method should be deleted once TravelDBHelper is deleted // For TravelOBFHelper it could always return "" and should be no problem diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java index 1b94b138ac..0816a2d2ef 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java @@ -1,15 +1,18 @@ package net.osmand.plus.wikivoyage.data; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import net.osmand.Collator; import net.osmand.CollatorStringMatcher; import net.osmand.GPXUtilities; +import net.osmand.GPXUtilities.GPXFile; import net.osmand.IndexConstants; import net.osmand.OsmAndCollator; import net.osmand.PlatformUtil; import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; +import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter; import net.osmand.data.Amenity; import net.osmand.data.LatLon; import net.osmand.osm.PoiCategory; @@ -22,13 +25,14 @@ import org.apache.commons.logging.Log; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import static net.osmand.CollatorStringMatcher.StringMatcherMode.*; +import static net.osmand.CollatorStringMatcher.StringMatcherMode.CHECK_EQUALS_FROM_SPACE; public class TravelObfHelper implements TravelHelper { @@ -37,6 +41,7 @@ public class TravelObfHelper implements TravelHelper { public static final int SEARCH_RADIUS = 100000; private final OsmandApplication app; + private final Collator collator; private List popularArticles = new ArrayList<>(); private final Map cachedArticles; @@ -44,6 +49,7 @@ public class TravelObfHelper implements TravelHelper { public TravelObfHelper(OsmandApplication app) { this.app = app; + collator = OsmAndCollator.primaryCollator(); localDataHelper = new TravelLocalDataHelper(app); cachedArticles = new HashMap<>(); } @@ -66,14 +72,13 @@ public class TravelObfHelper implements TravelHelper { @NonNull public List loadPopularArticles() { String language = app.getLanguage(); - popularArticles.clear(); - List amenities; + List popularArticles = new ArrayList<>(); for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) { try { final LatLon location = app.getMapViewTrackingUtilities().getMapLocation(); BinaryMapIndexReader.SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( location, SEARCH_RADIUS, -1, getSearchRouteArticleFilter(), null); - amenities = travelBookReader.searchPoi(req); + List amenities = travelBookReader.searchPoi(req); if (amenities.size() > 0) { for (Amenity a : amenities) { if (!Algorithms.isEmpty(a.getName(language))) { @@ -100,11 +105,12 @@ public class TravelObfHelper implements TravelHelper { LOG.error(e.getMessage()); } } + this.popularArticles = popularArticles; return popularArticles; } - BinaryMapIndexReader.SearchPoiTypeFilter getSearchRouteArticleFilter() { - return new BinaryMapIndexReader.SearchPoiTypeFilter() { + SearchPoiTypeFilter getSearchRouteArticleFilter() { + return new SearchPoiTypeFilter() { @Override public boolean accept(PoiCategory type, String subcategory) { return subcategory.equals(ROUTE_ARTICLE); @@ -117,16 +123,24 @@ public class TravelObfHelper implements TravelHelper { }; } - private TravelArticle readArticle(Amenity amenity, String lang) { + private TravelArticle readArticle(@NonNull Amenity amenity, @Nullable String lang) { TravelArticle res = new TravelArticle(); - res.title = Algorithms.isEmpty(amenity.getName(lang)) ? amenity.getName() : amenity.getName(lang); + String title = Algorithms.isEmpty(amenity.getName(lang)) ? amenity.getName() : amenity.getName(lang); + if (Algorithms.isEmpty(title)) { + Map namesMap = amenity.getNamesMap(true); + if (!namesMap.isEmpty()) { + lang = namesMap.keySet().iterator().next(); + title = amenity.getName(lang); + } + } + res.title = title; res.content = amenity.getDescription(lang); res.isPartOf = emptyIfNull(amenity.getTagContent(Amenity.IS_PART, lang)); res.lat = amenity.getLocation().getLatitude(); res.lon = amenity.getLocation().getLongitude(); res.imageTitle = emptyIfNull(amenity.getTagContent(Amenity.IMAGE_TITLE, lang)); res.routeId = getRouteId(amenity); - res.originalId = 0; //? + res.originalId = 0; res.lang = lang; res.contentsJson = emptyIfNull(amenity.getTagContent(Amenity.CONTENT_JSON, lang)); res.aggregatedPartOf = emptyIfNull(amenity.getTagContent(Amenity.IS_AGGR_PART, lang)); @@ -148,24 +162,90 @@ public class TravelObfHelper implements TravelHelper { @NonNull @Override - public List search(String searchQuery) { + public List search(@NonNull String searchQuery) { List res = new ArrayList<>(); + List searchObjects = null; + for (BinaryMapIndexReader reader : app.getResourceManager().getTravelRepositories()) { + try { + BinaryMapIndexReader.SearchRequest searchRequest = BinaryMapIndexReader. + buildSearchPoiRequest(0, 0, searchQuery, + 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(), null, null); + + searchObjects = reader.searchPoiByName(searchRequest); + } catch (IOException e) { + LOG.error(e); + } + } + if (!Algorithms.isEmpty(searchObjects)) { + String baseLng = app.getLanguage(); + for (Amenity obj : searchObjects) { + WikivoyageSearchResult r = new WikivoyageSearchResult(); + TravelArticle article = readArticle(obj, baseLng); + r.articleTitles = new ArrayList<>(Collections.singletonList(article.title)); + r.imageTitle = article.imageTitle; + r.routeId = article.routeId; + r.isPartOf = new ArrayList<>(Collections.singletonList(article.isPartOf)); + r.langs = new ArrayList<>(Collections.singletonList(baseLng)); + res.add(r); + cachedArticles.put(article.routeId, article); + } + res = new ArrayList<>(groupSearchResultsByRouteId(res)); + sortSearchResults(res); + } return res; } + private void sortSearchResults(@NonNull List list) { + Collections.sort(list, new Comparator() { + + @Override + public int compare(WikivoyageSearchResult res1, WikivoyageSearchResult res2) { + return collator.compare(res1.articleTitles.get(0), res2.articleTitles.get(0)); + } + }); + } + + @NonNull + private Collection groupSearchResultsByRouteId(@NonNull List res) { + String baseLng = app.getLanguage(); + Map wikivoyage = new HashMap<>(); + for (WikivoyageSearchResult rs : res) { + WikivoyageSearchResult prev = wikivoyage.get(rs.routeId); + if (prev != null) { + int insInd = prev.langs.size(); + if (rs.langs.get(0).equals(baseLng)) { + insInd = 0; + } else if (rs.langs.get(0).equals("en")) { + if (!prev.langs.get(0).equals(baseLng)) { + insInd = 0; + } else { + insInd = 1; + } + } + prev.articleTitles.add(insInd, rs.articleTitles.get(0)); + prev.langs.add(insInd, rs.langs.get(0)); + prev.isPartOf.add(insInd, rs.isPartOf.get(0)); + } else { + wikivoyage.put(rs.routeId, rs); + } + } + return wikivoyage.values(); + } + @NonNull @Override public List getPopularArticles() { return popularArticles; } + @NonNull @Override - public Map> getNavigationMap(TravelArticle article) { - return null; + public Map> getNavigationMap(@NonNull final TravelArticle article) { + return Collections.emptyMap(); } @Override - public TravelArticle getArticleById(String routeId, String lang) { + public TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang) { TravelArticle article = cachedArticles.get(routeId); if (article != null) { return article; @@ -177,29 +257,28 @@ public class TravelObfHelper implements TravelHelper { return localDataHelper.getSavedArticle(routeId, lang); } - public TravelArticle getArticleByIdFromTravelBooks(final String routeId, final String lang) { + private TravelArticle getArticleByIdFromTravelBooks(final String routeId, final String lang) { TravelArticle article = null; final List amenities = new ArrayList<>(); for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) { try { - int left = 0; - int right = Integer.MAX_VALUE; - int top = 0; - int bottom = Integer.MAX_VALUE; BinaryMapIndexReader.SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( - left, right, top, bottom, -1, getSearchRouteArticleFilter(), + 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, -1, getSearchRouteArticleFilter(), new ResultMatcher() { + boolean done = false; + @Override public boolean publish(Amenity amenity) { if (getRouteId(amenity).equals(routeId)) { amenities.add(amenity); + done = true; } return false; } @Override public boolean isCancelled() { - return false; + return done; } }); @@ -215,34 +294,32 @@ public class TravelObfHelper implements TravelHelper { return article; } + @Nullable @Override - public TravelArticle getArticleByTitle(final String title, final String lang) { + public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull final String lang) { TravelArticle article = null; final List amenities = new ArrayList<>(); for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) { try { - int left = 0; - int right = Integer.MAX_VALUE; - int top = 0; - int bottom = Integer.MAX_VALUE; BinaryMapIndexReader.SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( - 0, 0, title, left, right, top, bottom, + 0, 0, title, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(), new ResultMatcher() { + boolean done = false; + @Override public boolean publish(Amenity amenity) { - Collator collator = OsmAndCollator.primaryCollator(); - if (CollatorStringMatcher.cmatches(collator, title, amenity.getName(lang), - CHECK_EQUALS_FROM_SPACE) && amenity.getSubType().equals(ROUTE_ARTICLE)) { + if (CollatorStringMatcher.cmatches(collator, title, amenity.getName(lang), CHECK_EQUALS_FROM_SPACE)) { amenities.add(amenity); + done = true; } return false; } @Override public boolean isCancelled() { - return false; + return done; } - }); + }, null); travelBookReader.searchPoiByName(req); } catch (IOException e) { @@ -264,22 +341,28 @@ public class TravelObfHelper implements TravelHelper { } } + @NonNull @Override - public String getArticleId(String title, String lang) { + public String getArticleId(@NonNull String title, @NonNull String lang) { + TravelArticle a = null; for (TravelArticle article : cachedArticles.values()) { if (article.getTitle().equals(title)) { - return article.getRouteId(); + a = article; + break; } } - TravelArticle article = getArticleByTitle(title, lang); - if (article != null) { - return article.getRouteId(); + if (a == null) { + TravelArticle article = getArticleByTitle(title, lang); + if (article != null) { + a = article; + } } - return null; + return a != null && a.getRouteId() != null ? a.getRouteId() : ""; } + @NonNull @Override - public ArrayList getArticleLangs(String routeId) { + public ArrayList getArticleLangs(@NonNull String routeId) { ArrayList res = new ArrayList<>(); res.add("en"); for (TravelArticle article : popularArticles) { @@ -290,15 +373,17 @@ public class TravelObfHelper implements TravelHelper { return res; } + @NonNull @Override - public String getGPXName(TravelArticle article) { + public String getGPXName(@NonNull final TravelArticle article) { return article.getTitle().replace('/', '_').replace('\'', '_') .replace('\"', '_') + IndexConstants.GPX_FILE_EXT; } + @NonNull @Override - public File createGpxFile(TravelArticle article) { - final GPXUtilities.GPXFile gpx = article.getGpxFile(); + public File createGpxFile(@NonNull final TravelArticle article) { + final GPXFile gpx = article.getGpxFile(); File file = app.getAppPath(IndexConstants.GPX_TRAVEL_DIR + getGPXName(article)); if (!file.exists()) { GPXUtilities.writeGpxFile(file, gpx);