diff --git a/OsmAnd-java/src/net/osmand/router/RoutingConfiguration.java b/OsmAnd-java/src/net/osmand/router/RoutingConfiguration.java index 037cd619cd..7b7d4ca14d 100644 --- a/OsmAnd-java/src/net/osmand/router/RoutingConfiguration.java +++ b/OsmAnd-java/src/net/osmand/router/RoutingConfiguration.java @@ -135,6 +135,12 @@ public class RoutingConfiguration { return routers.get(applicationMode); } + + public void removeImpassableRoad(RouteDataObject obj) { + impassableRoadIds.remove(obj.id); + impassableRoads.remove(obj); + + } } private static int parseSilentInt(String t, int v) { diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 3e7adf30cc..ddc776da96 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,8 @@ 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 --> + Select on map + Avoid roads… Tram and train Changes in 1.9: * Updated maps styles with road surface rendering, transport layers and hiking symbols diff --git a/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java b/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java index 5057cc3d47..beff07b766 100644 --- a/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java +++ b/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java @@ -42,7 +42,7 @@ public class CurrentPositionHelper { ctx = new RoutePlannerFrontEnd(false).buildRoutingContext(cfg, null, app.getResourceManager().getRoutingMapFiles()); } - private RouteDataObject runUpdateInThread(Location loc) { + public synchronized RouteDataObject runUpdateInThread(double lat , double lon) { RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd(false); try { if(ctx == null || am != app.getSettings().getApplicationMode()) { @@ -51,7 +51,7 @@ public class CurrentPositionHelper { return null; } } - RouteSegment sg = rp.findRouteSegment(loc.getLatitude(), loc.getLongitude(), ctx); + RouteSegment sg = rp.findRouteSegment(lat, lon, ctx); if(sg == null) { return null; } @@ -64,13 +64,13 @@ public class CurrentPositionHelper { private void scheduleRouteSegmentFind(final Location loc){ if(calculatingThread == Thread.currentThread()) { - lastFound = runUpdateInThread(loc); + lastFound = runUpdateInThread(loc.getLatitude(), loc.getLongitude()); } else if(calculatingThread == null && loc != null) { Runnable run = new Runnable() { @Override public void run() { try { - lastFound = runUpdateInThread(loc); + lastFound = runUpdateInThread(loc.getLatitude(), loc.getLongitude()); if (lastAskedLocation != loc) { // refresh and run new task if needed getLastKnownRouteSegment(lastAskedLocation); diff --git a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java index 85ccc9cf21..d4f4afbfd7 100644 --- a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java +++ b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java @@ -214,6 +214,10 @@ public class OsmAndLocationProvider implements SensorEventListener { currentPositionHelper = new CurrentPositionHelper(app); locationSimulation = new OsmAndLocationSimulation(app, this); } + + public RouteDataObject findRoute(double lat , double lon) { + return currentPositionHelper.runUpdateInThread(lat, lon); + } public void resumeAllUpdates() { final LocationManager service = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE); diff --git a/OsmAnd/src/net/osmand/plus/OsmandApplication.java b/OsmAnd/src/net/osmand/plus/OsmandApplication.java index f00eeb7db9..a7e63613f8 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandApplication.java +++ b/OsmAnd/src/net/osmand/plus/OsmandApplication.java @@ -25,6 +25,7 @@ import net.osmand.plus.activities.SettingsActivity; import net.osmand.plus.api.SQLiteAPI; import net.osmand.plus.api.SQLiteAPIImpl; import net.osmand.plus.download.DownloadActivity; +import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.helpers.WaypointHelper; import net.osmand.plus.monitoring.LiveMonitoringHelper; import net.osmand.plus.render.NativeOsmandLibrary; @@ -109,6 +110,7 @@ public class OsmandApplication extends Application { private TargetPointsHelper targetPointsHelper; private RoutingConfiguration.Builder defaultRoutingConfig; private WaypointHelper waypointHelper; + private AvoidSpecificRoads avoidSpecificRoads; private boolean applicationInitializing = false; private Locale preferredLocale = null; @@ -161,6 +163,7 @@ public class OsmandApplication extends Application { taskManager = new OsmAndTaskManager(this); resourceManager = new ResourceManager(this); daynightHelper = new DayNightHelper(this); + avoidSpecificRoads = new AvoidSpecificRoads(this); locationProvider = new OsmAndLocationProvider(this); savingTrackHelper = new SavingTrackHelper(this); liveMonitoringHelper = new LiveMonitoringHelper(this); @@ -217,6 +220,10 @@ public class OsmandApplication extends Application { public OsmAndTaskManager getTaskManager() { return taskManager; } + + public AvoidSpecificRoads getAvoidSpecificRoads() { + return avoidSpecificRoads; + } public OsmAndLocationProvider getLocationProvider() { @@ -227,6 +234,7 @@ public class OsmandApplication extends Application { return appCustomization; } + public void setAppCustomization(OsmAndAppCustomization appCustomization) { this.appCustomization = appCustomization; this.appCustomization.setup(this); diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 6c49b9fc60..d9a87f8ee5 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -758,6 +758,17 @@ public class MapActivityActions implements DialogProvider { } }).reg(); } + if(routingHelper.isRouteCalculated()) { + optionsMenuHelper.item(R.string.impassable_road) + .icons(R.drawable.ic_action_road_works_dark, R.drawable.ic_action_road_works_light) + .listen(new OnContextMenuClick() { + @Override + public boolean onContextMenuClick(ArrayAdapter adapter, int itemId, int pos, boolean isChecked) { + app.getAvoidSpecificRoads().showDialog(mapActivity); + return true; + } + }).reg(); + } // 5-9. Default actions (Layers, Configure Map screen, Settings, Search, Favorites) optionsMenuHelper.item(R.string.search_button) diff --git a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java index accaf3e288..a6293ccb71 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java @@ -24,7 +24,6 @@ import net.osmand.render.RenderingRulesStorage; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.View; -import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Toast; diff --git a/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java b/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java new file mode 100644 index 0000000000..56a5072d82 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/helpers/AvoidSpecificRoads.java @@ -0,0 +1,172 @@ +package net.osmand.plus.helpers; + +import java.util.ArrayList; +import java.util.List; + +import net.osmand.CallbackWithObject; +import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; +import net.osmand.binary.RouteDataObject; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.views.AnimateDraggingMapThread; +import net.osmand.plus.views.ContextMenuLayer; +import net.osmand.router.RoutingConfiguration; +import net.osmand.util.MapUtils; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +public class AvoidSpecificRoads { + private List missingRoads; + private OsmandApplication app; + + public AvoidSpecificRoads(OsmandApplication app) { + this.app = app; + missingRoads = getBuilder().getImpassableRoads(); + } + + + + protected net.osmand.router.RoutingConfiguration.Builder getBuilder() { + return RoutingConfiguration.getDefault(); + } + + + + public ArrayAdapter createAdapter(final MapActivity ctx) { + final ArrayList points = new ArrayList(); + points.add(new RouteDataObject((RouteRegion) null)); + points.addAll(missingRoads); + final LatLon mapLocation = ctx.getMapLocation(); + return new ArrayAdapter(ctx, + R.layout.waypoint_reached, R.id.title, points) { + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + // User super class to create the View + View v = convertView; + if (position == 0) { + TextView tv = new TextView(ctx); + tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + v = tv; + } else { + if (v == null || v.findViewById(R.id.info_close) == null) { + v = ctx.getLayoutInflater().inflate(R.layout.waypoint_reached, null); + } + final RouteDataObject obj = getItem(position); + v.findViewById(R.id.all_points).setVisibility(View.GONE); + ((ImageView) v.findViewById(R.id.waypoint_icon)).setImageResource(app.getSettings().isLightContentMenu()? + R.drawable.ic_action_road_works_light : R.drawable.ic_action_road_works_dark); + double dist = MapUtils.getDistance(mapLocation, MapUtils.get31LatitudeY(obj.getPoint31YTile(0)) , + MapUtils.get31LongitudeX(obj.getPoint31XTile(0))); + ((TextView)v.findViewById(R.id.waypoint_dist)).setText(OsmAndFormatter.getFormattedDistance((float) dist, app)); + + ((TextView)v.findViewById(R.id.waypoint_text)).setText(getText(obj)); + View remove = v.findViewById(R.id.info_close); + remove.setVisibility(View.VISIBLE); + remove.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + remove(obj); + getBuilder().removeImpassableRoad(obj); + notifyDataSetChanged(); + } + }); + + } + return v; + } + + + }; + } + + + protected String getText(RouteDataObject obj) { + return RoutingHelper.formatStreetName(obj.getName(), obj.getRef(), obj.getDestinationName()); + } + + public void showDialog(final MapActivity mapActivity) { + Builder bld = new AlertDialog.Builder(mapActivity); + bld.setTitle(R.string.impassable_road); + final ArrayAdapter listAdapter = createAdapter(mapActivity); + bld.setAdapter(listAdapter, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + if(which == 0) { + selectFromMap(mapActivity); + } else { + RouteDataObject obj = missingRoads.get(which - 1); + double lat = MapUtils.get31LatitudeY(obj.getPoint31YTile(0)); + double lon = MapUtils.get31LongitudeX(obj.getPoint31XTile(0)); + showOnMap(app, mapActivity, lat, lon, getText(obj), dialog); + } + } + + }); + bld.show(); + } + + + protected void selectFromMap(final MapActivity mapActivity) { + ContextMenuLayer cm = mapActivity.getMapLayers().getContextMenuLayer(); + cm.setSelectOnMap(new CallbackWithObject() { + + @Override + public boolean processResult(LatLon result) { + findRoad(mapActivity, result); + return true; + } + + }); + } + private void findRoad(final MapActivity activity, final LatLon loc) { + new AsyncTask() { + + @Override + protected RouteDataObject doInBackground(LatLon... params) { + return app.getLocationProvider().findRoute(loc.getLatitude(), loc.getLongitude()); + } + + protected void onPostExecute(RouteDataObject result) { + if(result != null) { + getBuilder().addImpassableRoad(result); + showDialog(activity); + } + }; + }.execute(loc); + } + + public static void showOnMap(OsmandApplication app, Activity a, double lat, double lon, String name, + DialogInterface dialog) { + if (!(a instanceof MapActivity)) { + return; + } + MapActivity ctx = (MapActivity) a; + AnimateDraggingMapThread thread = ctx.getMapView().getAnimatedDraggingThread(); + int fZoom = ctx.getMapView().getZoom() < 15 ? 15 : ctx.getMapView().getZoom(); + if (thread.isAnimating()) { + ctx.getMapView().setIntZoom(fZoom); + ctx.getMapView().setLatLon(lat, lon); + } else { + thread.startMoving(lat, lon, fZoom, true); + } + ctx.getMapLayers().getContextMenuLayer().setLocation(new LatLon(lat, lon), name); + dialog.dismiss(); + } + +} diff --git a/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java b/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java index f5781ac746..29e81d39c7 100644 --- a/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java @@ -7,11 +7,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import net.osmand.CallbackWithObject; import net.osmand.data.LatLon; import net.osmand.data.RotatedTileBox; import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import alice.util.Sleep; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; @@ -70,6 +72,7 @@ public class ContextMenuLayer extends OsmandMapLayer { private Drawable boxLeg; private float scaleCoefficient = 1; private Rect textPadding; + private CallbackWithObject selectOnMap = null; public ContextMenuLayer(MapActivity activity){ this.activity = activity; @@ -170,6 +173,12 @@ public class ContextMenuLayer extends OsmandMapLayer { } } + + public void setSelectOnMap(CallbackWithObject selectOnMap) { + this.selectOnMap = selectOnMap; + } + + private void layoutText() { Rect padding = new Rect(); if (textView.getLineCount() > 0) { @@ -333,6 +342,14 @@ public class ContextMenuLayer extends OsmandMapLayer { public boolean onSingleTap(PointF point, RotatedTileBox tileBox) { boolean nativeMode = (Build.VERSION.SDK_INT >= 14) || view.getSettings().SCROLL_MAP_BY_GESTURES.get(); int val = pressedInTextView(tileBox, point.x, point.y); + if(selectOnMap != null) { + LatLon latlon = tileBox.getLatLonFromPixel(point.x, point.y); + CallbackWithObject cb = selectOnMap; + selectOnMap = null; + cb.processResult(latlon); + setLocation(latlon, null); + return true; + } if (val == 2) { setLocation(null, ""); //$NON-NLS-1$ view.refreshMap();