Merge branch 'master' of ssh://github.com/osmandapp/Osmand

This commit is contained in:
Alexey Pelykh 2014-03-04 19:33:04 +02:00
commit 40d5335dbd
37 changed files with 733 additions and 255 deletions

View file

@ -18,6 +18,7 @@ public class RenderingContext {
}
}
public int renderedState = 0;
// FIELDS OF THAT CLASS ARE USED IN C++
public boolean interrupted = false;
public boolean nightMode = false;

View file

@ -33,6 +33,7 @@ public class BinaryMapDataObject {
this.coordinates = coordinates;
}
public String getName(){
if(objectNames == null){
return "";

View file

@ -1541,6 +1541,10 @@ public class BinaryMapIndexReader {
return top;
}
public int getZoom() {
return zoom;
}
public void clearSearchResults(){
// recreate whole list to allow GC collect old data
searchResults = new ArrayList<T>();
@ -1598,6 +1602,10 @@ public class BinaryMapIndexReader {
}
}
public boolean isRegisteredRule(int id) {
return decodingRules.containsKey(id);
}
public void initMapEncodingRule(int type, int id, String tag, String val) {
if(!encodingRules.containsKey(tag)){
encodingRules.put(tag, new HashMap<String, Integer>());
@ -2070,7 +2078,7 @@ public class BinaryMapIndexReader {
}
public List<RouteSubregion> searchRouteIndexTree(SearchRequest<RouteDataObject> req, List<RouteSubregion> list) throws IOException {
public List<RouteSubregion> searchRouteIndexTree(SearchRequest<?> req, List<RouteSubregion> list) throws IOException {
req.numberOfVisitedObjects = 0;
req.numberOfAcceptedObjects = 0;
req.numberOfAcceptedSubtrees = 0;

View file

@ -674,7 +674,7 @@ public class BinaryMapRouteReaderAdapter {
}
}
public void initRouteTypesIfNeeded(SearchRequest<RouteDataObject> req, List<RouteSubregion> list) throws IOException {
public void initRouteTypesIfNeeded(SearchRequest<?> req, List<RouteSubregion> list) throws IOException {
for (RouteSubregion rs : list) {
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
initRouteRegion(rs.routeReg);
@ -736,7 +736,7 @@ public class BinaryMapRouteReaderAdapter {
}
}
public List<RouteSubregion> searchRouteRegionTree(SearchRequest<RouteDataObject> req, List<RouteSubregion> list,
public List<RouteSubregion> searchRouteRegionTree(SearchRequest<?> req, List<RouteSubregion> list,
List<RouteSubregion> toLoad) throws IOException {
for (RouteSubregion rs : list) {
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {

View file

@ -61,6 +61,10 @@ public class RouteDataObject {
return null;
}
public TIntObjectHashMap<String> getNames() {
return names;
}
public String getRef(){
if(names != null ) {
return names.get(region.refTypeRule);

View file

@ -98,7 +98,7 @@ public class BinaryRoutePlanner {
graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD;
if(TRACE_ROUTING){
printRoad(">", segment);
printRoad(">", segment, !forwardSearch);
}
if(segment instanceof FinalRouteSegment) {
if(RoutingContext.SHOW_GC_SIZE){
@ -136,9 +136,9 @@ public class BinaryRoutePlanner {
}
if (ctx.planRouteIn2Directions()) {
forwardSearch = (nonHeuristicSegmentsComparator.compare(graphDirectSegments.peek(), graphReverseSegments.peek()) < 0);
if (graphDirectSegments.size() * 1.3 > graphReverseSegments.size()) {
if (graphDirectSegments.size() * 2 > graphReverseSegments.size()) {
forwardSearch = false;
} else if (graphDirectSegments.size() < 1.3 * graphReverseSegments.size()) {
} else if (graphDirectSegments.size() < 2 * graphReverseSegments.size()) {
forwardSearch = true;
}
} else {
@ -236,14 +236,18 @@ public class BinaryRoutePlanner {
}
private void printRoad(String prefix, RouteSegment segment) {
private void printRoad(String prefix, RouteSegment segment, Boolean reverseWaySearch) {
String pr;
if(segment.parentRoute != null){
pr = " pend="+segment.parentSegmentEnd +" parent=" + segment.parentRoute.road;
} else {
pr = "";
}
println(prefix +"" + segment.road + " dir="+segment.getDirectionAssigned()+" ind=" + segment.getSegmentStart() +
String p = "";
if(reverseWaySearch != null) {
p = (reverseWaySearch?"B" : "F");
}
println(p+prefix +"" + segment.road + " dir="+segment.getDirectionAssigned()+" ind=" + segment.getSegmentStart() +
" ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
}
@ -304,7 +308,7 @@ public class BinaryRoutePlanner {
final RouteDataObject road = segment.road;
boolean initDirectionAllowed = checkIfInitialMovementAllowedOnSegment(ctx, reverseWaySearch, visitedSegments, segment, road);
if(TEST_SPECIFIC && road.getId() == TEST_ID ) {
printRoad(" ! " + +segment.distanceFromStart + " ", segment);
printRoad(" ! " + +segment.distanceFromStart + " ", segment, reverseWaySearch);
}
boolean directionAllowed = initDirectionAllowed;
if(!directionAllowed) {
@ -367,15 +371,23 @@ public class BinaryRoutePlanner {
// long nt = System.nanoTime();
// float devDistance = ctx.precalculatedRouteDirection.getDeviationDistance(x, y);
// // 1. linear method
// // segmentDist = segmentDist * (1 + ctx.precalculatedRouteDirection.getDeviationDistance(x, y) / ctx.config.DEVIATION_RADIUS);
// segmentDist = segmentDist * (1 + devDistance / ctx.config.DEVIATION_RADIUS);
// // 2. exponential method
// segmentDist = segmentDist * (float) Math.pow(1.5, devDistance / 500);
// 3. next by method
// segmentDist = devDistance ;
// ctx.timeNanoToCalcDeviation += (System.nanoTime() - nt);
}
// could be expensive calculation
// 3. get intersected ways
final RouteSegment roadNext = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
float distStartObstacles = segment.distanceFromStart + calculateTimeWithObstacles(ctx, road, segmentDist , obstaclesTime);
if(ctx.precalculatedRouteDirection != null && ctx.precalculatedRouteDirection.isFollowNext()) {
// reset to f
// distStartObstacles = 0;
// more precise but slower
distStartObstacles = ctx.precalculatedRouteDirection.getDeviationDistance(x, y) / ctx.getRouter().getMaxDefaultSpeed();
}
// We don't check if there are outgoing connections
previous = processIntersections(ctx, graphSegments, visitedSegments, distStartObstacles,
@ -433,7 +445,7 @@ public class BinaryRoutePlanner {
frs.opposite = opposite;
graphSegments.add(frs);
if(TRACE_ROUTING){
printRoad(" >> Final segment : ", frs);
printRoad(" >> Final segment : ", frs, reverseWaySearch);
}
return true;
}
@ -634,7 +646,7 @@ public class BinaryRoutePlanner {
printRoad(" !? distFromStart=" + +distFromStart + " from " + segment.getRoad().getId() +
" dir=" + segment.getDirectionAssigned() +
" distToEnd=" + distanceToEnd +
" segmentPoint="+ segmentPoint + " -- ", next);
" segmentPoint="+ segmentPoint + " -- ", next, true);
}
if (!visitedSegments.containsKey(calculateRoutePointId(next, next.isPositive()))) {
if (next.getParentRoute() == null
@ -643,7 +655,7 @@ public class BinaryRoutePlanner {
next.distanceFromStart = distFromStart;
next.distanceToEnd = distanceToEnd;
if (TRACE_ROUTING) {
printRoad(" >>", next);
printRoad(" >>", next, null);
}
// put additional information to recover whole route after
next.setParentRoute(segment);

View file

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List;
import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.data.QuadPoint;
import net.osmand.data.QuadRect;
import net.osmand.data.QuadTree;
@ -18,6 +19,7 @@ public class PrecalculatedRouteDirection {
private float minSpeed;
private float maxSpeed;
private float[] tms;
private boolean followNext;
private static final int SHIFT = (1 << (31 - 17));
private static final int[] SHIFTS = new int[]{1 << (31 - 15), 1 << (31 - 13), 1 << (31 - 12),
1 << (31 - 11), 1 << (31 - 7)};
@ -42,6 +44,11 @@ public class PrecalculatedRouteDirection {
init(ls);
}
private PrecalculatedRouteDirection(LatLon[] ls, float maxSpeed) {
this.maxSpeed = maxSpeed;
init(ls);
}
private PrecalculatedRouteDirection(PrecalculatedRouteDirection parent, int s1, int s2) {
this.minSpeed = parent.minSpeed;
this.maxSpeed = parent.maxSpeed;
@ -81,6 +88,10 @@ public class PrecalculatedRouteDirection {
return null;
}
public static PrecalculatedRouteDirection build(LatLon[] ls, float maxSpeed){
return new PrecalculatedRouteDirection(ls, maxSpeed);
}
private void init(List<RouteSegmentResult> ls) {
TIntArrayList px = new TIntArrayList();
@ -105,6 +116,19 @@ public class PrecalculatedRouteDirection {
init(px, py, speedSegments);
}
private void init(LatLon[] ls) {
TIntArrayList px = new TIntArrayList();
TIntArrayList py = new TIntArrayList();
List<Float> speedSegments = new ArrayList<Float>();
for (LatLon s : ls) {
float routeSpd = maxSpeed; // (s.getDistance() / s.getRoutingTime())
px.add(MapUtils.get31TileNumberX(s.getLongitude()));
py.add(MapUtils.get31TileNumberY(s.getLatitude()));
speedSegments.add(routeSpd);
}
init(px, py, speedSegments);
}
private void init(TIntArrayList px, TIntArrayList py, List<Float> speedSegments) {
float totaltm = 0;
List<Float> times = new ArrayList<Float>();
@ -217,6 +241,15 @@ public class PrecalculatedRouteDirection {
return ((long) x31) << 32l + ((long)y31);
}
public void setFollowNext(boolean followNext) {
this.followNext = followNext;
}
public boolean isFollowNext() {
return followNext;
}
public PrecalculatedRouteDirection adopt(RoutingContext ctx) {
int ind1 = getIndex(ctx.startX, ctx.startY);
int ind2 = getIndex(ctx.targetX, ctx.targetY);
@ -235,6 +268,7 @@ public class PrecalculatedRouteDirection {
// routeDirection.startY31 = ctx.startY;
routeDirection.endPoint = calc(ctx.targetX, ctx.targetX);
routeDirection.endFinishTime = (float) BinaryRoutePlanner.squareRootDist(pointsX[ind2], pointsY[ind2], ctx.targetX, ctx.targetY) / maxSpeed;
routeDirection.followNext = followNext;
// routeDirection.endX31 = ctx.targetX;
// routeDirection.endY31 = ctx.targetY;

View file

@ -84,13 +84,17 @@ public class RoutePlannerFrontEnd {
}
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates) throws IOException, InterruptedException {
return searchRoute(ctx, start, end, intermediates, null);
}
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates,
PrecalculatedRouteDirection routeDirection) throws IOException, InterruptedException {
if(ctx.calculationProgress == null) {
ctx.calculationProgress = new RouteCalculationProgress();
}
boolean intermediatesEmpty = intermediates == null || intermediates.isEmpty();
PrecalculatedRouteDirection routeDirection = null;
double maxDistance = MapUtils.getDistance(start, end);
if(!intermediatesEmpty) {
LatLon b = start;
@ -99,7 +103,8 @@ public class RoutePlannerFrontEnd {
b = l;
}
}
if(ctx.calculationMode == RouteCalculationMode.COMPLEX && maxDistance > Math.max(ctx.config.DEVIATION_RADIUS * 4, 30000)) {
if(ctx.calculationMode == RouteCalculationMode.COMPLEX && routeDirection == null
&& maxDistance > Math.max(ctx.config.DEVIATION_RADIUS * 4, 30000)) {
RoutingContext nctx = buildRoutingContext(ctx.config, ctx.nativeLib, ctx.getMaps(), RouteCalculationMode.BASE);
nctx.calculationProgress = ctx.calculationProgress ;
List<RouteSegmentResult> ls = searchRoute(nctx, start, end, intermediates);

View file

@ -9,6 +9,7 @@ import java.util.Iterator;
import java.util.List;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment;
@ -295,11 +296,30 @@ public class RouteResultPreparation {
additional.append("description = \"").append(res.getDescription()).append("\" ");
println(MessageFormat.format("\t<segment id=\"{0}\" start=\"{1}\" end=\"{2}\" {3}/>", (res.getObject().getId()) + "",
res.getStartPointIndex() + "", res.getEndPointIndex() + "", additional.toString()));
printAdditionalPointInfo(res);
}
}
println("</test>");
}
private void printAdditionalPointInfo(RouteSegmentResult res) {
boolean plus = res.getStartPointIndex() < res.getEndPointIndex();
for(int k = res.getStartPointIndex(); k != res.getEndPointIndex(); ) {
int[] tp = res.getObject().getPointTypes(k);
if(tp != null) {
for(int t = 0; t < tp.length; t++) {
RouteTypeRule rr = res.getObject().region.quickGetEncodingRule(tp[t]);
println("\t<point tag=\""+rr.getTag()+"\"" + " value=\""+rr.getValue()+"\"/>");
}
}
if(plus) {
k++;
} else {
k--;
}
}
}
private void addTurnInfo(boolean leftside, List<RouteSegmentResult> result) {
int prevSegment = -1;

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -9,6 +9,15 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="android_19_location_disabled">Since KitKat version you can\'t download and update map in previous storage location (%s). Do you want to change to allowed one and copy all files there?
\n Note : old files will stay untouched.
\n Note : it will not be possible to share files between OsmAnd and OsmAnd+. </string>
<string name="application_dir_change_warning2">OsmAnd could try to move the data to new destination. Do you want it?</string>
<string name="copying_osmand_one_file_descr">Copying file (%s) to new destination...</string>
<string name="copying_osmand_files_descr">Copying OsmAnd files to new destination (%s)</string>
<string name="copying_osmand_files">Copying OsmAnd files</string>
<string name="calculate_osmand_route_gpx">Calculate OsmAnd offline route</string>
<string name="app_mode_truck">Truck</string>
<string name="guidance_preferences_descr">Navigation preferences</string>
<string name="routing_preferences_descr">Routing preferences</string>
<string name="speech_rate_descr">Specify speech rate for TTS</string>
@ -1250,7 +1259,7 @@ Afghanistan, Albania, Algeria, Andorra, Angola, Anguilla, Antigua and Barbuda, A
<string name="osmand_routing_experimental">OsmAnd offline navigation is an experimental feature and it does not work for distances of more than about 20 km.\n\nNavigation service is temporarily switched to online CloudMade.</string>
<string name="specified_dir_doesnt_exist">Can not find specified directory.</string>
<string name="application_dir">Storage directory</string>
<string name="application_dir_change_warning">Changing the storage directory will not move or delete the data. This must be performed separately and outside OsmAnd. Continue anyway?</string>
<string name="osmand_net_previously_installed">A previous OsmAnd version is installed. All offline data will be supported by the new application. But Favorite points should be exported in the old application and later imported by the new one.</string>
<string name="build_installed">Build {0} successfully installed ({1}).</string>
<string name="downloading_build">Downloading build&#8230;</string>

View file

@ -45,6 +45,10 @@ public class ApplicationMode {
carLocation().parent(CAR).
icon(R.drawable.ic_motorcycle, R.drawable.ic_action_motorcycle_light, R.drawable.ic_action_motorcycle_dark).reg();
public static final ApplicationMode TRUCK = create(R.string.app_mode_truck, "truck").speed(15.3f, 40).
carLocation().parent(CAR).
icon(R.drawable.ic_truck, R.drawable.ic_action_truck_light, R.drawable.ic_action_truck_dark).reg();
static {
ApplicationMode[] exceptPedestrian = new ApplicationMode[] { DEFAULT, CAR, BICYCLE, BOAT, AIRCRAFT };
ApplicationMode[] exceptAirBoat = new ApplicationMode[] { DEFAULT, CAR, BICYCLE};

View file

@ -8,8 +8,8 @@ import net.osmand.CallbackWithObject;
import net.osmand.Location;
import net.osmand.access.AccessibleToast;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routing.RouteProvider;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
import net.osmand.plus.routing.RoutingHelper;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@ -72,8 +72,11 @@ public class OsmAndLocationSimulation {
new CallbackWithObject<GPXUtilities.GPXFile>() {
@Override
public boolean processResult(GPXUtilities.GPXFile result) {
GPXRouteParams prms = new RouteProvider.GPXRouteParams(result, false, ch
.isChecked(), app.getSettings());
GPXRouteParamsBuilder builder = GPXRouteParams.GPXRouteParamsBuilder.newBuilder(result, app.getSettings());
if(ch.isChecked()){
builder.announceWaypoints();
}
GPXRouteParams prms = builder.build();
startAnimationThread(app.getRoutingHelper(), ma, prms.getPoints(), true,
speedup.getProgress() + 1);
return true;

View file

@ -651,7 +651,7 @@ public class OsmandSettings {
public float getSettingsZoomScale(float density){
// by default scale between [0, 1[ density (because of lots map complains)
return MAP_ZOOM_SCALE_BY_DENSITY.get() + (float)Math.min(Math.sqrt(Math.max(0, density - 1)), 1);
return MAP_ZOOM_SCALE_BY_DENSITY.get() + (float)Math.sqrt(Math.max(0, density - 1));
}
@ -739,6 +739,7 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache();
public final OsmandPreference<Boolean> SPEAK_GPX_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache();
public final OsmandPreference<Boolean> CALC_GPX_ROUTE = new BooleanPreference("calc_gpx_route", false).makeGlobal().cache();
@ -992,8 +993,22 @@ public class OsmandSettings {
public static final String EXTERNAL_STORAGE_DIR = "external_storage_dir"; //$NON-NLS-1$
public File getExternalStorageDirectory() {
return new File(settingsAPI.getString(globalPreferences,EXTERNAL_STORAGE_DIR,
ctx.getExternalServiceAPI().getExternalStorageDirectory()));
String defaultLocation = ctx.getExternalServiceAPI().getExternalStorageDirectory();
if(Build.VERSION.SDK_INT >= VERSION_DEFAULTLOCATION_CHANGED && !new File(defaultLocation, IndexConstants.APP_DIR).exists()) {
defaultLocation += "/Android/data/" + ctx.getPackageName();
}
return new File(settingsAPI.getString(globalPreferences, EXTERNAL_STORAGE_DIR,
defaultLocation));
}
public static final int VERSION_DEFAULTLOCATION_CHANGED = 19;
public String getDefaultExternalStorageLocation() {
String defaultLocation = ctx.getExternalServiceAPI().getExternalStorageDirectory();
if(Build.VERSION.SDK_INT >= VERSION_DEFAULTLOCATION_CHANGED) {
defaultLocation += "/Android/data/" + ctx.getPackageName();
}
return defaultLocation;
}
public boolean setExternalStorageDirectory(String externalStorageDir) {

View file

@ -11,6 +11,8 @@ import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import net.osmand.IndexConstants;
import net.osmand.access.AccessibleAlertBuilder;
import net.osmand.access.AccessibleToast;
import net.osmand.plus.ClientContext;
import net.osmand.plus.OsmandApplication;
@ -18,6 +20,7 @@ import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.SettingsGeneralActivity.MoveFilesToDifferentDirectory;
import net.osmand.plus.base.BasicProgressAsyncTask;
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
import net.osmand.plus.download.DownloadActivityType;
@ -36,6 +39,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask.Status;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
@ -89,6 +93,7 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
private TextView progressPercent;
private ImageView cancel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -162,7 +167,10 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
DownloadIndexAdapter adapter = new DownloadIndexAdapter(this, list);
setListAdapter(adapter);
if(getMyApplication().getResourceManager().getIndexFileNames().isEmpty()) {
boolean showedDialog = SuggestExternalDirectoryDialog.showDialog(this, null, null);
boolean showedDialog = false;
if(Build.VERSION.SDK_INT < OsmandSettings.VERSION_DEFAULTLOCATION_CHANGED) {
SuggestExternalDirectoryDialog.showDialog(this, null, null);
}
if(!showedDialog) {
showDialogOfFreeDownloadsIfNeeded();
}
@ -182,7 +190,39 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
return true;
}
});
if(Build.VERSION.SDK_INT >= OsmandSettings.VERSION_DEFAULTLOCATION_CHANGED) {
if(!settings.getExternalStorageDirectory().getAbsolutePath().equals(settings.getDefaultExternalStorageLocation())) {
AccessibleAlertBuilder ab = new AccessibleAlertBuilder(this);
ab.setMessage(getString(R.string.android_19_location_disabled, settings.getExternalStorageDirectory()));
ab.setPositiveButton(R.string.default_buttons_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
copyFilesForAndroid19();
}
});
ab.setNegativeButton(R.string.default_buttons_cancel, null);
ab.show();
}
}
}
private void copyFilesForAndroid19() {
final String newLoc = settings.getDefaultExternalStorageLocation();
MoveFilesToDifferentDirectory task =
new MoveFilesToDifferentDirectory(DownloadIndexActivity.this,
new File(settings.getExternalStorageDirectory(), IndexConstants.APP_DIR),
new File(newLoc, IndexConstants.APP_DIR)) {
protected Boolean doInBackground(Void[] params) {
Boolean result = super.doInBackground(params);
if(result) {
settings.setExternalStorageDirectory(newLoc);
getMyApplication().getResourceManager().resetStoreDirectory();
getMyApplication().getResourceManager().reloadIndexes(progress) ;
}
return result;
};
};
task.execute();
}
@Override

View file

@ -367,10 +367,10 @@ public class MapActivity extends AccessibleActivity {
public void changeZoom(int stp){
// delta = Math.round(delta * OsmandMapTileView.ZOOM_DELTA) * OsmandMapTileView.ZOOM_DELTA_1;
boolean changeLocation = true;
if (settings.AUTO_ZOOM_MAP.get() == AutoZoomMap.NONE) {
changeLocation = false;
}
boolean changeLocation = false;
// if (settings.AUTO_ZOOM_MAP.get() == AutoZoomMap.NONE) {
// changeLocation = false;
// }
final int newZoom = mapView.getZoom() + stp;
mapView.getAnimatedDraggingThread().startZooming(newZoom, changeLocation);
if (app.accessibilityEnabled())

View file

@ -4,30 +4,27 @@ package net.osmand.plus.activities;
import java.io.File;
import java.util.Date;
import android.content.SharedPreferences;
import android.widget.ScrollView;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.rastermaps.SettingsRasterMapsActivity;
import net.osmand.util.Algorithms;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceClickListener;
import android.text.SpannableString;
import android.text.format.DateFormat;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.TypedValue;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
public class SettingsActivity extends SettingsBaseActivity {

View file

@ -2,23 +2,32 @@ package net.osmand.plus.activities;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import net.osmand.CallbackWithObject;
import net.osmand.IProgress;
import net.osmand.IndexConstants;
import net.osmand.access.AccessibleToast;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.ClientContext;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandSettings.DrivingRegion;
import net.osmand.plus.OsmandSettings.MetricsConstants;
import net.osmand.plus.ProgressDialogImplementation;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
import net.osmand.plus.render.NativeOsmandLibrary;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.render.RenderingRulesStorage;
import net.osmand.util.Algorithms;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
@ -101,12 +110,12 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
dialog.dismiss();
showOtherDialog();
}
}, new Runnable() {
}, new CallbackWithObject<String>() {
@Override
public void run() {
Toast.makeText(SettingsGeneralActivity.this, getString(R.string.application_dir_change_warning),
Toast.LENGTH_LONG).show();
reloadIndexes();
public boolean processResult(String result) {
warnAboutChangingStorage(result);
return true;
}
});
return false;
@ -265,6 +274,97 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
return true;
}
public static class MoveFilesToDifferentDirectory extends AsyncTask<Void, Void, Boolean> {
private File to;
private Context ctx;
private File from;
protected ProgressDialogImplementation progress;
private Runnable runOnSuccess;
public MoveFilesToDifferentDirectory(Context ctx, File from, File to) {
this.ctx = ctx;
this.from = from;
this.to = to;
}
public void setRunOnSuccess(Runnable runOnSuccess) {
this.runOnSuccess = runOnSuccess;
}
@Override
protected void onPreExecute() {
progress = ProgressDialogImplementation.createProgressDialog(
ctx, ctx.getString(R.string.copying_osmand_files),
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPostExecute(Boolean result) {
if(result != null && result.booleanValue() && runOnSuccess != null) {
runOnSuccess.run();
}
if(progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
}
private void movingFiles(File f, File t, int depth) throws IOException {
if(depth <= 2) {
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
}
if (f.isDirectory()) {
t.mkdirs();
File[] lf = f.listFiles();
if (lf != null) {
for (int i = 0; i < lf.length; i++) {
if (lf[i] != null) {
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
}
}
}
f.delete();
} else if (f.isFile()) {
if(t.exists()) {
Algorithms.removeAllFiles(t);
}
boolean rnm = false;
try {
rnm = f.renameTo(t);
} catch(RuntimeException e) {
}
if (!rnm) {
FileInputStream fin = new FileInputStream(f);
FileOutputStream fout = new FileOutputStream(t);
try {
Algorithms.streamCopy(fin, fout);
} finally {
fin.close();
fout.close();
}
f.delete();
}
}
if(depth <= 2) {
progress.finishTask();
}
}
@Override
protected Boolean doInBackground(Void... params) {
to.mkdirs();
try {
movingFiles(from, to, 0);
} catch (IOException e) {
Toast.makeText(ctx, R.string.input_output_error, Toast.LENGTH_LONG);
return false;
}
return true;
}
}
private void warnAboutChangingStorage(final String newValue) {
final String newDir = newValue != null ? newValue.trim() : newValue;
File path = new File(newDir);
@ -273,22 +373,42 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
AccessibleToast.makeText(this, R.string.specified_dir_doesnt_exist, Toast.LENGTH_LONG).show();
return;
}
Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.application_dir_change_warning));
builder.setMessage(getString(R.string.application_dir_change_warning2));
builder.setPositiveButton(R.string.default_buttons_yes, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MoveFilesToDifferentDirectory task =
new MoveFilesToDifferentDirectory(SettingsGeneralActivity.this,
new File(settings.getExternalStorageDirectory(), IndexConstants.APP_DIR), new File(newDir,
IndexConstants.APP_DIR));
task.setRunOnSuccess(new Runnable() {
@Override
public void run() {
updateSettingsToNewDir(newDir);
}
});
task.execute();
}
});
builder.setNeutralButton(R.string.default_buttons_no, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateSettingsToNewDir(newDir);
}
});
builder.setNegativeButton(R.string.default_buttons_cancel, null);
builder.show();
}
private void updateSettingsToNewDir(final String newDir) {
// edit the preference
settings.setExternalStorageDirectory(newDir);
getMyApplication().getResourceManager().resetStoreDirectory();
reloadIndexes();
updateApplicationDirTextAndSummary();
}
});
builder.setNegativeButton(R.string.default_buttons_cancel, null);
builder.show();
}
public void reloadIndexes() {
setSupportProgressBarIndeterminateVisibility(true);

View file

@ -233,7 +233,7 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
if (MORE_VALUE.equals(newValue)) {
// listPref.set(oldValue); // revert the change..
final Intent intent = new Intent(this, DownloadIndexActivity.class);
intent.putExtra(DownloadIndexActivity.FILTER_KEY, "voice");
intent.putExtra(DownloadIndexActivity.FILTER_KEY, getString(R.string.voice));
startActivity(intent);
} else {
super.onPreferenceChange(preference, newValue);

View file

@ -19,6 +19,7 @@ import net.osmand.plus.TargetPointsHelper;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
import net.osmand.plus.routing.RouteProvider.RouteService;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@ -66,10 +67,11 @@ public class NavigateAction {
public boolean navigateUsingGPX(final ApplicationMode appMode, final LatLon endForRouting,
final GPXFile result) {
Builder builder = new AlertDialog.Builder(mapActivity);
final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get()};
final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get(), settings.CALC_GPX_ROUTE.get()};
builder.setMultiChoiceItems(new String[] { getString(R.string.gpx_option_reverse_route),
getString(R.string.gpx_option_destination_point), getString(R.string.gpx_option_from_start_point),
getString(R.string.announce_gpx_waypoints) }, props,
getString(R.string.announce_gpx_waypoints),
getString(R.string.calculate_osmand_route_gpx)}, props,
new OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
@ -83,9 +85,20 @@ public class NavigateAction {
boolean passWholeWay = props[2];
boolean useDestination = props[1];
boolean announceGpxWpt = props[3];
boolean calculateOsmAndRoute = props[4];
settings.SPEAK_GPX_WPT.set(announceGpxWpt);
GPXRouteParams gpxRoute = new GPXRouteParams(result, reverse, announceGpxWpt, settings);
settings.CALC_GPX_ROUTE.set(calculateOsmAndRoute);
GPXRouteParamsBuilder bld = GPXRouteParamsBuilder.newBuilder(result, settings);
if(reverse) {
bld.reverse();
}
if(announceGpxWpt) {
bld.announceWaypoints();
}
if(calculateOsmAndRoute) {
bld.calculateOsmAndRoute();
}
GPXRouteParams gpxRoute = bld.build();
Location loc = getLastKnownLocation();
if(passWholeWay && loc != null){
gpxRoute.setStartPoint(loc);

View file

@ -16,6 +16,7 @@ import net.osmand.plus.R;
import net.osmand.plus.TargetPointsHelper;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
@ -123,14 +124,26 @@ public class FailSafeFuntions {
@Override
protected void onPostExecute(GPXFile result) {
final GPXRouteParams gpxRoute = result == null ? null : new GPXRouteParams(result, false,
settings.SPEAK_GPX_WPT.get(), settings);
final GPXRouteParams gpxRoute;
if (result != null) {
GPXRouteParamsBuilder builder = GPXRouteParamsBuilder.newBuilder(result, settings);
if (settings.SPEAK_GPX_WPT.get()) {
builder.announceWaypoints();
}
if(settings.CALC_GPX_ROUTE.get()) {
builder.calculateOsmAndRoute();
}
gpxRoute = builder.build();
} else {
gpxRoute = null;
}
LatLon endPoint = pointToNavigate != null ? pointToNavigate : gpxRoute.getLastPoint();
net.osmand.Location startPoint = gpxRoute == null ? null : gpxRoute.getStartPointForRoute();
if (endPoint == null) {
notRestoreRoutingMode(ma, app);
} else {
ma.followRoute(settings.getApplicationMode(), endPoint, targetPoints.getIntermediatePoints(), startPoint, gpxRoute);
ma.followRoute(settings.getApplicationMode(), endPoint,
targetPoints.getIntermediatePoints(), startPoint, gpxRoute);
}
}
};

View file

@ -4,6 +4,7 @@ import java.io.InputStream;
import java.util.HashSet;
import java.util.Locale;
import net.osmand.CallbackWithObject;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
@ -17,7 +18,7 @@ public class SuggestExternalDirectoryDialog {
public static boolean showDialog(Activity a, final DialogInterface.OnClickListener otherListener,
final Runnable reloadListener){
final CallbackWithObject<String> selector){
final boolean showOther = otherListener != null;
final OsmandApplication app = (OsmandApplication) a.getApplication();
Builder bld = new AlertDialog.Builder(a);
@ -46,10 +47,11 @@ public class SuggestExternalDirectoryDialog {
otherListener.onClick(dialog, which);
} else {
dialog.dismiss();
if(selector != null) {
selector.processResult(extMounts[which]);
} else {
app.getSettings().setExternalStorageDirectory(extMounts[which]);
app.getResourceManager().resetStoreDirectory();
if(reloadListener != null) {
reloadListener.run();
}
}
}

View file

@ -10,6 +10,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import net.osmand.AndroidUtils;
@ -182,7 +183,7 @@ public class DownloadOsmandIndexesHelper {
}
}
private static String reparseDate(Context ctx, String date) {
protected static String reparseDate(Context ctx, String date) {
try {
Date d = simpleDateFormat.parse(date);
return AndroidUtils.formatDate(ctx, d.getTime());

View file

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
@ -218,7 +219,9 @@ public class IndexItem implements Comparable<IndexItem> {
entry.zipStream = zipStream;
entry.unzipFolder = unzipDir;
try {
Date d = DateFormat.getDateFormat((Context) ctx).parse(date);
final java.text.DateFormat format = DateFormat.getDateFormat((Context) ctx);
format.setTimeZone(TimeZone.getTimeZone("GMT+01:00"));
Date d = format.parse(date);
entry.dateModified = d.getTime();
} catch (ParseException e1) {
log.error("ParseException", e1);

View file

@ -301,7 +301,13 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
OsmBaseStorage st = new OsmBaseStorage();
st.parseOSM(new ByteArrayInputStream(res.getBytes("UTF-8")), null, null, true); //$NON-NLS-1$
EntityId id = new Entity.EntityId(EntityType.NODE, nodeId);
// Node entity = (Node) st.getRegisteredEntities().get(id);
Node entity = (Node) st.getRegisteredEntities().get(id);
// merge non existing tags
for(String rtag : entity.getTagKeySet()) {
if(!n.getTagKeySet().contains(rtag)) {
n.putTag(rtag, entity.getTag(rtag));
}
}
entityInfo = st.getRegisteredEntityInfo().get(id);
return entityInfo;
}

View file

@ -1,9 +1,11 @@
package net.osmand.plus.render;
import gnu.trove.iterator.TIntObjectIterator;
import gnu.trove.list.TLongList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.list.array.TLongArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.TLongSet;
import gnu.trove.set.hash.TLongHashSet;
@ -20,18 +22,19 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.osmand.IProgress;
import net.osmand.ResultMatcher;
import net.osmand.NativeLibrary.NativeSearchResult;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.access.AccessibleToast;
import net.osmand.binary.BinaryMapDataObject;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
import net.osmand.binary.RouteDataObject;
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
import net.osmand.binary.RouteDataObject;
import net.osmand.data.QuadPointDouble;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
@ -66,10 +69,10 @@ public class MapRenderRepositories {
// It is needed to not draw object twice if user have map index that intersects by boundaries
public static boolean checkForDuplicateObjectIds = true;
private final static Log log = PlatformUtil.getLog(MapRenderRepositories.class);
private final OsmandApplication context;
private final static int BASEMAP_ZOOM = 11;
private final static int zoomOnlyForBasemaps = 11;
static int zoomForBaseRouteRendering = 14;
private Handler handler;
private Map<String, BinaryMapIndexReader> files = new ConcurrentHashMap<String, BinaryMapIndexReader>();
private Set<String> nativeFiles = new HashSet<String>();
@ -91,6 +94,8 @@ public class MapRenderRepositories {
private RotatedTileBox prevBmpLocation = null;
// already rendered bitmap
private Bitmap prevBmp;
// to track necessity of map download (1 (if basemap) + 2 (if normal map)
private int previousRenderedState;
// location of rendered bitmap
private RotatedTileBox bmpLocation = null;
@ -98,6 +103,7 @@ public class MapRenderRepositories {
private Bitmap bmp;
// Field used in C++
private boolean interrupted = false;
private int renderedState = 0; // (1 (if basemap) + 2 (if normal map)
private RenderingContext currentRenderingContext;
private SearchRequest<BinaryMapDataObject> searchRequest;
private OsmandSettings prefs;
@ -252,7 +258,7 @@ public class MapRenderRepositories {
}
NativeSearchResult resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, renderingReq,
checkForDuplicateObjectIds, this, /*context.getString(R.string.switch_to_raster_map_to_see)*/ "");
checkForDuplicateObjectIds, this, "");
if (checkWhetherInterrupted()) {
resultHandler.deleteNativeResult();
return false;
@ -268,6 +274,77 @@ public class MapRenderRepositories {
return true;
}
private void readRouteDataAsMapObjects(SearchRequest<BinaryMapDataObject> sr, BinaryMapIndexReader c,
final ArrayList<BinaryMapDataObject> tempResult, final TLongSet ids) {
final boolean basemap = c.isBasemap();
try {
for (RouteRegion reg : c.getRoutingIndexes()) {
List<RouteSubregion> parent = sr.getZoom() < 15 ? reg.getBaseSubregions() : reg.getSubregions();
List<RouteSubregion> searchRouteIndexTree = c.searchRouteIndexTree(sr, parent);
final MapIndex nmi = new MapIndex();
c.loadRouteIndexData(searchRouteIndexTree, new ResultMatcher<RouteDataObject>() {
@Override
public boolean publish(RouteDataObject r) {
if (basemap) {
renderedState |= 1;
} else {
renderedState |= 2;
}
if (checkForDuplicateObjectIds && !basemap) {
if (ids.contains(r.getId()) && r.getId() > 0) {
// do not add object twice
return false;
}
ids.add(r.getId());
}
int[] coordinantes = new int[r.getPointsLength() * 2];
int[] roTypes = r.getTypes();
for(int k = 0; k < roTypes.length; k++) {
int type = roTypes[k];
registerMissingType(nmi, r, type);
}
for(int k = 0; k < coordinantes.length/2; k++ ) {
coordinantes[2 * k] = r.getPoint31XTile(k);
coordinantes[2 * k + 1] = r.getPoint31YTile(k);
}
BinaryMapDataObject mo = new BinaryMapDataObject(coordinantes, roTypes, new int[0][], r.getId());
TIntObjectHashMap<String> names = r.getNames();
if(names != null) {
TIntObjectIterator<String> it = names.iterator();
while(it.hasNext()) {
it.advance();
registerMissingType(nmi, r, it.key());
mo.putObjectName(it.key(), it.value());
}
}
mo.setMapIndex(nmi);
tempResult.add(mo);
return false;
}
private void registerMissingType(final MapIndex nmi, RouteDataObject r, int type) {
if (!nmi.isRegisteredRule(type)) {
RouteTypeRule rr = r.region.quickGetEncodingRule(type);
String tag = rr.getTag();
int additional = ("highway".equals(tag) || "route".equals(tag) || "railway".equals(tag)
|| "aeroway".equals(tag) || "aerialway".equals(tag)) ? 0 : 1;
nmi.initMapEncodingRule(additional, type, rr.getTag(), rr.getValue());
}
}
@Override
public boolean isCancelled() {
return !interrupted;
}
});
}
} catch (IOException e) {
log.debug("Search failed " + c.getRegionNames(), e); //$NON-NLS-1$
}
}
private boolean loadVectorData(QuadRect dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq) {
double cBottomLatitude = dataBox.bottom;
double cTopLatitude = dataBox.top;
@ -277,18 +354,102 @@ public class MapRenderRepositories {
long now = System.currentTimeMillis();
System.gc(); // to clear previous objects
int count = 0;
ArrayList<BinaryMapDataObject> tempResult = new ArrayList<BinaryMapDataObject>();
ArrayList<BinaryMapDataObject> basemapResult = new ArrayList<BinaryMapDataObject>();
TLongSet ids = new TLongHashSet();
int[] count = new int[]{0};
boolean[] ocean = new boolean[]{false};
boolean[] land = new boolean[]{false};
List<BinaryMapDataObject> coastLines = new ArrayList<BinaryMapDataObject>();
List<BinaryMapDataObject> basemapCoastLines = new ArrayList<BinaryMapDataObject>();
int leftX = MapUtils.get31TileNumberX(cLeftLongitude);
int rightX = MapUtils.get31TileNumberX(cRightLongitude);
int bottomY = MapUtils.get31TileNumberY(cBottomLatitude);
int topY = MapUtils.get31TileNumberY(cTopLatitude);
BinaryMapIndexReader.SearchFilter searchFilter = new BinaryMapIndexReader.SearchFilter() {
TLongSet ids = new TLongHashSet();
MapIndex mi = readMapObjectsForRendering(zoom, renderingReq, tempResult, basemapResult, ids, count, ocean,
land, coastLines, basemapCoastLines, leftX, rightX, bottomY, topY);
int renderRouteDataFile = 0;
if (renderingReq.searchRenderingAttribute("showRoadMapsAttribute")) {
renderRouteDataFile = renderingReq.getIntPropertyValue(renderingReq.ALL.R_ATTR_INT_VALUE);
}
if (checkWhetherInterrupted()) {
return false;
}
if (renderRouteDataFile >= 0 && zoom >= zoomOnlyForBasemaps ) {
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, null);
for (BinaryMapIndexReader c : files.values()) {
// false positive case when we have 2 sep maps Country-roads & Country
if(c.getMapIndexes().size() == 0 || renderRouteDataFile == 1) {
readRouteDataAsMapObjects(searchRequest, c, tempResult, ids);
}
}
log.info(String.format("Route objects %s", tempResult.size() +""));
}
String coastlineTime = "";
boolean addBasemapCoastlines = true;
boolean emptyData = zoom > zoomOnlyForBasemaps && tempResult.isEmpty() && coastLines.isEmpty();
boolean basemapMissing = zoom <= zoomOnlyForBasemaps && basemapCoastLines.isEmpty() && mi == null;
boolean detailedLandData = zoom >= zoomForBaseRouteRendering && tempResult.size() > 0 && renderRouteDataFile < 0;
if (!coastLines.isEmpty()) {
long ms = System.currentTimeMillis();
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
basemapCoastLines.isEmpty(), true, tempResult);
addBasemapCoastlines = (!coastlinesWereAdded && !detailedLandData) || zoom <= zoomOnlyForBasemaps;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
} else {
addBasemapCoastlines = !detailedLandData;
}
if (addBasemapCoastlines) {
long ms = System.currentTimeMillis();
boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom,
true, true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
}
if (addBasemapCoastlines && mi != null) {
BinaryMapDataObject o = new BinaryMapDataObject(new int[]{leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX,
topY}, new int[]{ocean[0] && !land[0] ? mi.coastlineEncodingType : (mi.landEncodingType)}, null, -1);
o.setMapIndex(mi);
tempResult.add(o);
}
if (emptyData || basemapMissing) {
// message
MapIndex mapIndex;
if (!tempResult.isEmpty()) {
mapIndex = tempResult.get(0).getMapIndex();
} else {
mapIndex = new MapIndex();
mapIndex.initMapEncodingRule(0, 1, "natural", "coastline");
mapIndex.initMapEncodingRule(0, 2, "name", "");
}
}
if (zoom <= zoomOnlyForBasemaps || emptyData) {
tempResult.addAll(basemapResult);
}
if (count[0] > 0) {
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom));
log.info(String.format("Searching: %s ms %s (%s results found)", System.currentTimeMillis() - now, coastlineTime, count[0])); //$NON-NLS-1$
}
cObjects = tempResult;
cObjectsBox = dataBox;
return true;
}
private MapIndex readMapObjectsForRendering(final int zoom, final RenderingRuleSearchRequest renderingReq,
ArrayList<BinaryMapDataObject> tempResult, ArrayList<BinaryMapDataObject> basemapResult,
TLongSet ids, int[] count, boolean[] ocean, boolean[] land, List<BinaryMapDataObject> coastLines,
List<BinaryMapDataObject> basemapCoastLines, int leftX, int rightX, int bottomY, int topY) {
BinaryMapIndexReader.SearchFilter searchFilter = new BinaryMapIndexReader.SearchFilter() {
@Override
public boolean accept(TIntArrayList types, BinaryMapIndexReader.MapIndex root) {
for (int j = 0; j < types.size(); j++) {
@ -318,11 +479,10 @@ public class MapRenderRepositories {
if (zoom > 16) {
searchFilter = null;
}
boolean ocean = false;
boolean land = false;
MapIndex mi = null;
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
for (BinaryMapIndexReader c : files.values()) {
boolean basemap = c.isBasemap();
searchRequest.clearSearchResults();
List<BinaryMapDataObject> res;
try {
@ -331,99 +491,52 @@ public class MapRenderRepositories {
res = new ArrayList<BinaryMapDataObject>();
log.debug("Search failed " + c.getRegionNames(), e); //$NON-NLS-1$
}
if(res.size() > 0) {
if(basemap) {
renderedState |= 1;
} else {
renderedState |= 2;
}
}
for (BinaryMapDataObject r : res) {
if (checkForDuplicateObjectIds) {
if (checkForDuplicateObjectIds && !basemap) {
if (ids.contains(r.getId()) && r.getId() > 0) {
// do not add object twice
continue;
}
ids.add(r.getId());
}
count++;
count[0]++;
if (r.containsType(r.getMapIndex().coastlineEncodingType)) {
if (c.isBasemap()) {
if (basemap) {
basemapCoastLines.add(r);
} else {
coastLines.add(r);
}
} else {
// do not mess coastline and other types
if (c.isBasemap()) {
if (basemap) {
basemapResult.add(r);
} else {
tempResult.add(r);
}
}
if (checkWhetherInterrupted()) {
return false;
return null;
}
}
if (searchRequest.isOcean()) {
mi = c.getMapIndexes().get(0);
ocean = true;
ocean[0] = true;
}
if (searchRequest.isLand()) {
mi = c.getMapIndexes().get(0);
land = true;
land[0] = true;
}
}
String coastlineTime = "";
boolean addBasemapCoastlines = true;
boolean emptyData = zoom > BASEMAP_ZOOM && tempResult.isEmpty() && coastLines.isEmpty();
boolean basemapMissing = zoom <= BASEMAP_ZOOM && basemapCoastLines.isEmpty() && mi == null;
boolean detailedLandData = zoom >= 14 && tempResult.size() > 0;
if (!coastLines.isEmpty()) {
long ms = System.currentTimeMillis();
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
basemapCoastLines.isEmpty(), true, tempResult);
addBasemapCoastlines = (!coastlinesWereAdded && !detailedLandData) || zoom <= BASEMAP_ZOOM;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
} else {
addBasemapCoastlines = !detailedLandData;
}
if (addBasemapCoastlines) {
long ms = System.currentTimeMillis();
boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom,
true, true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
}
if (addBasemapCoastlines && mi != null) {
BinaryMapDataObject o = new BinaryMapDataObject(new int[]{leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX,
topY}, new int[]{ocean && !land ? mi.coastlineEncodingType : (mi.landEncodingType)}, null, -1);
o.setMapIndex(mi);
tempResult.add(o);
}
if (emptyData || basemapMissing) {
// message
MapIndex mapIndex;
if (!tempResult.isEmpty()) {
mapIndex = tempResult.get(0).getMapIndex();
} else {
mapIndex = new MapIndex();
mapIndex.initMapEncodingRule(0, 1, "natural", "coastline");
mapIndex.initMapEncodingRule(0, 2, "name", "");
}
}
if (zoom <= BASEMAP_ZOOM || emptyData) {
tempResult.addAll(basemapResult);
}
if (count > 0) {
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom));
log.info(String.format("Searching: %s ms %s (%s results found)", System.currentTimeMillis() - now, coastlineTime, count)); //$NON-NLS-1$
}
cObjects = tempResult;
cObjectsBox = dataBox;
return true;
return mi;
}
private void validateLatLonBox(QuadRect box) {
@ -442,60 +555,13 @@ public class MapRenderRepositories {
}
// only single thread to read !
public synchronized boolean checkIfMapIsEmpty(int leftX, int rightX, int topY, int bottomY, int zoom){
final boolean[] empty = new boolean[] {true};
SearchRequest<BinaryMapDataObject> searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom,
null, new ResultMatcher<BinaryMapDataObject>() {
@Override
public boolean publish(BinaryMapDataObject object) {
empty[0] = false;
return false;
}
@Override
public boolean isCancelled() {
return !empty[0];
public boolean isLastMapRenderedEmpty(boolean checkBaseMap){
if(checkBaseMap) {
return prevBmp != null && previousRenderedState == 0;
} else {
return prevBmp != null && previousRenderedState == 1;
}
});
SearchRequest<RouteDataObject> searchRouteRequest = BinaryMapIndexReader.buildSearchRouteRequest(leftX, rightX, topY, bottomY,
new ResultMatcher<RouteDataObject>() {
@Override
public boolean publish(RouteDataObject object) {
empty[0] = false;
return false;
}
@Override
public boolean isCancelled() {
return !empty[0];
}
});
for (BinaryMapIndexReader c : files.values()) {
if (!c.isBasemap()) {
try {
c.searchMapIndex(searchRequest);
} catch (IOException e) {
// lots of FalsePositive cases
return false;
}
if (!empty[0]) {
return false;
}
for (RouteRegion r : c.getRoutingIndexes()) {
try {
List<RouteSubregion> regs = c.searchRouteIndexTree(searchRouteRequest, r.getSubregions());
if(!regs.isEmpty()) {
return false;
}
} catch (IOException e) {
// lots of FalsePositive cases
return false;
}
}
}
}
return empty[0];
}
public synchronized void loadMap(RotatedTileBox tileRect, List<IMapDownloaderCallback> notifyList) {
@ -539,10 +605,10 @@ public class MapRenderRepositories {
// prevent editing
requestedBox = new RotatedTileBox(tileRect);
// calculate data box
QuadRect dataBox = requestedBox.getLatLonBounds();
long now = System.currentTimeMillis();
if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right
|| cObjectsBox.bottom < dataBox.bottom || (nativeLib != null) == (cNativeObjects == null)) {
// increase data box in order for rotate
@ -556,6 +622,7 @@ public class MapRenderRepositories {
dataBox.bottom -= hi;
}
validateLatLonBox(dataBox);
renderedState = 0;
boolean loaded;
if(nativeLib != null) {
cObjects = new LinkedList<BinaryMapDataObject>();
@ -618,6 +685,7 @@ public class MapRenderRepositories {
Bitmap reuse = prevBmp;
this.prevBmp = this.bmp;
this.prevBmpLocation = this.bmpLocation;
this.previousRenderedState = renderedState;
if (reuse != null && reuse.getWidth() == currentRenderingContext.width && reuse.getHeight() == currentRenderingContext.height) {
bmp = reuse;
bmp.eraseColor(currentRenderingContext.defaultColor);
@ -726,6 +794,7 @@ public class MapRenderRepositories {
cObjectsBox = new QuadRect();
requestedBox = prevBmpLocation = null;
previousRenderedState = 0;
// Do not clear main bitmap to not cause a screen refresh
// prevBmp = null;
// bmp = null;

View file

@ -3,6 +3,7 @@ package net.osmand.plus.routing;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
@ -48,6 +49,7 @@ import net.osmand.router.GeneralRouter;
import net.osmand.router.GeneralRouter.GeneralRouterProfile;
import net.osmand.router.GeneralRouter.RoutingParameter;
import net.osmand.router.GeneralRouter.RoutingParameterType;
import net.osmand.router.PrecalculatedRouteDirection;
import net.osmand.router.RoutePlannerFrontEnd;
import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode;
import net.osmand.router.RouteSegmentResult;
@ -115,9 +117,9 @@ public class RouteProvider {
List<Location> points = new ArrayList<Location>();
List<RouteDirectionInfo> directions;
DataTileManager<WptPt> wpt;
boolean calculateOsmAndRoute = false;
public GPXRouteParams(GPXFile file, boolean reverse, boolean announceWaypoints, OsmandSettings settings){
prepareEverything(file, reverse, announceWaypoints, settings.DRIVING_REGION.get().leftHandDriving);
private GPXRouteParams(){
}
public void setStartPoint(Location startPoint) {
@ -144,6 +146,45 @@ public class RouteProvider {
return null;
}
public static class GPXRouteParamsBuilder {
private GPXRouteParams obj = new GPXRouteParams();
private GPXFile file;
private boolean leftHandDriving;
private boolean reverse;
private boolean announceWaypoints;
private GPXRouteParamsBuilder(GPXFile f, OsmandSettings settings) {
this.file = f;
leftHandDriving = settings.DRIVING_REGION.get().leftHandDriving;
// obj = new GPXRouteParams(file, reverse, announceWaypoints, settings)
// TODO Auto-generated constructor stub
}
public GPXRouteParamsBuilder reverse() {
this.reverse = true;
return this;
}
public GPXRouteParamsBuilder announceWaypoints() {
this.announceWaypoints = true;
return this;
}
public GPXRouteParamsBuilder calculateOsmAndRoute() {
obj.calculateOsmAndRoute = true;
return this;
}
public static GPXRouteParamsBuilder newBuilder(GPXFile f, OsmandSettings settings) {
return new GPXRouteParamsBuilder(f, settings);
}
public GPXRouteParams build(){
obj.prepareEverything(file, reverse, announceWaypoints, leftHandDriving);
return obj;
}
}
private void prepareEverything(GPXFile file, boolean reverse, boolean announceWaypoints, boolean leftSide){
if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){
directions = parseCloudmadeRoute(points, file, OSMAND_ROUTER.equals(file.author), leftSide, 10);
@ -210,7 +251,10 @@ public class RouteProvider {
}
try {
RouteCalculationResult res;
if(params.gpxRoute != null && !params.gpxRoute.points.isEmpty()){
boolean calcGPXRoute = params.gpxRoute != null && !params.gpxRoute.points.isEmpty();
if (params.type == RouteService.OSMAND || (calcGPXRoute && params.gpxRoute.calculateOsmAndRoute)) {
res = findVectorMapsRoute(params, calcGPXRoute);
} else if(calcGPXRoute){
res = calculateGpxRoute(params);
} else if (params.type == RouteService.YOURS) {
res = findYOURSRoute(params);
@ -218,8 +262,6 @@ public class RouteProvider {
res = findORSRoute(params);
} else if (params.type == RouteService.OSRM) {
res = findOSRMRoute(params);
} else if (params.type == RouteService.OSMAND) {
res = findVectorMapsRoute(params);
} else if (params.type == RouteService.BROUTER) {
res = findBROUTERRoute(params);
} else {
@ -246,45 +288,20 @@ public class RouteProvider {
private RouteCalculationResult calculateGpxRoute(RouteCalculationParams pars) {
RouteCalculationResult res;
// get the closest point to start and to end
float minDist = Integer.MAX_VALUE;
int startI = 0;
GPXRouteParams params = pars.gpxRoute;
List<Location> gpxRoute = params.points;
int endI = gpxRoute.size();
if (pars.start != null) {
for (int i = 0; i < gpxRoute.size(); i++) {
float d = gpxRoute.get(i).distanceTo(pars.start);
if (d < minDist) {
startI = i;
minDist = d;
}
}
} else {
pars.start = gpxRoute.get(0);
}
Location l = new Location("temp"); //$NON-NLS-1$
l.setLatitude(pars.end.getLatitude());
l.setLongitude(pars.end.getLongitude());
minDist = Integer.MAX_VALUE;
// get in reverse order taking into account ways with cycle
for (int i = gpxRoute.size() - 1; i >= startI; i--) {
float d = gpxRoute.get(i).distanceTo(l);
if (d < minDist) {
endI = i + 1;
// slightly modify to allow last point to be added
minDist = d - 40;
}
}
ArrayList<Location> sublist = new ArrayList<Location>(gpxRoute.subList(startI, endI));
int[] startI = new int[]{0};
int[] endI = new int[]{gpxRoute.size()};
ArrayList<Location> sublist = findGpxLocations(pars, startI, endI);
pars.intermediates = null;
if(params.directions == null){
res = new RouteCalculationResult(sublist, null, pars, params.wpt);
} else {
List<RouteDirectionInfo> subdirections = new ArrayList<RouteDirectionInfo>();
for (RouteDirectionInfo info : params.directions) {
if(info.routePointOffset >= startI && info.routePointOffset < endI){
if(info.routePointOffset >= startI[0] && info.routePointOffset < endI[0]){
RouteDirectionInfo ch = new RouteDirectionInfo(info.getAverageSpeed(), info.getTurnType());
ch.routePointOffset = info.routePointOffset - startI;
ch.routePointOffset = info.routePointOffset - startI[0];
ch.setDescriptionRoute(info.getDescriptionRoute());
// recalculate
@ -298,6 +315,49 @@ public class RouteProvider {
return res;
}
private ArrayList<Location> findGpxLocations(RouteCalculationParams pars, int[] startI, int[] endI) {
GPXRouteParams params = pars.gpxRoute;
List<Location> gpxRoute = params.points;
float minDist = Integer.MAX_VALUE;
int start = 0;
int end = gpxRoute.size();
if (pars.start != null) {
for (int i = 0; i < gpxRoute.size(); i++) {
float d = gpxRoute.get(i).distanceTo(pars.start);
if (d < minDist) {
start = i;
minDist = d;
}
}
} else {
pars.start = gpxRoute.get(0);
}
Location l = new Location("temp"); //$NON-NLS-1$
l.setLatitude(pars.end.getLatitude());
l.setLongitude(pars.end.getLongitude());
minDist = Integer.MAX_VALUE;
// get in reverse order taking into account ways with cycle
for (int i = gpxRoute.size() - 1; i >= start; i--) {
float d = gpxRoute.get(i).distanceTo(l);
if (d < minDist) {
end = i + 1;
// slightly modify to allow last point to be added
minDist = d - 40;
}
}
ArrayList<Location> sublist = new ArrayList<Location>(gpxRoute.subList(start, end));
if(startI != null) {
startI[0] = start;
}
if(endI != null) {
endI[0] = end;
}
return sublist;
}
protected String getString(ClientContext ctx, int resId){
if(ctx == null){
return ""; //$NON-NLS-1$
@ -370,10 +430,63 @@ public class RouteProvider {
return new RouteCalculationResult(res, null, params, null);
}
protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params) throws IOException {
protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params, boolean calcGPXRoute) throws IOException {
BinaryMapIndexReader[] files = params.ctx.getTodoAPI().getRoutingMapFiles();
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(false);
OsmandSettings settings = params.ctx.getSettings();
GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode);
if(generalRouter == null) {
return applicationModeNotSupported(params);
}
RoutingConfiguration cf = initOsmAndRoutingConfig(params, settings, generalRouter);
if(cf == null){
return applicationModeNotSupported(params);
}
PrecalculatedRouteDirection precalculated = null;
if(calcGPXRoute) {
ArrayList<Location> sublist = findGpxLocations(params, null, null);
LatLon[] latLon = new LatLon[sublist.size()];
for(int k = 0; k < latLon.length; k ++) {
latLon[k] = new LatLon(sublist.get(k).getLatitude(), sublist.get(k).getLongitude());
}
precalculated = PrecalculatedRouteDirection.build(latLon, generalRouter.getMaxDefaultSpeed());
precalculated.setFollowNext(true);
//cf.planRoadDirection = 1;
}
// BUILD context
RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
RouteCalculationMode.NORMAL);
RoutingContext complexCtx = null;
boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get()
&& precalculated == null;
if(complex) {
complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
RouteCalculationMode.COMPLEX);
complexCtx.calculationProgress = params.calculationProgress;
complexCtx.leftSideNavigation = params.leftSide;
}
ctx.leftSideNavigation = params.leftSide;
ctx.calculationProgress = params.calculationProgress;
if(params.previousToRecalculate != null) {
// not used any more
// ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute();
}
LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude());
LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude());
List<LatLon> inters = new ArrayList<LatLon>();
if (params.intermediates != null) {
inters = new ArrayList<LatLon>(params.intermediates);
}
return calcOfflineRouteImpl(params, router, ctx, complexCtx, st, en, inters, precalculated);
}
private RoutingConfiguration initOsmAndRoutingConfig(final RouteCalculationParams params, OsmandSettings settings,
GeneralRouter generalRouter) throws IOException, FileNotFoundException {
File routingXml = params.ctx.getAppPath(IndexConstants.ROUTING_XML_FILE);
RoutingConfiguration.Builder config ;
if (routingXml.exists() && routingXml.canRead()) {
@ -393,12 +506,9 @@ public class RouteProvider {
} else if(params.mode.isDerivedRoutingFrom(ApplicationMode.CAR)){
p = GeneralRouterProfile.CAR;
} else {
return applicationModeNotSupported(params);
}
GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode);
if(generalRouter == null) {
return applicationModeNotSupported(params);
return null;
}
Map<String, String> paramsR = new LinkedHashMap<String, String>();
for(Map.Entry<String, RoutingParameter> e : generalRouter.getParameters().entrySet()){
String key = e.getKey();
@ -427,32 +537,20 @@ public class RouteProvider {
RoutingConfiguration cf = config.build(p.name().toLowerCase(), params.start.hasBearing() ?
params.start.getBearing() / 180d * Math.PI : null,
memoryLimit, paramsR);
boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get();
RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
RouteCalculationMode.NORMAL);
RoutingContext complexCtx = null;
if(complex) {
complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
RouteCalculationMode.COMPLEX);
complexCtx.calculationProgress = params.calculationProgress;
}
ctx.leftSideNavigation = params.leftSide;
ctx.calculationProgress = params.calculationProgress;
if(params.previousToRecalculate != null) {
// not used any more
// ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute();
}
LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude());
LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude());
List<LatLon> inters = new ArrayList<LatLon>();
if (params.intermediates != null) {
inters = new ArrayList<LatLon>(params.intermediates);
return cf;
}
private RouteCalculationResult calcOfflineRouteImpl(final RouteCalculationParams params,
RoutePlannerFrontEnd router, RoutingContext ctx, RoutingContext complexCtx, LatLon st, LatLon en,
List<LatLon> inters, PrecalculatedRouteDirection precalculated) throws IOException {
try {
List<RouteSegmentResult> result ;
if(complexCtx != null) {
try {
result = router.searchRoute(complexCtx, st, en, inters);
result = router.searchRoute(complexCtx, st, en, inters, precalculated);
// discard ctx and replace with calculated
ctx = complexCtx;
} catch(final RuntimeException e) {

View file

@ -165,7 +165,7 @@ public class DownloadedRegionsLayer extends OsmandMapLayer {
int right = MapUtils.get31TileNumberX(tileBox.getRightBottomLatLon().getLongitude());
int top = MapUtils.get31TileNumberY(tileBox.getLeftTopLatLon().getLatitude());
int bottom = MapUtils.get31TileNumberY(tileBox.getRightBottomLatLon().getLatitude());
final boolean empty = rm.getRenderer().checkIfMapIsEmpty(left, right, top, bottom, tileBox.getZoom());
final boolean empty = rm.getRenderer().isLastMapRenderedEmpty(false);
noMapsPresent = empty;
if (!empty && tileBox.getZoom() >= ZOOM_TO_SHOW_MAP_NAMES) {
return Collections.emptyList();

View file

@ -393,7 +393,7 @@ public class MapControlsLayer extends OsmandMapLayer {
final AlertDialog.Builder bld = new AlertDialog.Builder(view.getContext());
float scale = view.getZoomScale();
int p = (int) ((scale > 0 ? 1 : -1) * Math.round(scale * scale * 100)) + 100;
final TIntArrayList tlist = new TIntArrayList(new int[] { 75, 100, 150, 200, 300, 400 });
final TIntArrayList tlist = new TIntArrayList(new int[] { 75, 100, 150, 200, 300, 400, 500 });
final List<String> values = new ArrayList<String>();
int i = -1;
for (int k = 0; k <= tlist.size(); k++) {