diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml
index c303adf04e..4365db3245 100644
--- a/OsmAnd/res/values/strings.xml
+++ b/OsmAnd/res/values/strings.xml
@@ -10,6 +10,7 @@
- For wording and consistency, please note https://osmand.net/help-online?id=technical-articles#Creating_a_Consistent_User_Experience
Thx - Hardy
-->
+ Public transport
Select road on the map or from the list below that you want to avoid during navigation:
Show along the route
Simulate navigation
diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java
index e3e071b9cd..51bd3b1aa0 100644
--- a/OsmAnd/src/net/osmand/plus/AppInitializer.java
+++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java
@@ -44,6 +44,7 @@ import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper;
import net.osmand.plus.routing.RoutingHelper;
+import net.osmand.plus.routing.TransportRoutingHelper;
import net.osmand.plus.search.QuickSearchHelper;
import net.osmand.plus.views.corenative.NativeCoreContext;
import net.osmand.plus.voice.CommandPlayer;
@@ -458,6 +459,7 @@ public class AppInitializer implements IProgress {
app.applyTheme(app);
app.inAppPurchaseHelper = startupInit(new InAppPurchaseHelper(app), InAppPurchaseHelper.class);
app.poiTypes = startupInit(MapPoiTypes.getDefaultNoInit(), MapPoiTypes.class);
+ app.transportRoutingHelper = startupInit(new TransportRoutingHelper(app), TransportRoutingHelper.class);
app.routingHelper = startupInit(new RoutingHelper(app), RoutingHelper.class);
app.resourceManager = startupInit(new ResourceManager(app), ResourceManager.class);
app.daynightHelper = startupInit(new DayNightHelper(app), DayNightHelper.class);
diff --git a/OsmAnd/src/net/osmand/plus/ApplicationMode.java b/OsmAnd/src/net/osmand/plus/ApplicationMode.java
index dac0b648ab..7c26428b85 100644
--- a/OsmAnd/src/net/osmand/plus/ApplicationMode.java
+++ b/OsmAnd/src/net/osmand/plus/ApplicationMode.java
@@ -57,6 +57,9 @@ public class ApplicationMode {
public static final ApplicationMode TRAIN = create(R.string.app_mode_train, "train").speed(25f, 40).
carLocation().icon(R.drawable.map_action_train, R.drawable.ic_action_train).reg();
+ public static final ApplicationMode PUBLIC_TRANSPORT = create(R.string.app_mode_public_transport, "public_transport").
+ icon(R.drawable.map_action_bus_dark, R.drawable.ic_action_bus_dark).reg();
+
static {
ApplicationMode[] exceptDefault = new ApplicationMode[]{CAR, PEDESTRIAN, BICYCLE, BOAT, AIRCRAFT, BUS, TRAIN};
ApplicationMode[] exceptPedestrianAndDefault = new ApplicationMode[]{CAR, BICYCLE, BOAT, AIRCRAFT, BUS, TRAIN};
diff --git a/OsmAnd/src/net/osmand/plus/OsmandApplication.java b/OsmAnd/src/net/osmand/plus/OsmandApplication.java
index 55748624a2..4be50587b7 100644
--- a/OsmAnd/src/net/osmand/plus/OsmandApplication.java
+++ b/OsmAnd/src/net/osmand/plus/OsmandApplication.java
@@ -57,6 +57,7 @@ import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper;
import net.osmand.plus.routing.RoutingHelper;
+import net.osmand.plus.routing.TransportRoutingHelper;
import net.osmand.plus.search.QuickSearchHelper;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.wikivoyage.data.TravelDbHelper;
@@ -106,6 +107,7 @@ public class OsmandApplication extends MultiDexApplication {
PoiFiltersHelper poiFilters;
MapPoiTypes poiTypes;
RoutingHelper routingHelper;
+ TransportRoutingHelper transportRoutingHelper;
FavouritesDbHelper favorites;
CommandPlayer player;
GpxSelectionHelper selectedGpxHelper;
@@ -402,6 +404,10 @@ public class OsmandApplication extends MultiDexApplication {
return routingHelper;
}
+ public TransportRoutingHelper getTransportRoutingHelper() {
+ return transportRoutingHelper;
+ }
+
public RoutingOptionsHelper getRoutingOptionsHelper() {
return routingOptionsHelper;
}
diff --git a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java
index 4abacf44ed..c49e349c54 100644
--- a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java
+++ b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java
@@ -379,8 +379,8 @@ public class TargetPointsHelper {
}
public void updateRouteAndRefresh(boolean updateRoute) {
- if(updateRoute && ( routingHelper.isRouteBeingCalculated() || routingHelper.isRouteCalculated() ||
- routingHelper.isFollowingMode() || routingHelper.isRoutePlanningMode())) {
+ if(updateRoute && (routingHelper.isPublicTransportMode() || routingHelper.isRouteBeingCalculated() ||
+ routingHelper.isRouteCalculated() || routingHelper.isFollowingMode() || routingHelper.isRoutePlanningMode())) {
updateRoutingHelper();
}
updateListeners();
@@ -388,15 +388,14 @@ public class TargetPointsHelper {
private void updateRoutingHelper() {
LatLon start = settings.getPointToStart();
- Location lastKnownLocation = ctx.getLocationProvider().getLastKnownLocation();
+ LatLon finish = settings.getPointToNavigate();
List is = getIntermediatePointsLatLonNavigation();
+ Location lastKnownLocation = ctx.getLocationProvider().getLastKnownLocation();
if((routingHelper.isFollowingMode() && lastKnownLocation != null) || start == null) {
- routingHelper.setFinalAndCurrentLocation(settings.getPointToNavigate(),
- is, lastKnownLocation);
+ routingHelper.setFinalAndCurrentLocation(finish, is, lastKnownLocation);
} else {
Location loc = wrap(start);
- routingHelper.setFinalAndCurrentLocation(settings.getPointToNavigate(),
- is, loc);
+ routingHelper.setFinalAndCurrentLocation(finish, is, loc);
}
}
diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
index 86168b5947..155522dc84 100644
--- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
@@ -110,9 +110,11 @@ import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.NewGpxData;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager;
+import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.RoutingHelper;
-import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback;
+import net.osmand.plus.routing.TransportRoutingHelper;
+import net.osmand.plus.routing.TransportRoutingHelper.TransportRouteCalculationProgressCallback;
import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab;
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchType;
@@ -439,7 +441,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
private void createProgressBarForRouting() {
final ProgressBar pb = (ProgressBar) findViewById(R.id.map_horizontal_progress);
- app.getRoutingHelper().setProgressBar(new RouteCalculationProgressCallback() {
+ final RouteCalculationProgressCallback progressCallback = new RouteCalculationProgressCallback() {
@Override
public void start() {
@@ -501,6 +503,25 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
dashboardOnMap.routeCalculationFinished();
pb.setVisibility(View.GONE);
}
+ };
+
+ app.getRoutingHelper().setProgressBar(progressCallback);
+
+ app.getTransportRoutingHelper().setProgressBar(new TransportRouteCalculationProgressCallback() {
+ @Override
+ public void start() {
+ progressCallback.start();
+ }
+
+ @Override
+ public void updateProgress(int progress) {
+ progressCallback.updateProgress(progress);
+ }
+
+ @Override
+ public void finish() {
+ progressCallback.finish();
+ }
});
}
diff --git a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java
index e655960eea..af25adabeb 100644
--- a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java
+++ b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java
@@ -25,7 +25,7 @@ import net.osmand.plus.R;
import net.osmand.plus.dashboard.DashboardOnMap;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.routing.RoutingHelper;
-import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
+import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.util.MapUtils;
diff --git a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
index 9704c9f38d..bd395ee44c 100644
--- a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
+++ b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
@@ -80,7 +80,7 @@ import net.osmand.plus.mapillary.MapillaryPlugin.MapillaryFirstDialogFragment;
import net.osmand.plus.osmedit.OsmNotesMenu;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.routing.RoutingHelper;
-import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
+import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.srtmplugin.ContourLinesMenu;
import net.osmand.plus.srtmplugin.HillshadeMenu;
import net.osmand.plus.srtmplugin.SRTMPlugin;
diff --git a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java
index 8e3e85ae94..a5ed90a0d9 100644
--- a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java
+++ b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java
@@ -108,7 +108,8 @@ public class ResourceManager {
TRANSPORT,
ADDRESS,
QUICK_SEARCH,
- ROUTING
+ ROUTING,
+ TRANSPORT_ROUTING
}
public static class BinaryMapReaderResource {
@@ -998,7 +999,20 @@ public class ResourceManager {
}
return readers.toArray(new BinaryMapIndexReader[readers.size()]);
}
-
+
+ public BinaryMapIndexReader[] getTransportRoutingMapFiles() {
+ List readers = new ArrayList<>(fileReaders.size());
+ for(BinaryMapReaderResource r : fileReaders.values()) {
+ if(r.isUseForRouting()) {
+ BinaryMapIndexReader reader = r.getReader(BinaryMapReaderResourceType.TRANSPORT_ROUTING);
+ if (reader != null) {
+ readers.add(reader);
+ }
+ }
+ }
+ return readers.toArray(new BinaryMapIndexReader[readers.size()]);
+ }
+
public BinaryMapIndexReader[] getQuickSearchFiles() {
List readers = new ArrayList<>(fileReaders.size());
for(BinaryMapReaderResource r : fileReaders.values()) {
diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java
index 00c30e6fa2..bba5f73a7e 100644
--- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java
+++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java
@@ -71,7 +71,7 @@ import net.osmand.plus.mapmarkers.MapMarkerSelectionFragment;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
-import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
+import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.views.MapControlsLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.router.GeneralRouter;
diff --git a/OsmAnd/src/net/osmand/plus/routing/IRouteInformationListener.java b/OsmAnd/src/net/osmand/plus/routing/IRouteInformationListener.java
new file mode 100644
index 0000000000..917e2081c5
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/routing/IRouteInformationListener.java
@@ -0,0 +1,12 @@
+package net.osmand.plus.routing;
+
+import net.osmand.ValueHolder;
+
+public interface IRouteInformationListener {
+
+ void newRouteIsCalculated(boolean newRoute, ValueHolder showToast);
+
+ void routeWasCancelled();
+
+ void routeWasFinished();
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
index df11e56b6e..c9f6d15b95 100644
--- a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
+++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
@@ -36,21 +36,12 @@ public class RoutingHelper {
private static final org.apache.commons.logging.Log log = PlatformUtil.getLog(RoutingHelper.class);
- public interface IRouteInformationListener {
-
- void newRouteIsCalculated(boolean newRoute, ValueHolder showToast);
-
- void routeWasCancelled();
-
- void routeWasFinished();
- }
-
private static final float POSITION_TOLERANCE = 60;
-
- private List> listeners = new LinkedList>();
+ private List> listeners = new LinkedList<>();
private OsmandApplication app;
+ private TransportRoutingHelper transportRoutingHelper;
private boolean isFollowingMode = false;
private boolean isRoutePlanningMode = false;
@@ -99,9 +90,13 @@ public class RoutingHelper {
settings = context.getSettings();
voiceRouter = new VoiceRouter(this, settings);
provider = new RouteProvider();
+ transportRoutingHelper = context.getTransportRoutingHelper();
setAppMode(settings.APPLICATION_MODE.get());
}
+ public TransportRoutingHelper getTransportRoutingHelper() {
+ return transportRoutingHelper;
+ }
public boolean isFollowingMode() {
return isFollowingMode;
@@ -160,13 +155,19 @@ public class RoutingHelper {
this.isRoutePlanningMode = isRoutePlanningMode;
}
-
-
- public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, List intermediatePoints, Location currentLocation){
- RouteCalculationResult previousRoute = route;
- clearCurrentRoute(finalLocation, intermediatePoints);
- // to update route
- setCurrentLocation(currentLocation, false, previousRoute, true);
+ public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, List intermediatePoints, Location currentLocation) {
+ if (isPublicTransportMode()) {
+ clearCurrentRoute(null, null);
+ if (currentLocation != null) {
+ transportRoutingHelper.setFinalAndCurrentLocation(finalLocation,
+ new LatLon(currentLocation.getLatitude(), currentLocation.getLongitude()));
+ }
+ } else {
+ RouteCalculationResult previousRoute = route;
+ clearCurrentRoute(finalLocation, intermediatePoints);
+ // to update route
+ setCurrentLocation(currentLocation, false, previousRoute, true);
+ }
}
public synchronized void clearCurrentRoute(LatLon newFinalLocation, List newIntermediatePoints) {
@@ -265,7 +266,7 @@ public class RoutingHelper {
}
public void addListener(IRouteInformationListener l){
- listeners.add(new WeakReference(l));
+ listeners.add(new WeakReference<>(l));
}
public boolean removeListener(IRouteInformationListener lt){
@@ -664,7 +665,7 @@ public class RoutingHelper {
app.runInUIThread(new Runnable() {
@Override
public void run() {
- ValueHolder showToast = new ValueHolder();
+ ValueHolder showToast = new ValueHolder<>();
showToast.value = true;
Iterator> it = listeners.iterator();
while (it.hasNext()) {
@@ -936,8 +937,27 @@ public class RoutingHelper {
}
public void recalculateRouteDueToSettingsChange() {
- clearCurrentRoute(finalLocation, intermediatePoints);
- recalculateRouteInBackground(lastFixedLocation, finalLocation, intermediatePoints, currentGPXRoute, route, true, false);
+ if (isPublicTransportMode()) {
+ Location start = lastFixedLocation;
+ LatLon finish = finalLocation;
+ clearCurrentRoute(null, null);
+ if (start != null && finish != null) {
+ transportRoutingHelper.setFinalAndCurrentLocation(finish,
+ new LatLon(start.getLatitude(), start.getLongitude()));
+ } else {
+ transportRoutingHelper.recalculateRouteDueToSettingsChange();
+ }
+ } else {
+ if (finalLocation == null && intermediatePoints == null) {
+ LatLon finish = settings.getPointToNavigate();
+ List intermediates = app.getTargetPointsHelper().getIntermediatePointsLatLonNavigation();
+ clearCurrentRoute(finish, intermediates);
+ setCurrentLocation(lastFixedLocation, false);
+ } else {
+ clearCurrentRoute(finalLocation, intermediatePoints);
+ recalculateRouteInBackground(lastFixedLocation, finalLocation, intermediatePoints, currentGPXRoute, route, true, false);
+ }
+ }
}
private void recalculateRouteInBackground(final Location start, final LatLon end, final List intermediates,
@@ -1060,6 +1080,9 @@ public class RoutingHelper {
void finish();
}
+ public boolean isPublicTransportMode() {
+ return mode == ApplicationMode.PUBLIC_TRANSPORT;
+ }
public boolean isRouteBeingCalculated(){
return currentRunningJob instanceof RouteRecalculationThread;
diff --git a/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java
new file mode 100644
index 0000000000..df686bd9a4
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/routing/TransportRoutingHelper.java
@@ -0,0 +1,341 @@
+package net.osmand.plus.routing;
+
+import android.support.annotation.NonNull;
+
+import net.osmand.PlatformUtil;
+import net.osmand.ValueHolder;
+import net.osmand.binary.BinaryMapIndexReader;
+import net.osmand.data.LatLon;
+import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.OsmandPlugin;
+import net.osmand.plus.R;
+import net.osmand.plus.routing.RouteProvider.RouteService;
+import net.osmand.router.RouteCalculationProgress;
+import net.osmand.router.RoutingConfiguration;
+import net.osmand.router.TransportRoutePlanner;
+import net.osmand.router.TransportRoutePlanner.TransportRouteResult;
+import net.osmand.router.TransportRoutePlanner.TransportRoutingContext;
+import net.osmand.router.TransportRoutingConfiguration;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static net.osmand.plus.notifications.OsmandNotification.NotificationType.NAVIGATION;
+
+public class TransportRoutingHelper {
+
+ private static final org.apache.commons.logging.Log log = PlatformUtil.getLog(TransportRoutingHelper.class);
+
+ private List> listeners = new LinkedList<>();
+
+ private OsmandApplication app;
+
+ private List routes;
+ private int currentRoute;
+
+ private LatLon startLocation;
+ private LatLon endLocation;
+ private boolean useSchedule;
+
+ private Thread currentRunningJob;
+ private String lastRouteCalcError;
+ private String lastRouteCalcErrorShort;
+ private long lastTimeEvaluatedRoute = 0;
+
+ private TransportRouteCalculationProgressCallback progressRoute;
+
+ public TransportRoutingHelper(@NonNull OsmandApplication app) {
+ this.app = app;
+ }
+
+ public LatLon getStartLocation() {
+ return startLocation;
+ }
+
+ public LatLon getEndLocation() {
+ return endLocation;
+ }
+
+ public boolean isUseSchedule() {
+ return useSchedule;
+ }
+
+ public void setUseSchedule(boolean useSchedule) {
+ this.useSchedule = useSchedule;
+ }
+
+ public int getCurrentRoute() {
+ return currentRoute;
+ }
+
+ public List getRoutes() {
+ return routes;
+ }
+
+ public void setCurrentRoute(int currentRoute) {
+ this.currentRoute = currentRoute;
+ }
+
+ public void recalculateRouteDueToSettingsChange() {
+ clearCurrentRoute(endLocation);
+ recalculateRouteInBackground(startLocation, endLocation);
+ }
+
+ private void recalculateRouteInBackground(LatLon start, LatLon end) {
+ if (start == null || end == null) {
+ return;
+ }
+ TransportRouteCalculationParams params = new TransportRouteCalculationParams();
+ params.start = start;
+ params.end = end;
+ params.useSchedule = useSchedule;
+ params.type = RouteService.OSMAND;
+ params.ctx = app;
+ params.calculationProgress = new RouteCalculationProgress();
+
+ startRouteCalculationThread(params);
+ }
+
+ private void startRouteCalculationThread(TransportRouteCalculationParams params) {
+ synchronized (this) {
+ final Thread prevRunningJob = currentRunningJob;
+ RouteRecalculationThread newThread =
+ new RouteRecalculationThread("Calculating public transport route", params);
+ currentRunningJob = newThread;
+ startProgress(params);
+ updateProgress(params);
+ if (prevRunningJob != null) {
+ newThread.setWaitPrevJob(prevRunningJob);
+ }
+ currentRunningJob.start();
+ }
+ }
+
+ public void setProgressBar(TransportRouteCalculationProgressCallback progressRoute) {
+ this.progressRoute = progressRoute;
+ }
+
+ private void startProgress(final TransportRouteCalculationParams params) {
+ final TransportRouteCalculationProgressCallback progressRoute = this.progressRoute;
+ if (progressRoute != null) {
+ progressRoute.start();
+ }
+ }
+
+ private void updateProgress(final TransportRouteCalculationParams params) {
+ final TransportRouteCalculationProgressCallback progressRoute = this.progressRoute;
+ if (progressRoute != null) {
+ app.runInUIThread(new Runnable() {
+
+ @Override
+ public void run() {
+ RouteCalculationProgress calculationProgress = params.calculationProgress;
+ if (isRouteBeingCalculated()) {
+ float pr = calculationProgress.getLinearProgress();
+ progressRoute.updateProgress((int) pr);
+ Thread t = currentRunningJob;
+ if (t instanceof RouteRecalculationThread && ((RouteRecalculationThread) t).params != params) {
+ // different calculation started
+ } else {
+ updateProgress(params);
+ }
+ } else {
+ progressRoute.finish();
+ }
+ }
+ }, 300);
+ }
+ }
+
+ public boolean isRouteBeingCalculated() {
+ return currentRunningJob instanceof RouteRecalculationThread;
+ }
+
+ private void setNewRoute(final List res) {
+ app.runInUIThread(new Runnable() {
+ @Override
+ public void run() {
+ ValueHolder showToast = new ValueHolder<>();
+ showToast.value = true;
+ Iterator> it = listeners.iterator();
+ while (it.hasNext()) {
+ WeakReference ref = it.next();
+ IRouteInformationListener l = ref.get();
+ if (l == null) {
+ it.remove();
+ } else {
+ l.newRouteIsCalculated(true, showToast);
+ }
+ }
+ if (showToast.value && OsmandPlugin.isDevelopment()) {
+ String msg = "Public transport routes calculated: " + res.size();
+ app.showToastMessage(msg);
+ }
+ }
+ });
+ }
+
+ public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, LatLon currentLocation) {
+ clearCurrentRoute(finalLocation);
+ // to update route
+ setCurrentLocation(currentLocation);
+ }
+
+ public synchronized void clearCurrentRoute(LatLon newFinalLocation) {
+ routes = null;
+ app.getWaypointHelper().setNewRoute(new RouteCalculationResult(""));
+ app.runInUIThread(new Runnable() {
+ @Override
+ public void run() {
+ Iterator> it = listeners.iterator();
+ while (it.hasNext()) {
+ WeakReference ref = it.next();
+ IRouteInformationListener l = ref.get();
+ if (l == null) {
+ it.remove();
+ } else {
+ l.routeWasCancelled();
+ }
+ }
+ }
+ });
+ this.endLocation = newFinalLocation;
+ if (currentRunningJob instanceof RouteRecalculationThread) {
+ ((RouteRecalculationThread) currentRunningJob).stopCalculation();
+ }
+ }
+
+ private void setCurrentLocation(LatLon currentLocation) {
+ if (endLocation == null || currentLocation == null) {
+ return;
+ }
+ startLocation = currentLocation;
+ recalculateRouteInBackground(currentLocation, endLocation);
+ }
+
+ private void showMessage(final String msg) {
+ app.runInUIThread(new Runnable() {
+ @Override
+ public void run() {
+ app.showToastMessage(msg);
+ }
+ });
+ }
+
+ public interface TransportRouteCalculationProgressCallback {
+
+ void start();
+
+ void updateProgress(int progress);
+
+ void finish();
+ }
+
+ public static class TransportRouteCalculationParams {
+
+ public LatLon start;
+ public LatLon end;
+
+ public OsmandApplication ctx;
+ public RouteService type;
+ public boolean useSchedule;
+ public RouteCalculationProgress calculationProgress;
+ public TransportRouteCalculationResultListener resultListener;
+
+ public interface TransportRouteCalculationResultListener {
+ void onRouteCalculated(List route);
+ }
+ }
+
+ private class RouteRecalculationThread extends Thread {
+
+ private final TransportRouteCalculationParams params;
+ private Thread prevRunningJob;
+
+ public RouteRecalculationThread(String name, TransportRouteCalculationParams params) {
+ super(name);
+ this.params = params;
+ if (params.calculationProgress == null) {
+ params.calculationProgress = new RouteCalculationProgress();
+ }
+ }
+
+ public void stopCalculation() {
+ params.calculationProgress.isCancelled = true;
+ }
+
+ private List calculateRouteImpl(TransportRouteCalculationParams params) throws IOException {
+ RoutingConfiguration.Builder config = params.ctx.getDefaultRoutingConfig();
+ BinaryMapIndexReader[] files = params.ctx.getResourceManager().getTransportRoutingMapFiles();
+
+ TransportRoutingConfiguration cfg = new TransportRoutingConfiguration(config);
+ cfg.useSchedule = params.useSchedule;
+ TransportRoutePlanner planner = new TransportRoutePlanner();
+ TransportRoutingContext ctx = new TransportRoutingContext(cfg, files);
+ return planner.buildRoute(ctx, params.start, params.end);
+ }
+
+ @Override
+ public void run() {
+ synchronized (TransportRoutingHelper.this) {
+ currentRunningJob = this;
+ }
+ if (prevRunningJob != null) {
+ while (prevRunningJob.isAlive()) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ synchronized (TransportRoutingHelper.this) {
+ currentRunningJob = this;
+ }
+ }
+
+ List res = null;
+ String error = null;
+ try {
+ res = calculateRouteImpl(params);
+ } catch (IOException e) {
+ error = e.getMessage();
+ log.error(e);
+ }
+ if (params.calculationProgress.isCancelled) {
+ synchronized (TransportRoutingHelper.this) {
+ currentRunningJob = null;
+ }
+ return;
+ }
+ synchronized (TransportRoutingHelper.this) {
+ routes = res;
+ if (res != null) {
+ if (params.resultListener != null) {
+ params.resultListener.onRouteCalculated(res);
+ }
+ }
+ currentRunningJob = null;
+ }
+ if (res != null) {
+ setNewRoute(res);
+ } else if (error != null) {
+ lastRouteCalcError = app.getString(R.string.error_calculating_route) + ":\n" + error;
+ lastRouteCalcErrorShort = app.getString(R.string.error_calculating_route);
+ showMessage(lastRouteCalcError);
+ } else {
+ lastRouteCalcError = app.getString(R.string.empty_route_calculated);
+ lastRouteCalcErrorShort = app.getString(R.string.empty_route_calculated);
+ showMessage(lastRouteCalcError);
+ }
+ app.getNotificationHelper().refreshNotification(NAVIGATION);
+ lastTimeEvaluatedRoute = System.currentTimeMillis();
+ }
+
+ public void setWaitPrevJob(Thread prevRunningJob) {
+ this.prevRunningJob = prevRunningJob;
+ }
+ }
+}
diff --git a/OsmAnd/src/net/osmand/plus/views/POIMapLayer.java b/OsmAnd/src/net/osmand/plus/views/POIMapLayer.java
index f03da3dac1..f475fedef8 100644
--- a/OsmAnd/src/net/osmand/plus/views/POIMapLayer.java
+++ b/OsmAnd/src/net/osmand/plus/views/POIMapLayer.java
@@ -39,7 +39,7 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.routing.RoutingHelper;
-import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
+import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.views.MapTextLayer.MapTextProvider;
import net.osmand.util.Algorithms;
diff --git a/OsmAnd/src/net/osmand/plus/views/RouteLayer.java b/OsmAnd/src/net/osmand/plus/views/RouteLayer.java
index dd7349b754..3b0ef78466 100644
--- a/OsmAnd/src/net/osmand/plus/views/RouteLayer.java
+++ b/OsmAnd/src/net/osmand/plus/views/RouteLayer.java
@@ -17,6 +17,9 @@ import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
+import net.osmand.osm.edit.Node;
+import net.osmand.osm.edit.OSMSettings;
+import net.osmand.osm.edit.Way;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.R;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
@@ -24,6 +27,10 @@ import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu.TrackChartPoints;
import net.osmand.plus.routing.RouteCalculationResult;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
+import net.osmand.plus.routing.TransportRoutingHelper;
+import net.osmand.router.TransportRoutePlanner;
+import net.osmand.router.TransportRoutePlanner.TransportRouteResult;
+import net.osmand.router.TransportRoutePlanner.TransportRouteResultSegment;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
@@ -42,6 +49,7 @@ public class RouteLayer extends OsmandMapLayer {
private OsmandMapTileView view;
private final RoutingHelper helper;
+ private final TransportRoutingHelper transportHelper;
// keep array lists created
private List actionPoints = new ArrayList();
@@ -63,8 +71,9 @@ public class RouteLayer extends OsmandMapLayer {
private RenderingLineAttributes attrs;
- public RouteLayer(RoutingHelper helper){
+ public RouteLayer(RoutingHelper helper) {
this.helper = helper;
+ this.transportHelper = helper.getTransportRoutingHelper();
}
public void setTrackChartPoints(TrackDetailsMenu.TrackChartPoints trackChartPoints) {
@@ -119,7 +128,9 @@ public class RouteLayer extends OsmandMapLayer {
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
- if (helper.getFinalLocation() != null && helper.getRoute().isCalculated()) {
+ if ((helper.isPublicTransportMode() && transportHelper.getRoutes() != null) ||
+ (helper.getFinalLocation() != null && helper.getRoute().isCalculated())) {
+
updateAttrs(settings, tileBox);
if(coloredArrowUp == null) {
@@ -413,6 +424,7 @@ public class RouteLayer extends OsmandMapLayer {
private class RouteSimplificationGeometry {
RouteCalculationResult route;
+ TransportRouteResult transportRoute;
double mapDensity;
TreeMap zooms = new TreeMap<>();
List locations = Collections.emptyList();
@@ -426,7 +438,7 @@ public class RouteLayer extends OsmandMapLayer {
public void updateRoute(RotatedTileBox tb, RouteCalculationResult route) {
if(tb.getMapDensity() != mapDensity || this.route != route) {
this.route = route;
- if(route == null) {
+ if (route == null) {
locations = Collections.emptyList();
} else {
locations = route.getImmutableAllLocations();
@@ -436,6 +448,36 @@ public class RouteLayer extends OsmandMapLayer {
}
}
+ public void updateTransportRoute(RotatedTileBox tb, TransportRouteResult route) {
+ if (tb.getMapDensity() != mapDensity || this.transportRoute != route) {
+ this.transportRoute = route;
+ if (route == null) {
+ locations = Collections.emptyList();
+ } else {
+ LatLon start = transportHelper.getStartLocation();
+ LatLon end = transportHelper.getEndLocation();
+ List list = new ArrayList<>();
+ calculateTransportResult(start, end, route, list);
+ List locs = new ArrayList<>();
+ for (Way w : list) {
+ //Location loc = new Location("transport");
+ //loc.setLatitude(w.getLatitude());
+ //loc.setLongitude(w.getLongitude());
+ //locs.add(loc);
+ for (Node n : w.getNodes()) {
+ Location ln = new Location("transport");
+ ln.setLatitude(n.getLatitude());
+ ln.setLongitude(n.getLongitude());
+ locs.add(ln);
+ }
+ }
+ locations = locs;
+ }
+ this.mapDensity = tb.getMapDensity();
+ zooms.clear();
+ }
+ }
+
private RouteGeometryZoom getGeometryZoom(RotatedTileBox tb) {
RouteGeometryZoom zm = zooms.get(tb.getZoom());
if(zm == null) {
@@ -555,16 +597,32 @@ public class RouteLayer extends OsmandMapLayer {
}
public void drawLocations(RotatedTileBox tb, Canvas canvas, double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) {
- RouteCalculationResult route = helper.getRoute();
- routeGeometry.updateRoute(tb, route);
- routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
- helper.getLastProjection(), route == null ? 0 : route.getCurrentRoute());
- List rd = helper.getRouteDirections();
- Iterator it = rd.iterator();
- if (tb.getZoom() >= 14) {
- List actionPoints = calculateActionPoints(topLatitude, leftLongitude, bottomLatitude, rightLongitude, helper.getLastProjection(),
- helper.getRoute().getRouteLocations(), helper.getRoute().getCurrentRoute(), it, tb.getZoom());
- drawAction(tb, canvas, actionPoints);
+ if (helper.isPublicTransportMode()) {
+ int currentRoute = transportHelper.getCurrentRoute();
+ List routes = transportHelper.getRoutes();
+ TransportRouteResult route = routes != null && routes.size() > currentRoute ? routes.get(currentRoute) : null;
+ routeGeometry.updateRoute(tb, null);
+ routeGeometry.updateTransportRoute(tb, route);
+ if (route != null) {
+ LatLon start = transportHelper.getStartLocation();
+ Location startLocation = new Location("transport");
+ startLocation.setLatitude(start.getLatitude());
+ startLocation.setLongitude(start.getLongitude());
+ routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude, startLocation, 0);
+ }
+ } else {
+ RouteCalculationResult route = helper.getRoute();
+ routeGeometry.updateTransportRoute(tb, null);
+ routeGeometry.updateRoute(tb, route);
+ routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
+ helper.getLastProjection(), route == null ? 0 : route.getCurrentRoute());
+ List rd = helper.getRouteDirections();
+ Iterator it = rd.iterator();
+ if (tb.getZoom() >= 14) {
+ List actionPoints = calculateActionPoints(topLatitude, leftLongitude, bottomLatitude, rightLongitude, helper.getLastProjection(),
+ helper.getRoute().getRouteLocations(), helper.getRoute().getCurrentRoute(), it, tb.getZoom());
+ drawAction(tb, canvas, actionPoints);
+ }
}
}
@@ -711,6 +769,27 @@ public class RouteLayer extends OsmandMapLayer {
}
-
+ private void calculateTransportResult(LatLon start, LatLon end, TransportRouteResult r, List res) {
+ if (r != null) {
+ LatLon p = start;
+ for (TransportRouteResultSegment s : r.getSegments()) {
+ LatLon floc = s.getStart().getLocation();
+ addWalk(res, p, floc);
+ res.addAll(s.getGeometry());
+ p = s.getEnd().getLocation();
+ }
+ addWalk(res, p, end);
+ }
+ }
+ private void addWalk(List res, LatLon s, LatLon e) {
+ double dist = MapUtils.getDistance(s, e);
+ if (dist > 50) {
+ Way way = new Way(-1);
+ way.putTag(OSMSettings.OSMTagKey.NAME.getValue(), String.format("Walk %.1f m", dist));
+ way.addNode(new Node(s.getLatitude(), s.getLongitude(), -1));
+ way.addNode(new Node(e.getLatitude(), e.getLongitude(), -1));
+ res.add(way);
+ }
+ }
}