Geocoding lookup service in progress

This commit is contained in:
Alexey Kulish 2016-01-20 21:45:12 +03:00
parent 68705fd8cf
commit bc7901965f
14 changed files with 644 additions and 272 deletions

View file

@ -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

View file

@ -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 "";

View file

@ -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);
}

View file

@ -57,7 +57,8 @@ public class CurrentPositionHelper {
private void scheduleRouteSegmentFind(final Location loc, final boolean storeFound, final ResultMatcher<GeocodingResult> geoCoding, final ResultMatcher<RouteDataObject> result) {
private boolean scheduleRouteSegmentFind(final Location loc, final boolean storeFound, final ResultMatcher<GeocodingResult> geoCoding, final ResultMatcher<RouteDataObject> 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<GeocodingResult> res, final ResultMatcher<GeocodingResult> result) {
@ -171,12 +166,12 @@ public class CurrentPositionHelper {
return d;
}
public void getRouteSegment(Location loc, ResultMatcher<RouteDataObject> result) {
scheduleRouteSegmentFind(loc, false, null, result);
public boolean getRouteSegment(Location loc, ResultMatcher<RouteDataObject> result) {
return scheduleRouteSegmentFind(loc, false, null, result);
}
public void getGeocodingResult(Location loc, ResultMatcher<GeocodingResult> result) {
scheduleRouteSegmentFind(loc, false, result, null);
public boolean getGeocodingResult(Location loc, ResultMatcher<GeocodingResult> result) {
return scheduleRouteSegmentFind(loc, false, result, null);
}
public RouteDataObject getLastKnownRouteSegment(Location loc) {

View file

@ -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<LatLon> lookupLocations = new ConcurrentLinkedQueue<>();
private ConcurrentHashMap<LatLon, List<AddressLookupRequest>> 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<AddressLookupRequest> 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<AddressLookupRequest> requests = addressLookupRequestsMap.get(request.latLon);
if (requests != null && requests.size() > 0) {
requests.remove(request);
}
}
}
private boolean hasAnyRequest(LatLon latLon) {
synchronized (this) {
List<AddressLookupRequest> requests = addressLookupRequestsMap.get(latLon);
return requests != null && requests.size() > 0;
}
}
@SuppressWarnings("unchecked")
private <P> void execute(AsyncTask<P, ?, ?> 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<GeocodingResult>() {
@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<AddressLookupRequest, AddressLookupRequest, Void> {
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<AddressLookupRequest> 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<AddressLookupRequest> 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<AddressLookupRequest> 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;
}
}
}

View file

@ -857,12 +857,12 @@ public class OsmAndLocationProvider implements SensorEventListener {
return currentPositionHelper.getLastKnownRouteSegment(getLastKnownLocation());
}
public void getRouteSegment(net.osmand.Location loc, ResultMatcher<RouteDataObject> result) {
currentPositionHelper.getRouteSegment(loc, result);
public boolean getRouteSegment(net.osmand.Location loc, ResultMatcher<RouteDataObject> result) {
return currentPositionHelper.getRouteSegment(loc, result);
}
public void getGeocodingResult(net.osmand.Location loc, ResultMatcher<GeocodingResult> result) {
currentPositionHelper.getGeocodingResult(loc, result);
public boolean getGeocodingResult(net.osmand.Location loc, ResultMatcher<GeocodingResult> result) {
return currentPositionHelper.getGeocodingResult(loc, result);
}
public net.osmand.Location getLastKnownLocation() {

View file

@ -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;
}

View file

@ -1551,12 +1551,23 @@ public class OsmandSettings {
List<String> 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<LatLon> ps = getIntermediatePoints();
List<String> 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<LatLon> ps = getIntermediatePoints();
List<String> 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);
}
}

View file

@ -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<StateChangedListener<Void>> listeners = new ArrayList<StateChangedListener<Void>>();
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;
}
}
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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<GeocodingResult>() {
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() {

View file

@ -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;

View file

@ -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<RouteSpinnerRow> 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,