diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index b00c6ef44d..9c058b6cff 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -13,14 +13,22 @@ public class ToDoConstants { */ public int DESCRIBE_ABOUT_AUTHORS = 8; + // TODO ANDROID // 42. Revise UI (icons/layouts). Support different devices. Add inactive/focus(!) icon versions. // Some icons are not fine (as back menu from map - it is blured). + + // TODO: draw EXIT!!!, YOURS (calc turn/angle/time). [other done] // 56. Add usage of CloudMade API for calculating route (show next turn & distance to it instead of mini map). // 57. Implement routing information about expected time arriving // 58. Implement difference about show route/follow route (show travel time/arrival time, show mini map/next turn, etc) + // 59. Show route information (directions/time, ....). Could be shown in context menu route. + // 46. Implement downloading strategy for tiles : select max zoom to download [16,15,14,...] // That means you can save internet because from [16 -> zoom -> 18], [14 -> zoom -> 16 - suitable for speed > 40], ... + + + // 58. Upload/Download zip-index from site & unzip them on phone // 50. Invent opening hours editor in order to edit POI hours better on device // 53. Add progress bars : to internet communication activities [editing/commiting/deleting poi], do not hide edit poi dialog if operation failed diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 2a6bd17132..5fa3bce80f 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -15,6 +15,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/OsmAnd/res/layout/route_info_list_item.xml b/OsmAnd/res/layout/route_info_list_item.xml new file mode 100644 index 0000000000..fe414738a2 --- /dev/null +++ b/OsmAnd/res/layout/route_info_list_item.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/OsmAnd/res/values-ru-rRU/strings.xml b/OsmAnd/res/values-ru-rRU/strings.xml index 0ada4af94d..8b663307a2 100644 --- a/OsmAnd/res/values-ru-rRU/strings.xml +++ b/OsmAnd/res/values-ru-rRU/strings.xml @@ -1,5 +1,9 @@ + О маршруте + Общая протяженность = {0}, время в пути = ''{1}''. + Выберите сервис для прокладки маршрута + Прокладка маршрута Директория на SD карточка не доступна для сохранения Вы хотите загрузить {0} - {1} ? Адрес diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 42e263ca4a..4c030fad21 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,9 @@ + About route + Overall distance = {0}, travelling time = ''{1}''. + Choose routing service + Routing Directory on SD card to save index is not accessible Do you want to download {0} - {1} ? Address diff --git a/OsmAnd/res/xml/settings_pref.xml b/OsmAnd/res/xml/settings_pref.xml index 71fd7f2aed..fadccf781c 100644 --- a/OsmAnd/res/xml/settings_pref.xml +++ b/OsmAnd/res/xml/settings_pref.xml @@ -18,13 +18,14 @@ + - + diff --git a/OsmAnd/src/com/osmand/OsmandSettings.java b/OsmAnd/src/com/osmand/OsmandSettings.java index b36d6a12b5..7a1ae5c292 100644 --- a/OsmAnd/src/com/osmand/OsmandSettings.java +++ b/OsmAnd/src/com/osmand/OsmandSettings.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import com.osmand.activities.RouteProvider.RouteService; import com.osmand.map.ITileSource; import com.osmand.map.TileSourceManager; import com.osmand.map.TileSourceManager.TileSourceTemplate; @@ -110,6 +111,24 @@ public class OsmandSettings { SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); return prefs.edit().putString(APPLICATION_MODE, p.name()).commit(); } + + // this value string is synchronized with settings_pref.xml preference name + public static final String ROUTER_SERVICE = "router_service"; //$NON-NLS-1$ + + public static RouteService getRouterService(Context ctx) { + SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); + int ord = prefs.getInt(ROUTER_SERVICE, RouteService.CLOUDMADE.ordinal()); + if(ord < RouteService.values().length){ + return RouteService.values()[ord]; + } else { + return RouteService.CLOUDMADE; + } + } + + public static boolean setRouterService(Context ctx, RouteService p) { + SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); + return prefs.edit().putInt(ROUTER_SERVICE, p.ordinal()).commit(); + } // this value string is synchronized with settings_pref.xml preference name public static final String SAVE_CURRENT_TRACK = "save_current_track"; //$NON-NLS-1$ diff --git a/OsmAnd/src/com/osmand/activities/EditPOIFilterActivity.java b/OsmAnd/src/com/osmand/activities/EditPOIFilterActivity.java index b4bde11bd9..8a5d792f70 100644 --- a/OsmAnd/src/com/osmand/activities/EditPOIFilterActivity.java +++ b/OsmAnd/src/com/osmand/activities/EditPOIFilterActivity.java @@ -176,6 +176,8 @@ public class EditPOIFilterActivity extends ListActivity { } if (subCategories.size() == accepted.size()) { filter.selectSubTypesToAccept(amenity, null); + } else if(accepted.size() == 0){ + filter.setTypeToAccept(amenity, false); } else { filter.selectSubTypesToAccept(amenity, accepted); } diff --git a/OsmAnd/src/com/osmand/activities/FavouritesActivity.java b/OsmAnd/src/com/osmand/activities/FavouritesActivity.java index 02c4131653..ea53233b55 100644 --- a/OsmAnd/src/com/osmand/activities/FavouritesActivity.java +++ b/OsmAnd/src/com/osmand/activities/FavouritesActivity.java @@ -38,7 +38,6 @@ import com.osmand.osm.LatLon; import com.osmand.osm.MapUtils; /** - * @author Maxim Frolov * */ public class FavouritesActivity extends ListActivity { diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index ede7d2c7aa..68a365786f 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -94,7 +94,6 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat private SavingTrackHelper savingTrackHelper; private RoutingHelper routingHelper; - private boolean calculateRouteOnGps = false; private WakeLock wakeLock; @@ -171,7 +170,11 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat routingHelper.setAppMode(OsmandSettings.getApplicationMode(this)); if(!Algoritms.objectEquals(routingHelper.getFinalLocation(), pointToNavigate)){ + // there is no way how to clear mode. Only user can do : clear point to navigate, exit from app & set up new point. + // that case help to not calculate route at all. + routingHelper.setFollowingMode(false); routingHelper.setFinalAndCurrentLocation(pointToNavigate, null); + } navigationLayer.setPointToNavigate(pointToNavigate); @@ -354,7 +357,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat updateSpeedBearing(location); locationLayer.setLastKnownLocation(location); - if(calculateRouteOnGps){ + if(routingHelper.isFollowingMode()){ routingHelper.setCurrentLocation(location); } if (location != null) { @@ -405,7 +408,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat } routingHelper.setFinalAndCurrentLocation(point, null); if(point == null){ - calculateRouteOnGps = false; + routingHelper.setFollowingMode(false); } navigationLayer.setPointToNavigate(point); updateNavigateToPointMenu(); @@ -507,6 +510,8 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat @Override protected void onResume() { super.onResume(); + // routing helper with current activity + routingHelper = RoutingHelper.getInstance(this); if(mapView.getMap() != OsmandSettings.getMapTileSource(this)){ mapView.setMap(OsmandSettings.getMapTileSource(this)); } @@ -672,10 +677,18 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat Location map = new Location("map"); //$NON-NLS-1$ map.setLatitude(lat); map.setLongitude(lon); - calculateRouteOnGps = true; + routingHelper.setFollowingMode(true); routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), map); } }); + if(routingHelper.isRouterEnabled()){ + builder.setNeutralButton(R.string.route_about, new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(MapActivity.this, ShowRouteInfoActivity.class)); + } + }); + } builder.setNegativeButton(R.string.only_show, new DialogInterface.OnClickListener(){ @Override @@ -684,11 +697,12 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat Location map = new Location("map"); //$NON-NLS-1$ map.setLatitude(lat); map.setLongitude(lon); - calculateRouteOnGps = false; + routingHelper.setFollowingMode(false); routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), map); } }); builder.show(); + } protected void reloadTile(final int zoom, final double latitude, final double longitude){ diff --git a/OsmAnd/src/com/osmand/activities/RouteProvider.java b/OsmAnd/src/com/osmand/activities/RouteProvider.java index 2a4b575231..1b59f91453 100644 --- a/OsmAnd/src/com/osmand/activities/RouteProvider.java +++ b/OsmAnd/src/com/osmand/activities/RouteProvider.java @@ -32,6 +32,17 @@ import com.osmand.osm.LatLon; public class RouteProvider { private static final org.apache.commons.logging.Log log = LogUtil.getLog(RouteProvider.class); + public enum RouteService { + CLOUDMADE("CloudMade"), YOURS("YOURS"); //$NON-NLS-1$ //$NON-NLS-2$ + private final String name; + private RouteService(String name){ + this.name = name; + } + public String getName() { + return name; + } + } + public RouteProvider(){ } @@ -75,11 +86,15 @@ public class RouteProvider { listDistance[i - 1] += listDistance[i]; } } - if(directions != null){ - int sum =0; - for(int i=directions.size() - 1; i>=0; i--){ + if (directions != null) { + int sum = 0; + for (int i = directions.size() - 1; i >= 0; i--) { directions.get(i).afterLeftTime = sum; sum += directions.get(i).expectedTime; + directions.get(i).distance = listDistance[directions.get(i).routePointOffset]; + if(i < directions.size() - 1){ + directions.get(i).distance -=listDistance[directions.get(i + 1).routePointOffset]; + } } } } @@ -93,15 +108,19 @@ public class RouteProvider { } - public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode){ + public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode, RouteService type){ long time = System.currentTimeMillis(); if (start != null && end != null) { if(log.isInfoEnabled()){ - log.info("Start finding route from " + start + " to " + end); //$NON-NLS-1$ //$NON-NLS-2$ + log.info("Start finding route from " + start + " to " + end +" using " + type.getName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } try { -// RouteCalculationResult res = findYOURSRoute(start, end, mode); - RouteCalculationResult res = findCloudMadeRoute(start, end, mode); + RouteCalculationResult res; + if (type == RouteService.YOURS) { + res = findYOURSRoute(start, end, mode); + } else { + res = findCloudMadeRoute(start, end, mode); + } if(log.isInfoEnabled() && res.locations != null){ log.info("Finding route contained " + res.locations.size() + " points for " + (System.currentTimeMillis() - time) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } @@ -221,6 +240,7 @@ public class RouteProvider { if(list.getLength() > 0){ directions = new ArrayList(); } + RouteDirectionInfo previous = null; for (int i = 0; i < list.getLength(); i++) { Element item = (Element) list.item(i); try { @@ -242,13 +262,50 @@ public class RouteProvider { } int offset = Integer.parseInt(getContentFromNode(item, "offset")); //$NON-NLS-1$ dirInfo.routePointOffset = offset; + + if(previous != null && previous.turnType != TurnType.C && previous.turnType != null){ + // calculate angle + if(previous.routePointOffset > 0){ + float paz = res.get(previous.routePointOffset - 1).bearingTo(res.get(previous.routePointOffset)); + float caz; + if(previous.turnType.isExit() && dirInfo.routePointOffset < res.size() - 1){ + caz = res.get(dirInfo.routePointOffset).bearingTo(res.get(dirInfo.routePointOffset + 1)); + } else { + caz = res.get(dirInfo.routePointOffset - 1).bearingTo(res.get(dirInfo.routePointOffset)); + } + float angle = caz - paz; + if(angle < 0){ + angle += 360; + } + if(previous.turnAngle == 0f){ + previous.turnAngle = angle; + } + } + } + directions.add(dirInfo); + + previous = dirInfo; } catch (NumberFormatException e) { log.info("Exception", e); //$NON-NLS-1$ } catch (IllegalArgumentException e) { log.info("Exception", e); //$NON-NLS-1$ } } + if(previous != null && previous.turnType != TurnType.C && previous.turnType != null){ + // calculate angle + if(previous.routePointOffset > 0 && previous.routePointOffset < res.size() - 1){ + float paz = res.get(previous.routePointOffset - 1).bearingTo(res.get(previous.routePointOffset)); + float caz = res.get(previous.routePointOffset).bearingTo(res.get(res.size() -1)); + float angle = caz - paz; + if(angle < 0){ + angle += 360; + } + if(previous.turnAngle == 0f){ + previous.turnAngle = angle; + } + } + } diff --git a/OsmAnd/src/com/osmand/activities/RoutingHelper.java b/OsmAnd/src/com/osmand/activities/RoutingHelper.java index 0aaf2bdccc..fa5142b6ab 100644 --- a/OsmAnd/src/com/osmand/activities/RoutingHelper.java +++ b/OsmAnd/src/com/osmand/activities/RoutingHelper.java @@ -1,16 +1,20 @@ package com.osmand.activities; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import android.app.Activity; import android.location.Location; import android.util.FloatMath; import android.widget.Toast; import com.osmand.LogUtil; +import com.osmand.OsmandSettings; import com.osmand.R; import com.osmand.OsmandSettings.ApplicationMode; import com.osmand.activities.RouteProvider.RouteCalculationResult; +import com.osmand.activities.RouteProvider.RouteService; import com.osmand.osm.LatLon; import com.osmand.osm.MapUtils; @@ -19,7 +23,9 @@ public class RoutingHelper { private static final org.apache.commons.logging.Log log = LogUtil.getLog(RoutingHelper.class); // activity to show messages & refresh map when route is calculated - private MapActivity activity; + private Activity activity; + + private boolean isFollowingMode = false; // instead of this properties RouteCalculationResult could be used private List routeNodes = new ArrayList(); @@ -63,13 +69,20 @@ public class RoutingHelper { } private static RoutingHelper INSTANCE = new RoutingHelper(); - public static RoutingHelper getInstance(MapActivity activity){ - INSTANCE.activity = activity; + public static RoutingHelper getInstance(Activity ctx){ + INSTANCE.activity = ctx; return INSTANCE; } + public boolean isFollowingMode() { + return isFollowingMode; + } + + public void setFollowingMode(boolean isFollowingMode) { + this.isFollowingMode = isFollowingMode; + } public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, Location currentLocation){ this.finalLocation = finalLocation; @@ -107,9 +120,7 @@ public class RoutingHelper { Location lastPoint = routeNodes.get(routeNodes.size() - 1); if(currentRoute > routeNodes.size() - 3 && currentLocation.distanceTo(lastPoint) < 60){ if(lastFixedLocation != null && lastFixedLocation.distanceTo(lastPoint) < 60){ - if(activity != null){ - showMessage(activity.getString(R.string.arrived_at_destination)); - } + showMessage(activity.getString(R.string.arrived_at_destination)); updateCurrentRoute(routeNodes.size() - 1); // clear final location to prevent all time showing message finalLocation = null; @@ -231,16 +242,26 @@ public class RoutingHelper { currentRoute = 0; } - public synchronized int getDistance(double lat, double lon){ + public synchronized int getLeftDistance(){ if(listDistance != null && currentRoute < listDistance.length){ int dist = listDistance[currentRoute]; Location l = routeNodes.get(currentRoute); - dist += MapUtils.getDistance(lat, lon, l.getLatitude(), l.getLongitude()); + if(lastFixedLocation != null){ + dist += lastFixedLocation.distanceTo(l); + } return dist; } return 0; } + public Location getLocationFromRouteDirection(RouteDirectionInfo i){ + if(i.routePointOffset < routeNodes.size()){ + return routeNodes.get(i.routePointOffset); + } + return null; + } + + public RouteDirectionInfo getNextRouteDirectionInfo(){ if(directionInfo != null && currentDirectionInfo < directionInfo.size() - 1){ return directionInfo.get(currentDirectionInfo + 1); @@ -248,6 +269,13 @@ public class RoutingHelper { return null; } + public List getRouteDirections(){ + if(directionInfo != null && currentDirectionInfo < directionInfo.size()){ + return directionInfo.subList(currentDirectionInfo, directionInfo.size()); + } + return Collections.emptyList(); + } + public int getDistanceToNextRouteDirection() { if (directionInfo != null && currentDirectionInfo < directionInfo.size()) { int dist = listDistance[currentRoute]; @@ -282,6 +310,7 @@ public class RoutingHelper { } public void calculateRoute(final Location start, final LatLon end){ + final RouteService service = OsmandSettings.getRouterService(activity); if(currentRunningJob == null){ // do not evaluate very often if (System.currentTimeMillis() - lastTimeEvaluatedRoute > evalWaitInterval) { @@ -289,7 +318,7 @@ public class RoutingHelper { currentRunningJob = new Thread(new Runnable() { @Override public void run() { - RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode); + RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode, service); synchronized (RoutingHelper.this) { if (res.isCalculated()) { setNewRoute(res); @@ -303,13 +332,15 @@ public class RoutingHelper { } currentRunningJob = null; } - if (activity != null) { + if (res.isCalculated()) { int[] dist = res.getListDistance(); int l = dist != null && dist.length > 0 ? dist[0] : 0; showMessage(activity.getString(R.string.new_route_calculated_dist) + MapUtils.getFormattedDistance(l)); - // be aware that is non ui thread - activity.getMapView().refreshMap(); + if (activity instanceof MapActivity) { + // be aware that is non ui thread + ((MapActivity) activity).getMapView().refreshMap(); + } } else { if (res.getErrorMessage() != null) { showMessage(activity.getString(R.string.error_calculating_route) + res.getErrorMessage()); @@ -319,7 +350,6 @@ public class RoutingHelper { showMessage(activity.getString(R.string.empty_route_calculated)); } } - } lastTimeEvaluatedRoute = System.currentTimeMillis(); } }, "Calculating route"); //$NON-NLS-1$ @@ -382,26 +412,63 @@ public class RoutingHelper { - public static enum TurnType { - C , // continue (go straight) - TL, // turn left - TSLL, // turn slight left - TSHL, // turn sharp left - TR, // turn right - TSLR, // turn slight right - TSHR, // turn sharp right - TU, // U-turn + public static class TurnType { + public static final TurnType C = new TurnType("C"); // continue (go straight) //$NON-NLS-1$ + public static final TurnType TL = new TurnType("TL"); // turn left //$NON-NLS-1$ + public static final TurnType TSLL = new TurnType("TSLL"); // turn slight left //$NON-NLS-1$ + public static final TurnType TSHL = new TurnType("TSHL"); // turn sharp left //$NON-NLS-1$ + public static final TurnType TR = new TurnType("TR"); // turn right //$NON-NLS-1$ + public static final TurnType TSLR = new TurnType("TSLR"); // turn slight right //$NON-NLS-1$ + public static final TurnType TSHR = new TurnType("TSHR"); // turn sharp right //$NON-NLS-1$ + public static final TurnType TU = new TurnType("TU"); // U-turn //$NON-NLS-1$ + public static TurnType[] vals = new TurnType[] {C, TL, TSLL, TSHL, TR, TSLR, TSHR, TU}; - // TODO Exit3... + + public static TurnType valueOf(String s){ + for(TurnType v : vals){ + if(v.getValue().equals(s)){ + return v; + } + } + if(s!= null && s.startsWith("EXIT")){ //$NON-NLS-1$ + return getExitTurn(Integer.parseInt(s.substring(4))); + } + return null; + } + + private final String value; + private int exitOut; + + public static TurnType getExitTurn(int out){ + return new TurnType("EXIT", out); //$NON-NLS-1$ + } + private TurnType(String value, int exitOut){ + this.value = value; + this.exitOut = exitOut; + } + private TurnType(String value){ + this.value = value; + } + public String getValue() { + return value; + } + public int getExitOut() { + return exitOut; + } + public boolean isExit(){ + return value.equals("EXIT"); //$NON-NLS-1$ + } } public static class RouteDirectionInfo { - public String descriptionRoute; + public String descriptionRoute = ""; //$NON-NLS-1$ public int expectedTime; - public float turnAngle; + public float turnAngle; // calculated CW head rotation if previous direction to NORTH public TurnType turnType; public int routePointOffset; + // calculated vars public int afterLeftTime; + public int distance; } diff --git a/OsmAnd/src/com/osmand/activities/SettingsActivity.java b/OsmAnd/src/com/osmand/activities/SettingsActivity.java index 9d5cd7a71f..3470b56c9f 100644 --- a/OsmAnd/src/com/osmand/activities/SettingsActivity.java +++ b/OsmAnd/src/com/osmand/activities/SettingsActivity.java @@ -24,6 +24,7 @@ import com.osmand.ProgressDialogImplementation; import com.osmand.R; import com.osmand.ResourceManager; import com.osmand.OsmandSettings.ApplicationMode; +import com.osmand.activities.RouteProvider.RouteService; import com.osmand.map.TileSourceManager; import com.osmand.map.TileSourceManager.TileSourceTemplate; @@ -46,6 +47,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference private EditTextPreference userPassword; private Preference reloadIndexes; private Preference downloadIndexes; + private ListPreference routerPreference; @Override public void onCreate(Bundle savedInstanceState) { @@ -93,6 +95,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference positionOnMap.setOnPreferenceChangeListener(this); tileSourcePreference =(ListPreference) screen.findPreference(OsmandSettings.MAP_TILE_SOURCES); tileSourcePreference.setOnPreferenceChangeListener(this); + routerPreference =(ListPreference) screen.findPreference(OsmandSettings.ROUTER_SERVICE); + routerPreference.setOnPreferenceChangeListener(this); } @@ -141,10 +145,20 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference applicationMode.setEntries(values); applicationMode.setEntryValues(valueEntries); applicationMode.setValue(OsmandSettings.getApplicationMode(this).name()); + + + String[] entries = new String[RouteService.values().length]; + String entry = OsmandSettings.getRouterService(this).getName(); + for(int i=0; i list = TileSourceManager.getKnownSourceTemplates(); - String[] entries = new String[list.size()]; + entries = new String[list.size()]; for (int i = 0; i < list.size(); i++) { entries[i] = list.get(i).getName(); } @@ -206,6 +220,18 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference } else if(preference == positionOnMap){ edit.putInt(OsmandSettings.POSITION_ON_MAP, positionOnMap.findIndexOfValue((String) newValue)); edit.commit(); + } else if (preference == routerPreference) { + RouteService s = null; + for(RouteService r : RouteService.values()){ + if(r.getName().equals(newValue)){ + s = r; + break; + } + } + if(s != null){ + edit.putInt(OsmandSettings.ROUTER_SERVICE, s.ordinal()); + } + edit.commit(); } else if (preference == tileSourcePreference) { edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue); edit.commit(); diff --git a/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java b/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java new file mode 100644 index 0000000000..8540a84736 --- /dev/null +++ b/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java @@ -0,0 +1,148 @@ +/** + * + */ +package com.osmand.activities; + +import java.text.MessageFormat; +import java.util.List; + +import android.app.ListActivity; +import android.content.Intent; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Paint.Style; +import android.graphics.drawable.Drawable; +import android.location.Location; +import android.os.Bundle; +import android.text.format.DateFormat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.osmand.OsmandSettings; +import com.osmand.R; +import com.osmand.activities.RoutingHelper.RouteDirectionInfo; +import com.osmand.activities.RoutingHelper.TurnType; +import com.osmand.osm.MapUtils; +import com.osmand.views.MapInfoLayer; + +/** + * + */ +public class ShowRouteInfoActivity extends ListActivity { + + + + + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + ListView lv = new ListView(this); + lv.setId(android.R.id.list); + TextView header = new TextView(this); + RoutingHelper helper = RoutingHelper.getInstance(this); + int time = helper.getLeftTime()* 1000; + int dist = helper.getLeftDistance(); + header.setText(MessageFormat.format(getString(R.string.route_general_information), MapUtils.getFormattedDistance(dist), + DateFormat.format("kk:mm", time))); //$NON-NLS-1$ + lv.addHeaderView(header); + setContentView(lv); + setListAdapter(new RouteInfoAdapter(RoutingHelper.getInstance(this).getRouteDirections())); + } + + public void onListItemClick(ListView parent, View v, int position, long id) { + RouteDirectionInfo item = ((RouteInfoAdapter)getListAdapter()).getItem(position); + RoutingHelper inst = RoutingHelper.getInstance(this); + Location loc = inst.getLocationFromRouteDirection(item); + if(loc != null){ + OsmandSettings.setMapLocationToShow(this, loc.getLatitude(),loc.getLongitude()); + startActivity(new Intent(this, MapActivity.class)); + } + } + + + class RouteDrawable extends Drawable { + Paint paintRouteDirection; + Path p = new Path(); + Matrix m = new Matrix(); + public RouteDrawable(){ + m.setScale(0.33f, 0.33f); + paintRouteDirection = new Paint(); + paintRouteDirection.setStyle(Style.FILL_AND_STROKE); + paintRouteDirection.setColor(Color.rgb(100, 0, 255)); + paintRouteDirection.setAntiAlias(true); + } + + + public void setRouteType(TurnType t){ + MapInfoLayer.calcTurnPath(p, t, m); + } + + @Override + public void draw(Canvas canvas) { + canvas.drawPath(p, paintRouteDirection); + } + + @Override + public int getOpacity() { + return 0; + } + + @Override + public void setAlpha(int alpha) { + paintRouteDirection.setAlpha(alpha); + + } + + @Override + public void setColorFilter(ColorFilter cf) { + paintRouteDirection.setColorFilter(cf); + } + + } + + class RouteInfoAdapter extends ArrayAdapter { + RouteInfoAdapter(List list) { + super(ShowRouteInfoActivity.this, R.layout.route_info_list_item, list); + this.setNotifyOnChange(false); + } + + + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + if (row == null) { + LayoutInflater inflater = getLayoutInflater(); + row = inflater.inflate(R.layout.route_info_list_item, parent, false); + } + RouteDirectionInfo model = (RouteDirectionInfo) getItem(position); + TextView label = (TextView) row.findViewById(R.id.description); + TextView distanceLabel = (TextView) row.findViewById(R.id.distance); + TextView timeLabel = (TextView) row.findViewById(R.id.time); + ImageView icon = (ImageView) row.findViewById(R.id.direction); + + if(!(icon.getDrawable() instanceof RouteDrawable)){ + icon.setImageDrawable(new RouteDrawable()); + } + ((RouteDrawable) icon.getDrawable()).setRouteType(model.turnType); + distanceLabel.setText(MapUtils.getFormattedDistance(model.distance)); + label.setText(model.descriptionRoute); + if(model.expectedTime < 3600){ + timeLabel.setText(DateFormat.format("mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$ + } else { + timeLabel.setText(DateFormat.format("k:mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$ + } + return row; + } + } + +} + diff --git a/OsmAnd/src/com/osmand/views/MapInfoLayer.java b/OsmAnd/src/com/osmand/views/MapInfoLayer.java index 5487cc9160..ab86bbdb0b 100644 --- a/OsmAnd/src/com/osmand/views/MapInfoLayer.java +++ b/OsmAnd/src/com/osmand/views/MapInfoLayer.java @@ -2,6 +2,7 @@ package com.osmand.views; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; @@ -10,6 +11,7 @@ import android.graphics.Paint.Style; import android.location.Location; import android.text.format.DateFormat; +import com.osmand.Algoritms; import com.osmand.Messages; import com.osmand.activities.MapActivity; import com.osmand.activities.RoutingHelper.RouteDirectionInfo; @@ -58,6 +60,8 @@ public class MapInfoLayer implements OsmandMapLayer { private int centerMiniRouteY; private int centerMiniRouteX; private float scaleMiniRoute; + private Matrix pathTransform; + private TurnType cachedTurnType; public MapInfoLayer(MapActivity map, RouteLayer layer){ @@ -105,6 +109,7 @@ public class MapInfoLayer implements OsmandMapLayer { boundsForZoom = new RectF(0, 32, 35, 64); boundsForSpeed = new RectF(35, 32, 110, 64); boundsForMiniRoute = new RectF(0, 64, 96, 196); + boundsForLeftTime = new RectF(0, 0, 75, 32); @@ -125,6 +130,8 @@ public class MapInfoLayer implements OsmandMapLayer { pathForCompass2.lineTo(9, 15); pathForTurn = new Path(); + pathTransform = new Matrix(); + pathTransform.setTranslate(boundsForMiniRoute.left, boundsForMiniRoute.top); } public boolean distChanged(int oldDist, int dist){ @@ -139,7 +146,7 @@ public class MapInfoLayer implements OsmandMapLayer { if(map.getPointToNavigate() != null){ int d = 0; if(map.getRoutingHelper().isRouterEnabled()){ - d = map.getRoutingHelper().getDistance(view.getLatitude(), view.getLongitude()); + d = map.getRoutingHelper().getLeftDistance(); } if (d == 0) { Location.distanceBetween(view.getLatitude(), view.getLongitude(), map.getPointToNavigate().getLatitude(), map @@ -209,24 +216,10 @@ public class MapInfoLayer implements OsmandMapLayer { } - private void calcTurnPath(TurnType turnType){ - pathForTurn.reset(); -// if(turnType == TurnType.C){ - int c = (int) ((boundsForMiniRoute.right - boundsForMiniRoute.left) /2 + boundsForMiniRoute.left); - pathForTurn.moveTo(c + 8, boundsForMiniRoute.bottom - 32); - pathForTurn.lineTo(c + 8, boundsForMiniRoute.top + 32); - pathForTurn.lineTo(c + 20, boundsForMiniRoute.top + 32); - pathForTurn.lineTo(c, boundsForMiniRoute.top + 5); - pathForTurn.lineTo(c - 20, boundsForMiniRoute.top + 32); - pathForTurn.lineTo(c - 8, boundsForMiniRoute.top + 32); - pathForTurn.lineTo(c - 8, boundsForMiniRoute.bottom - 32); - pathForTurn.close(); -// } - } - private void drawRouteInfo(Canvas canvas) { - if(routeLayer != null && routeLayer.getHelper().isRouterEnabled()){ - if (showMiniMap) { + if(routeLayer != null && routeLayer.getHelper().isRouterEnabled() && !routeLayer.getHelper().isFollowingMode() ){ + int d = routeLayer.getHelper().getDistanceToNextRouteDirection(); + if (showMiniMap || d == 0) { if (!routeLayer.getPath().isEmpty()) { canvas.save(); canvas.clipRect(boundsForMiniRoute); @@ -240,39 +233,34 @@ public class MapInfoLayer implements OsmandMapLayer { canvas.restore(); } } else { - int d = routeLayer.getHelper().getDistanceToNextRouteDirection(); - if(d > 0){ - canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray); - canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack); - RouteDirectionInfo next = routeLayer.getHelper().getNextRouteDirectionInfo(); - if(next != null){ - calcTurnPath(next.turnType); - canvas.drawPath(pathForTurn, paintRouteDirection); - canvas.drawPath(pathForTurn, paintBlack); - canvas.drawText(MapUtils.getFormattedDistance(d), - boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9, paintBlack); + canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray); + canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack); + RouteDirectionInfo next = routeLayer.getHelper().getNextRouteDirectionInfo(); + if (next != null) { + if (!Algoritms.objectEquals(cachedTurnType, next.turnType)) { + cachedTurnType = next.turnType; + calcTurnPath(pathForTurn, cachedTurnType, pathTransform); } - } else { - // TEST -// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray); -// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack); -// calcTurnPath(TurnType.C); -// canvas.drawPath(pathForTurn, paintRouteDirection); -// canvas.drawPath(pathForTurn, paintBlack); -// canvas.drawText(MapUtils.getFormattedDistance(300), -// boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9, paintBlack); + canvas.drawPath(pathForTurn, paintRouteDirection); + canvas.drawPath(pathForTurn, paintBlack); + canvas.drawText(MapUtils.getFormattedDistance(d), boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9, + paintBlack); } } - + boolean followingMode = routeLayer.getHelper().isFollowingMode(); int time = routeLayer.getHelper().getLeftTime() * 1000; if(time == 0){ cachedLeftTime = 0; cachedLeftTimeString = null; } else { - if(Math.abs(System.currentTimeMillis() + time - cachedLeftTime) > 30000){ - cachedLeftTime = System.currentTimeMillis() + time; - cachedLeftTimeString = DateFormat.format("k:mm", cachedLeftTime).toString(); //$NON-NLS-1$ + long toFindTime = time; + if(followingMode){ + toFindTime += System.currentTimeMillis(); + } + if(Math.abs(toFindTime - cachedLeftTime) > 30000){ + cachedLeftTime = toFindTime; + cachedLeftTimeString = DateFormat.format("kk:mm", cachedLeftTime).toString(); //$NON-NLS-1$ } } if(cachedLeftTimeString != null) { @@ -284,10 +272,111 @@ public class MapInfoLayer implements OsmandMapLayer { canvas.drawText(cachedLeftTimeString, boundsForLeftTime.left + 5, boundsForLeftTime.bottom - 9, paintBlack); } - } + } else { + // TEST + // TODO remove +// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray); +// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack); +// canvas.drawPath(pathForTurn, paintRouteDirection); +// canvas.drawPath(pathForTurn, paintBlack); +// canvas.drawText(MapUtils.getFormattedDistance(300), +// boundsForMiniRoute.left + 15, boundsForMiniRoute.bottom - 9, paintBlack); + } + } + + public static void calcTurnPath(Path pathForTurn, TurnType turnType, Matrix transform) { + pathForTurn.reset(); + // draw path 96x96 + int c = 48; + int w = 16; + pathForTurn.moveTo(c, 94); + float sarrowL = 30; // side of arrow + float harrowL = (float) Math.sqrt(2) * sarrowL; // hypotenuse of arrow + float spartArrowL = (float) ((sarrowL - w / Math.sqrt(2)) / 2); + float hpartArrowL = (float) (harrowL - w) / 2; + + if (turnType == TurnType.C) { + int h = 65; + + pathForTurn.rMoveTo(w / 2, 0); + pathForTurn.rLineTo(0, -h); + pathForTurn.rLineTo(hpartArrowL, 0); + pathForTurn.rLineTo(-harrowL / 2, -harrowL / 2); // center + pathForTurn.rLineTo(-harrowL / 2, harrowL / 2); + pathForTurn.rLineTo(hpartArrowL, 0); + pathForTurn.rLineTo(0, h); + } else if (turnType == TurnType.TR || turnType == TurnType.TL) { + int b = turnType == TurnType.TR ? 1 : -1; + int h = 36; + float quadShiftX = 22; + float quadShiftY = 22; + + pathForTurn.rMoveTo(-b * 8, 0); + pathForTurn.rLineTo(0, -h); + pathForTurn.rQuadTo(0, -quadShiftY, b * quadShiftX, -quadShiftY); + pathForTurn.rLineTo(0, hpartArrowL); + pathForTurn.rLineTo(b * harrowL / 2, -harrowL / 2); // center + pathForTurn.rLineTo(-b * harrowL / 2, -harrowL / 2); + pathForTurn.rLineTo(0, hpartArrowL); + pathForTurn.rQuadTo(-b * (quadShiftX + w), 0, -b * (quadShiftX + w), quadShiftY + w); + pathForTurn.rLineTo(0, h); + } else if (turnType == TurnType.TSLR || turnType == TurnType.TSLL) { + int b = turnType == TurnType.TSLR ? 1 : -1; + int h = 40; + int quadShiftY = 22; + float quadShiftX = (float) (quadShiftY / (1 + Math.sqrt(2))); + float nQuadShiftX = (sarrowL - 2 * spartArrowL) - quadShiftX - w; + float nQuadShifty = quadShiftY + (sarrowL - 2 * spartArrowL); + + pathForTurn.rMoveTo(-b * 4, 0); + pathForTurn.rLineTo(0, -h /* + partArrowL */); + pathForTurn.rQuadTo(0, -quadShiftY + quadShiftX /*- partArrowL*/, b * quadShiftX, -quadShiftY /*- partArrowL*/); + pathForTurn.rLineTo(b * spartArrowL, spartArrowL); + pathForTurn.rLineTo(0, -sarrowL); // center + pathForTurn.rLineTo(-b * sarrowL, 0); + pathForTurn.rLineTo(b * spartArrowL, spartArrowL); + pathForTurn.rQuadTo(b * nQuadShiftX, -nQuadShiftX, b * nQuadShiftX, nQuadShifty); + pathForTurn.rLineTo(0, h); + } else if (turnType == TurnType.TSHR || turnType == TurnType.TSHL) { + int b = turnType == TurnType.TSHR ? 1 : -1; + int h = 45; + float quadShiftX = 22; + float quadShiftY = -(float) (quadShiftX / (1 + Math.sqrt(2))); + float nQuadShiftX = -(sarrowL - 2 * spartArrowL) - quadShiftX - w; + float nQuadShiftY = -quadShiftY + (sarrowL - 2 * spartArrowL); + + pathForTurn.rMoveTo(-b * 8, 0); + pathForTurn.rLineTo(0, -h); + pathForTurn.rQuadTo(0, -(quadShiftX - quadShiftY), b * quadShiftX, quadShiftY); + pathForTurn.rLineTo(-b * spartArrowL, spartArrowL); + pathForTurn.rLineTo(b * sarrowL, 0); // center + pathForTurn.rLineTo(0, -sarrowL); + pathForTurn.rLineTo(-b * spartArrowL, spartArrowL); + pathForTurn.rCubicTo(b * nQuadShiftX / 2, nQuadShiftX / 2, b * nQuadShiftX, nQuadShiftX / 2, b * nQuadShiftX, nQuadShiftY); + pathForTurn.rLineTo(0, h); + } else if(turnType == TurnType.TU){ + int h = 54; + float quadShiftX = 13; + float quadShiftY = 13; + + pathForTurn.rMoveTo(28, 0); + pathForTurn.rLineTo(0, -h); + pathForTurn.rQuadTo(0, -(quadShiftY+w), -(quadShiftX+w), -(quadShiftY+w)); + pathForTurn.rQuadTo(-(quadShiftX+w), 0, -(quadShiftX+w), (quadShiftY+w)); + pathForTurn.rLineTo(-hpartArrowL, 0); + pathForTurn.rLineTo(harrowL/2, harrowL/2); // center + pathForTurn.rLineTo(harrowL/2, -harrowL/2); + pathForTurn.rLineTo(-hpartArrowL, 0); + pathForTurn.rQuadTo(0, -quadShiftX, quadShiftX, -quadShiftY); + pathForTurn.rQuadTo(quadShiftX, 0, quadShiftX, quadShiftY); + pathForTurn.rLineTo(0, h); + } else if(turnType != null && turnType.isExit()){ + // TODO !!! & check how it works + } + pathForTurn.close(); + pathForTurn.transform(transform); } - @Override public void destroyLayer() { } diff --git a/OsmAnd/src/com/osmand/views/RouteLayer.java b/OsmAnd/src/com/osmand/views/RouteLayer.java index 05d41bdb3f..66bf613510 100644 --- a/OsmAnd/src/com/osmand/views/RouteLayer.java +++ b/OsmAnd/src/com/osmand/views/RouteLayer.java @@ -66,7 +66,7 @@ public class RouteLayer implements OsmandMapLayer { view.isPointOnTheRotatedMap(helper.getCurrentLocation().getLatitude(), helper.getCurrentLocation().getLongitude())){ boundsRect = new Rect(-w / 2, -h, 3 * w / 2, h); } else { - boundsRect = new Rect(0, -h, w, h); + boundsRect = new Rect(0, 0, w, h); } view.calculateTileRectangle(boundsRect, view.getCenterPointX(), view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);