Merge branch 'master' into travel_obf_gpx

# Conflicts:
#	OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java
This commit is contained in:
Dima-1 2021-01-08 13:31:56 +02:00
commit 279349919d
77 changed files with 1031 additions and 349 deletions

View file

@ -2544,7 +2544,7 @@ public class GPXUtilities {
if (maxlat == null) {
maxlat = parser.getAttributeValue("", "maxLat");
}
if (maxlat == null) {
if (maxlon == null) {
maxlon = parser.getAttributeValue("", "maxLon");
}

View file

@ -1,11 +1,5 @@
package net.osmand.binary;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapAddressReaderAdapter.AddressRegion;
import net.osmand.binary.BinaryMapAddressReaderAdapter.CitiesBlock;
@ -29,42 +23,50 @@ import net.osmand.binary.OsmandIndex.TransportPart;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
public class CachedOsmandIndexes {
private OsmAndStoredIndex storedIndex;
private OsmAndStoredIndex.Builder storedIndexBuilder;
private Log log = PlatformUtil.getLog(CachedOsmandIndexes.class);
private boolean hasChanged = true;
public static final int VERSION = 2;
public void addToCache(BinaryMapIndexReader reader, File f) {
hasChanged = true;
if(storedIndexBuilder == null) {
if (storedIndexBuilder == null) {
storedIndexBuilder = OsmandIndex.OsmAndStoredIndex.newBuilder();
storedIndexBuilder.setVersion(VERSION);
storedIndexBuilder.setDateCreated(System.currentTimeMillis());
if(storedIndex != null) {
for(FileIndex ex : storedIndex.getFileIndexList()) {
storedIndexBuilder.addFileIndex(ex);
if (storedIndex != null) {
for (FileIndex ex : storedIndex.getFileIndexList()) {
if (!ex.getFileName().equals(f.getName())) {
storedIndexBuilder.addFileIndex(ex);
}
}
}
}
FileIndex.Builder fileIndex = OsmandIndex.FileIndex.newBuilder();
long d = reader.getDateCreated();
fileIndex.setDateModified(d== 0?f.lastModified() : d);
fileIndex.setDateModified(d == 0 ? f.lastModified() : d);
fileIndex.setSize(f.length());
fileIndex.setVersion(reader.getVersion());
fileIndex.setFileName(f.getName());
for(MapIndex index : reader.getMapIndexes()) {
for (MapIndex index : reader.getMapIndexes()) {
MapPart.Builder map = OsmandIndex.MapPart.newBuilder();
map.setSize(index.getLength());
map.setOffset(index.getFilePointer());
if(index.getName() != null) {
if (index.getName() != null) {
map.setName(index.getName());
}
for(MapRoot mr : index.getRoots() ) {
for (MapRoot mr : index.getRoots()) {
MapLevel.Builder lev = OsmandIndex.MapLevel.newBuilder();
lev.setSize(mr.length);
lev.setOffset(mr.filePointer);
@ -78,36 +80,36 @@ public class CachedOsmandIndexes {
}
fileIndex.addMapIndex(map);
}
for(AddressRegion index : reader.getAddressIndexes()) {
for (AddressRegion index : reader.getAddressIndexes()) {
AddressPart.Builder addr = OsmandIndex.AddressPart.newBuilder();
addr.setSize(index.getLength());
addr.setOffset(index.getFilePointer());
if(index.getName() != null) {
if (index.getName() != null) {
addr.setName(index.getName());
}
if(index.getEnName() != null) {
if (index.getEnName() != null) {
addr.setNameEn(index.getEnName());
}
addr.setIndexNameOffset(index.getIndexNameOffset());
for(CitiesBlock mr : index.getCities() ) {
for (CitiesBlock mr : index.getCities()) {
CityBlock.Builder cblock = OsmandIndex.CityBlock.newBuilder();
cblock.setSize(mr.length);
cblock.setOffset(mr.filePointer);
cblock.setType(mr.type);
addr.addCities(cblock);
}
for(String s : index.getAttributeTagsTable()) {
for (String s : index.getAttributeTagsTable()) {
addr.addAdditionalTags(s);
}
fileIndex.addAddressIndex(addr);
}
for(PoiRegion index : reader.getPoiIndexes()) {
for (PoiRegion index : reader.getPoiIndexes()) {
PoiPart.Builder poi = OsmandIndex.PoiPart.newBuilder();
poi.setSize(index.getLength());
poi.setOffset(index.getFilePointer());
if(index.getName() != null) {
if (index.getName() != null) {
poi.setName(index.getName());
}
poi.setLeft(index.left31);
@ -116,12 +118,12 @@ public class CachedOsmandIndexes {
poi.setBottom(index.bottom31);
fileIndex.addPoiIndex(poi.build());
}
for(TransportIndex index : reader.getTransportIndexes()) {
for (TransportIndex index : reader.getTransportIndexes()) {
TransportPart.Builder transport = OsmandIndex.TransportPart.newBuilder();
transport.setSize(index.getLength());
transport.setOffset(index.getFilePointer());
if(index.getName() != null) {
if (index.getName() != null) {
transport.setName(index.getName());
}
transport.setLeft(index.getLeft());
@ -130,33 +132,33 @@ public class CachedOsmandIndexes {
transport.setBottom(index.getBottom());
transport.setStopsTableLength(index.stopsFileLength);
transport.setStopsTableOffset(index.stopsFileOffset);
// if(index.incompleteRoutesLength > 0) {
// if(index.incompleteRoutesLength > 0) {
transport.setIncompleteRoutesLength(index.incompleteRoutesLength);
transport.setIncompleteRoutesOffset(index.incompleteRoutesOffset);
// }
// }
transport.setStringTableLength(index.stringTable.length);
transport.setStringTableOffset(index.stringTable.fileOffset);
fileIndex.addTransportIndex(transport);
}
for(RouteRegion index : reader.getRoutingIndexes()) {
for (RouteRegion index : reader.getRoutingIndexes()) {
RoutingPart.Builder routing = OsmandIndex.RoutingPart.newBuilder();
routing.setSize(index.getLength());
routing.setOffset(index.getFilePointer());
if(index.getName() != null) {
if (index.getName() != null) {
routing.setName(index.getName());
}
for(RouteSubregion sub : index.getSubregions()) {
for (RouteSubregion sub : index.getSubregions()) {
addRouteSubregion(routing, sub, false);
}
for(RouteSubregion sub : index.getBaseSubregions()) {
for (RouteSubregion sub : index.getBaseSubregions()) {
addRouteSubregion(routing, sub, true);
}
fileIndex.addRoutingIndex(routing);
}
storedIndexBuilder.addFileIndex(fileIndex);
}
private void addRouteSubregion(RoutingPart.Builder routing, RouteSubregion sub, boolean base) {
@ -171,11 +173,11 @@ public class CachedOsmandIndexes {
rpart.setShifToData(sub.shiftToData);
routing.addSubregions(rpart);
}
public BinaryMapIndexReader getReader(File f) throws IOException {
public BinaryMapIndexReader getReader(File f, boolean useStoredIndex) throws IOException {
RandomAccessFile mf = new RandomAccessFile(f.getPath(), "r");
FileIndex found = null;
if (storedIndex != null) {
if (storedIndex != null && useStoredIndex) {
for (int i = 0; i < storedIndex.getFileIndexCount(); i++) {
FileIndex fi = storedIndex.getFileIndex(i);
if (f.length() == fi.getSize() && f.getName().equals(fi.getFileName())) {
@ -191,26 +193,26 @@ public class CachedOsmandIndexes {
reader = new BinaryMapIndexReader(mf, f);
addToCache(reader, f);
if (log.isDebugEnabled()) {
log.debug("Initializing db " + f.getAbsolutePath() + " " + (System.currentTimeMillis() - val ) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
log.debug("Initializing db " + f.getAbsolutePath() + " " + (System.currentTimeMillis() - val) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
} else {
reader = initFileIndex(found, mf, f);
}
return reader;
}
private BinaryMapIndexReader initFileIndex(FileIndex found, RandomAccessFile mf, File f) throws IOException {
BinaryMapIndexReader reader = new BinaryMapIndexReader(mf, f, false);
reader.version = found.getVersion();
reader.dateCreated = found.getDateModified();
for(MapPart index : found.getMapIndexList()) {
for (MapPart index : found.getMapIndexList()) {
MapIndex mi = new MapIndex();
mi.length = (int) index.getSize();
mi.filePointer = (int) index.getOffset();
mi.name = index.getName();
for(MapLevel mr : index.getLevelsList()) {
for (MapLevel mr : index.getLevelsList()) {
MapRoot root = new MapRoot();
root.length = (int) mr.getSize();
root.filePointer = (int) mr.getOffset();
@ -226,15 +228,15 @@ public class CachedOsmandIndexes {
reader.indexes.add(mi);
reader.basemap = reader.basemap || mi.isBaseMap();
}
for(AddressPart index : found.getAddressIndexList()) {
for (AddressPart index : found.getAddressIndexList()) {
AddressRegion mi = new AddressRegion();
mi.length = (int) index.getSize();
mi.filePointer = (int) index.getOffset();
mi.name = index.getName();
mi.enName = index.getNameEn();
mi.indexNameOffset = index.getIndexNameOffset();
for(CityBlock mr : index.getCitiesList() ) {
for (CityBlock mr : index.getCitiesList()) {
CitiesBlock cblock = new CitiesBlock();
cblock.length = (int) mr.getSize();
cblock.filePointer = (int) mr.getOffset();
@ -245,8 +247,8 @@ public class CachedOsmandIndexes {
reader.addressIndexes.add(mi);
reader.indexes.add(mi);
}
for(PoiPart index : found.getPoiIndexList()) {
for (PoiPart index : found.getPoiIndexList()) {
PoiRegion mi = new PoiRegion();
mi.length = (int) index.getSize();
mi.filePointer = (int) index.getOffset();
@ -258,14 +260,14 @@ public class CachedOsmandIndexes {
reader.poiIndexes.add(mi);
reader.indexes.add(mi);
}
for(TransportPart index : found.getTransportIndexList()) {
for (TransportPart index : found.getTransportIndexList()) {
TransportIndex mi = new TransportIndex();
mi.length = (int) index.getSize();
mi.filePointer = (int) index.getOffset();
mi.name = index.getName();
mi.left = index.getLeft();
mi.right =index.getRight();
mi.right = index.getRight();
mi.top = index.getTop();
mi.bottom = index.getBottom();
mi.stopsFileLength = index.getStopsTableLength();
@ -278,14 +280,14 @@ public class CachedOsmandIndexes {
reader.transportIndexes.add(mi);
reader.indexes.add(mi);
}
for(RoutingPart index : found.getRoutingIndexList()) {
for (RoutingPart index : found.getRoutingIndexList()) {
RouteRegion mi = new RouteRegion();
mi.length = (int) index.getSize();
mi.filePointer = (int) index.getOffset();
mi.name = index.getName();
for(RoutingSubregion mr : index.getSubregionsList()) {
for (RoutingSubregion mr : index.getSubregionsList()) {
RouteSubregion sub = new RouteSubregion(mi);
sub.length = (int) mr.getSize();
sub.filePointer = (int) mr.getOffset();
@ -294,7 +296,7 @@ public class CachedOsmandIndexes {
sub.top = mr.getTop();
sub.bottom = mr.getBottom();
sub.shiftToData = mr.getShifToData();
if(mr.getBasemap()) {
if (mr.getBasemap()) {
mi.basesubregions.add(sub);
} else {
mi.subregions.add(sub);
@ -303,7 +305,7 @@ public class CachedOsmandIndexes {
reader.routingIndexes.add(mi);
reader.indexes.add(mi);
}
return reader;
}
@ -313,7 +315,7 @@ public class CachedOsmandIndexes {
try {
storedIndex = OsmandIndex.OsmAndStoredIndex.newBuilder().mergeFrom(is).build();
hasChanged = false;
if(storedIndex.getVersion() != version){
if (storedIndex.getVersion() != version) {
storedIndex = null;
}
} finally {
@ -321,7 +323,7 @@ public class CachedOsmandIndexes {
}
log.info("Initialize cache " + (System.currentTimeMillis() - time));
}
public void writeToFile(File f) throws IOException {
if (hasChanged) {
FileOutputStream outputStream = new FileOutputStream(f);

View file

@ -533,16 +533,19 @@ public class BinaryRoutePlanner {
long fid = to.getRoad().getId();
for (int i = 0; i < from.getRoad().getRestrictionLength(); i++) {
long id = from.getRoad().getRestrictionId(i);
int tp = from.getRoad().getRestrictionType(i);
if (fid == id) {
int tp = from.getRoad().getRestrictionType(i);
if (tp == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN ||
tp == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN ||
tp == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON ||
tp == MapRenderingTypes.RESTRICTION_NO_U_TURN) {
if (tp == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN
|| tp == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN
|| tp == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON
|| tp == MapRenderingTypes.RESTRICTION_NO_U_TURN) {
return false;
}
break;
}
if (tp == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) {
return false;
}
}
}
return true;
@ -647,24 +650,36 @@ public class BinaryRoutePlanner {
int type = -1;
if (!reverseWay) {
for (int i = 0; i < road.getRestrictionLength(); i++) {
int rt = road.getRestrictionType(i);
long rv = road.getRestrictionVia(i);
if (road.getRestrictionId(i) == next.road.id) {
if(!via || road.getRestrictionVia(i) == viaId) {
type = road.getRestrictionType(i);
if (!via || rv == viaId) {
type = rt;
break;
}
}
if (rv == viaId && rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) {
type = MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON;
break;
}
}
} else {
for (int i = 0; i < next.road.getRestrictionLength(); i++) {
int rt = next.road.getRestrictionType(i);
long rv = next.road.getRestrictionVia(i);
long restrictedTo = next.road.getRestrictionId(i);
if (restrictedTo == road.id) {
if(!via || next.road.getRestrictionVia(i) == viaId) {
if (!via || rv == viaId) {
type = rt;
break;
}
}
if (rv == viaId && rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) {
type = MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON;
break;
}
// Check if there is restriction only to the other than current road
if (rt == MapRenderingTypes.RESTRICTION_ONLY_RIGHT_TURN || rt == MapRenderingTypes.RESTRICTION_ONLY_LEFT_TURN
|| rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) {

View file

@ -34,6 +34,7 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@ -41,6 +42,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -67,6 +69,9 @@ public class SearchUICore {
private MapPoiTypes poiTypes;
private static boolean debugMode = false;
private static final Set<String> FILTER_DUPLICATE_POI_SUBTYPE = new TreeSet<String>(
Arrays.asList("building", "internet_access_yes"));
public SearchUICore(MapPoiTypes poiTypes, String locale, boolean transliterate) {
this.poiTypes = poiTypes;
@ -244,12 +249,17 @@ public class SearchUICore {
String type2 = a2.getType().getKeyName();
String subType1 = a1.getSubType();
String subType2 = a2.getSubType();
if(a1.getId().longValue() == a2.getId().longValue() && (subType1.equals("building") || subType2.equals("building"))) {
boolean isEqualId = a1.getId().longValue() == a2.getId().longValue();
if (isEqualId && (FILTER_DUPLICATE_POI_SUBTYPE.contains(subType1)
|| FILTER_DUPLICATE_POI_SUBTYPE.contains(subType2))) {
return true;
}
if (!type1.equals(type2)) {
} else if (!type1.equals(type2)) {
return false;
}
if (type1.equals("natural")) {
similarityRadius = 50000;
} else if (subType1.equals(subType2)) {
@ -987,15 +997,29 @@ public class SearchUICore {
// here 2 points are amenity
Amenity a1 = (Amenity) o1.object;
Amenity a2 = (Amenity) o2.object;
String type1 = a1.getType().getKeyName();
String type2 = a2.getType().getKeyName();
int cmp = c.collator.compare(type1, type2);
String subType1 = a1.getSubType() == null ? "" : a1.getSubType();
String subType2 = a2.getSubType() == null ? "" : a2.getSubType();
int cmp = 0;
if (FILTER_DUPLICATE_POI_SUBTYPE.contains(subType1)) {
cmp = 1;
} else if (FILTER_DUPLICATE_POI_SUBTYPE.contains(subType2)) {
cmp = -1;
}
if (cmp != 0) {
return cmp;
}
cmp = c.collator.compare(type1, type2);
if (cmp != 0) {
return cmp;
}
String subType1 = a1.getSubType() == null ? "" : a1.getSubType();
String subType2 = a2.getSubType() == null ? "" : a2.getSubType();
cmp = c.collator.compare(subType1, subType2);
if (cmp != 0) {
return cmp;

View file

@ -15,13 +15,11 @@ import java.util.TreeSet;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.LatLon;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -76,41 +74,52 @@ public class RouteTestingTest {
} else {
binaryMapIndexReaders = new BinaryMapIndexReader[]{new BinaryMapIndexReader(raf, new File(fl))};
}
RoutingConfiguration config = builder.build(params.containsKey("vehicle") ? params.get("vehicle") : "car",
RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3, params);
RoutingContext ctx = fe.buildRoutingContext(config, null, binaryMapIndexReaders,
RoutePlannerFrontEnd.RouteCalculationMode.NORMAL);
ctx.leftSideNavigation = false;
List<RouteSegmentResult> routeSegments = fe.searchRoute(ctx, te.getStartPoint(), te.getEndPoint(), te.getTransitPoint());
Set<Long> reachedSegments = new TreeSet<Long>();
Assert.assertNotNull(routeSegments);
int prevSegment = -1;
for (int i = 0; i <= routeSegments.size(); i++) {
if (i == routeSegments.size() || routeSegments.get(i).getTurnType() != null) {
if (prevSegment >= 0) {
String name = routeSegments.get(prevSegment).getDescription();
long segmentId = routeSegments.get(prevSegment).getObject().getId() >> (RouteResultPreparation.SHIFT_ID);
System.out.println("segmentId: " + segmentId + " description: " + name);
for (int planRoadDirection = -1; planRoadDirection <= 1; planRoadDirection++) {
if (params.containsKey("wrongPlanRoadDirection")) {
if (params.get("wrongPlanRoadDirection").equals(planRoadDirection + "")) {
continue;
}
prevSegment = i;
}
if (i < routeSegments.size()) {
reachedSegments.add(routeSegments.get(i).getObject().getId() >> (RouteResultPreparation.SHIFT_ID));
}
}
Map<Long, String> expectedResults = te.getExpectedResults();
Iterator<Entry<Long, String>> it = expectedResults.entrySet().iterator();
while (it.hasNext()) {
Entry<Long, String> es = it.next();
if (es.getValue().equals("false")) {
Assert.assertTrue("Expected segment " + (es.getKey()) + " was wrongly reached in route segments "
+ reachedSegments.toString(), !reachedSegments.contains(es.getKey()));
} else {
Assert.assertTrue("Expected segment " + (es.getKey()) + " weren't reached in route segments "
+ reachedSegments.toString(), reachedSegments.contains(es.getKey()));
}
}
RoutingConfiguration config = builder.build(params.containsKey("vehicle") ? params.get("vehicle") : "car",
RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3, params);
config.planRoadDirection = planRoadDirection;
RoutingContext ctx = fe.buildRoutingContext(config, null, binaryMapIndexReaders,
RoutePlannerFrontEnd.RouteCalculationMode.NORMAL);
ctx.leftSideNavigation = false;
List<RouteSegmentResult> routeSegments = fe.searchRoute(ctx, te.getStartPoint(), te.getEndPoint(),
te.getTransitPoint());
Set<Long> reachedSegments = new TreeSet<Long>();
Assert.assertNotNull(routeSegments);
int prevSegment = -1;
for (int i = 0; i <= routeSegments.size(); i++) {
if (i == routeSegments.size() || routeSegments.get(i).getTurnType() != null) {
if (prevSegment >= 0) {
String name = routeSegments.get(prevSegment).getDescription();
long segmentId = routeSegments.get(prevSegment).getObject()
.getId() >> (RouteResultPreparation.SHIFT_ID);
System.out.println("segmentId: " + segmentId + " description: " + name);
}
prevSegment = i;
}
if (i < routeSegments.size()) {
reachedSegments.add(routeSegments.get(i).getObject().getId() >> (RouteResultPreparation.SHIFT_ID));
}
}
Map<Long, String> expectedResults = te.getExpectedResults();
Iterator<Entry<Long, String>> it = expectedResults.entrySet().iterator();
while (it.hasNext()) {
Entry<Long, String> es = it.next();
if (es.getValue().equals("false")) {
Assert.assertTrue("Expected segment " + (es.getKey()) + " was wrongly reached in route segments "
+ reachedSegments.toString(), !reachedSegments.contains(es.getKey()));
} else {
Assert.assertTrue("Expected segment " + (es.getKey()) + " weren't reached in route segments "
+ reachedSegments.toString(), reachedSegments.contains(es.getKey()));
}
}
}
}
}

View file

@ -267,4 +267,7 @@
<string name="privacy_policy_agree">\"Jarraitu\" sakatuz, Telegram eta OsmAnd pribatutasun-politiken baldintzak onartzen dituzu.</string>
<string name="privacy_policy_telegram_client">OsmAnd aztarnariak Telegram plataforma irekia erabiltzen duten bezeroetako bat da. Zure kontaktuek Telegram-eko beste edozein bezero erabil dezakete.</string>
<string name="last_update_from_telegram_date">Telegram-eko azken eguneratzea: %1$s</string>
<string name="shared_string_export">Esportatu</string>
<string name="logcat_buffer">Logcat bufferra</string>
<string name="send_report">Bidali txostena</string>
</resources>

View file

@ -14,7 +14,7 @@
app:theme="?attr/toolbar_theme"
android:background="?attr/pstsTabBackground"/>
<WebView
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View file

@ -63,7 +63,8 @@
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
<WebView
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/content_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View file

@ -4,7 +4,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView android:id="@+id/webView"
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>

View file

@ -4,12 +4,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</net.osmand.plus.widgets.WebViewEx>
<include layout="@layout/mapillary_no_internet"
android:id="@+id/mapillaryNoInternetLayout"

View file

@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/printDialogWebview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View file

@ -74,7 +74,7 @@
android:layout_height="0dp"
android:layout_weight="1">
<WebView
<net.osmand.plus.widgets.WebViewEx
android:id="@+id/content_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View file

@ -4032,4 +4032,19 @@
<string name="routing_attr_allow_intermittent_description">Gewässer erlauben, die nicht ständig Wasser führen</string>
<string name="routing_attr_allow_intermittent_name">Gewässer erlauben, die nicht ständig Wasser führen</string>
<string name="voice_prompts_timetable">Zeiten der Sprachansagen</string>
<string name="add_online_routing_engine">Online Routenplaner hinzufügen</string>
<string name="edit_online_routing_engine">Online Routenplaner bearbeiten</string>
<string name="shared_string_vehicle">Fahrzeug</string>
<string name="shared_string_api_key">API Schlüssel</string>
<string name="shared_string_server_url">Server URL</string>
<string name="shared_string_enter_param">Parameter eingeben</string>
<string name="online_routing_example_hint">Die URL mit allen Parametern wird so aussehen:</string>
<string name="test_route_calculation">Routenberechnung testen</string>
<string name="routing_engine_vehicle_type_foot">Zu Fuß</string>
<string name="routing_engine_vehicle_type_bike">Fahrrad</string>
<string name="routing_engine_vehicle_type_car">Auto</string>
<string name="message_error_recheck_parameters">Fehler, Parameter erneut prüfen</string>
<string name="shared_string_subtype">Subtyp</string>
<string name="keep_it_empty_if_not">Leer lassen, wenn kein API-Schlüssel vorhanden</string>
<string name="copy_address">Adresse kopieren</string>
</resources>

View file

@ -4028,4 +4028,20 @@
<string name="routing_attr_allow_intermittent_description">Permesi navigi per periode sekiĝantaj akvovojoj</string>
<string name="routing_attr_allow_intermittent_name">Permesi sezonajn akvovojojn</string>
<string name="voice_prompts_timetable">Tempoj de voĉaj anoncoj</string>
<string name="add_online_routing_engine">Aldoni enretan navigilon</string>
<string name="edit_online_routing_engine">Redakti enretan navigilon</string>
<string name="shared_string_subtype">Subspeco</string>
<string name="shared_string_vehicle">Veturilo</string>
<string name="shared_string_api_key">API-ŝlosilo</string>
<string name="shared_string_server_url">Ligilo al servilo</string>
<string name="shared_string_enter_param">Enigu parametron</string>
<string name="keep_it_empty_if_not">Se malnecesa, enigu nenion</string>
<string name="online_routing_example_hint">Ligilo kun ĉiuj parametroj aspektos kiel tiu ĉi:</string>
<string name="routing_engine_vehicle_type_driving">Stirado</string>
<string name="test_route_calculation">Testi kalkuli kurson</string>
<string name="routing_engine_vehicle_type_foot">Piediranto</string>
<string name="routing_engine_vehicle_type_bike">Biciklo</string>
<string name="routing_engine_vehicle_type_car">Aŭtomobilo</string>
<string name="message_error_recheck_parameters">Eraro, rekontrolu parametrojn</string>
<string name="copy_address">Kopii adreson</string>
</resources>

View file

@ -4033,4 +4033,20 @@
<string name="routing_attr_allow_intermittent_description">Permite cursos de agua intermitentes</string>
<string name="routing_attr_allow_intermittent_name">Permitir cursos de agua intermitentes</string>
<string name="voice_prompts_timetable">Tiempo de los avisos por voz</string>
<string name="add_online_routing_engine">Añadir motor de navegación en línea</string>
<string name="edit_online_routing_engine">Editar motor de navegación en línea</string>
<string name="shared_string_subtype">Subtipo</string>
<string name="shared_string_vehicle">Vehículo</string>
<string name="shared_string_api_key">Clave de la API</string>
<string name="shared_string_server_url">URL del servidor</string>
<string name="shared_string_enter_param">Ingresa parámetro</string>
<string name="keep_it_empty_if_not">Si no, mantenerlo vacío</string>
<string name="online_routing_example_hint">La URL con todos los parámetros se verá así:</string>
<string name="test_route_calculation">Cálculo de la ruta de prueba</string>
<string name="routing_engine_vehicle_type_driving">Automóvil</string>
<string name="routing_engine_vehicle_type_foot">Peatón</string>
<string name="routing_engine_vehicle_type_bike">Bicicleta</string>
<string name="routing_engine_vehicle_type_car">Automóvil</string>
<string name="message_error_recheck_parameters">Error, vuelve a comprobar los parámetros</string>
<string name="copy_address">Copiar dirección</string>
</resources>

View file

@ -785,7 +785,7 @@
<string name="no_fav_to_save">Ez dago gogoko punturik gordetzeko</string>
<string name="shared_string_import">Inportatu</string>
<string name="error_occurred_loading_gpx">Ezin izan da GPX kargatu.</string>
<string name="send_report">Bidali informea</string>
<string name="send_report">Bidali txostena</string>
<string name="none_region_found">Ezin izan da deskargatutako maparik aurkitu memoria txartelean.</string>
<string name="poi_namefinder_query_empty">Idatzi interesgune bat bilatzeko</string>
<string name="any_poi">Edozein</string>
@ -4008,4 +4008,18 @@ Area honi dagokio: %1$s x %2$s</string>
<string name="plan_route_split_before">Zatitu aurretik</string>
<string name="plan_route_split_after">Zatitu ondoren</string>
<string name="plan_route_add_new_segment">Gehitu segmentu berria</string>
<string name="shared_string_subtype">Azpimota</string>
<string name="shared_string_vehicle">Ibilgailua</string>
<string name="shared_string_api_key">API gakoa</string>
<string name="shared_string_server_url">Zerbitzariaren URLa</string>
<string name="shared_string_enter_param">Sartu parametroa</string>
<string name="keep_it_empty_if_not">Mantendu hutsik hala ez bada</string>
<string name="online_routing_example_hint">Parametro guztiak dituen URLak itxura hau izango du:</string>
<string name="test_route_calculation">Proba ibilbidearen kalkulua</string>
<string name="routing_engine_vehicle_type_driving">Gidatzen</string>
<string name="routing_engine_vehicle_type_foot">Oinez</string>
<string name="routing_engine_vehicle_type_bike">Bizikleta</string>
<string name="routing_engine_vehicle_type_car">Kotxea</string>
<string name="message_error_recheck_parameters">Errorea, egiaztatu parametroak berriro</string>
<string name="copy_address">Kopiatu helbidea</string>
</resources>

View file

@ -163,7 +163,7 @@
<string name="local_osm_changes_backup">پشتیبان‌گیری در قالب تغییر OSM</string>
<string name="delete_point">حذف نقطه</string>
<string name="use_kalman_filter_compass">استفاده از پالایهٔ Kalman</string>
<string name="cancel_route">حذف مسیر</string>
<string name="cancel_route">کنارگذاشتن مسیر؟</string>
<string name="max_speed_none">هیچ‌کدام</string>
<string name="dropbox_plugin_name">افزونهٔ دراپ‌باکس</string>
<string name="av_use_external_recorder_descr">برای فیلم‌برداری از ضبط‌کنندهٔ سیستم استفاده شود.</string>
@ -644,7 +644,7 @@
<string name="auto_announce_off">توقف اعلام خودکار</string>
<string name="use_fluorescent_overlays_descr">برای نمایش ردها و مسیرها از رنگ‌های شب‌نما استفاده شود.</string>
<string name="offline_edition">ویرایش آفلاین</string>
<string name="offline_edition_descr">ویرایش‌ها را همیشه آفلاین انجام می‌دهم.</string>
<string name="offline_edition_descr">اگر ویرایش آفلاین فعال باشد، تغییرات ابتدا روی دستگاه ذخیره می‌شود و با درخواست شما آپلود می‌گردد. در غیر این صورت دردَم آپلود خواهد شد.</string>
<string name="local_openstreetmap_uploading">در حال آپلود…</string>
<string name="local_openstreetmap_were_uploaded">تعداد {0} یادداشت/POI آپلود شد</string>
<string name="update_poi_does_not_change_indexes">تغییراتی که به‌وسیلهٔ برنامه روی POIها انجام می‌دهید روی نقشه‌های دانلود‌شده تأثیری ندارد. تغییرات روی فایل دیگری در دستگاه ذخیره می‌شود.</string>
@ -1687,7 +1687,7 @@
<string name="access_direction_haptic_feedback_descr">بیان‌کردن جهت مقصد با لرزش.</string>
<string name="use_osm_live_routing_description">مسیریابی با استفاده از به‌روزرسانی‌های OsmAnd Live فعال شود.</string>
<string name="use_osm_live_routing">مسیریابی با OsmAnd Live</string>
<string name="access_no_destination">مقصد تنظیم نشده</string>
<string name="access_no_destination">افزونهٔ قابلیت دسترسی: مقصدی تنظیم نشده</string>
<string name="map_widget_magnetic_bearing">سویهٔ مغناطیسی</string>
<string name="map_widget_bearing">سویهٔ نسبی</string>
<string name="access_disable_offroute_recalc">اگر از مسیر خارج شدم، مسیر تازه‌ای پیدا نکن</string>
@ -2151,7 +2151,7 @@
<string name="number_of_contributors">تعداد مشارکت‌کنندگان</string>
<string name="number_of_edits">تعداد ویرایش‌ها</string>
<string name="reports_for">گزارش برای</string>
<string name="file_name_containes_illegal_char">در نام فایل از نویسهٔ غیرمجاز استفاده شده است</string>
<string name="file_name_containes_illegal_char">نویسهٔ غیرمجاز در نام فایل</string>
<string name="configure_screen_quick_action">کنش فوری</string>
<string name="quick_action_item_action">کنش %d</string>
<string name="quick_action_item_screen">صفحهٔ %d</string>
@ -2301,7 +2301,7 @@
<string name="quick_action_showhide_osmbugs_descr">دکمه‌ای برای آشکار/پنهان کردن یادداشت‌های OSM بر روی نقشه.</string>
<string name="sorted_by_distance">مرتب‌شده بر اساس مسافت</string>
<string name="search_favorites">جست‌وجو در علاقه‌مندی‌ها</string>
<string name="hillshade_menu_download_descr">«لایهٔ سایه‌روشن» را دانلود کنید تا سایه‌های عمودی را ببینید.</string>
<string name="hillshade_menu_download_descr">لایهٔ «سایه‌روشن» را دانلود کنید تا سایه‌زنی‌های عمودی را ببینید.</string>
<string name="hillshade_purchase_header">افزونهٔ «منحنی‌های میزان» را نصب کنید تا طبقه‌بندی عمودی محدوده‌ها را ببینید.</string>
<string name="hide_from_zoom_level">از این زوم پنهان شود</string>
<string name="srtm_menu_download_descr">نقشهٔ «منحنی میزان» را برای استفاده در این منطقه دانلود کنید.</string>
@ -2664,7 +2664,7 @@
<string name="copy_location_name">کپی موقعیت/نام POI</string>
<string name="toast_empty_name_error">مکان بی‌نام</string>
<string name="show_closed_notes">دیدن یادداشت‌های بسته</string>
<string name="switch_osm_notes_visibility_desc">پنهان/آشکارکردن یادداشت‌های OSM.</string>
<string name="switch_osm_notes_visibility_desc">پنهان یا آشکارکردن یادداشت‌های OSM.</string>
<string name="gpx_file_desc">GPX - مناسب برای استفاده در JOSM یا سایر ویرایشگرهای OSM.</string>
<string name="osc_file_desc">OSC - مناسب برای استفاده در OSM.</string>
<string name="shared_string_gpx_file">فایل GPX</string>
@ -3188,9 +3188,9 @@
<string name="rendering_attr_showLez_description">محدوده‌های کاهش آلودگی هوای شهر را روی نقشه نشان بده. روی مسیریابی اثر نمی‌گذارد.</string>
<string name="rendering_attr_showLez_name">محدوده‌های کاهش</string>
<string name="temporary_conditional_routing">در نظر گرفتن محدودیت‌های موقت در مسیریابی</string>
<string name="routing_attr_piste_type_downhill_name">اسکی آلپاین/دان‌هیل</string>
<string name="routing_attr_piste_type_downhill_name">اسکی آلپاین و دانهیل</string>
<string name="routing_attr_piste_type_downhill_description">سراشیبی‌های اسکی آلپاین یا دان‌هیل و دسترسی به بالابرهای اسکی.</string>
<string name="routing_attr_piste_type_nordic_name">اسکی کراس/نوردیک</string>
<string name="routing_attr_piste_type_nordic_name">اسکی کراس‌کانتری و نوردیک</string>
<string name="routing_attr_piste_type_nordic_description">مسیرهای اسکی کراس یا نوردیک.</string>
<string name="shared_string_crash">شکست</string>
<string name="shared_string_open_track">باز کن</string>
@ -3456,7 +3456,7 @@
<string name="button_rate">امتیاز بدهید</string>
<string name="monitoring_prefs_descr">ناوبری، صحت ردنگاری</string>
<string name="multimedia_notes_prefs_descr">اندازهٔ عکس، کیفیت صدا و ویدئو</string>
<string name="osm_editing_prefs_descr">ثبت ورود، گذرواژه، ویرایش آفلاین</string>
<string name="osm_editing_prefs_descr">نام کاربری، گذرواژه، ویرایش آفلاین</string>
<string name="accessibility_prefs_descr">انتخاب نماد، رنگ و نام</string>
<string name="live_monitoring">ردیابی آنلاین</string>
<string name="save_track_logging_accuracy">صحت ردنگاری</string>
@ -3464,7 +3464,7 @@
<string name="photo_notes">یادداشت‌های عکسی</string>
<string name="route_recalculation">محاسبهٔ مجدد مسیر</string>
<string name="login_and_pass">نام کاربری و گذرواژه</string>
<string name="plugin_global_prefs_info">این تنظیمات افزونه، سراسری است و روی همهٔ پروفایل‌ها به کار گرفته می‌شود.</string>
<string name="plugin_global_prefs_info">این تنظیمات افزونه، سراسری است و روی همهٔ پروفایل‌ها به کار گرفته می‌شود</string>
<string name="osm_editing">ویرایش OSM</string>
<string name="app_mode_osm">OSM</string>
<string name="select_nav_icon_descr">نمادی که هنگام حرکت یا ناوبری نمایش داده می‌شود.</string>
@ -3594,7 +3594,7 @@
<string name="shared_string_terrain">ناهمواری‌ها</string>
<string name="hillshade_description">نقشهٔ سایه‌روشن که شیب‌ها، بلندی‌ها و پستی‌ها را با استفاده از سایه‌های تیره نمایان می‌کند.</string>
<string name="terrain_slider_description">کمینه و بیشینهٔ زوم برای نمایش لایه را مشخص کنید.</string>
<string name="hillshade_download_description">برای مشاهدهٔ سایه‌روشن‌ها روی نقشه باید نقشهٔ دیگری را نیز دانلود کنید.</string>
<string name="hillshade_download_description">"باید نقشهٔ دیگری را نیز دانلود کنید تا سایه‌روشن‌ها را روی نقشه ببینید."</string>
<string name="slope_download_description">برای مشاهدهٔ شیب‌ها روی نقشه باید نقشهٔ دیگری را نیز دانلود کنید.</string>
<string name="slope_read_more">دربارهٔ شیب‌ها می‌توانید در %1$s بیشتر بخوانید.</string>
<string name="shared_string_transparency">شفافیت</string>
@ -3604,7 +3604,7 @@
<string name="shared_string_hillshade">سایه‌روشن</string>
<string name="n_items_of_z">%1$s از %2$s</string>
<string name="download_slope_maps">شیب‌ها</string>
<string name="quick_action_show_hide_terrain">آشکار/پنهان کردن ناهمواری‌ها</string>
<string name="quick_action_show_hide_terrain">آشکار یا پنهان کردن ناهمواری‌ها</string>
<string name="quick_action_terrain_hide">پنهان‌کردن ناهمواری‌ها</string>
<string name="quick_action_terrain_show">نمایش ناهمواری‌ها</string>
<string name="quick_action_terrain_descr">دکمه‌ای برای آشکار یا پنهان کردن لایهٔ ناهمواری‌ها روی نقشه.</string>
@ -3717,12 +3717,12 @@
\n
\n</string>
<string name="back_to_editing">بازگشت به ویرایش</string>
<string name="create_edit_poi">ایجاد / ویرایش POI</string>
<string name="add_edit_favorite">افزودن / ویرایش علاقه‌مندی</string>
<string name="create_edit_poi">ایجاد یا ویرایش POI</string>
<string name="add_edit_favorite">افزودن یا ویرایش علاقه‌مندی</string>
<string name="additional_actions_descr">برای دسترسی به این کنش‌ها می‌توانید روی دکمهٔ «%1$s» بزنید.</string>
<string name="quick_action_transport_hide">مخفی‌کردن حمل‌ونقل عمومی</string>
<string name="quick_action_transport_show">نمایش حمل‌ونقل عمومی</string>
<string name="quick_action_show_hide_transport">آشکار/پنهان کردن حمل‌ونقل عمومی</string>
<string name="quick_action_show_hide_transport">آشکار یا پنهان کردن حمل‌ونقل عمومی</string>
<string name="quick_action_transport_descr">دکمه‌ای برای آشکار یا پنهان کردن حمل‌ونقل عمومی روی نقشه.</string>
<string name="quick_action_switch_profile_descr">با لمس دکمهٔ عملیاتی بین پروفایل‌های انتخاب‌شده جابه‌جا شوید.</string>
<string name="shared_string_add_profile">افزودن پروفایل</string>
@ -3823,7 +3823,7 @@
<string name="quick_action_remove_next_destination">حذف نزدیک‌ترین مقصد</string>
<string name="please_provide_point_name_error">لطفاً نام نقطه را بنویسید</string>
<string name="search_download_wikipedia_maps">دانلود نقشه‌های ویکی‌پدیا</string>
<string name="plugin_wikipedia_description">از ویکی‌پدیا دربارهٔ نقاط توجه اطلاعات کسب کنید؛ مانند یک راهنمای آفلاین جیبی. کافی است افزونهٔ ویکی‌پدیا را فعال کنید و از مقاله‌های مربوط به چیزهای دوروبرتان لذت ببرید.</string>
<string name="plugin_wikipedia_description">دربارهٔ نقاط توجه، از ویکی‌پدیا اطلاعات کسب کنید. یک راهنمای آفلاینِ جیبی که مقاله‌هایی دربارهٔ مکان‌ها و مقصدها دارد.</string>
<string name="app_mode_wheelchair">صندلی چرخ‌دار</string>
<string name="osm_edit_closed_note">یادداشت اُاِس‌اِمی بسته</string>
<string name="add_hidden_group_info">نقطهٔ اضافه‌شده روی نقشه دیده نمی‌شود، زیرا گروه انتخاب‌شده پنهان است. آن را در «%s» پیدا می‌کنید.</string>
@ -3864,11 +3864,11 @@
\n</string>
<string name="plan_route_trim_before">حذفِ قبل</string>
<string name="plan_route_trim_after">حذفِ بعد</string>
<string name="plan_route_change_route_type_before">تغییر نوع مسیرِ بعد آن</string>
<string name="plan_route_change_route_type_after">تغییر نوع مسیرِ قبل آن</string>
<string name="plan_route_change_route_type_before">تغییر نوع مسیرِ بعد</string>
<string name="plan_route_change_route_type_after">تغییر نوع مسیرِ قبل</string>
<string name="track_coloring_solid">تک‌رنگ</string>
<string name="lenght_limit_description">طول وسیلهٔ نقلیهٔ خود را مشخص کنید. ممکن است محدودیت‌های مسیر برای وسایل نقلیهٔ طویل اِعمال شود.</string>
<string name="quick_action_remove_next_destination_descr">مقصد کنونی مسیر حذف خواهد شد. اگر این قرار است مقصد باشد، ناوبری متوقف می‌شود.</string>
<string name="quick_action_remove_next_destination_descr">مقصد بعدیِ مسیر شما را حذف خواهد کرد. البته اگر مقصد نهایی باشد، ناوبری را متوقف می‌کند.</string>
<string name="add_to_a_track">افزودن به یک رد</string>
<string name="save_as_new_track">ذخیره به‌عنوان رد جدید</string>
<string name="reverse_route">برعکس‌کردن مسیر</string>
@ -3886,7 +3886,7 @@
<string name="navigation_profile">پروفایل ناوبری</string>
<string name="route_between_points_add_track_desc">یک فایل رد انتخاب کنید تا پارهٔ جدید را به آن بیفزایید.</string>
<string name="street_level_imagery">تصاویر نمای خیابان</string>
<string name="plan_route_exit_dialog_descr">آیا می‌خواهید خارج شوید و همهٔ تغییرات مسیر طراحی‌شده را از بین ببرید؟</string>
<string name="plan_route_exit_dialog_descr">آیا می‌خواهید همهٔ تغییرات در مسیر طراحی‌شده از بین برود؟</string>
<string name="in_case_of_reverse_direction">اگر برعکس حرکت کردم</string>
<string name="start_of_the_track">ابتدای رد</string>
<string name="follow_track_descr">انتخاب فایل رد برای دنبال‌کردن</string>
@ -3963,15 +3963,15 @@
\nنمودار پس از بازمحاسبهٔ مسیر فراهم می‌شود.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="message_you_need_add_two_points_to_show_graphs">دست‌کم دو نقطه اضافه کنید</string>
<string name="login_open_street_map">ثبت ورود در اوپن‌استریت‌مپ</string>
<string name="login_open_street_map_org">ثبت ورود در OpenStreetMap.org</string>
<string name="login_open_street_map">ورود به اوپن‌استریت‌مپ</string>
<string name="login_open_street_map_org">ورود به OpenStreetMap.org</string>
<string name="sign_in_with_open_street_map">ثبت ورود از طریق اوپن‌استریت‌مپ</string>
<string name="open_street_map_login_mode">برای آپلود تغییرات جدید باید ثبت ورود (login) کنید.
<string name="open_street_map_login_mode">برای آپلود تغییرات جدید باید وارد شوید (login).
\n
\nبرای ثبت ورود می‌توانید از روش امن OAuth یا روش نام کاربری و گذرواژه استفاده کنید.</string>
\nبرای ورود می‌توانید از روش امن OAuth یا روش نام کاربری و گذرواژه استفاده کنید.</string>
<string name="use_login_password">استفاده از نام کاربری و گذرواژه</string>
<string name="login_account">حساب</string>
<string name="user_login">ثبت ورود</string>
<string name="user_login">ورود</string>
<string name="manage_subscription">مدیریت اشتراک</string>
<string name="subscription_payment_issue_title">روی دکمه بزنید و یک شیوهٔ پرداخت در گوگل‌پلی تنظیم کنید تا اشتراک خود را اصلاح نمایید.</string>
<string name="markers_history">تاریخچهٔ نشانه‌ها</string>
@ -4006,4 +4006,35 @@
<string name="plan_route_add_new_segment">افزودن یک بخش جدید</string>
<string name="profile_type_osmand_string">نمایهٔ OsmAnd</string>
<string name="profile_type_user_string">نمایهٔ کاربر</string>
<string name="voice_prompts_timetable">زمان‌های پیام‌های گفتاری</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd از MGRS استفاده می‌کند که شبیه قالب UTM NATO است.</string>
<string name="contour_lines_thanks">سپاسگزاریم که Contour lines را خریدید</string>
<string name="enter_text_separated">برچسب‌ها را بنویسید و با کاما جدا کنید.</string>
<string name="osm_edit_close_note">بستن یادداشت OSM</string>
<string name="osm_edit_comment_note">نظردادن به یادداشت OSM</string>
<string name="osm_login_descr">می‌توانید با روش ایمن OAuth وارد شوید یا از نام‌کاربری و گذرواژه‌تان استفاده کنید.</string>
<string name="app_mode_motorboat">قایق‌موتوری</string>
<string name="cannot_upload_image">آپلود عکس ناموفق بود، لطفاً بعداً دوباره امتحان کنید</string>
<string name="select_picture">انتخاب تصویر</string>
<string name="shared_string_resources">منابع</string>
<string name="approximate_file_size">اندازهٔ تخمینی فایل</string>
<string name="select_data_to_export">دادهٔ موردنظر برای برون‌برد در فایل را انتخاب کنید.</string>
<string name="file_size_needed_for_import">برای درون‌برد لازم است</string>
<string name="reverse_all_points">برعکس‌کردن همهٔ نقطه‌ها</string>
<string name="profile_by_default_description">پروفایلِ هنگام شروع برنامه را انتخاب کنید.</string>
<string name="shared_string_last_used">آخرین استفاده</string>
<string name="add_online_routing_engine">افزودن موتور مسیریابی آنلاین</string>
<string name="edit_online_routing_engine">ویرایش موتور مسیریابی آنلاین</string>
<string name="shared_string_vehicle">وسیله نقلیه</string>
<string name="shared_string_api_key">کلید API</string>
<string name="shared_string_enter_param">پارامتر را وارد کنید</string>
<string name="online_routing_example_hint">URL با همهٔ پارامترها شبیه این است:</string>
<string name="test_route_calculation">آزمایش محاسبهٔ مسیر</string>
<string name="routing_engine_vehicle_type_driving">رانندگی</string>
<string name="routing_engine_vehicle_type_foot">پا</string>
<string name="routing_engine_vehicle_type_bike">دوچرخه</string>
<string name="routing_engine_vehicle_type_car">خودرو</string>
<string name="message_error_recheck_parameters">خطا، پارامترها را بازبینی کنید</string>
</resources>

View file

@ -3895,4 +3895,12 @@
<string name="poi_water_source_tap">Robinet</string>
<string name="poi_vaccination_covid19">Vaccination : covid19</string>
<string name="poi_health_specialty_vaccination_yes">Vaccination</string>
<string name="poi_wildlife_crossing_bat_tunnel">Tunnel à chauve-souris</string>
<string name="poi_wildlife_crossing_bat_bridge">Pont à chauve-souris</string>
<string name="poi_wildlife_crossing">Passage de faune</string>
<string name="poi_swimming_area">Zone de baignade</string>
<string name="poi_lavoir">Lavoir</string>
<string name="poi_waste_transfer_station">Station de traitement des déchets</string>
<string name="poi_weightbridge">Pont de levage</string>
<string name="poi_ranger_station">Poste de garde forestier</string>
</resources>

View file

@ -4007,4 +4007,20 @@
<string name="routing_attr_allow_streams_description">Autoriser les cours deau et les drains</string>
<string name="routing_attr_allow_streams_name">Autoriser les cours deau et les drains</string>
<string name="voice_prompts_timetable">Nombre d\'annonces vocales</string>
<string name="keep_it_empty_if_not">Si non, laissez vide</string>
<string name="shared_string_subtype">Sous-type</string>
<string name="shared_string_vehicle">Véhicule</string>
<string name="shared_string_api_key">Clé d\'API</string>
<string name="shared_string_server_url">URL du serveur</string>
<string name="shared_string_enter_param">Saisissez le paramètre</string>
<string name="test_route_calculation">Calculer un itinéraire dessai</string>
<string name="routing_engine_vehicle_type_driving">En voiture</string>
<string name="routing_engine_vehicle_type_foot">A pieds</string>
<string name="routing_engine_vehicle_type_bike">Vélo</string>
<string name="routing_engine_vehicle_type_car">Automobile</string>
<string name="message_error_recheck_parameters">Erreur, vérifiez les paramètres</string>
<string name="add_online_routing_engine">Ajouter un moteur de routage en ligne</string>
<string name="edit_online_routing_engine">Modifier le moteur de routage en ligne</string>
<string name="online_routing_example_hint">L\'URL avec tous les paramètres sera de la forme :</string>
<string name="copy_address">Copier l\'adresse</string>
</resources>

View file

@ -585,7 +585,7 @@
<string name="choose_intersected_street">Keresztező utca kijelölése</string>
<string name="Closest_Amenities">Legközelebbi hasznos létesítmények</string>
<string name="app_mode_default">Térképböngészés</string>
<string name="app_mode_car">Vezetés</string>
<string name="app_mode_car">Autóvezetés</string>
<string name="app_mode_bicycle">Kerékpározás</string>
<string name="app_mode_pedestrian">Gyaloglás</string>
<string name="position_on_map_center">Középen</string>
@ -1292,7 +1292,7 @@
<string name="speak_poi">Közeli érdekes helyek (POI)</string>
<string name="download_additional_maps">Letöltöd a hiányzó térképeket %1$s (%2$d MB)?</string>
<string name="rendering_value_browse_map_name">Térképböngészés</string>
<string name="rendering_value_car_name">Autó</string>
<string name="rendering_value_car_name">Személyautó</string>
<string name="rendering_value_bicycle_name">Kerékpár</string>
<string name="rendering_value_pedestrian_name">Gyalogos</string>
<string name="record_plugin_description">Ez a bővítmény aktiválja a nyomvonalak rögzítésének és mentésének lehetőségét, ha megnyomja a GPX naplózó gombot a térképképernyőn, valamint képes minden navigációs útvonalat automatikusan egy GPX-fájlba naplózni.
@ -4019,4 +4019,21 @@
<string name="routing_attr_allow_streams_name">Patakok és vízelvezető árkok engedélyezése</string>
<string name="routing_attr_allow_intermittent_description">Időszakos vízfolyások engedélyezése</string>
<string name="routing_attr_allow_intermittent_name">Időszakos vízfolyások engedélyezése</string>
<string name="routing_engine_vehicle_type_driving">Autóvezetés</string>
<string name="routing_engine_vehicle_type_foot">Gyaloglás</string>
<string name="routing_engine_vehicle_type_bike">Kerékpár</string>
<string name="routing_engine_vehicle_type_car">Személyautó</string>
<string name="voice_prompts_timetable">Hangutasítások ideje</string>
<string name="add_online_routing_engine">Online útvonaltervező hozzáadása</string>
<string name="edit_online_routing_engine">Online útvonaltervező szerkesztése</string>
<string name="shared_string_subtype">Altípus</string>
<string name="shared_string_vehicle">Jármű</string>
<string name="shared_string_api_key">API-kulcs</string>
<string name="shared_string_server_url">Kiszolgáló URL-je</string>
<string name="shared_string_enter_param">Paraméter megadása</string>
<string name="keep_it_empty_if_not">Hagyja üresen, ha nem</string>
<string name="online_routing_example_hint">Az összes paraméterrel rendelkező URL így néz ki:</string>
<string name="test_route_calculation">Útvonaltervezés kipróbálása</string>
<string name="message_error_recheck_parameters">Hiba, ellenőrizze újra a paramétereket</string>
<string name="copy_address">Cím másolása</string>
</resources>

View file

@ -4032,4 +4032,20 @@
<string name="gpx_upload_public_visibility_descr">„ציבורי” משמעו שהעקבות מופיעים באופן ציבורי בעקבות ה־GPS שלך וברישומי עקבות GPS ציבוריים וברישומי מעקב ציבוריים עם חותמות זמן בתצורה גולמית. הנתונים שמוגשים דרך ה־API אינם מפנים אל עמוד העקבות שלך. חותמות הזמן של נקודות המעקב אינן זמינות דרך ה־API של ה־GPS ונקודות המעקב אינן מסודרות בהתאם לזמן שתועדו.</string>
<string name="gpx_upload_private_visibility_descr">„פרטי” משמעות שהעקבות לא תופענה ברישומים ציבוריים אך נקודות מעקב ממתוכן תהיינה זמינות בסדר אקראי דרך ה־API הציבורי של ה־GPS ללא חותמות זמן.</string>
<string name="voice_prompts_timetable">זמני הכרזות</string>
<string name="add_online_routing_engine">הוספת מנוע ניווט מקוון</string>
<string name="edit_online_routing_engine">עריכת מנוע הניווט המקוון</string>
<string name="shared_string_subtype">תת־סוג</string>
<string name="shared_string_vehicle">כלי רכב</string>
<string name="shared_string_api_key">מפתח API</string>
<string name="shared_string_server_url">כתובת השרת</string>
<string name="shared_string_enter_param">נא למלא משתנים</string>
<string name="keep_it_empty_if_not">להשאיר ריק אם לא</string>
<string name="online_routing_example_hint">כתובת עם כל המשתנים נראית כך:</string>
<string name="test_route_calculation">בדיקת חישוב מסלול</string>
<string name="routing_engine_vehicle_type_driving">נהיגה</string>
<string name="routing_engine_vehicle_type_foot">ברגל</string>
<string name="routing_engine_vehicle_type_bike">אופנוע</string>
<string name="routing_engine_vehicle_type_car">מכונית</string>
<string name="message_error_recheck_parameters">שגיאה, נא לבדוק את המשתנים מחדש</string>
<string name="copy_address">העתקת כתובת</string>
</resources>

View file

@ -2350,4 +2350,10 @@
<string name="profile_type_base_string">ბაზური პროფილი</string>
<string name="profile_type_descr_string">ტიპი: %s</string>
<string name="settings_routing_mode_string">რეჟიმი: %s</string>
<string name="routing_attr_avoid_footways_description">საცალფეხო გზების არიდება</string>
<string name="routing_attr_avoid_footways_name">საცალფეხო ფზების არიდება</string>
<string name="shared_string_is_saved">შენახულია</string>
<string name="sort_last_modified">ბოლო ცვლილება</string>
<string name="sort_name_descending">სახელი: ჰ-ა</string>
<string name="sort_name_ascending">სახელი: ა-ჰ</string>
</resources>

View file

@ -121,7 +121,7 @@
<string name="poi_vehicle_inspection">Stacja diagnostyczna</string>
<string name="poi_car_wash">Myjnia samochodowa</string>
<string name="poi_fuel">Stacja benzynowa;Stacja paliw;CPN;Tanksztela</string>
<string name="poi_electricity_combined_charging">Stacja ładowania</string>
<string name="poi_electricity_combined_charging">Stacja ładująca; Stacja ładowania pojazdów elektrycznych; Stacja ładująca EV; Elektryczny punkt ładowania; Punkt ładowania; Elektroniczna stacja ładująca; Sprzęt do zasilania pojazdów elektrycznych</string>
<string name="poi_vehicle_ramp">Podnośnik</string>
<string name="poi_compressed_air">Kompresor</string>
<string name="poi_parking">Parking</string>
@ -3880,4 +3880,20 @@
<string name="poi_water_source_river">Rzeka</string>
<string name="poi_vaccination_covid19">Szczepienia: COVID19</string>
<string name="poi_health_specialty_vaccination_yes">Szczepienia</string>
<string name="poi_swimming_area">Kąpielisko</string>
<string name="poi_waste_transfer_station">Stacja przeładunkowa</string>
<string name="poi_weightbridge">Waga pomostowa</string>
<string name="poi_ranger_station">Stacja strażników</string>
<string name="poi_water_source_powered_pump">Pompa zasilana</string>
<string name="poi_water_source_water_works">Stacja uzdatniania wody</string>
<string name="poi_water_source_tube_well">Studnia rurowa</string>
<string name="poi_lifeguard_base">Baza ratowników</string>
<string name="poi_mobile_money_agent">Mobilny agent pieniędzy</string>
<string name="poi_liaison_subnational">Subnarodowe</string>
<string name="poi_liaison_representative_office">Przedstawicielstwo</string>
<string name="poi_consulate_honorary_consul">Konsul honorowy</string>
<string name="poi_consulate_consular_office">Biuro konsularne</string>
<string name="poi_embassy_interests_section">Sekcja zainteresowań</string>
<string name="poi_diplomatic_liaison">Łączność</string>
<string name="poi_liaison_filter">Łączność</string>
</resources>

View file

@ -4032,4 +4032,17 @@
<string name="routing_attr_allow_streams_name">Zezwalaj na strumienie i dreny</string>
<string name="routing_attr_allow_intermittent_description">Zezwalaj na przerywane drogi wodne</string>
<string name="routing_attr_allow_intermittent_name">Zezwalaj na przerywane drogi wodne</string>
<string name="voice_prompts_timetable">Czas monitów głosowych</string>
<string name="shared_string_subtype">Podtyp</string>
<string name="shared_string_vehicle">Pojazd</string>
<string name="shared_string_api_key">Klucz API</string>
<string name="shared_string_server_url">Adres URL serwera</string>
<string name="shared_string_enter_param">Wpisz param</string>
<string name="keep_it_empty_if_not">Jeśli nie, zostaw to puste</string>
<string name="online_routing_example_hint">Adres URL ze wszystkimi parametrami będzie wyglądał następująco:</string>
<string name="test_route_calculation">Obliczanie trasy testowej</string>
<string name="routing_engine_vehicle_type_bike">Rower</string>
<string name="routing_engine_vehicle_type_car">Samochód</string>
<string name="message_error_recheck_parameters">Błąd, ponownie sprawdź parametry</string>
<string name="copy_address">Skopiuj adres</string>
</resources>

View file

@ -4023,4 +4023,19 @@
<string name="routing_attr_allow_intermittent_description">Permitir vias de água intermitentes</string>
<string name="routing_attr_allow_intermittent_name">Permitir vias de água intermitentes</string>
<string name="voice_prompts_timetable">Horários de avisos de voz</string>
<string name="add_online_routing_engine">Adicionar mecanismo de roteamento online</string>
<string name="edit_online_routing_engine">Editar mecanismo de roteamento online</string>
<string name="shared_string_subtype">Subtipo</string>
<string name="shared_string_vehicle">Veículo</string>
<string name="shared_string_api_key">Chave de API</string>
<string name="shared_string_server_url">URL do servidor</string>
<string name="shared_string_enter_param">Digite o parâmetro</string>
<string name="keep_it_empty_if_not">Mantenha-o vazio se não</string>
<string name="online_routing_example_hint">O URL com todos os parâmetros terá a seguinte aparência:</string>
<string name="test_route_calculation">Cálculo da rota de teste</string>
<string name="routing_engine_vehicle_type_driving">Dirigindo</string>
<string name="routing_engine_vehicle_type_foot"></string>
<string name="routing_engine_vehicle_type_bike">Bicicleta</string>
<string name="routing_engine_vehicle_type_car">Carro</string>
<string name="message_error_recheck_parameters">Erro, verifique novamente os parâmetros</string>
</resources>

View file

@ -618,7 +618,7 @@
<string name="map_online_data_descr">Imprea sas mapas in lìnia (iscàrriga e archìvia sos tasseddos in sischeda de memòria).</string>
<string name="shared_string_online_maps">Mapas in lìnia</string>
<string name="online_map_settings_descr">Ischerta sas mitzas de sas mapas in lìnia o de sos tasseddos in cache.</string>
<string name="osmand_accessibility_description">Permitit de impreare sas funtzionalidades pro s\'atzessibilidade de su dispositivu ditetamente in OsmAnd, e fatzilitat, pro nàrrere, sa modìfica de sa lestresa de sas boghes de sìntesi vocale, sa cunfiguratzione de su movimentu de s\'ischermu, simpreu de una trackball pro s\'ismanniamentu o de uninterfàtzia vocale pro cosas che s\'annùntziu de sa positzione tua.</string>
<string name="osmand_accessibility_description">Permitit de impreare sas funtzionalidades pro s\'atzessibilidade de su dispositivu diretamente in OsmAnd, e fatzìlitat, pro nàrrere, sa modìfica de sa lestresa de sas boghes de sìntesi vocale, sa cunfiguratzione de su movimentu de s\'ischermu, simpreu de una trackball pro s\'ismanniamentu o de uninterfache vocale pro cosas che s\'annùntziu de sa positzione tua.</string>
<string name="plugins_screen">Estensiones</string>
<string name="prefs_plugins_descr">Sas estensiones abìlitant funtzionalidades agiuntivas e impostatziones avantzadas.</string>
<string name="prefs_plugins">Estensiones</string>
@ -909,7 +909,7 @@
<string name="search_osm_offline">Chirca impreende sa positzione geogràfica</string>
<string name="system_locale">Sistema</string>
<string name="preferred_locale_descr">Limba de interfache de s\'aplicatzione (impreada a pustis chi as a torrare a allùghere OsmAnd).</string>
<string name="preferred_locale">Limba interfàtzia</string>
<string name="preferred_locale">Limba de interfache</string>
<string name="incomplete_locale">non cumpridu</string>
<string name="shared_string_next">Imbeniente</string>
<string name="shared_string_previous">Antepostu</string>

View file

@ -4028,4 +4028,19 @@
<string name="routing_attr_allow_intermittent_description">Povoliť dočasné vodné toky</string>
<string name="routing_attr_allow_intermittent_name">Povoliť dočasné vodné toky</string>
<string name="voice_prompts_timetable">Časy hlasových pokynov</string>
<string name="add_online_routing_engine">Pridať online navigačnú službu</string>
<string name="edit_online_routing_engine">Upraviť online navigačnú službu</string>
<string name="shared_string_subtype">Podtyp</string>
<string name="shared_string_vehicle">Vozidlo</string>
<string name="shared_string_api_key">Kľúč API</string>
<string name="shared_string_server_url">Adresa URL serveru</string>
<string name="shared_string_enter_param">Zadajte parameter</string>
<string name="keep_it_empty_if_not">Ak nie, ponechajte prázdne</string>
<string name="online_routing_example_hint">Adresa URL so všetkými parametrami bude vyzerať nasledovne:</string>
<string name="test_route_calculation">Vyskúšať výpočet trasy</string>
<string name="routing_engine_vehicle_type_driving">Vedenie vozidla</string>
<string name="routing_engine_vehicle_type_foot">Chôdza</string>
<string name="routing_engine_vehicle_type_bike">Bicykel</string>
<string name="routing_engine_vehicle_type_car">Auto</string>
<string name="message_error_recheck_parameters">Chyba, skontrolujte parametre</string>
</resources>

View file

@ -944,7 +944,7 @@
<string name="poi_route_hiking_lwn_poi">Yerel yürüyüş güzergahı</string>
<string name="poi_route_hiking_ref_poi">Yürüyüş yolu başvurusu</string>
<string name="poi_opening_hours">Çalışma saatleri</string>
<string name="poi_collection_times">Koleksiyon kez</string>
<string name="poi_collection_times">Toplama zamanları</string>
<string name="poi_description">ıklama</string>
<string name="poi_phone">Telefon</string>
<string name="poi_website">İnternet sitesi</string>
@ -3137,4 +3137,12 @@
<string name="poi_diplomatic_services_non_immigrant_visas_filter">Göçmen olmayan vizeleri</string>
<string name="poi_military_checkpoint">Askeri denetim noktası</string>
<string name="poi_checkpoint_hiking">Yürüyüş denetim noktası</string>
<string name="poi_street_cabinet_street_lighting">Dolap türü: sokak aydınlatması</string>
<string name="poi_street_cabinet_water_management">Dolap türü: su yönetimi</string>
<string name="poi_street_cabinet_waste">Dolap türü: atık</string>
<string name="poi_street_cabinet_postal_service">Dolap türü: posta hizmeti</string>
<string name="poi_street_cabinet_gas">Dolap türü: gaz</string>
<string name="poi_street_cabinet_cable_tv">Dolap türü: kablo tv</string>
<string name="poi_street_cabinet_telecom">Dolap türü: telefon</string>
<string name="poi_street_cabinet_power">Dolap türü: elektrik</string>
</resources>

View file

@ -1701,7 +1701,7 @@
<string name="remove_the_tag">Etiketi Kaldır</string>
<string name="version_settings_descr">Gecelik derlemeleri indir.</string>
<string name="version_settings">kurar</string>
<string name="rendering_attr_streetLighting_name">Sokak Aydınlatma</string>
<string name="rendering_attr_streetLighting_name">Sokak aydınlatma</string>
<string name="proxy_pref_title">Vekil sunucu</string>
<string name="proxy_pref_descr">Bir proxy sunucusu belirtin.</string>
<string name="settings_privacy">Gizlilik</string>
@ -3982,5 +3982,21 @@
<string name="routing_attr_allow_streams_name">Dere ve kanalizasyonlara izin ver</string>
<string name="routing_attr_allow_intermittent_description">Aralıklı su yollarına izin verin</string>
<string name="routing_attr_allow_intermittent_name">Aralıklı su yollarına izin ver</string>
<string name="voice_prompts_timetable">Sesli uyarı zamanı</string>
<string name="voice_prompts_timetable">Sesli uyarı zamanları</string>
<string name="add_online_routing_engine">Çevrim içi yönlendirme motoru ekle</string>
<string name="edit_online_routing_engine">Çevrim içi yönlendirme motorunu düzenle</string>
<string name="shared_string_subtype">Alt tür</string>
<string name="shared_string_vehicle">Araç</string>
<string name="shared_string_api_key">API anahtarı</string>
<string name="shared_string_server_url">Sunucu URL\'si</string>
<string name="shared_string_enter_param">Parametre gir</string>
<string name="keep_it_empty_if_not">Değilse boş tut</string>
<string name="online_routing_example_hint">Tüm parametreleri ile URL şu şekilde görünecektir:</string>
<string name="test_route_calculation">Güzergah hesaplamayı test et</string>
<string name="routing_engine_vehicle_type_driving">Araba sürme</string>
<string name="routing_engine_vehicle_type_foot">Yürüme</string>
<string name="routing_engine_vehicle_type_bike">Bisiklet</string>
<string name="routing_engine_vehicle_type_car">Araba</string>
<string name="message_error_recheck_parameters">Hata, parametreleri tekrar gözden geçirin</string>
<string name="copy_address">Adresi kopyala</string>
</resources>

View file

@ -4024,4 +4024,19 @@
<string name="routing_attr_allow_streams_description">Дозволити потоки та стічні канали</string>
<string name="routing_attr_allow_streams_name">Дозволити потоки та стічні канали</string>
<string name="voice_prompts_timetable">Голосові підказки</string>
<string name="add_online_routing_engine">Додати мережний рушій маршрутизації</string>
<string name="edit_online_routing_engine">Змінити мережний рушій маршрутизації</string>
<string name="shared_string_subtype">Підтип</string>
<string name="shared_string_vehicle">Транспортний засіб</string>
<string name="shared_string_api_key">Ключ API</string>
<string name="shared_string_server_url">URL-адреса сервера</string>
<string name="shared_string_enter_param">Введіть параметр</string>
<string name="keep_it_empty_if_not">Залиште порожнім, якщо не маєте ключа API</string>
<string name="online_routing_example_hint">URL-адреса з усіма параметрами виглядатиме так:</string>
<string name="test_route_calculation">Тестове обчислення маршруту</string>
<string name="routing_engine_vehicle_type_driving">Водіння</string>
<string name="routing_engine_vehicle_type_foot">Пішки</string>
<string name="routing_engine_vehicle_type_bike">Велосипед</string>
<string name="routing_engine_vehicle_type_car">Автомобіль</string>
<string name="message_error_recheck_parameters">Помилка, повторно перевірте параметри</string>
</resources>

View file

@ -4023,4 +4023,20 @@
<string name="routing_attr_allow_intermittent_description">允許間歇水路</string>
<string name="routing_attr_allow_intermittent_name">允許間歇水路</string>
<string name="voice_prompts_timetable">語音提示時間</string>
<string name="add_online_routing_engine">新增線上路線引擎</string>
<string name="edit_online_routing_engine">編輯線上路線引擎</string>
<string name="shared_string_subtype">子類型</string>
<string name="shared_string_vehicle">車輛</string>
<string name="shared_string_api_key">API 金鑰</string>
<string name="shared_string_server_url">伺服器 URL</string>
<string name="shared_string_enter_param">輸入參數</string>
<string name="keep_it_empty_if_not">否則請保持空白</string>
<string name="online_routing_example_hint">帶有所有參數的 URL 如下所示:</string>
<string name="test_route_calculation">測試路線計算</string>
<string name="routing_engine_vehicle_type_driving">駕駛</string>
<string name="routing_engine_vehicle_type_foot">步行</string>
<string name="routing_engine_vehicle_type_bike">自行車</string>
<string name="routing_engine_vehicle_type_car">汽車</string>
<string name="message_error_recheck_parameters">錯誤,重新檢查參數</string>
<string name="copy_address">複製地址</string>
</resources>

View file

@ -11,6 +11,10 @@
Thx - Hardy
-->
<string name="online_routing_engines">Online routing engines</string>
<string name="online_routing_engine">Online routing engine</string>
<string name="copy_address">Copy address</string>
<string name="message_error_recheck_parameters">Error, recheck parameters</string>
<string name="routing_engine_vehicle_type_car">Car</string>
<string name="routing_engine_vehicle_type_bike">Bike</string>
@ -4026,5 +4030,4 @@
<string name="routing_attr_freeride_policy_description">\'Freeride\' and \'Off-piste\' are unofficial routes and passages. Typically ungroomed, unmaintained and not checked in the evening. Enter at your own risk.</string>
<string name="voice_prompts_timetable">Voice prompts times</string>
</resources>

View file

@ -23,12 +23,13 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import net.osmand.plus.widgets.WebViewEx;
/**
* WebView that its scroll position can be observed.
*/
public class ObservableWebView extends WebView implements Scrollable {
public class ObservableWebView extends WebViewEx implements Scrollable {
// Fields that should be saved onSaveInstanceState
private int mPrevScrollY;

View file

@ -673,15 +673,15 @@ public class OsmAndLocationProvider implements SensorEventListener {
private void stopLocationRequests() {
LocationManager service = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE);
if(gpsStatusListener != null) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (gpsStatusListener != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
service.unregisterGnssStatusCallback((GnssStatus.Callback) gpsStatusListener);
} else {
service.removeGpsStatusListener((Listener) gpsStatusListener);
}
}
service.removeUpdates(gpsListener);
while(!networkListeners.isEmpty()) {
while (!networkListeners.isEmpty()) {
service.removeUpdates(networkListeners.poll());
}
}
@ -812,8 +812,7 @@ public class OsmAndLocationProvider implements SensorEventListener {
setLocation(location);
}
private void setLocation(net.osmand.Location location) {
if (location == null) {
private void setLocation(net.osmand.Location location) { if (location == null) {
updateGPSInfo(null);
}

View file

@ -3,7 +3,6 @@
*/
package net.osmand.plus.activities;
import android.view.Window;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import android.annotation.SuppressLint;

View file

@ -576,7 +576,7 @@ public class DownloadIndexesThread {
manager.indexVoiceFiles(this);
manager.indexFontFiles(this);
if (vectorMapsToReindex) {
warnings = manager.indexingMaps(this);
warnings = manager.indexingMaps(this, filesToReindex);
}
List<String> wns = manager.indexAdditionalMaps(this);
if (wns != null) {

View file

@ -29,20 +29,29 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.*;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.Version;
import net.osmand.plus.activities.ActivityResultListener;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.FontCache;
@ -51,6 +60,7 @@ import net.osmand.plus.mapcontextmenu.builders.cards.CardsRowBuilder;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask;
import net.osmand.plus.mapcontextmenu.builders.cards.NoImagesCard;
import net.osmand.plus.mapcontextmenu.controllers.AmenityMenuController;
import net.osmand.plus.mapcontextmenu.controllers.TransportStopController;
import net.osmand.plus.openplacereviews.AddPhotosBottomSheetDialogFragment;
import net.osmand.plus.openplacereviews.OPRConstants;
@ -65,6 +75,7 @@ import net.osmand.plus.widgets.TextViewEx;
import net.osmand.plus.widgets.tools.ClickableSpanTouchListener;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import org.openplacereviews.opendb.util.exception.FailedVerificationException;
@ -72,7 +83,13 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask.GetImageCardsListener;
@ -91,13 +108,15 @@ public class MenuBuilder {
private boolean firstRow;
protected boolean matchWidthDivider;
protected boolean light;
private long objectId;
private Amenity amenity;
private LatLon latLon;
private boolean hidden;
private boolean showTitleIfTruncated = true;
private boolean showNearestWiki = false;
private boolean showNearestPoi = false;
private boolean showOnlinePhotos = true;
protected List<Amenity> nearestWiki = new ArrayList<>();
protected List<Amenity> nearestPoi = new ArrayList<>();
private List<OsmandPlugin> menuPlugins = new ArrayList<>();
@Nullable
private CardsRowBuilder onlinePhotoCardsRow;
@ -208,10 +227,18 @@ public class MenuBuilder {
return showNearestWiki;
}
public boolean isShowNearestPoi() {
return showNearestPoi;
}
public void setShowNearestWiki(boolean showNearestWiki) {
this.showNearestWiki = showNearestWiki;
}
public void setShowNearestPoi(boolean showNearestPoi) {
this.showNearestPoi = showNearestPoi;
}
public void setShowTitleIfTruncated(boolean showTitleIfTruncated) {
this.showTitleIfTruncated = showTitleIfTruncated;
}
@ -224,9 +251,8 @@ public class MenuBuilder {
this.showOnlinePhotos = showOnlinePhotos;
}
public void setShowNearestWiki(boolean showNearestWiki, long objectId) {
this.objectId = objectId;
this.showNearestWiki = showNearestWiki;
public void setAmenity(Amenity amenity) {
this.amenity = amenity;
}
public void addMenuPlugin(OsmandPlugin plugin) {
@ -246,6 +272,7 @@ public class MenuBuilder {
buildTitleRow(view);
}
buildNearestWikiRow(view);
buildNearestPoiRow(view);
if (needBuildPlainMenuItems()) {
buildPlainMenuItems(view);
}
@ -325,10 +352,20 @@ public class MenuBuilder {
}
protected void buildNearestWikiRow(View view) {
if (processNearestWiki() && nearestWiki.size() > 0) {
buildRow(view, R.drawable.ic_action_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")", 0,
true, getCollapsableWikiView(view.getContext(), true),
false, 0, false, null, false);
buildNearestRow(view, nearestWiki, processNearestWiki(),
R.drawable.ic_action_wikipedia, app.getString(R.string.wiki_around));
}
protected void buildNearestPoiRow(View view) {
buildNearestRow(view, nearestPoi, processNearestPoi(),
nearestPoi.isEmpty() ? 0 : AmenityMenuController.getRightIconId(nearestPoi.get(0)),
app.getString(R.string.speak_poi));
}
protected void buildNearestRow(View view, List<Amenity> nearestAmenities, boolean process, int iconId, String text) {
if (process && nearestAmenities.size() > 0) {
buildRow(view, iconId, null, text + " (" + nearestAmenities.size() + ")", 0, true,
getCollapsableView(view.getContext(), true, nearestAmenities), false, 0, false, null, false);
}
}
@ -1118,20 +1155,23 @@ public class MenuBuilder {
return new CollapsableView(textView, this, collapsed);
}
protected CollapsableView getCollapsableWikiView(Context context, boolean collapsed) {
protected CollapsableView getCollapsableView(Context context, boolean collapsed, List<Amenity> nearestAmenities) {
LinearLayout view = (LinearLayout) buildCollapsableContentView(context, collapsed, true);
for (final Amenity wiki : nearestWiki) {
for (final Amenity poi : nearestAmenities) {
TextViewEx button = buildButtonInCollapsableView(context, false, false);
String name = wiki.getName(preferredMapAppLang, transliterateNames);
String name = poi.getName(preferredMapAppLang, transliterateNames);
if (Algorithms.isBlank(name)) {
name = AmenityMenuController.getTypeStr(poi);
}
button.setText(name);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LatLon latLon = new LatLon(wiki.getLocation().getLatitude(), wiki.getLocation().getLongitude());
PointDescription pointDescription = mapActivity.getMapLayers().getPoiMapLayer().getObjectName(wiki);
mapActivity.getContextMenu().show(latLon, pointDescription, wiki);
LatLon latLon = new LatLon(poi.getLocation().getLatitude(), poi.getLocation().getLongitude());
PointDescription pointDescription = mapActivity.getMapLayers().getPoiMapLayer().getObjectName(poi);
mapActivity.getContextMenu().show(latLon, pointDescription, poi);
}
});
view.addView(button);
@ -1191,35 +1231,48 @@ public class MenuBuilder {
}
protected boolean processNearestWiki() {
if (showNearestWiki && latLon != null) {
QuadRect rect = MapUtils.calculateLatLonBbox(
latLon.getLatitude(), latLon.getLongitude(), 250);
PoiUIFilter wikiPoiFilter = app.getPoiFilters().getTopWikiPoiFilter();
nearestWiki = getAmenities(rect, wikiPoiFilter);
Collections.sort(nearestWiki, new Comparator<Amenity>() {
@Override
public int compare(Amenity o1, Amenity o2) {
double d1 = MapUtils.getDistance(latLon, o1.getLocation());
double d2 = MapUtils.getDistance(latLon, o2.getLocation());
return Double.compare(d1, d2);
}
});
Long id = objectId;
List<Amenity> wikiList = new ArrayList<>();
for (Amenity wiki : nearestWiki) {
if (wiki.getId().equals(id)) {
wikiList.add(wiki);
}
if (showNearestWiki && latLon != null && amenity != null) {
PoiUIFilter filter = app.getPoiFilters().getTopWikiPoiFilter();
if (filter != null) {
nearestWiki = getSortedAmenities(filter, latLon);
return true;
}
nearestWiki.removeAll(wikiList);
return true;
}
return false;
}
protected boolean processNearestPoi() {
if (showNearestPoi && latLon != null && amenity != null) {
PoiCategory pc = amenity.getType();
PoiType pt = pc.getPoiTypeByKeyName(amenity.getSubType());
PoiUIFilter filter = app.getPoiFilters().getFilterById(PoiUIFilter.STD_PREFIX + pt.getKeyName());
if (filter != null) {
nearestPoi = getSortedAmenities(filter, latLon);
return true;
}
}
return false;
}
private List<Amenity> getSortedAmenities(PoiUIFilter filter, final LatLon latLon) {
QuadRect rect = MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), 250);
List<Amenity> nearestAmenities = getAmenities(rect, filter);
nearestAmenities.remove(amenity);
Collections.sort(nearestAmenities, new Comparator<Amenity>() {
@Override
public int compare(Amenity o1, Amenity o2) {
double d1 = MapUtils.getDistance(latLon, o1.getLocation());
double d2 = MapUtils.getDistance(latLon, o2.getLocation());
return Double.compare(d1, d2);
}
});
return nearestAmenities;
}
private List<Amenity> getAmenities(QuadRect rect, PoiUIFilter wikiPoiFilter) {
return wikiPoiFilter.searchAmenities(rect.top, rect.left,
rect.bottom, rect.right, -1, null);

View file

@ -35,6 +35,7 @@ import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.helpers.enums.MetricsConstants;
import net.osmand.plus.mapcontextmenu.CollapsableView;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.controllers.AmenityMenuController;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.views.layers.POIMapLayer;
@ -78,7 +79,9 @@ public class AmenityMenuBuilder extends MenuBuilder {
public AmenityMenuBuilder(@NonNull MapActivity mapActivity, final @NonNull Amenity amenity) {
super(mapActivity);
this.amenity = amenity;
setShowNearestWiki(true, amenity.getId());
setAmenity(amenity);
setShowNearestWiki(true);
setShowNearestPoi(!amenity.getType().isWiki());
metricSystem = mapActivity.getMyApplication().getSettings().METRIC_SYSTEM.get();
}
@ -86,6 +89,10 @@ public class AmenityMenuBuilder extends MenuBuilder {
protected void buildNearestWikiRow(View view) {
}
@Override
protected void buildNearestPoiRow(View view) {
}
private void buildRow(View view, int iconId, String text, String textPrefix,
boolean collapsable, final CollapsableView collapsableView,
int textColor, boolean isWiki, boolean isText, boolean needLinks,
@ -664,11 +671,19 @@ public class AmenityMenuBuilder extends MenuBuilder {
if (processNearestWiki() && nearestWiki.size() > 0) {
AmenityInfoRow wikiInfo = new AmenityInfoRow(
"nearest_wiki", R.drawable.ic_plugin_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")", true,
getCollapsableWikiView(view.getContext(), true),
getCollapsableView(view.getContext(), true, nearestWiki),
0, false, false, false, 1000, null, false, false, false, 0);
buildAmenityRow(view, wikiInfo);
}
if (processNearestPoi() && nearestPoi.size() > 0) {
AmenityInfoRow poiInfo = new AmenityInfoRow(
"nearest_poi", AmenityMenuController.getRightIconId(amenity), null, app.getString(R.string.speak_poi) + " (" + nearestPoi.size() + ")", true,
getCollapsableView(view.getContext(), true, nearestPoi),
0, false, false, false, 1000, null, false, false, false, 0);
buildAmenityRow(view, poiInfo);
}
if (osmEditingEnabled && amenity.getId() != null
&& amenity.getId() > 0 &&
(amenity.getId() % 2 == 0 || (amenity.getId() >> 1) < Integer.MAX_VALUE)) {

View file

@ -59,9 +59,9 @@ public class FavouritePointMenuBuilder extends MenuBuilder {
}
@Override
protected void buildNearestWikiRow(View view) {
protected void buildNearestRow(View view, List<Amenity> nearestAmenities, boolean process, int iconId, String text) {
if (originObject == null || !(originObject instanceof Amenity)) {
super.buildNearestWikiRow(view);
super.buildNearestRow(view, nearestAmenities, process, iconId, text);
}
}

View file

@ -1,6 +1,7 @@
package net.osmand.plus.mapcontextmenu.builders.cards;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
@ -23,6 +24,7 @@ import androidx.core.content.ContextCompat;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.widgets.WebViewEx;
public abstract class AbstractCard {
@ -55,7 +57,7 @@ public abstract class AbstractCard {
@SuppressLint("SetJavaScriptEnabled")
@SuppressWarnings("deprecation")
protected static void openUrl(@NonNull Context ctx,
protected static void openUrl(@NonNull Activity ctx,
@NonNull OsmandApplication app,
@Nullable String title,
@NonNull String url,
@ -90,7 +92,7 @@ public abstract class AbstractCard {
}
});
final WebView wv = new WebView(ctx);
final WebView wv = new WebViewEx(ctx);
wv.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {

View file

@ -116,7 +116,7 @@ public class AmenityMenuController extends MenuController {
return getRightIconId(amenity);
}
private static int getRightIconId(Amenity amenity) {
public static int getRightIconId(Amenity amenity) {
String id = null;
PoiType st = amenity.getType().getPoiTypeByKeyName(amenity.getSubType());
if (st != null) {

View file

@ -36,6 +36,7 @@ public class ShareMenu extends BaseMenuController {
public enum ShareItem {
MESSAGE(R.drawable.ic_action_message, R.string.shared_string_send),
CLIPBOARD(R.drawable.ic_action_copy, R.string.shared_string_copy),
ADDRESS(R.drawable.ic_action_copy, R.string.copy_address),
NAME(R.drawable.ic_action_copy, R.string.copy_location_name),
COORDINATES(R.drawable.ic_action_copy, R.string.copy_coordinates),
GEO(R.drawable.ic_world_globe_dark, R.string.share_geo),
@ -66,6 +67,7 @@ public class ShareMenu extends BaseMenuController {
List<ShareItem> list = new LinkedList<>();
list.add(ShareItem.MESSAGE);
list.add(ShareItem.CLIPBOARD);
list.add(ShareItem.ADDRESS);
list.add(ShareItem.NAME);
list.add(ShareItem.COORDINATES);
list.add(ShareItem.GEO);
@ -121,6 +123,15 @@ public class ShareMenu extends BaseMenuController {
case CLIPBOARD:
ShareDialog.sendToClipboard(mapActivity, sms);
break;
case ADDRESS:
if (!Algorithms.isEmpty(address)) {
ShareDialog.sendToClipboard(mapActivity, address);
} else {
Toast.makeText(mapActivity,
R.string.no_address_found,
Toast.LENGTH_LONG).show();
}
break;
case NAME:
if (!Algorithms.isEmpty(title)) {
ShareDialog.sendToClipboard(mapActivity, title);

View file

@ -19,6 +19,7 @@ import com.google.android.material.appbar.AppBarLayout;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.widgets.WebViewEx;
public class GpxDescriptionDialogFragment extends BaseOsmAndDialogFragment {
@ -48,7 +49,7 @@ public class GpxDescriptionDialogFragment extends BaseOsmAndDialogFragment {
AppBarLayout appBar = new AppBarLayout(ctx);
appBar.addView(topBar);
WebView webView = new WebView(ctx);
WebView webView = new WebViewEx(ctx);
webView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
webView.getSettings().setTextZoom((int) (getResources().getConfiguration().fontScale * 100f));
Bundle args = getArguments();

View file

@ -3,6 +3,7 @@ package net.osmand.plus.onlinerouting;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.plus.R;
import net.osmand.util.Algorithms;
@ -26,11 +27,13 @@ public class OnlineRoutingEngine {
private Map<String, String> params = new HashMap<>();
public OnlineRoutingEngine(@NonNull String stringKey,
@NonNull ServerType serverType,
@NonNull String vehicleKey,
Map<String, String> params) {
@NonNull ServerType serverType,
@NonNull String vehicleKey,
@Nullable Map<String, String> params) {
this(stringKey, serverType, vehicleKey);
this.params = params;
if (!Algorithms.isEmpty(params)) {
this.params.putAll(params);
}
}
public OnlineRoutingEngine(@NonNull String stringKey,
@ -96,8 +99,9 @@ public class OnlineRoutingEngine {
}
public static OnlineRoutingEngine createNewEngine(@NonNull ServerType serverType,
@NonNull String vehicleKey) {
return new OnlineRoutingEngine(generateKey(), serverType, vehicleKey);
@NonNull String vehicleKey,
@Nullable Map<String, String> params) {
return new OnlineRoutingEngine(generateKey(), serverType, vehicleKey, params);
}
private static String generateKey() {

View file

@ -132,8 +132,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
view = getInflater().inflate(
R.layout.online_routing_engine_fragment, container, false);
segmentsContainer = (ViewGroup) view.findViewById(R.id.segments_container);
@ -402,7 +402,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
if (isEditingMode()) {
engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.serverType, engine.getVehicleKey());
} else {
engineToSave = OnlineRoutingEngine.createNewEngine(engine.serverType, engine.getVehicleKey());
engineToSave = OnlineRoutingEngine.createNewEngine(engine.serverType, engine.getVehicleKey(), null);
}
engineToSave.putParameter(EngineParameterType.CUSTOM_SERVER_URL, engine.customServerUrl);
@ -568,8 +568,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
}
public static void showInstance(@NonNull FragmentActivity activity,
@NonNull ApplicationMode appMode,
String editedEngineKey) {
@NonNull ApplicationMode appMode,
String editedEngineKey) {
FragmentManager fm = activity.getSupportFragmentManager();
if (!fm.isStateSaved() && fm.findFragmentByTag(OnlineRoutingEngineFragment.TAG) == null) {
OnlineRoutingEngineFragment fragment = new OnlineRoutingEngineFragment();

View file

@ -91,7 +91,7 @@ public class OnlineRoutingHelper {
JSONObject json = new JSONObject(jsonString);
readFromJson(json, engines);
} catch (JSONException e) {
LOG.debug("Error when create a new JSONObject: " + e.toString());
LOG.debug("Error when reading engines from JSON ", e);
}
}
return engines;
@ -99,57 +99,50 @@ public class OnlineRoutingHelper {
private void saveToSettings() {
if (!Algorithms.isEmpty(cachedEngines)) {
JSONObject json = new JSONObject();
if (writeToJson(json, cachedEngines)) {
try {
JSONObject json = new JSONObject();
writeToJson(json, cachedEngines);
settings.ONLINE_ROUTING_ENGINES.set(json.toString());
} catch (JSONException e) {
LOG.debug("Error when writing engines to JSON ", e);
}
} else {
settings.ONLINE_ROUTING_ENGINES.set(null);
}
}
private static void readFromJson(JSONObject json, List<OnlineRoutingEngine> engines) {
try {
if (!json.has("items")) {
return;
}
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, String>>() {
}.getType();
JSONArray itemsJson = json.getJSONArray("items");
for (int i = 0; i < itemsJson.length(); i++) {
JSONObject object = itemsJson.getJSONObject(i);
String key = object.getString("key");
String vehicleKey = object.getString("vehicle");
ServerType serverType = ServerType.valueOf(object.getString("serverType"));
String paramsString = object.getString("params");
HashMap<String, String> params = gson.fromJson(paramsString, type);
engines.add(new OnlineRoutingEngine(key, serverType, vehicleKey, params));
}
} catch (JSONException e) {
LOG.debug("Error when reading engines from JSON: " + e.toString());
public static void readFromJson(JSONObject json, List<OnlineRoutingEngine> engines) throws JSONException {
if (!json.has("items")) {
return;
}
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, String>>() {
}.getType();
JSONArray itemsJson = json.getJSONArray("items");
for (int i = 0; i < itemsJson.length(); i++) {
JSONObject object = itemsJson.getJSONObject(i);
String key = object.getString("key");
String vehicleKey = object.getString("vehicle");
ServerType serverType = ServerType.valueOf(object.getString("serverType"));
String paramsString = object.getString("params");
HashMap<String, String> params = gson.fromJson(paramsString, type);
engines.add(new OnlineRoutingEngine(key, serverType, vehicleKey, params));
}
}
private static boolean writeToJson(JSONObject json, List<OnlineRoutingEngine> engines) {
public static void writeToJson(JSONObject json, List<OnlineRoutingEngine> engines) throws JSONException {
JSONArray jsonArray = new JSONArray();
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, String>>() {
}.getType();
try {
for (OnlineRoutingEngine engine : engines) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("key", engine.getStringKey());
jsonObject.put("serverType", engine.getServerType().name());
jsonObject.put("vehicle", engine.getVehicleKey());
jsonObject.put("params", gson.toJson(engine.getParams(), type));
jsonArray.put(jsonObject);
}
json.put("items", jsonArray);
return true;
} catch (JSONException e) {
LOG.debug("Error when writing engines to JSON: " + e.toString());
return false;
for (OnlineRoutingEngine engine : engines) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("key", engine.getStringKey());
jsonObject.put("serverType", engine.getServerType().name());
jsonObject.put("vehicle", engine.getVehicleKey());
jsonObject.put("params", gson.toJson(engine.getParams(), type));
jsonArray.put(jsonObject);
}
json.put("items", jsonArray);
}
}

View file

@ -138,7 +138,11 @@ public class OsmOAuthAuthorizationAdapter {
@Override
protected void onPostExecute(@NonNull OAuth1RequestToken requestToken) {
loadWebView(rootLayout, nightMode, client.getService().getAuthorizationUrl(requestToken));
if (requestToken != null) {
loadWebView(rootLayout, nightMode, client.getService().getAuthorizationUrl(requestToken));
} else {
app.showShortToastMessage(app.getString(R.string.internet_not_available));
}
}
}

View file

@ -45,7 +45,11 @@ public class OsmOAuthHelper {
}
public void authorize(@NonNull String oauthVerifier) {
authorizationAdapter.authorize(oauthVerifier, this);
if (oauthVerifier != null) {
authorizationAdapter.authorize(oauthVerifier, this);
} else {
updateAdapter();
}
}
public void resetAuthorization() {

View file

@ -621,7 +621,11 @@ public class ResourceManager {
}
}
public List<String> indexingMaps(final IProgress progress) {
public List<String> indexingMaps(IProgress progress) {
return indexingMaps(progress, Collections.<File>emptyList());
}
public List<String> indexingMaps(final IProgress progress, List<File> filesToReindex) {
long val = System.currentTimeMillis();
ArrayList<File> files = new ArrayList<File>();
File appPath = context.getAppPath(null);
@ -688,7 +692,7 @@ public class ResourceManager {
try {
BinaryMapIndexReader mapReader = null;
try {
mapReader = cachedOsmandIndexes.getReader(f);
mapReader = cachedOsmandIndexes.getReader(f, !filesToReindex.contains(f));
if (mapReader.getVersion() != IndexConstants.BINARY_MAP_VERSION) {
mapReader = null;
}

View file

@ -73,7 +73,7 @@ public class AnnounceTimeDistances {
// Do not play prepare: for pedestrian and slow transport
// same check as speed < 150/(90-22) m/s = 2.2 m/s = 8 km/h
// if (DEFAULT_SPEED < 2.3) {
// if (DEFAULT_SPEED < 2.3) {
if (PREPARE_DISTANCE_END - TURN_IN_DISTANCE < 150) {
PREPARE_DISTANCE_END = PREPARE_DISTANCE * 2;
}

View file

@ -24,7 +24,8 @@ public enum ExportSettingsType {
MAP_SOURCES(R.string.quick_action_map_source_title, R.drawable.ic_map),
OFFLINE_MAPS(R.string.shared_string_maps, R.drawable.ic_map),
TTS_VOICE(R.string.local_indexes_cat_tts, R.drawable.ic_action_volume_up),
VOICE(R.string.local_indexes_cat_voice, R.drawable.ic_action_volume_up);
VOICE(R.string.local_indexes_cat_voice, R.drawable.ic_action_volume_up),
ONLINE_ROUTING_ENGINES(R.string.online_routing_engines, R.drawable.ic_world_globe_dark);
@StringRes
private final int titleId;
@ -59,6 +60,6 @@ public enum ExportSettingsType {
public boolean isResourcesCategory() {
return this == CUSTOM_RENDER_STYLE || this == CUSTOM_ROUTING || this == MAP_SOURCES
|| this == OFFLINE_MAPS || this == VOICE || this == TTS_VOICE;
|| this == OFFLINE_MAPS || this == VOICE || this == TTS_VOICE || this == ONLINE_ROUTING_ENGINES;
}
}

View file

@ -48,7 +48,6 @@ import net.osmand.plus.helpers.enums.TracksSortByMode;
import net.osmand.plus.mapillary.MapillaryPlugin;
import net.osmand.plus.mapmarkers.CoordinateInputFormats.Format;
import net.osmand.plus.mapmarkers.MapMarkersMode;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.profiles.LocationIcon;
import net.osmand.plus.profiles.NavigationIcon;
import net.osmand.plus.profiles.ProfileIconColors;
@ -1016,7 +1015,7 @@ public class OsmandSettings {
ROUTE_SERVICE.setModeDefaultValue(ApplicationMode.AIRCRAFT, RouteService.STRAIGHT);
}
public final CommonPreference<String> ONLINE_ROUTING_ENGINES = new StringPreference(this, "online_routing_engines", null);
public final CommonPreference<String> ONLINE_ROUTING_ENGINES = new StringPreference(this, "online_routing_engines", null).makeGlobal();
public final CommonPreference<NavigationIcon> NAVIGATION_ICON = new EnumStringPreference<>(this, "navigation_icon", NavigationIcon.DEFAULT, NavigationIcon.values()).makeProfile().cache();

View file

@ -92,11 +92,6 @@ public class AvoidRoadsSettingsItem extends CollectionSettingsItem<AvoidRoadInfo
return false;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@Override
public boolean shouldShowDuplicates() {
return false;

View file

@ -72,6 +72,11 @@ public abstract class CollectionSettingsItem<T> extends SettingsItem {
return true;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
public abstract boolean isDuplicate(@NonNull T item);
@NonNull

View file

@ -109,11 +109,6 @@ public class FavoritesSettingsItem extends CollectionSettingsItem<FavoriteGroup>
return false;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@NonNull
@Override
public FavoriteGroup renameItem(@NonNull FavoriteGroup item) {

View file

@ -103,11 +103,6 @@ public class HistoryMarkersSettingsItem extends CollectionSettingsItem<MapMarker
return false;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@NonNull
@Override
public MapMarker renameItem(@NonNull MapMarker item) {

View file

@ -130,11 +130,6 @@ public class MapSourcesSettingsItem extends CollectionSettingsItem<ITileSource>
return "map_sources";
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@Override
void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException {
try {

View file

@ -103,11 +103,6 @@ public class MarkersSettingsItem extends CollectionSettingsItem<MapMarker> {
return false;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@NonNull
@Override
public MapMarker renameItem(@NonNull MapMarker item) {

View file

@ -0,0 +1,137 @@
package net.osmand.plus.settings.backend.backup;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameterType;
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class OnlineRoutingSettingsItem extends CollectionSettingsItem<OnlineRoutingEngine> {
private OnlineRoutingHelper onlineRoutingHelper;
public OnlineRoutingSettingsItem(@NonNull OsmandApplication app, @NonNull List<OnlineRoutingEngine> items) {
super(app, null, items);
}
public OnlineRoutingSettingsItem(@NonNull OsmandApplication app, @Nullable OnlineRoutingSettingsItem baseItem, @NonNull List<OnlineRoutingEngine> items) {
super(app, baseItem, items);
}
public OnlineRoutingSettingsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException {
super(app, json);
}
@Override
protected void init() {
super.init();
onlineRoutingHelper = app.getOnlineRoutingHelper();
existingItems = new ArrayList<>(onlineRoutingHelper.getEngines());
}
@NonNull
@Override
public SettingsItemType getType() {
return SettingsItemType.ONLINE_ROUTING_ENGINES;
}
@NonNull
@Override
public String getName() {
return "online_routing_engines";
}
@NonNull
@Override
public String getPublicName(@NonNull Context ctx) {
return ctx.getString(R.string.online_routing_engine);
}
@Override
public void apply() {
List<OnlineRoutingEngine> newItems = getNewItems();
if (!newItems.isEmpty() || !duplicateItems.isEmpty()) {
appliedItems = new ArrayList<>(newItems);
for (OnlineRoutingEngine duplicate : duplicateItems) {
if (shouldReplace) {
onlineRoutingHelper.deleteEngine(duplicate.getStringKey());
}
appliedItems.add(shouldReplace ? duplicate : renameItem(duplicate));
}
for (OnlineRoutingEngine engine : appliedItems) {
onlineRoutingHelper.saveEngine(engine);
}
}
}
@Override
public boolean isDuplicate(@NonNull OnlineRoutingEngine routingEngine) {
for (OnlineRoutingEngine engine : existingItems) {
if (engine.getStringKey().equals(routingEngine.getStringKey())
|| engine.getName(app).equals(routingEngine.getName(app))) {
return true;
}
}
return false;
}
@NonNull
@Override
public OnlineRoutingEngine renameItem(@NonNull OnlineRoutingEngine item) {
int number = 0;
while (true) {
number++;
OnlineRoutingEngine renamedItem = OnlineRoutingEngine.createNewEngine(item.getServerType(), item.getVehicleKey(), item.getParams());
renamedItem.putParameter(EngineParameterType.CUSTOM_NAME, renamedItem.getName(app) + "_" + number);
if (!isDuplicate(renamedItem)) {
return renamedItem;
}
}
}
@Override
void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException {
try {
OnlineRoutingHelper.readFromJson(json, items);
} catch (JSONException e) {
warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType())));
throw new IllegalArgumentException("Json parse error", e);
}
}
@Override
void writeItemsToJson(@NonNull JSONObject json) {
if (!items.isEmpty()) {
try {
OnlineRoutingHelper.writeToJson(json, items);
} catch (JSONException e) {
warnings.add(app.getString(R.string.settings_item_write_error, String.valueOf(getType())));
SettingsHelper.LOG.error("Failed write to json", e);
}
}
}
@Nullable
@Override
SettingsItemReader<? extends SettingsItem> getReader() {
return getJsonReader();
}
@Nullable
@Override
SettingsItemWriter<? extends SettingsItem> getWriter() {
return getJsonWriter();
}
}

View file

@ -113,11 +113,6 @@ public class OsmEditsSettingsItem extends CollectionSettingsItem<OpenstreetmapPo
return ctx.getString(R.string.osm_edits);
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@Override
public boolean shouldShowDuplicates() {
return false;

View file

@ -106,11 +106,6 @@ public class OsmNotesSettingsItem extends CollectionSettingsItem<OsmNotesPoint>
return ctx.getString(R.string.osm_notes);
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@Override
public boolean shouldShowDuplicates() {
return false;

View file

@ -105,11 +105,6 @@ public class PoiUiFiltersSettingsItem extends CollectionSettingsItem<PoiUIFilter
return "poi_ui_filters";
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@Override
void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException {
try {

View file

@ -89,11 +89,6 @@ public class QuickActionsSettingsItem extends CollectionSettingsItem<QuickAction
}
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@NonNull
@Override
public String getName() {

View file

@ -148,11 +148,6 @@ public class SearchHistorySettingsItem extends CollectionSettingsItem<HistoryEnt
return false;
}
@Override
public boolean shouldReadOnCollecting() {
return true;
}
@NonNull
@Override
public HistoryEntry renameItem(@NonNull HistoryEntry item) {

View file

@ -33,6 +33,7 @@ import net.osmand.plus.helpers.SearchHistoryHelper;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.OsmNotesPoint;
@ -624,6 +625,10 @@ public class SettingsHelper {
resourcesItems.put(ExportSettingsType.CUSTOM_ROUTING, Arrays.asList(fl));
}
}
List<OnlineRoutingEngine> onlineRoutingEngines = app.getOnlineRoutingHelper().getEngines();
if (!Algorithms.isEmpty(onlineRoutingEngines)) {
resourcesItems.put(ExportSettingsType.ONLINE_ROUTING_ENGINES, onlineRoutingEngines);
}
List<ITileSource> iTileSources = new ArrayList<>();
Set<String> tileSourceNames = app.getSettings().getTileSourceEntries(true).keySet();
for (String name : tileSourceNames) {
@ -701,6 +706,7 @@ public class SettingsHelper {
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
List<OnlineRoutingEngine> onlineRoutingEngines = new ArrayList<>();
for (Object object : data) {
if (object instanceof QuickAction) {
@ -741,6 +747,8 @@ public class SettingsHelper {
historyEntries.add((HistoryEntry) object);
} else if (object instanceof GlobalSettingsItem) {
settingsItems.add((GlobalSettingsItem) object);
} else if (object instanceof OnlineRoutingEngine) {
onlineRoutingEngines.add((OnlineRoutingEngine) object);
}
}
if (!quickActions.isEmpty()) {
@ -793,6 +801,9 @@ public class SettingsHelper {
if (!historyEntries.isEmpty()) {
settingsItems.add(new SearchHistorySettingsItem(app, historyEntries));
}
if (!onlineRoutingEngines.isEmpty()) {
settingsItems.add(new OnlineRoutingSettingsItem(app, onlineRoutingEngines));
}
return settingsItems;
}
@ -848,6 +859,7 @@ public class SettingsHelper {
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
List<OnlineRoutingEngine> onlineRoutingEngines = new ArrayList<>();
for (SettingsItem item : settingsItems) {
switch (item.getType()) {
@ -942,6 +954,10 @@ public class SettingsHelper {
case GPX:
tracksFilesList.add((GpxSettingsItem) item);
break;
case ONLINE_ROUTING_ENGINES:
OnlineRoutingSettingsItem onlineRoutingSettingsItem = (OnlineRoutingSettingsItem) item;
onlineRoutingEngines.addAll(onlineRoutingSettingsItem.getItems());
break;
default:
break;
}
@ -1004,6 +1020,9 @@ public class SettingsHelper {
if (!historyEntries.isEmpty()) {
settingsToOperate.put(ExportSettingsType.SEARCH_HISTORY, historyEntries);
}
if (!onlineRoutingEngines.isEmpty()) {
settingsToOperate.put(ExportSettingsType.ONLINE_ROUTING_ENGINES, onlineRoutingEngines);
}
return settingsToOperate;
}

View file

@ -19,5 +19,6 @@ public enum SettingsItemType {
FAVOURITES,
ACTIVE_MARKERS,
HISTORY_MARKERS,
SEARCH_HISTORY
SEARCH_HISTORY,
ONLINE_ROUTING_ENGINES
}

View file

@ -146,6 +146,9 @@ class SettingsItemsFactory {
case GPX:
item = new GpxSettingsItem(app, json);
break;
case ONLINE_ROUTING_ENGINES:
item = new OnlineRoutingSettingsItem(app, json);
break;
}
return item;
}

View file

@ -23,6 +23,7 @@ import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.ProfileIconColors;
import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources;
@ -163,6 +164,9 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter<RecyclerView
itemHolder.icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_flag, activeColorRes));
} else if (currentItem instanceof HistoryEntry) {
itemHolder.title.setText(((HistoryEntry) currentItem).getName().getName());
} else if (currentItem instanceof OnlineRoutingEngine) {
itemHolder.title.setText(((OnlineRoutingEngine) currentItem).getName(app));
itemHolder.icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_world_globe_dark, activeColorRes));
}
itemHolder.divider.setVisibility(shouldShowDivider(position) ? View.VISIBLE : View.GONE);
}

View file

@ -40,6 +40,7 @@ import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.OsmNotesPoint;
@ -362,6 +363,10 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
HistoryEntry historyEntry = (HistoryEntry) object;
builder.setTitle(historyEntry.getName().getName());
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_history, activeColorRes));
} else if (object instanceof OnlineRoutingEngine) {
OnlineRoutingEngine onlineRoutingEngine = (OnlineRoutingEngine) object;
builder.setTitle(onlineRoutingEngine.getName(app));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_world_globe_dark, activeColorRes));
}
}

View file

@ -24,6 +24,7 @@ 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.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.dashboard.DashboardOnMap;
import net.osmand.plus.dialogs.SelectMapStyleBottomSheetDialogFragment;
@ -36,6 +37,7 @@ import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.backend.backup.SettingsHelper;
import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import java.util.List;
@ -150,12 +152,11 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
dismissFragment();
fm.popBackStack(DRAWER_SETTINGS_ID + ".new", FragmentManager.POP_BACK_STACK_INCLUSIVE);
switch (type) {
case CUSTOM_ROUTING:
case GLOBAL:
case PROFILE:
BaseSettingsFragment.showInstance(
requireActivity(),
BaseSettingsFragment.SettingsScreenType.MAIN_SETTINGS
);
case CUSTOM_ROUTING:
case ONLINE_ROUTING_ENGINES:
BaseSettingsFragment.showInstance(requireActivity(), SettingsScreenType.MAIN_SETTINGS);
break;
case QUICK_ACTIONS:
fm.beginTransaction()
@ -190,19 +191,13 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
case AVOID_ROADS:
new AvoidRoadsBottomSheetDialogFragment().show(fm, AvoidRoadsBottomSheetDialogFragment.TAG);
break;
case TRACKS:
case OSM_NOTES:
case OSM_EDITS:
OsmAndAppCustomization appCustomization = app.getAppCustomization();
final Intent favorites = new Intent(activity, appCustomization.getFavoritesActivity());
favorites.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
app.getSettings().FAVORITES_TAB.set(OsmEditingPlugin.OSM_EDIT_TAB);
startActivity(favorites);
break;
case FAVORITES:
Intent favoritesActivity = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
favoritesActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
app.getSettings().FAVORITES_TAB.set(FavoritesActivity.FAV_TAB);
startActivity(favoritesActivity);
case MULTIMEDIA_NOTES:
int tabId = getFavoritesTabId(type);
openFavouritesActivity(activity, tabId);
break;
case SEARCH_HISTORY:
if (activity instanceof MapActivity) {
@ -221,6 +216,29 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
}
}
private void openFavouritesActivity(Activity activity, int tabType) {
OsmAndAppCustomization appCustomization = app.getAppCustomization();
Intent favoritesActivity = new Intent(activity, appCustomization.getFavoritesActivity());
favoritesActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
app.getSettings().FAVORITES_TAB.set(tabType);
startActivity(favoritesActivity);
}
private int getFavoritesTabId(ExportSettingsType type) {
switch (type) {
case OSM_NOTES:
case OSM_EDITS:
return OsmEditingPlugin.OSM_EDIT_TAB;
case MULTIMEDIA_NOTES:
return AudioVideoNotesPlugin.NOTES_TAB;
case TRACKS:
return FavoritesActivity.GPX_TAB;
case FAVORITES:
default:
return FavoritesActivity.FAV_TAB;
}
}
@Override
public int getStatusBarColorId() {
return nightMode ? R.color.status_bar_color_dark : R.color.status_bar_color_light;

View file

@ -34,6 +34,7 @@ import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmNotesPoint;
import net.osmand.plus.poi.PoiUIFilter;
@ -205,6 +206,7 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment {
List<MapMarker> mapMarkers = new ArrayList<>();
List<MapMarker> mapMarkersGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
List<OnlineRoutingEngine> onlineRoutingEngines = new ArrayList<>();
for (Object object : duplicatesList) {
if (object instanceof ApplicationMode.ApplicationModeBean) {
@ -250,6 +252,8 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment {
}
} else if (object instanceof HistoryEntry) {
historyEntries.add((HistoryEntry) object);
} else if (object instanceof OnlineRoutingEngine) {
onlineRoutingEngines.add((OnlineRoutingEngine) object);
}
}
if (!profiles.isEmpty()) {
@ -320,6 +324,10 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment {
duplicates.add(getString(R.string.markers_history));
duplicates.addAll(mapMarkersGroups);
}
if (!onlineRoutingEngines.isEmpty()) {
duplicates.add(getString(R.string.online_routing_engines));
duplicates.addAll(onlineRoutingEngines);
}
return duplicates;
}

View file

@ -36,6 +36,7 @@ import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmNotesPoint;
import net.osmand.plus.poi.PoiUIFilter;
@ -50,6 +51,7 @@ import net.osmand.plus.settings.backend.backup.GpxSettingsItem;
import net.osmand.plus.settings.backend.backup.HistoryMarkersSettingsItem;
import net.osmand.plus.settings.backend.backup.MapSourcesSettingsItem;
import net.osmand.plus.settings.backend.backup.MarkersSettingsItem;
import net.osmand.plus.settings.backend.backup.OnlineRoutingSettingsItem;
import net.osmand.plus.settings.backend.backup.OsmEditsSettingsItem;
import net.osmand.plus.settings.backend.backup.OsmNotesSettingsItem;
import net.osmand.plus.settings.backend.backup.PoiUiFiltersSettingsItem;
@ -347,6 +349,7 @@ public class ImportSettingsFragment extends BaseSettingsListFragment {
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
List<OnlineRoutingEngine> onlineRoutingEngines = new ArrayList<>();
for (Object object : data) {
if (object instanceof ApplicationModeBean) {
appModeBeans.add((ApplicationModeBean) object);
@ -384,6 +387,8 @@ public class ImportSettingsFragment extends BaseSettingsListFragment {
}
} else if (object instanceof HistoryEntry) {
historyEntries.add((HistoryEntry) object);
} else if (object instanceof OnlineRoutingEngine) {
onlineRoutingEngines.add((OnlineRoutingEngine) object);
}
}
if (!appModeBeans.isEmpty()) {
@ -435,6 +440,10 @@ public class ImportSettingsFragment extends BaseSettingsListFragment {
SearchHistorySettingsItem baseItem = getBaseItem(SettingsItemType.SEARCH_HISTORY, SearchHistorySettingsItem.class);
settingsItems.add(new SearchHistorySettingsItem(app, baseItem, historyEntries));
}
if (!onlineRoutingEngines.isEmpty()) {
OnlineRoutingSettingsItem baseItem = getBaseItem(SettingsItemType.ONLINE_ROUTING_ENGINES, OnlineRoutingSettingsItem.class);
settingsItems.add(new OnlineRoutingSettingsItem(app, baseItem, onlineRoutingEngines));
}
return settingsItems;
}

View file

@ -16,7 +16,6 @@ import net.osmand.plus.UiUtilities;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.settings.backend.ExportSettingsType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -33,7 +32,7 @@ public class ImportedSettingsItemsAdapter extends
private OnItemClickListener listener;
ImportedSettingsItemsAdapter(@NonNull OsmandApplication app, Map<ExportSettingsType, List<?>> itemsMap,
boolean nightMode, OnItemClickListener listener) {
boolean nightMode, OnItemClickListener listener) {
this.app = app;
this.itemsMap = itemsMap;
this.nightMode = nightMode;
@ -154,6 +153,10 @@ public class ImportedSettingsItemsAdapter extends
holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_history, activeColorRes));
holder.title.setText(R.string.shared_string_search_history);
break;
case ONLINE_ROUTING_ENGINES:
holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_world_globe_dark, activeColorRes));
holder.title.setText(R.string.online_routing_engines);
break;
}
}

View file

@ -0,0 +1,49 @@
package net.osmand.plus.widgets;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.webkit.WebView;
import net.osmand.plus.OsmandApplication;
public class WebViewEx extends WebView {
public WebViewEx(Context context) {
super(context);
fixWebViewResetsLocaleToUserDefault(context);
}
public WebViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
fixWebViewResetsLocaleToUserDefault(context);
}
public WebViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
fixWebViewResetsLocaleToUserDefault(context);
}
public WebViewEx(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
fixWebViewResetsLocaleToUserDefault(context);
}
public WebViewEx(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
super(context, attrs, defStyleAttr, privateBrowsing);
fixWebViewResetsLocaleToUserDefault(context);
}
public void fixWebViewResetsLocaleToUserDefault(Context ctx) {
// issue details: https://issuetracker.google.com/issues/37113860
// also see: https://gist.github.com/amake/0ac7724681ac1c178c6f95a5b09f03ce
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
OsmandApplication app = (OsmandApplication) ctx.getApplicationContext();
app.checkPreferredLocale();
ctx.getResources().updateConfiguration(
new Configuration(app.getResources().getConfiguration()),
ctx.getResources().getDisplayMetrics());
}
}
}

View file

@ -17,7 +17,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.TextView;
@ -28,7 +27,6 @@ import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.Toolbar;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import androidx.core.view.MotionEventCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;

View file

@ -6,6 +6,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.Collator;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.IndexConstants;
import net.osmand.OsmAndCollator;
@ -21,6 +23,7 @@ import net.osmand.osm.PoiCategory;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
import net.osmand.search.core.SearchPhrase.NameStringMatcher;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
@ -84,7 +87,7 @@ public class TravelObfHelper implements TravelHelper {
}
@NonNull
public List<TravelArticle> loadPopularArticles() {
public synchronized List<TravelArticle> loadPopularArticles() {
String lang = app.getLanguage();
List<TravelArticle> popularArticles = new ArrayList<>();
for (BinaryMapIndexReader reader : getReaders()) {
@ -230,13 +233,27 @@ public class TravelObfHelper implements TravelHelper {
@NonNull
@Override
public List<WikivoyageSearchResult> search(@NonNull String searchQuery) {
public synchronized List<WikivoyageSearchResult> search(@NonNull String searchQuery) {
List<WikivoyageSearchResult> res = new ArrayList<>();
Map<File, List<Amenity>> amenityMap = new HashMap<>();
final String appLang = app.getLanguage();
final NameStringMatcher nm = new NameStringMatcher(searchQuery, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
for (BinaryMapIndexReader reader : getReaders()) {
try {
SearchRequest<Amenity> searchRequest = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, searchQuery,
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(), null, null);
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(), new ResultMatcher<Amenity>() {
@Override
public boolean publish(Amenity object) {
List<String> otherNames = object.getAllNames(false);
String localeName = object.getName(appLang);
return nm.matches(localeName) || nm.matches(otherNames);
}
@Override
public boolean isCancelled() {
return false;
}
}, null);
List<Amenity> amenities = reader.searchPoiByName(searchRequest);
if (!Algorithms.isEmpty(amenities)) {
@ -247,14 +264,35 @@ public class TravelObfHelper implements TravelHelper {
}
}
if (!Algorithms.isEmpty(amenityMap)) {
String appLang = app.getLanguage();
final boolean appLangEn = "en".equals(appLang);
for (Entry<File, List<Amenity>> entry : amenityMap.entrySet()) {
File file = entry.getKey();
for (Amenity amenity : entry.getValue()) {
Set<String> nameLangs = getLanguages(amenity);
if (nameLangs.contains(appLang)) {
TravelArticle article = readArticle(file, amenity, appLang, entry.getValue());
WikivoyageSearchResult r = new WikivoyageSearchResult(article, new ArrayList<>(nameLangs));
ArrayList<String> langs = new ArrayList<>(nameLangs);
Collections.sort(langs, new Comparator<String>() {
@Override
public int compare(String l1, String l2) {
if (l1.equals(appLang)) {
l1 = "1";
}
if (l2.equals(appLang)) {
l2 = "1";
}
if (!appLangEn) {
if (l1.equals("en")) {
l1 = "2";
}
if (l2.equals("en")) {
l2 = "2";
}
}
return l1.compareTo(l2);
}
});
WikivoyageSearchResult r = new WikivoyageSearchResult(article, langs);
res.add(r);
}
}

View file

@ -27,13 +27,14 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomnavigation.BottomNavigationView.OnNavigationItemSelectedListener;
import net.osmand.AndroidUtils;
import net.osmand.plus.AppInitializer;
import net.osmand.plus.LockableViewPager;
import net.osmand.plus.OnDialogFragmentResultListener;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.TabActivity;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.wikipedia.WikiArticleHelper;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
@ -314,7 +315,24 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
public void populateData() {
switchProgressBarVisibility(true);
new LoadWikivoyageData(this).execute();
if (app.isApplicationInitializing()) {
final WeakReference<WikivoyageExploreActivity> activityRef = new WeakReference<>(this);
app.getAppInitializer().addListener(new AppInitializer.AppInitializeListener() {
@Override
public void onProgress(AppInitializer init, AppInitializer.InitEvents event) {
}
@Override
public void onFinish(AppInitializer init) {
WikivoyageExploreActivity activity = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(activity)) {
new LoadWikivoyageData(activity).execute();
}
}
});
} else {
new LoadWikivoyageData(this).execute();
}
}
private void onDataLoaded() {
@ -364,8 +382,8 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
private static class LoadWikivoyageData extends AsyncTask<Void, Void, Void> {
private WeakReference<WikivoyageExploreActivity> activityRef;
private TravelHelper travelHelper;
private final WeakReference<WikivoyageExploreActivity> activityRef;
private final TravelHelper travelHelper;
LoadWikivoyageData(WikivoyageExploreActivity activity) {
travelHelper = activity.getMyApplication().getTravelHelper();
@ -381,7 +399,7 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
@Override
protected void onPostExecute(Void result) {
WikivoyageExploreActivity activity = activityRef.get();
if (activity != null) {
if (AndroidUtils.isActivityNotDestroyed(activity)) {
activity.onDataLoaded();
}
}