Fix geo intent search

This commit is contained in:
Victor Shcherb 2017-04-18 11:50:21 +03:00
parent 3777a1ed4e
commit 58c3e89efb
2 changed files with 46 additions and 340 deletions

View file

@ -1336,7 +1336,7 @@ public class GeoPointParserUtil {
}
public static class GeoParsedPoint {
private static final int NO_ZOOM = -1;
public static final int NO_ZOOM = -1;
private double lat = 0;
private double lon = 0;

View file

@ -15,7 +15,6 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import net.osmand.ResultMatcher;
import net.osmand.data.Amenity;
import net.osmand.data.City;
@ -34,7 +33,9 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.OsmandListActivity;
import net.osmand.plus.resources.RegionAddressRepository;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.util.Algorithms;
import net.osmand.util.GeoPointParserUtil;
import net.osmand.util.GeoPointParserUtil.GeoParsedPoint;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
@ -87,16 +88,20 @@ public class GeoIntentActivity extends OsmandListActivity {
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MapObject item = ((MapObjectAdapter) getListAdapter()).getItem(position);
OsmandSettings settings = getMyApplication().getSettings();
settings.setMapLocationToShow(item.getLocation().getLatitude(), item.getLocation().getLongitude(),
settings.getLastKnownMapZoom(), getString(item)); //$NON-NLS-1$
MapActivity.launchMapActivityMoveToTop(this);
private PointDescription getString(MapObject o) {
if (o instanceof Amenity) {
OsmandSettings settings = ((OsmandApplication) getApplication()).getSettings();
return new PointDescription(PointDescription.POINT_TYPE_POI,
OsmAndFormatter.getPoiStringWithoutType((Amenity) o, settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()));
}
if (o instanceof Street) {
return new PointDescription(PointDescription.POINT_TYPE_ADDRESS, ((Street) o).getCity().getName() + " " + o.getName());
}
return new PointDescription(PointDescription.POINT_TYPE_ADDRESS, o.toString());
}
private class GeoIntentTask extends AsyncTask<Void, Void, ExecutionResult> {
private class GeoIntentTask extends AsyncTask<Void, Void, GeoParsedPoint> {
private final ProgressDialog progress;
private final Intent intent;
@ -109,85 +114,54 @@ public class GeoIntentActivity extends OsmandListActivity {
protected void onPreExecute() {
}
/**
* Extracts information from geo and map intents:
*
* geo:47.6,-122.3<br/>
* geo:47.6,-122.3?z=11<br/>
* geo:0,0?q=34.99,-106.61(Treasure)<br/>
* geo:0,0?q=1600+Amphitheatre+Parkway%2C+CA<br/>
*
* @param uri
* The intent uri
* @return
*/
@Override
protected ExecutionResult doInBackground(Void... nothing) {
protected GeoParsedPoint doInBackground(Void... nothing) {
try {
while (getMyApplication().isApplicationInitializing()) {
Thread.sleep(200);
}
return extract(intent.getData()).execute();
Uri uri = intent.getData();
return GeoPointParserUtil.parse(uri.toString());
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(ExecutionResult result) {
protected void onPostExecute(GeoPointParserUtil.GeoParsedPoint p ) {
progress.dismiss();
if (result != null) {
if (result.isEmpty()) {
Toast.makeText(GeoIntentActivity.this, getString(R.string.search_nothing_found),
Toast.LENGTH_LONG).show();
} else {
if (result.hasZoom()) {
getMyApplication().getSettings().setLastKnownMapZoom(result.getZoom());
}
final List<MapObject> places = new ArrayList<MapObject>(result.getMapObjects());
setListAdapter(new MapObjectAdapter(places));
if (places.size() == 1) {
onItemClick(getListView(), getListAdapter().getView(0, null, null), 0, getListAdapter()
.getItemId(0));
}
if (p != null && p.isGeoPoint()) {
OsmandSettings settings = getMyApplication().getSettings();
PointDescription pd = new PointDescription(p.getLatitude(), p.getLongitude());
if(!Algorithms.isEmpty(p.getLabel())) {
pd.setName(p.getLabel());
}
finish();
} else {
Toast.makeText(GeoIntentActivity.this,
getString(R.string.search_offline_geo_error, intent.getData()), Toast.LENGTH_LONG).show();
settings.setMapLocationToShow(p.getLatitude(), p.getLongitude(),
settings.getLastKnownMapZoom(), pd); //$NON-NLS-1$
MapActivity.launchMapActivityMoveToTop(GeoIntentActivity.this);
}
Uri uri = intent.getData();
String searchString = p != null && p.isGeoAddress() ? p.getLabel() : uri.toString();
// TODO
MapActivity.launchMapActivityMoveToTop(GeoIntentActivity.this);
}
}
private class MapObjectAdapter extends ArrayAdapter<MapObject> {
public MapObjectAdapter(List<MapObject> places) {
super(GeoIntentActivity.this, R.layout.search_address_offline_list_item, places);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.search_address_offline_list_item, parent, false);
}
MapObject model = getItem(position);
TextView label = (TextView) row.findViewById(R.id.label);
TextView distanceLabel = (TextView) row.findViewById(R.id.distance_label);
if (location != null) {
int dist = (int) (MapUtils.getDistance(location, model.getLocation().getLatitude(), model.getLocation()
.getLongitude()));
distanceLabel.setText(OsmAndFormatter.getFormattedDistance(dist, (OsmandApplication) getApplication()));
} else {
distanceLabel.setText(""); //$NON-NLS-1$
}
label.setText(getString(model).getFullPlainName(getApplication()));
return row;
}
}
private PointDescription getString(MapObject o) {
if (o instanceof Amenity) {
OsmandSettings settings = ((OsmandApplication) getApplication()).getSettings();
return new PointDescription(PointDescription.POINT_TYPE_POI,
OsmAndFormatter.getPoiStringWithoutType((Amenity) o, settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()));
}
if (o instanceof Street) {
return new PointDescription(PointDescription.POINT_TYPE_ADDRESS, ((Street) o).getCity().getName() + " " + o.getName());
}
return new PointDescription(PointDescription.POINT_TYPE_ADDRESS, o.toString());
}
@Override
@ -202,274 +176,6 @@ public class GeoIntentActivity extends OsmandListActivity {
progressDlg = null;
}
}
/**
* Extracts information from geo and map intents:
*
* geo:47.6,-122.3<br/>
* geo:47.6,-122.3?z=11<br/>
* geo:0,0?q=34.99,-106.61(Treasure)<br/>
* geo:0,0?q=1600+Amphitheatre+Parkway%2C+CA<br/>
*
* @param uri
* The intent uri
* @return
*/
private MyService extract(final Uri uri) {
Log.v(this.getClass().toString(), "extract(" + "uri=" + uri + ")");
GeoPointParserUtil.GeoParsedPoint p = GeoPointParserUtil.parse(uri.toString());
if (p.isGeoPoint()) {
if (p.getLabel() != null) {
return new GeoPointSearch(p.getLatitude(), p.getLongitude(), p.getLabel(), p.getZoom());
}
return new GeoPointSearch(p.getLatitude(), p.getLongitude(), p.getZoom());
} else {
return new GeoAddressSearch(p.getQuery());
}
}
private final class GeoAddressSearch implements MyService {
private List<String> elements;
public GeoAddressSearch(String query) {
query = query.replaceAll("%20", ",").replaceAll("%0A", ",").replaceAll("\n", ",").replaceAll("\t", ",")
.replaceAll(" ", ",");
System.out.println(query);
// String is split on each comma
String[] s = query.substring(query.indexOf("q=") + 2).split(",");
elements = new ArrayList<String>();
for (int i = 0; i < s.length; i++) {
if (s[i].isEmpty()) {
continue;
}
elements.add(s[i].replace('+', ' ').trim());
}
}
public MapObject checkGeoPoint() {
double lat = Double.NaN;
double lon = Double.NaN;
for (String e : elements) {
if (e.startsWith("S") || e.startsWith("N")) {
try {
lat = Double.parseDouble(e.substring(1));
if (e.startsWith("S")) {
lat = -lat;
}
} catch (NumberFormatException es) {
}
} else if (e.startsWith("E") || e.startsWith("W")) {
try {
lon = Double.parseDouble(e.substring(1));
if (e.startsWith("W")) {
lon = -lon;
}
} catch (NumberFormatException es) {
}
} else if (e.contains(".")) {
try {
double n = Double.parseDouble(e);
if (Double.isNaN(lat)) {
lat = n;
} else {
lon = n;
}
} catch (NumberFormatException es) {
}
}
}
if (Double.isNaN(lat) || Double.isNaN(lon)) {
return null;
}
Amenity point = new Amenity();
((Amenity) point).setType(getMyApplication().getPoiTypes().getUserDefinedCategory());
((Amenity) point).setSubType("");
point.setLocation(lat, lon);
point.setName("Lat: " + lat + ", Lon: " + lon);
return point;
}
@Override
public ExecutionResult execute() {
if (elements.isEmpty()) {
return ExecutionResult.EMPTY;
}
List<String> q = new ArrayList<String>(elements);
MapObject geo = checkGeoPoint();
if (geo != null) {
return new ExecutionResult(Collections.singleton(geo));
}
// do not
if(DO_NOT_SEARCH_ADDRESS) {
return ExecutionResult.EMPTY;
}
// now try to search the City, Street, Etc.. if Street is not found,
// try to search POI
Collection<RegionAddressRepository> countriesToSearch = limitSearchToCountries(q);
// search cities for found countries
final List<Street> allStreets = new ArrayList<Street>();
final TLongObjectHashMap<City> cityIds = new TLongObjectHashMap<City>();
for (RegionAddressRepository rar : countriesToSearch) {
for (String element : q) {
if (element != null && element.length() > 2) {
rar.searchMapObjectsByName(element, new ResultMatcher<MapObject>() {
@Override
public boolean publish(MapObject object) {
if (object instanceof City && object.getId() != null) {
cityIds.put(object.getId(), (City) object);
} else if (object instanceof Street) {
allStreets.add((Street) object);
}
return false;
}
@Override
public boolean isCancelled() {
return false;
}
});
}
}
}
if (cityIds.isEmpty()) {
return new ExecutionResult(allStreets);
}
final List<MapObject> connectedStreets = new ArrayList<MapObject>();
Iterator<Street> p = allStreets.iterator();
while (p.hasNext()) {
Street s = p.next();
if (cityIds.contains(s.getCity().getId())) {
connectedStreets.add(s);
} else {
boolean tooFar = true;
for (City c : cityIds.valueCollection()) {
if (MapUtils.getDistance(c.getLocation(), s.getLocation()) < 50000) {
tooFar = false;
break;
}
}
if (tooFar) {
p.remove();
}
}
}
if (connectedStreets.isEmpty()) {
List<MapObject> all = new ArrayList<MapObject>();
all.addAll(cityIds.valueCollection());
all.addAll(allStreets);
return new ExecutionResult(all);
} else {
// add all other results to connected streets
connectedStreets.addAll(cityIds.valueCollection());
return new ExecutionResult(connectedStreets);
}
}
private Collection<RegionAddressRepository> limitSearchToCountries(List<String> q) {
ResourceManager resourceManager = getMyApplication().getResourceManager();
List<RegionAddressRepository> foundCountries = new ArrayList<RegionAddressRepository>();
RegionAddressRepository country;
Iterator<String> it = q.iterator();
while (it.hasNext()) {
String maybeCountry = it.next();
country = resourceManager.getRegionRepository(maybeCountry);
if (country != null) {
foundCountries.add(country);
it.remove();
}
}
Collection<RegionAddressRepository> countriesToSearch = foundCountries;
if (foundCountries.isEmpty()) {
// there is no country, we have to search each country
countriesToSearch = resourceManager.getAddressRepositories();
}
return countriesToSearch;
}
}
@SuppressWarnings("unused")
private class GeoPointSearch implements MyService {
private final MapObject point;
private final int zoom;
public GeoPointSearch(double lat, double lon) {
this(lat, lon, ExecutionResult.NO_ZOOM);
}
public GeoPointSearch(double lat, double lon, int zoom) {
this(lat, lon, "Lat: " + lat + ", Lon: " + lon, zoom);
}
public GeoPointSearch(double lat, double lon, String name) {
this(lat, lon, name, ExecutionResult.NO_ZOOM);
}
public GeoPointSearch(double lat, double lon, String name, int zoom) {
final Amenity amenity = new Amenity();
amenity.setLocation(lat, lon);
amenity.setName(name);
amenity.setType(getMyApplication().getPoiTypes().getUserDefinedCategory());
amenity.setSubType("");
this.point = amenity;
this.zoom = zoom;
}
@Override
public ExecutionResult execute() {
if (point != null) {
return new ExecutionResult(Collections.singletonList(point), zoom);
} else {
return ExecutionResult.EMPTY;
}
}
}
private static class ExecutionResult {
public static final int NO_ZOOM = -1;
public static final ExecutionResult EMPTY = new ExecutionResult(new ArrayList<MapObject>(), NO_ZOOM);
private final Collection<? extends MapObject> mapObjects;
private final int zoom;
public ExecutionResult(final Collection<? extends MapObject> mapObjects) {
this(mapObjects, NO_ZOOM);
}
public ExecutionResult(final Collection<? extends MapObject> mapObjects, final int zoom) {
this.mapObjects = mapObjects;
this.zoom = zoom;
}
public boolean isEmpty() {
return mapObjects.isEmpty();
}
public boolean hasZoom() {
return zoom != NO_ZOOM;
}
public Collection<? extends MapObject> getMapObjects() {
return mapObjects;
}
public int getZoom() {
return zoom;
}
@Override
public String toString() {
return "ExecutionResult{" + "mapObjects=" + mapObjects + ", zoom=" + zoom + '}';
}
}
private static interface MyService {
public ExecutionResult execute();
}
}