diff --git a/OsmAnd-java/src/net/osmand/data/LatLon.java b/OsmAnd-java/src/net/osmand/data/LatLon.java index bf64750420..595e53c6cf 100644 --- a/OsmAnd-java/src/net/osmand/data/LatLon.java +++ b/OsmAnd-java/src/net/osmand/data/LatLon.java @@ -1,7 +1,5 @@ package net.osmand.data; -import net.osmand.FloatMath; - import java.io.Serializable; public class LatLon implements Serializable { @@ -17,11 +15,11 @@ public class LatLon implements Serializable { public int hashCode() { final int prime = 31; int result = 1; - long temp; - temp = Double.doubleToLongBits(latitude); - result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(longitude); - result = prime * result + (int) (temp ^ (temp >>> 32)); + int temp; + temp = (int)Math.floor(latitude * 10000); + result = prime * result + temp; + temp = (int)Math.floor(longitude * 10000); + result = prime * result + temp; return result; } @@ -33,19 +31,10 @@ public class LatLon implements Serializable { return false; if (getClass() != obj.getClass()) return false; - LatLon other = (LatLon) obj; - if (Float.floatToIntBits((float) latitude) != Float.floatToIntBits((float) other.latitude)) - return false; - if (Float.floatToIntBits((float) longitude) != Float.floatToIntBits((float) other.longitude)) - return false; -/* - if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude)) - return false; - if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude)) - return false; -*/ - return true; + LatLon other = (LatLon) obj; + return Math.abs(latitude - other.latitude) < 0.00001 + && Math.abs(longitude - other.longitude) < 0.00001; } @Override diff --git a/OsmAnd/src/net/osmand/data/PointDescription.java b/OsmAnd/src/net/osmand/data/PointDescription.java index 9cdaf1cb22..d0c3b2eb79 100644 --- a/OsmAnd/src/net/osmand/data/PointDescription.java +++ b/OsmAnd/src/net/osmand/data/PointDescription.java @@ -235,6 +235,18 @@ public class PointDescription { // return o.getPointDescription(ctx).getFullPlainName(ctx, o.getLatitude(), o.getLongitude()); } + public boolean isSearchingAddress(Context ctx) { + return !Algorithms.isEmpty(name) && isLocation() && name.equals(getSearchAddressStr(ctx)); + } + + public static String getSearchAddressStr(Context ctx) { + return ctx.getString(R.string.looking_up_address) + ctx.getString(R.string.shared_string_ellipsis); + } + + public static String getAddressNotFoundStr(Context ctx) { + return ctx.getString(R.string.no_address_found); + } + public static String serializeToString(PointDescription p) { if (p == null) { return ""; diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java index 577da3300e..879612ec05 100644 --- a/OsmAnd/src/net/osmand/plus/AppInitializer.java +++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java @@ -328,6 +328,7 @@ public class AppInitializer implements IProgress { app.poiFilters = startupInit(new PoiFiltersHelper(app), PoiFiltersHelper.class); app.rendererRegistry = startupInit(new RendererRegistry(app), RendererRegistry.class); app.targetPointsHelper = startupInit(new TargetPointsHelper(app), TargetPointsHelper.class); + app.geocodingLookupService = startupInit(new GeocodingLookupService(app), GeocodingLookupService.class); } diff --git a/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java b/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java index 1da82e05b3..ede940c386 100644 --- a/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java +++ b/OsmAnd/src/net/osmand/plus/CurrentPositionHelper.java @@ -57,7 +57,8 @@ public class CurrentPositionHelper { - private void scheduleRouteSegmentFind(final Location loc, final boolean storeFound, final ResultMatcher geoCoding, final ResultMatcher result) { + private boolean scheduleRouteSegmentFind(final Location loc, final boolean storeFound, final ResultMatcher geoCoding, final ResultMatcher result) { + boolean res = false; if (loc != null) { Runnable run = new Runnable() { @Override @@ -83,15 +84,9 @@ public class CurrentPositionHelper { } } }; - if (!app.getRoutingHelper().startTaskInRouteThreadIfPossible(run)) { - if (result != null) { - result.publish(null); - } - if (geoCoding != null) { - geoCoding.publish(null); - } - } + res = app.getRoutingHelper().startTaskInRouteThreadIfPossible(run); } + return res; } protected void justifyResult(List res, final ResultMatcher result) { @@ -171,12 +166,12 @@ public class CurrentPositionHelper { return d; } - public void getRouteSegment(Location loc, ResultMatcher result) { - scheduleRouteSegmentFind(loc, false, null, result); + public boolean getRouteSegment(Location loc, ResultMatcher result) { + return scheduleRouteSegmentFind(loc, false, null, result); } - public void getGeocodingResult(Location loc, ResultMatcher result) { - scheduleRouteSegmentFind(loc, false, result, null); + public boolean getGeocodingResult(Location loc, ResultMatcher result) { + return scheduleRouteSegmentFind(loc, false, result, null); } public RouteDataObject getLastKnownRouteSegment(Location loc) { diff --git a/OsmAnd/src/net/osmand/plus/GeocodingLookupService.java b/OsmAnd/src/net/osmand/plus/GeocodingLookupService.java new file mode 100644 index 0000000000..eb8046438c --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/GeocodingLookupService.java @@ -0,0 +1,279 @@ +package net.osmand.plus; + +import android.os.AsyncTask; +import android.os.Build; + +import net.osmand.Location; +import net.osmand.ResultMatcher; +import net.osmand.binary.GeocodingUtilities.GeocodingResult; +import net.osmand.binary.RouteDataObject; +import net.osmand.data.LatLon; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class GeocodingLookupService { + + private OsmandApplication app; + private ConcurrentLinkedQueue lookupLocations = new ConcurrentLinkedQueue<>(); + private ConcurrentHashMap> addressLookupRequestsMap = new ConcurrentHashMap<>(); + private LatLon currentRequestedLocation = null; + + private boolean searchDone; + private String lastFoundAddress; + + public interface OnAddressLookupProgress { + void geocodingInProgress(); + } + + public interface OnAddressLookupResult { + void geocodingDone(String address); + } + + public static class AddressLookupRequest { + + private LatLon latLon; + private OnAddressLookupResult uiResultCallback; + private OnAddressLookupProgress uiProgressCallback; + + public AddressLookupRequest(LatLon latLon, OnAddressLookupResult uiResultCallback, + OnAddressLookupProgress uiProgressCallback) { + this.latLon = latLon; + this.uiResultCallback = uiResultCallback; + this.uiProgressCallback = uiProgressCallback; + } + + public LatLon getLatLon() { + return latLon; + } + } + + public GeocodingLookupService(OsmandApplication app) { + this.app = app; + } + + public void lookupAddress(AddressLookupRequest request) { + synchronized (this) { + LatLon requestedLocation = request.latLon; + LatLon existingLocation = null; + if (requestedLocation.equals(currentRequestedLocation)) { + existingLocation = currentRequestedLocation; + requestedLocation = existingLocation; + request.latLon = existingLocation; + } else if (lookupLocations.contains(requestedLocation)) { + for (LatLon latLon : lookupLocations) { + if (latLon.equals(requestedLocation)) { + existingLocation = latLon; + requestedLocation = latLon; + request.latLon = latLon; + break; + } + } + } + List list = addressLookupRequestsMap.get(requestedLocation); + if (list == null) { + list = new ArrayList<>(); + addressLookupRequestsMap.put(requestedLocation, list); + } + list.add(request); + if (existingLocation == null) { + lookupLocations.add(requestedLocation); + } + + if (currentRequestedLocation == null) { + execute(new AddressLookupRequestsAsyncTask(app)); + } + } + } + + public void cancel(AddressLookupRequest request) { + synchronized (this) { + List requests = addressLookupRequestsMap.get(request.latLon); + if (requests != null && requests.size() > 0) { + requests.remove(request); + } + } + } + + private boolean hasAnyRequest(LatLon latLon) { + synchronized (this) { + List requests = addressLookupRequestsMap.get(latLon); + return requests != null && requests.size() > 0; + } + } + + @SuppressWarnings("unchecked") + private

void execute(AsyncTask task, P... requests) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests); + } else { + task.execute(requests); + } + } + + private boolean geocode(final LatLon latLon) { + Location loc = new Location(""); + loc.setLatitude(latLon.getLatitude()); + loc.setLongitude(latLon.getLongitude()); + return app.getLocationProvider() + .getGeocodingResult(loc, new ResultMatcher() { + + @Override + public boolean publish(GeocodingResult object) { + String result = null; + if (object != null) { + OsmandSettings settings = app.getSettings(); + String lang = settings.MAP_PREFERRED_LOCALE.get(); + String geocodingResult = ""; + double relevantDistance = -1; + + if (object.building != null) { + String bldName = object.building.getName(lang); + if (!Algorithms.isEmpty(object.buildingInterpolation)) { + bldName = object.buildingInterpolation; + } + geocodingResult = object.street.getName(lang) + " " + bldName + ", " + + object.city.getName(lang); + } else if (object.street != null) { + geocodingResult = object.street.getName(lang) + ", " + object.city.getName(lang); + relevantDistance = object.getDistanceP(); + } else if (object.city != null) { + geocodingResult = object.city.getName(lang); + } else if (object.point != null) { + RouteDataObject rd = object.point.getRoad(); + String sname = rd.getName(lang); + if (Algorithms.isEmpty(sname)) { + sname = ""; + } + String ref = rd.getRef(); + if (!Algorithms.isEmpty(ref)) { + if (!Algorithms.isEmpty(sname)) { + sname += ", "; + } + sname += ref; + } + geocodingResult = sname; + relevantDistance = object.getDistanceP(); + } + + result = geocodingResult; + if (relevantDistance == -1) { + relevantDistance = object.getDistance(); + } + + if (!Algorithms.isEmpty(result) && relevantDistance > 100) { + result = app.getString(R.string.shared_string_near) + " " + result; + } + } + + lastFoundAddress = result; + searchDone = true; + + return true; + } + + @Override + public boolean isCancelled() { + return !hasAnyRequest(latLon); + } + + }); + } + + private class AddressLookupRequestsAsyncTask extends AsyncTask { + + private OsmandApplication app; + + public AddressLookupRequestsAsyncTask(OsmandApplication app) { + super(); + this.app = app; + } + + @Override + protected Void doInBackground(AddressLookupRequest... addressLookupRequests) { + for (;;) { + try { + while (!lookupLocations.isEmpty()) { + final LatLon latLon; + synchronized (GeocodingLookupService.this) { + latLon = lookupLocations.poll(); + currentRequestedLocation = latLon; + List requests = addressLookupRequestsMap.get(latLon); + if (requests == null || requests.size() == 0) { + addressLookupRequestsMap.remove(latLon); + continue; + } + } + + // geocode + searchDone = false; + while (!geocode(latLon)) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + long counter = 0; + while (!searchDone) { + try { + Thread.sleep(50); + counter++; + // call progress every 500 ms + if (counter == 10) { + counter = 0; + synchronized (GeocodingLookupService.this) { + List requests = addressLookupRequestsMap.get(latLon); + for (final AddressLookupRequest request : requests) { + if (request.uiProgressCallback != null) { + app.runInUIThread(new Runnable() { + @Override + public void run() { + request.uiProgressCallback.geocodingInProgress(); + } + }); + } + } + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + synchronized (GeocodingLookupService.this) { + List requests = addressLookupRequestsMap.get(latLon); + for (final AddressLookupRequest request : requests) { + if (request.uiResultCallback != null) { + app.runInUIThread(new Runnable() { + @Override + public void run() { + request.uiResultCallback.geocodingDone(lastFoundAddress); + } + }); + } + } + addressLookupRequestsMap.remove(latLon); + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + + synchronized (GeocodingLookupService.this) { + currentRequestedLocation = null; + if (lookupLocations.isEmpty()) { + break; + } + } + } + + return null; + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java index 3fd6ea564c..69be8df20b 100644 --- a/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java +++ b/OsmAnd/src/net/osmand/plus/OsmAndLocationProvider.java @@ -857,12 +857,12 @@ public class OsmAndLocationProvider implements SensorEventListener { return currentPositionHelper.getLastKnownRouteSegment(getLastKnownLocation()); } - public void getRouteSegment(net.osmand.Location loc, ResultMatcher result) { - currentPositionHelper.getRouteSegment(loc, result); + public boolean getRouteSegment(net.osmand.Location loc, ResultMatcher result) { + return currentPositionHelper.getRouteSegment(loc, result); } - public void getGeocodingResult(net.osmand.Location loc, ResultMatcher result) { - currentPositionHelper.getGeocodingResult(loc, result); + public boolean getGeocodingResult(net.osmand.Location loc, ResultMatcher result) { + return currentPositionHelper.getGeocodingResult(loc, result); } public net.osmand.Location getLastKnownLocation() { diff --git a/OsmAnd/src/net/osmand/plus/OsmandApplication.java b/OsmAnd/src/net/osmand/plus/OsmandApplication.java index b4e5b6dea0..8ff2c5d8fd 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandApplication.java +++ b/OsmAnd/src/net/osmand/plus/OsmandApplication.java @@ -96,7 +96,7 @@ public class OsmandApplication extends MultiDexApplication { AvoidSpecificRoads avoidSpecificRoads; BRouterServiceConnection bRouterServiceConnection; OsmandRegions regions; - + GeocodingLookupService geocodingLookupService; RoutingConfiguration.Builder defaultRoutingConfig; private Locale preferredLocale = null; @@ -329,6 +329,10 @@ public class OsmandApplication extends MultiDexApplication { return routingHelper; } + public GeocodingLookupService getGeocodingLookupService() { + return geocodingLookupService; + } + public CommandPlayer getPlayer() { return player; } diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 417c3e3742..79a86b80a0 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -1551,12 +1551,23 @@ public class OsmandSettings { List ds = getIntermediatePointDescriptions(ps.size()); ps.add(index, new LatLon(latitude, longitude)); ds.add(index, PointDescription.serializeToString(historyDescription)); - if (historyDescription != null) { + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); } return saveIntermediatePoints(ps,ds); } - + + public boolean updateIntermediatePoint(double latitude, double longitude, PointDescription historyDescription) { + List ps = getIntermediatePoints(); + List ds = getIntermediatePointDescriptions(ps.size()); + int i = ps.indexOf(new LatLon(latitude, longitude)); + ds.set(i, PointDescription.serializeToString(historyDescription)); + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { + SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); + } + return saveIntermediatePoints(ps,ds); + } + public boolean deleteIntermediatePoint( int index) { List ps = getIntermediatePoints(); List ds = getIntermediatePointDescriptions(ps.size()); @@ -1603,7 +1614,7 @@ public class OsmandSettings { boolean add = settingsAPI.edit(globalPreferences).putFloat(POINT_NAVIGATE_LAT, (float) latitude).putFloat(POINT_NAVIGATE_LON, (float) longitude).commit(); settingsAPI.edit(globalPreferences).putString(POINT_NAVIGATE_DESCRIPTION, PointDescription.serializeToString(p)).commit(); if(add){ - if(p != null){ + if(p != null && !p.isSearchingAddress(ctx)){ SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, p); } } diff --git a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java index ee4035a11e..10a4c04b63 100644 --- a/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java +++ b/OsmAnd/src/net/osmand/plus/TargetPointsHelper.java @@ -8,8 +8,10 @@ import net.osmand.StateChangedListener; import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.PointDescription; +import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.routing.RouteProvider.RouteService; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.util.ArrayList; @@ -24,7 +26,10 @@ public class TargetPointsHelper { private RoutingHelper routingHelper; private List> listeners = new ArrayList>(); private OsmandApplication ctx; - + + private AddressLookupRequest startPointRequest; + private AddressLookupRequest targetPointRequest; + public static class TargetPoint implements LocationPoint { public LatLon point; private PointDescription pointDescription; @@ -340,20 +345,73 @@ public class TargetPointsHelper { navigateToPoint(point, updateRoute, intermediate, null); } - public void navigateToPoint(LatLon point, boolean updateRoute, int intermediate, PointDescription historyName){ + public void navigateToPoint(final LatLon point, boolean updateRoute, int intermediate, PointDescription historyName){ if(point != null){ + final PointDescription pointDescription; + if (historyName == null) { + pointDescription = new PointDescription(PointDescription.POINT_TYPE_LOCATION, ""); + } else { + pointDescription = historyName; + } + boolean needAddress = false; + if (pointDescription.isLocation() && Algorithms.isEmpty(pointDescription.getName())) { + pointDescription.setName(PointDescription.getSearchAddressStr(ctx)); + needAddress = true; + } + if(intermediate < 0 || intermediate > intermediatePoints.size()) { + cancelTargetPointAddressRequest(); + if(intermediate > intermediatePoints.size()) { - TargetPoint pn = getPointToNavigate(); + final TargetPoint pn = getPointToNavigate(); if(pn != null) { settings.insertIntermediatePoint(pn.getLatitude(), pn.getLongitude(), pn.pointDescription, intermediatePoints.size()); + if (pn.pointDescription.isSearchingAddress(ctx)) { + AddressLookupRequest lookupRequest = new AddressLookupRequest(point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + pn.pointDescription.setName(address); + settings.updateIntermediatePoint(pn.getLatitude(), pn.getLongitude(), pn.pointDescription); + readFromSettings(settings); + updateRouteAndRefresh(false); + } + }, null); + ctx.getGeocodingLookupService().lookupAddress(lookupRequest); + } } } - settings.setPointToNavigate(point.getLatitude(), point.getLongitude(), historyName); + + settings.setPointToNavigate(point.getLatitude(), point.getLongitude(), pointDescription); + + if (needAddress) { + targetPointRequest = new AddressLookupRequest(point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + targetPointRequest = null; + pointDescription.setName(address); + settings.setPointToNavigate(point.getLatitude(), point.getLongitude(), pointDescription); + readFromSettings(settings); + updateRouteAndRefresh(false); + } + }, null); + ctx.getGeocodingLookupService().lookupAddress(targetPointRequest); + } } else { - settings.insertIntermediatePoint(point.getLatitude(), point.getLongitude(), historyName, + settings.insertIntermediatePoint(point.getLatitude(), point.getLongitude(), pointDescription, intermediate); + if (pointDescription.isSearchingAddress(ctx)) { + AddressLookupRequest lookupRequest = new AddressLookupRequest(point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + pointDescription.setName(address); + settings.updateIntermediatePoint(point.getLatitude(), point.getLongitude(), pointDescription); + readFromSettings(settings); + updateRouteAndRefresh(false); + } + }, null); + ctx.getGeocodingLookupService().lookupAddress(lookupRequest); + } } } else { settings.clearPointToNavigate(); @@ -363,9 +421,35 @@ public class TargetPointsHelper { updateRouteAndRefresh(updateRoute); } - public void setStartPoint(LatLon startPoint, boolean updateRoute, PointDescription name) { + public void setStartPoint(final LatLon startPoint, boolean updateRoute, PointDescription name) { if(startPoint != null) { - settings.setPointToStart(startPoint.getLatitude(), startPoint.getLongitude(), name); + final PointDescription pointDescription; + if (name == null) { + pointDescription = new PointDescription(PointDescription.POINT_TYPE_LOCATION, ""); + } else { + pointDescription = name; + } + boolean needAddress = false; + if (pointDescription.isLocation() && Algorithms.isEmpty(pointDescription.getName())) { + pointDescription.setName(PointDescription.getSearchAddressStr(ctx)); + needAddress = true; + } + settings.setPointToStart(startPoint.getLatitude(), startPoint.getLongitude(), pointDescription); + + cancelStartPointAddressRequest(); + if (needAddress) { + startPointRequest = new AddressLookupRequest(startPoint, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + startPointRequest = null; + pointDescription.setName(address); + settings.setPointToStart(startPoint.getLatitude(), startPoint.getLongitude(), pointDescription); + readFromSettings(settings); + updateRouteAndRefresh(false); + } + }, null); + ctx.getGeocodingLookupService().lookupAddress(startPointRequest); + } } else { settings.clearPointToStart(); } @@ -384,4 +468,18 @@ public class TargetPointsHelper { public Location getPointToStartLocation() { return wrap(getPointToStart()); } + + private void cancelStartPointAddressRequest() { + if (startPointRequest != null) { + ctx.getGeocodingLookupService().cancel(startPointRequest); + startPointRequest = null; + } + } + + private void cancelTargetPointAddressRequest() { + if (targetPointRequest != null) { + ctx.getGeocodingLookupService().cancel(targetPointRequest); + targetPointRequest = null; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java index 09631c6a09..0919799700 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java @@ -30,6 +30,7 @@ import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.PointDescription; +import net.osmand.plus.GeocodingLookupService; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -286,7 +287,7 @@ public class WaypointDialogHelper { final WaypointDialogHelper helper = this; - return new StableArrayAdapter(ctx, + final StableArrayAdapter listAdapter = new StableArrayAdapter(ctx, R.layout.waypoint_reached, R.id.title, points, activePoints) { @Override @@ -341,6 +342,29 @@ public class WaypointDialogHelper { return v; } }; + + for (Object p : points) { + if (p instanceof LocationPointWrapper) { + LocationPointWrapper w = (LocationPointWrapper) p; + if (w.type == WaypointHelper.TARGETS) { + final TargetPoint t = (TargetPoint) w.point; + if (t.getOriginalPointDescription() != null + && t.getOriginalPointDescription().isSearchingAddress(mapActivity)) { + GeocodingLookupService.AddressLookupRequest lookupRequest + = new GeocodingLookupService.AddressLookupRequest(t.point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + reloadListAdapter(listAdapter); + } + }, null); + app.getGeocodingLookupService().lookupAddress(lookupRequest); + } + + } + } + } + + return listAdapter; } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenu.java index 7c035c7c1b..3750f20ecc 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenu.java @@ -415,59 +415,49 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL } public void fabPressed() { - callMenuAction(true, new MenuAction() { - @Override - public void run() { - hide(); - final TargetPointsHelper targets = mapActivity.getMyApplication().getTargetPointsHelper(); - if (targets.getIntermediatePoints().isEmpty()) { - targets.navigateToPoint(latLon, true, -1, getPointDescriptionForTarget()); - mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); - } else { - Builder bld = new AlertDialog.Builder(mapActivity); - bld.setTitle(R.string.new_directions_point_dialog); - final int[] defaultVls = new int[]{0}; - bld.setSingleChoiceItems(new String[]{ - mapActivity.getString(R.string.clear_intermediate_points), - mapActivity.getString(R.string.keep_intermediate_points) - }, 0, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - defaultVls[0] = which; - } - }); - bld.setPositiveButton(R.string.shared_string_ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - if (defaultVls[0] == 0) { - targets.removeAllWayPoints(false); - targets.navigateToPoint(latLon, true, -1, getPointDescriptionForTarget()); - mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); - } else { - targets.navigateToPoint(latLon, true, -1, getPointDescriptionForTarget()); - mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); - } - } - }); - bld.setNegativeButton(R.string.shared_string_cancel, null); - bld.show(); + hide(); + final TargetPointsHelper targets = mapActivity.getMyApplication().getTargetPointsHelper(); + if (targets.getIntermediatePoints().isEmpty()) { + targets.navigateToPoint(latLon, true, -1, pointDescription); + mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); + } else { + Builder bld = new AlertDialog.Builder(mapActivity); + bld.setTitle(R.string.new_directions_point_dialog); + final int[] defaultVls = new int[]{0}; + bld.setSingleChoiceItems(new String[]{ + mapActivity.getString(R.string.clear_intermediate_points), + mapActivity.getString(R.string.keep_intermediate_points) + }, 0, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + defaultVls[0] = which; } - } - }); + }); + bld.setPositiveButton(R.string.shared_string_ok, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + if (defaultVls[0] == 0) { + targets.removeAllWayPoints(false); + targets.navigateToPoint(latLon, true, -1, pointDescription); + mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); + } else { + targets.navigateToPoint(latLon, true, -1, pointDescription); + mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(null, null, null, true); + } + } + }); + bld.setNegativeButton(R.string.shared_string_cancel, null); + bld.show(); + } } public void buttonWaypointPressed() { if (pointDescription.isDestination()) { mapActivity.getMapActions().editWaypoints(); } else { - callMenuAction(true, new MenuAction() { - @Override - public void run() { - mapActivity.getMapActions().addAsTarget(latLon.getLatitude(), latLon.getLongitude(), - getPointDescriptionForTarget()); - } - }); + mapActivity.getMapActions().addAsTarget(latLon.getLatitude(), latLon.getLongitude(), + pointDescription); } close(); } @@ -480,7 +470,7 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL @Override public void run() { String title = getTitleStr(); - if (pointDescription.isFavorite() || title.equals(addressNotKnownStr)) { + if (pointDescription.isFavorite() || !hasValidTitle()) { title = ""; } getFavoritePointEditor().add(latLon, title); @@ -508,68 +498,33 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL mapActivity.getMapActions().contextMenuPoint(latLon.getLatitude(), latLon.getLongitude(), menuAdapter, object); } - private void callMenuAction(boolean waitForAddress, MenuAction addAsTargetAction) { - if (searchingAddress && waitForAddress) { - addAsTargetAction.dlg = new ProgressDialog(mapActivity); - addAsTargetAction.dlg.setTitle(""); - addAsTargetAction.dlg.setMessage(addressNotKnownStr); - addAsTargetAction.dlg.setButton(Dialog.BUTTON_NEGATIVE, mapActivity.getResources().getString(R.string.shared_string_skip), new DialogInterface.OnClickListener() { + private void callMenuAction(boolean waitForAddressLookup, MenuAction menuAction) { + if (searchingAddress() && waitForAddressLookup) { + menuAction.dlg = new ProgressDialog(mapActivity); + menuAction.dlg.setTitle(""); + menuAction.dlg.setMessage(searchAddressStr); + menuAction.dlg.setButton(Dialog.BUTTON_NEGATIVE, mapActivity.getResources().getString(R.string.shared_string_skip), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - cancelSearch = true; + cancelSearchAddress(); } }); - addAsTargetAction.dlg.show(); - searchDoneAction = addAsTargetAction; + menuAction.dlg.show(); + searchDoneAction = menuAction; } else { - addAsTargetAction.run(); + menuAction.run(); } } - private PointDescription getPointDescriptionForTarget() { - return hasKnownTitle() ? null : pointDescription; - } - public void addAsLastIntermediate() { - callMenuAction(true, new MenuAction() { - @Override - public void run() { - mapActivity.getMyApplication().getTargetPointsHelper().navigateToPoint(latLon, - true, mapActivity.getMyApplication().getTargetPointsHelper().getIntermediatePoints().size(), - getPointDescriptionForTarget()); - close(); - } - }); - } - - public void setAsStartPoint(final boolean openRouteInfoMenu) { - callMenuAction(true, new MenuAction() { - @Override - public void run() { - mapActivity.getMyApplication().getTargetPointsHelper().setStartPoint(latLon, true, - getPointDescriptionForTarget()); - if (openRouteInfoMenu) { - mapActivity.getMapLayers().getMapControlsLayer().getMapRouteInfoMenu().show(); - } - } - }); - } - - public void setAsTargetPoint(final boolean openRouteInfoMenu) { - callMenuAction(true, new MenuAction() { - @Override - public void run() { - mapActivity.getMyApplication().getTargetPointsHelper().navigateToPoint(latLon, true, -1, - getPointDescriptionForTarget()); - if (openRouteInfoMenu) { - mapActivity.getMapLayers().getMapControlsLayer().getMapRouteInfoMenu().show(); - } - } - }); + mapActivity.getMyApplication().getTargetPointsHelper().navigateToPoint(latLon, + true, mapActivity.getMyApplication().getTargetPointsHelper().getIntermediatePoints().size(), + pointDescription); + close(); } public void addWptPt() { String title = getTitleStr(); - if (pointDescription.isWpt() || title.equals(addressNotKnownStr)) { + if (pointDescription.isWpt() || !hasValidTitle()) { title = ""; } @@ -722,10 +677,6 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL return menuController != null && menuController.displayDistanceDirection(); } - public boolean displayStreetNameInTitle() { - return menuController != null && menuController.displayStreetNameInTitle(); - } - public void updateData() { if (menuController != null) { menuController.updateData(); diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuTitleController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuTitleController.java index d5f6857abd..2c3b18a9c6 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuTitleController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuTitleController.java @@ -2,14 +2,10 @@ package net.osmand.plus.mapcontextmenu; import android.graphics.drawable.Drawable; -import net.osmand.Location; -import net.osmand.ResultMatcher; -import net.osmand.binary.GeocodingUtilities.GeocodingResult; -import net.osmand.binary.RouteDataObject; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; -import net.osmand.plus.OsmandSettings; -import net.osmand.plus.R; +import net.osmand.plus.GeocodingLookupService; +import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.activities.MapActivity; import net.osmand.util.Algorithms; @@ -22,9 +18,11 @@ public abstract class MenuTitleController { protected String commonTypeStr = ""; protected Drawable secondLineTypeIcon; protected String streetStr = ""; - protected String addressNotKnownStr; - protected boolean searchingAddress; - protected boolean cancelSearch; + + private AddressLookupRequest addressLookupRequest; + + protected String searchAddressStr; + protected String addressNotFoundStr; public abstract MapActivity getMapActivity(); @@ -37,18 +35,34 @@ public abstract class MenuTitleController { public abstract MenuController getMenuController(); public String getTitleStr() { - //if (Algorithms.isEmpty(nameStr) && searchingAddress) { - // searchingAddress did not work here once search was interrupted by a new search - if (Algorithms.isEmpty(nameStr) && needStreetName()) { - return addressNotKnownStr; + if (displayStreetNameInTitle() && searchingAddress()) { + return searchAddressStr; } else { return nameStr; } } - public boolean hasKnownTitle() { + public boolean searchingAddress() { + return addressLookupRequest != null; + } + + public void cancelSearchAddress() { + if (addressLookupRequest != null) { + getMapActivity().getMyApplication().getGeocodingLookupService().cancel(addressLookupRequest); + addressLookupRequest = null; + onSearchAddressDone(); + } + } + + public boolean displayStreetNameInTitle() { + MenuController menuController = getMenuController(); + return menuController != null && menuController.displayStreetNameInTitle(); + } + + // Has title which does not equal to "Looking up address" and "No address determined" + public boolean hasValidTitle() { String title = getTitleStr(); - return getMapActivity().getString(R.string.no_address_found).equals(title) || addressNotKnownStr.equals(title); + return !addressNotFoundStr.equals(title) && !searchAddressStr.equals(title); } public int getLeftIconId() { @@ -72,18 +86,10 @@ public abstract class MenuTitleController { } } - public String getCommonTypeStr() { - return commonTypeStr; - } - public String getStreetStr() { - MenuController menuController = getMenuController(); - if (menuController != null && menuController.needStreetName()) { - // Display "Looking up address..." status - //if (searchingAddress) { - // Again here searchingAddress does not work for case of search interrupted by new searcj, so: - if (Algorithms.isEmpty(streetStr)) { - return addressNotKnownStr; + if (needStreetName()) { + if (searchingAddress()) { + return searchAddressStr; } else { return streetStr; } @@ -93,7 +99,13 @@ public abstract class MenuTitleController { } protected void initTitle() { - addressNotKnownStr = getMapActivity().getString(R.string.looking_up_address) + getMapActivity().getString(R.string.shared_string_ellipsis); + searchAddressStr = PointDescription.getSearchAddressStr(getMapActivity()); + addressNotFoundStr = PointDescription.getAddressNotFoundStr(getMapActivity()); + + if (searchingAddress()) { + cancelSearchAddress(); + } + acquireIcons(); acquireNameAndType(); if (needStreetName()) { @@ -146,95 +158,30 @@ public abstract class MenuTitleController { } protected void acquireStreetName() { - if (searchingAddress) { - cancelSearch = true; - getMapActivity().getMyApplication().runInUIThread(new Runnable() { - @Override - public void run() { - acquireStreetName(); + addressLookupRequest = new AddressLookupRequest(getLatLon(), new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + addressLookupRequest = null; + if (Algorithms.isEmpty(address)) { + streetStr = PointDescription.getAddressNotFoundStr(getMapActivity()); + } else { + streetStr = address; } - }, 100); - return; - } - searchingAddress = true; - cancelSearch = false; - Location ll = new Location(""); - ll.setLatitude(getLatLon().getLatitude()); - ll.setLongitude(getLatLon().getLongitude()); - getMapActivity().getMyApplication().getLocationProvider() - .getGeocodingResult(ll, new ResultMatcher() { + if (displayStreetNameInTitle()) { + nameStr = streetStr; + getPointDescription().setName(nameStr); + } + onSearchAddressDone(); + } + }, new GeocodingLookupService.OnAddressLookupProgress() { + @Override + public void geocodingInProgress() { + // animate three dots + } + }); - @Override - public boolean publish(GeocodingResult object) { - if (object != null) { - OsmandSettings settings = getMapActivity().getMyApplication().getSettings(); - String lang = settings.MAP_PREFERRED_LOCALE.get(); - String geocodingResult = ""; - double relevantDistance = -1; - - if (object.building != null) { - String bldName = object.building.getName(lang); - if (!Algorithms.isEmpty(object.buildingInterpolation)) { - bldName = object.buildingInterpolation; - } - geocodingResult = object.street.getName(lang) + " " + bldName + ", " - + object.city.getName(lang); - } else if (object.street != null) { - geocodingResult = object.street.getName(lang) + ", " + object.city.getName(lang); - relevantDistance = object.getDistanceP(); - } else if (object.city != null) { - geocodingResult = object.city.getName(lang); - } else if (object.point != null) { - RouteDataObject rd = object.point.getRoad(); - String sname = rd.getName(lang); - if (Algorithms.isEmpty(sname)) { - sname = ""; - } - String ref = rd.getRef(); - if (!Algorithms.isEmpty(ref)) { - if (!Algorithms.isEmpty(sname)) { - sname += ", "; - } - sname += ref; - } - geocodingResult = sname; - relevantDistance = object.getDistanceP(); - } - - streetStr = geocodingResult; - if (relevantDistance == -1) { - relevantDistance = object.getDistance(); - } - - if (!Algorithms.isEmpty(streetStr) && relevantDistance > 100) { - streetStr = getMapActivity().getString(R.string.shared_string_near) + " " + streetStr; - } else if (Algorithms.isEmpty(streetStr)) { - streetStr = getMapActivity().getString(R.string.no_address_found); - } - - MenuController menuController = getMenuController(); - if (menuController == null || menuController.displayStreetNameInTitle()) { - nameStr = streetStr; - getPointDescription().setName(nameStr); - } - } - - searchingAddress = false; - getMapActivity().runOnUiThread(new Runnable() { - public void run() { - onSearchAddressDone(); - } - }); - return true; - } - - @Override - public boolean isCancelled() { - return cancelSearch; - } - - }); + getMapActivity().getMyApplication().getGeocodingLookupService().lookupAddress(addressLookupRequest); } protected void onSearchAddressDone() { diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapDataMenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapDataMenuController.java index 6e4b8ce5af..ba7069757c 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapDataMenuController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapDataMenuController.java @@ -141,11 +141,6 @@ public class MapDataMenuController extends MenuController { } } - @Override - protected int getSupportedMenuStatesPortrait() { - return MenuState.HEADER_ONLY | MenuState.HALF_SCREEN; - } - @Override public boolean needTypeStr() { return true; diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/MapRouteInfoMenu.java index 7eb7daf808..d35f1fa5b5 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/MapRouteInfoMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/MapRouteInfoMenu.java @@ -25,6 +25,8 @@ import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.RotatedTileBox; import net.osmand.plus.ApplicationMode; +import net.osmand.plus.GeocodingLookupService; +import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.IconsCache; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; @@ -58,6 +60,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener { private final MapContextMenu contextMenu; private final RoutingHelper routingHelper; private OsmandMapTileView mapView; + private GeocodingLookupService geocodingLookupService; private boolean selectFromMapTouch; private boolean selectFromMapForTarget; @@ -69,6 +72,9 @@ public class MapRouteInfoMenu implements IRouteInformationListener { private boolean nightMode; private boolean switched; + private AddressLookupRequest startPointRequest; + private AddressLookupRequest targetPointRequest; + private static final long SPINNER_MY_LOCATION_ID = 1; private static final long SPINNER_FAV_ID = 2; private static final long SPINNER_MAP_ID = 3; @@ -84,23 +90,39 @@ public class MapRouteInfoMenu implements IRouteInformationListener { routingHelper = mapActivity.getRoutingHelper(); mapView = mapActivity.getMapView(); routingHelper.addListener(this); + geocodingLookupService = mapActivity.getMyApplication().getGeocodingLookupService(); } public boolean onSingleTap(PointF point, RotatedTileBox tileBox) { if (selectFromMapTouch) { LatLon latlon = tileBox.getLatLonFromPixel(point.x, point.y); selectFromMapTouch = false; - contextMenu.showMinimized(latlon, null, null); if (selectFromMapForTarget) { - contextMenu.setAsTargetPoint(true); + getTargets().navigateToPoint(latlon, true, -1); } else { - contextMenu.setAsStartPoint(true); + getTargets().setStartPoint(latlon, true, null); } + contextMenu.showMinimized(latlon, null, null); + show(); return true; } return false; } + private void cancelStartPointAddressRequest() { + if (startPointRequest != null) { + geocodingLookupService.cancel(startPointRequest); + startPointRequest = null; + } + } + + private void cancelTargetPointAddressRequest() { + if (targetPointRequest != null) { + geocodingLookupService.cancel(targetPointRequest); + targetPointRequest = null; + } + } + public void setVisible(boolean visible) { if (visible) { if (showMenu) { @@ -532,7 +554,18 @@ public class MapRouteInfoMenu implements IRouteInformationListener { if (i > 0) { via.append(" "); } - via.append(getRoutePointDescription(points.get(i).point, points.get(i).getOnlyName())); + String description = points.get(i).getOnlyName(); + via.append(getRoutePointDescription(points.get(i).point, description)); + boolean needAddress = new PointDescription(PointDescription.POINT_TYPE_LOCATION, description).isSearchingAddress(mapActivity); + if (needAddress) { + AddressLookupRequest lookupRequest = new AddressLookupRequest(points.get(i).point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + updateMenu(); + } + }, null); + geocodingLookupService.lookupAddress(lookupRequest); + } } return via.toString(); } @@ -567,6 +600,21 @@ public class MapRouteInfoMenu implements IRouteInformationListener { String oname = start.getOnlyName().length() > 0 ? start.getOnlyName() : (mapActivity.getString(R.string.route_descr_map_location) + " " + getRoutePointDescription(start.getLatitude(), start.getLongitude())); fromActions.add(new RouteSpinnerRow(SPINNER_START_ID, R.drawable.ic_action_get_my_location, oname)); + + final LatLon latLon = start.point; + final PointDescription pointDescription = start.getOriginalPointDescription(); + boolean needAddress = pointDescription != null && pointDescription.isSearchingAddress(mapActivity); + cancelStartPointAddressRequest(); + if (needAddress) { + startPointRequest = new AddressLookupRequest(latLon, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + startPointRequest = null; + updateMenu(); + } + }, null); + geocodingLookupService.lookupAddress(startPointRequest); + } } final Spinner fromSpinner = ((Spinner) view.findViewById(R.id.FromSpinner)); RouteSpinnerArrayAdapter fromAdapter = new RouteSpinnerArrayAdapter(view.getContext()); @@ -587,10 +635,28 @@ public class MapRouteInfoMenu implements IRouteInformationListener { final Spinner toSpinner = ((Spinner) view.findViewById(R.id.ToSpinner)); final TargetPointsHelper targets = getTargets(); ArrayList toActions = new ArrayList<>(); - if (targets.getPointToNavigate() != null) { + + TargetPoint finish = getTargets().getPointToNavigate(); + if (finish != null) { toActions.add(new RouteSpinnerRow(SPINNER_FINISH_ID, R.drawable.ic_action_get_my_location, getRoutePointDescription(targets.getPointToNavigate().point, targets.getPointToNavigate().getOnlyName()))); + + final LatLon latLon = finish.point; + final PointDescription pointDescription = finish.getOriginalPointDescription(); + boolean needAddress = pointDescription != null && pointDescription.isSearchingAddress(mapActivity); + cancelTargetPointAddressRequest(); + if (needAddress) { + targetPointRequest = new AddressLookupRequest(latLon, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + targetPointRequest = null; + updateMenu(); + } + }, null); + geocodingLookupService.lookupAddress(targetPointRequest); + } + } else { toSpinner.setPromptId(R.string.route_descr_select_destination); toActions.add(new RouteSpinnerRow(SPINNER_HINT_ID, R.drawable.ic_action_get_my_location,