Address search in progress

This commit is contained in:
Alexey Kulish 2016-06-24 22:48:50 +03:00
parent cd68355c97
commit 85553fd2c3
39 changed files with 1009 additions and 743 deletions

View file

@ -15,7 +15,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="8dp"
android:layout_gravity="center"
android:layout_gravity="top"
android:scaleType="centerInside"
android:visibility="visible"/>

View file

@ -43,13 +43,12 @@ import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.MultiTouchSupport.MultiTouchZoomListener;
import net.osmand.core.samples.android.sample1.adapters.SearchListAdapter;
import net.osmand.core.samples.android.sample1.adapters.SearchListItem;
import net.osmand.core.samples.android.sample1.adapters.SearchListPositionItem;
import net.osmand.core.samples.android.sample1.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallback;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MainActivity extends Activity {
@ -84,7 +83,7 @@ public class MainActivity extends Activity {
private SearchAPI searchAPI;
private ListView searchListView;
private SearchListAdapter adapter;
private final static int MAX_SEARCH_RESULTS_CORE = 500;
private final static int MAX_SEARCH_RESULTS_CORE = 300;
private final static int MAX_SEARCH_RESULTS_IU = 50;
// Germany
@ -204,7 +203,7 @@ public class MainActivity extends Activity {
//Setup search
searchAPI = new SearchAPI(obfsCollection);
searchAPI = new SearchAPI(obfsCollection, MapUtils.LANGUAGE);
final EditText searchEditText = (EditText) findViewById(R.id.searchEditText);
searchEditText.addTextChangedListener(new TextWatcher() {
@ -218,9 +217,7 @@ public class MainActivity extends Activity {
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 2) {
runSearch(getScreenBounds31(), s.toString());
}
runSearch(getScreenCenter31(), getScreenBounds31(), s.toString());
}
});
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@ -255,9 +252,13 @@ public class MainActivity extends Activity {
hideSearchList();
mapView.requestFocus();
SearchListItem item = adapter.getItem(position);
PointI target = Utilities.convertLatLonTo31(new LatLon(item.getLatitude(), item.getLongitude()));
setTarget(target);
setZoom(17f);
if (item instanceof SearchListPositionItem) {
SearchListPositionItem positionItem = (SearchListPositionItem) item;
PointI target = Utilities.convertLatLonTo31(
new LatLon(positionItem.getLatitude(), positionItem.getLongitude()));
setTarget(target);
setZoom(17f);
}
}
});
@ -289,6 +290,12 @@ public class MainActivity extends Activity {
return (SampleApplication) getApplication();
}
private PointI getScreenCenter31() {
PointI point = new PointI();
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth() / 2, mapView.getHeight() / 2), point);
return point;
}
private AreaI getScreenBounds31() {
PointI topLeftPoint = new PointI();
PointI bottomRightPoint = new PointI();
@ -398,33 +405,31 @@ public class MainActivity extends Activity {
|| gestureDetector.onTouchEvent(event);
}
private void runSearch(AreaI bounds31, String keyword) {
private void runSearch(PointI position31, AreaI bounds31, String keyword) {
searchAPI.setSearchLocation31(position31);
searchAPI.setObfAreaFilter(bounds31);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS_CORE,
// Intermediate search callback
new SearchCallback() {
new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems) {
processSearchResult(searchItems);
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
}
},
// Core search callback
new SearchCallback() {
new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems) {
processSearchResult(searchItems);
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
}
});
}
private void processSearchResult(List<SearchItem> searchItems) {
if (searchItems != null) {
LatLon latLon = Utilities.convert31ToLatLon(target31);
double latitude = latLon.getLatitude();
double longitude = latLon.getLongitude();
private void processSearchResult(List<SearchObject> searchObjects) {
if (searchObjects != null) {
List<SearchListItem> rows = new ArrayList<>();
for (SearchItem item : searchItems) {
for (SearchObject item : searchObjects) {
SearchListItem listItem =
SearchListItem.buildListItem((SampleApplication)getApplication(), item);
if (listItem != null) {

View file

@ -1,43 +0,0 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.items.AddressSearchItem;
import net.osmand.util.Algorithms;
public class AddressSearchListItem extends SearchListItem {
private String nameStr;
private String typeStr;
public AddressSearchListItem(SampleApplication app, AddressSearchItem searchItem) {
super(app, searchItem);
StringBuilder sb = new StringBuilder();
String localizedName = searchItem.getLocalizedNames().get(MapUtils.LANGUAGE);
if (Algorithms.isEmpty(localizedName)) {
localizedName = searchItem.getNativeName();
}
if (!Algorithms.isEmpty(searchItem.getNamePrefix())) {
sb.append(searchItem.getNamePrefix());
sb.append(" ");
}
sb.append(localizedName);
if (!Algorithms.isEmpty(searchItem.getNameSuffix())) {
sb.append(" ");
sb.append(searchItem.getNameSuffix());
}
nameStr = sb.toString();
typeStr = searchItem.getType();
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getType() {
return typeStr;
}
}

View file

@ -1,84 +0,0 @@
package net.osmand.core.samples.android.sample1.adapters;
import android.graphics.drawable.Drawable;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.items.AmenitySearchItem;
import net.osmand.data.Amenity;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.util.Algorithms;
import java.util.Map.Entry;
public class AmenitySearchListItem extends SearchListItem {
private Amenity amenity;
private String nameStr;
private String typeStr;
public AmenitySearchListItem(SampleApplication app, AmenitySearchItem searchItem) {
super(app, searchItem);
amenity = parseAmenity(searchItem);
nameStr = amenity.getName(MapUtils.LANGUAGE);
typeStr = getTypeStr();
}
private Amenity parseAmenity(AmenitySearchItem searchItem) {
MapPoiTypes poiTypes = app.getPoiTypes();
Amenity a = new Amenity();
PoiCategory category = poiTypes.getPoiCategoryByName(searchItem.getCategory());
a.setType(category);
a.setSubType(searchItem.getSubcategory());
a.setName(searchItem.getNativeName());
for (Entry<String, String> entry : searchItem.getLocalizedNames().entrySet()) {
a.setName(entry.getKey(), entry.getValue());
}
a.setAdditionalInfo(searchItem.getValues());
return a;
}
public Amenity getAmenity() {
return amenity;
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getType() {
return typeStr;
}
private String getTypeStr() {
/*
PoiCategory pc = amenity.getType();
PoiType pt = pc.getPoiTypeByKeyName(amenity.getSubType());
String typeStr = amenity.getSubType();
if (pt != null) {
typeStr = pt.getTranslation();
} else if (typeStr != null) {
typeStr = Algorithms.capitalizeFirstLetterAndLowercase(typeStr.replace('_', ' '));
}
return typeStr;
*/
return Algorithms.capitalizeFirstLetterAndLowercase(amenity.getSubType().replace('_', ' '));
}
@Override
public Drawable getIcon() {
Drawable drawable = null;
PoiType st = amenity.getType().getPoiTypeByKeyName(amenity.getSubType());
if (st != null) {
drawable = app.getIconsCache().getIcon(st.getOsmTag() + "_" + st.getOsmValue());
}
return drawable;
}
}

View file

@ -0,0 +1,28 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.CitySearchObject;
public class CitySearchListItem extends SearchListPositionItem{
private String nameStr;
private String typeStr;
public CitySearchListItem(SampleApplication app, CitySearchObject searchItem) {
super(app, searchItem);
nameStr = searchItem.getName(MapUtils.LANGUAGE);
typeStr = "City";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -0,0 +1,119 @@
package net.osmand.core.samples.android.sample1.adapters;
import android.graphics.drawable.Drawable;
import net.osmand.core.jni.Amenity.DecodedCategory;
import net.osmand.core.jni.Amenity.DecodedValue;
import net.osmand.core.jni.DecodedCategoryList;
import net.osmand.core.jni.DecodedValueList;
import net.osmand.core.jni.QStringList;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.data.Amenity;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.util.Algorithms;
import java.util.HashMap;
import java.util.Map;
public class PoiSearchListItem extends SearchListPositionItem {
private Amenity amenity;
private String nameStr;
private String typeStr;
public PoiSearchListItem(SampleApplication app, PoiSearchObject searchItem) {
super(app, searchItem);
amenity = parseAmenity(searchItem);
nameStr = amenity.getName(MapUtils.LANGUAGE);
typeStr = getTypeStr();
}
private Amenity parseAmenity(PoiSearchObject searchItem) {
String categoryName = "";
String subcategoryName = "";
Map<String, String> values = new HashMap<>();
net.osmand.core.jni.Amenity coreAmenity = searchItem.getAmenity();
DecodedCategoryList catList = coreAmenity.getDecodedCategories();
if (catList.size() > 0) {
DecodedCategory decodedCategory = catList.get(0);
categoryName = decodedCategory.getCategory();
subcategoryName = decodedCategory.getSubcategory();
}
DecodedValueList decodedValueList = coreAmenity.getDecodedValues();
if (decodedValueList.size() > 0) {
for (int i = 0; i < decodedValueList.size(); i++) {
DecodedValue decodedValue = decodedValueList.get(i);
String tag = decodedValue.getDeclaration().getTagName();
String value = decodedValue.getValue();
values.put(tag, value);
}
}
MapPoiTypes poiTypes = app.getPoiTypes();
Amenity a = new Amenity();
PoiCategory category = poiTypes.getPoiCategoryByName(categoryName);
a.setType(category);
a.setSubType(subcategoryName);
a.setName(searchItem.getNativeName());
QStringStringHash localizedNamesMap = coreAmenity.getLocalizedNames();
QStringList locNamesKeys = localizedNamesMap.keys();
for (int i = 0; i < locNamesKeys.size(); i++) {
String key = locNamesKeys.get(i);
String val = localizedNamesMap.get(key);
a.setName(key, val);
}
a.setAdditionalInfo(values);
return a;
}
public Amenity getAmenity() {
return amenity;
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
private String getTypeStr() {
/*
PoiCategory pc = amenity.getTypeName();
PoiType pt = pc.getPoiTypeByKeyName(amenity.getSubType());
String typeStr = amenity.getSubType();
if (pt != null) {
typeStr = pt.getTranslation();
} else if (typeStr != null) {
typeStr = Algorithms.capitalizeFirstLetterAndLowercase(typeStr.replace('_', ' '));
}
return typeStr;
*/
return Algorithms.capitalizeFirstLetterAndLowercase(amenity.getSubType().replace('_', ' '));
}
@Override
public Drawable getIcon() {
Drawable drawable = null;
PoiType st = amenity.getType().getPoiTypeByKeyName(amenity.getSubType());
if (st != null) {
drawable = app.getIconsCache().getIcon(st.getOsmTag() + "_" + st.getOsmValue());
}
return drawable;
}
}

View file

@ -0,0 +1,29 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.CitySearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PostcodeSearchObject;
public class PostcodeSearchListItem extends SearchListPositionItem {
private String nameStr;
private String typeStr;
public PostcodeSearchListItem(SampleApplication app, PostcodeSearchObject searchItem) {
super(app, searchItem);
nameStr = searchItem.getNativeName();
typeStr = "Postcode";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -25,8 +25,11 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
public void updateDistance(double latitude, double longitude) {
for (int i = 0; i < getCount(); i++) {
SearchListItem item = getItem(i);
item.setDistance(Utilities.distance(
longitude, latitude, item.getLongitude(), item.getLatitude()));
if (item instanceof SearchListPositionItem) {
SearchListPositionItem positionItem = (SearchListPositionItem) item;
positionItem.setDistance(Utilities.distance(
longitude, latitude, positionItem.getLongitude(), positionItem.getLatitude()));
}
}
}
@ -51,11 +54,17 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
imageView.setImageDrawable(listItem.getIcon());
title.setText(listItem.getName());
subtitle.setText(listItem.getType());
if (listItem.getDistance() == 0) {
distance.setText("");
subtitle.setText(listItem.getTypeName());
if (listItem instanceof SearchListPositionItem) {
SearchListPositionItem positionItem = (SearchListPositionItem) listItem;
if (positionItem.getDistance() == 0) {
distance.setText("");
} else {
distance.setText(Utils.getFormattedDistance(positionItem.getDistance()));
}
distance.setVisibility(View.VISIBLE);
} else {
distance.setText(Utils.getFormattedDistance(listItem.getDistance()));
distance.setVisibility(View.INVISIBLE);
}
return view;
}

View file

@ -3,52 +3,49 @@ package net.osmand.core.samples.android.sample1.adapters;
import android.graphics.drawable.Drawable;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.items.AddressSearchItem;
import net.osmand.core.samples.android.sample1.search.items.AmenitySearchItem;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.objects.CitySearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PostcodeSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.VillageSearchObject;
public class SearchListItem {
protected SampleApplication app;
private SearchItem searchItem;
private SearchObject searchObject;
public SearchListItem(SampleApplication app, SearchItem searchItem) {
public SearchListItem(SampleApplication app, SearchObject searchObject) {
this.app = app;
this.searchItem = searchItem;
this.searchObject = searchObject;
}
public static SearchListItem buildListItem(SampleApplication app, SearchItem item) {
if (item instanceof AmenitySearchItem) {
return new AmenitySearchListItem(app, (AmenitySearchItem) item);
} else if (item instanceof AddressSearchItem) {
return new AddressSearchListItem(app, (AddressSearchItem) item);
public static SearchListItem buildListItem(SampleApplication app, SearchObject item) {
switch (item.getType()) {
case POI:
return new PoiSearchListItem(app, (PoiSearchObject) item);
case STREET:
return new StreetSearchListItem(app, (StreetSearchObject) item);
case CITY:
return new CitySearchListItem(app, (CitySearchObject) item);
case VILLAGE:
return new VillageSearchListItem(app, (VillageSearchObject) item);
case POSTCODE:
return new PostcodeSearchListItem(app, (PostcodeSearchObject) item);
}
return null;
}
public double getLatitude() {
return searchItem.getLatitude();
}
public double getLongitude() {
return searchItem.getLongitude();
protected SearchObject getSearchObject() {
return searchObject;
}
public String getName() {
return searchItem.getName();
return searchObject.getNativeName();
}
public String getType() {
return searchItem.getType();
}
public double getDistance() {
return searchItem.getDistance();
}
public void setDistance(double distance) {
searchItem.setDistance(distance);
public String getTypeName() {
return searchObject.getType().name();
}
public Drawable getIcon() {

View file

@ -0,0 +1,44 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
public class SearchListPositionItem extends SearchListItem {
private double latitude;
private double longitude;
public SearchListPositionItem(SampleApplication app, SearchPositionObject searchObject) {
super(app, searchObject);
PointI position31 = searchObject.getPosition31();
LatLon latLon = Utilities.convert31ToLatLon(position31);
latitude = latLon.getLatitude();
longitude = latLon.getLongitude();
}
public SearchPositionObject getSearchPositionObject() {
return (SearchPositionObject) getSearchObject();
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public double getDistance() {
return getSearchPositionObject().getDistance();
}
public void setDistance(double distance) {
getSearchPositionObject().setDistance(distance);
}
}

View file

@ -0,0 +1,45 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.jni.ObfAddressStreetGroupSubtype;
import net.osmand.core.jni.StreetGroup;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
public class StreetSearchListItem extends SearchListItem {
private String nameStr;
private String typeStr;
public StreetSearchListItem(SampleApplication app, StreetSearchObject searchItem) {
super(app, searchItem);
nameStr = searchItem.getName(MapUtils.LANGUAGE);
StreetGroup streetGroup = searchItem.getStreet().getStreetGroup();
if (streetGroup != null) {
typeStr = streetGroup.getNativeName() + "" + getTypeStr(streetGroup);
} else {
typeStr = "Street";
}
}
private String getTypeStr(StreetGroup streetGroup) {
String typeStr;
if (streetGroup.getSubtype() != ObfAddressStreetGroupSubtype.Unknown) {
typeStr = streetGroup.getSubtype().name();
} else {
typeStr = streetGroup.getType().name();
}
return typeStr;
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -0,0 +1,29 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.SampleApplication;
import net.osmand.core.samples.android.sample1.search.objects.CitySearchObject;
import net.osmand.core.samples.android.sample1.search.objects.VillageSearchObject;
public class VillageSearchListItem extends SearchListPositionItem{
private String nameStr;
private String typeStr;
public VillageSearchListItem(SampleApplication app, VillageSearchObject searchItem) {
super(app, searchItem);
nameStr = searchItem.getName(MapUtils.LANGUAGE);
typeStr = "Village";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -5,11 +5,13 @@ import android.support.annotation.NonNull;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.ObfsCollection;
import net.osmand.core.jni.PointI;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.requests.CoreSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.IntermediateSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.SearchRequest;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
public class SearchAPI {
@ -17,23 +19,44 @@ public class SearchAPI {
private ObfsCollection obfsCollection;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private PointI searchLocation;
private PointI searchLocation31;
private double searchRadius;
private String lang;
private SearchRequestExecutor executor;
private SearchString searchString;
private SearchScope searchScope;
private List<SearchItem> searchItems;
private List<SearchObject> searchObjects;
public interface SearchCallback {
void onSearchFinished(List<SearchItem> searchItems);
private SearchCallbackInternal internalCallback = new SearchCallbackInternal() {
@Override
public void onSearchObjectsFound(List<SearchObject> searchObjects) {
setSearchObjects(searchObjects);
}
@Override
public void onNewTokenFound(SearchToken oldToken, SearchToken newToken) {
searchString.replaceToken(oldToken, newToken);
}
};
public interface SearchApiCallback {
void onSearchFinished(List<SearchObject> searchObjects);
}
public SearchAPI(@NonNull ObfsCollection obfsCollection) {
public interface SearchCallbackInternal {
void onSearchObjectsFound(List<SearchObject> searchObjects);
void onNewTokenFound(SearchToken oldToken, SearchToken newToken);
}
public SearchAPI(@NonNull ObfsCollection obfsCollection, String lang) {
this.obfsCollection = obfsCollection;
this.executor = new SearchRequestExecutor();
this.searchString = new SearchString();
this.searchScope = new SearchScope(this);
this.lang = lang;
}
public String getLang() {
return lang;
}
public AreaI getSearchableArea() {
@ -52,12 +75,12 @@ public class SearchAPI {
this.obfAreaFilter = obfAreaFilter;
}
public PointI getSearchLocation() {
return searchLocation;
public PointI getSearchLocation31() {
return searchLocation31;
}
public void setSearchLocation(PointI searchLocation) {
this.searchLocation = searchLocation;
public void setSearchLocation31(PointI position31) {
this.searchLocation31 = position31;
}
public double getSearchRadius() {
@ -72,35 +95,32 @@ public class SearchAPI {
return obfsCollection;
}
public SearchString getSearchString() {
return searchString;
public SearchString getSearchStringCopy() {
return searchString.copy();
}
public SearchScope getSearchScope() {
return searchScope;
public List<SearchObject> getSearchObjects() {
return searchObjects;
}
public List<SearchItem> getSearchItems() {
return searchItems;
}
public void setSearchItems(List<SearchItem> searchItems) {
this.searchItems = searchItems;
public void setSearchObjects(List<SearchObject> searchObjects) {
this.searchObjects = searchObjects;
}
public void startSearch(String query, int maxSearchResults,
SearchCallback intermediateSearchCallback,
SearchCallback coreSearchCallback) {
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
searchString.setQueryText(query);
searchScope.updateScope();
SearchScope searchScope = new SearchScope(this);
IntermediateSearchRequest intermediateSearchRequest = null;
if (searchItems != null && !searchItems.isEmpty()) {
if (searchObjects != null && !searchObjects.isEmpty()) {
intermediateSearchRequest =
new IntermediateSearchRequest(this, maxSearchResults, intermediateSearchCallback);
new IntermediateSearchRequest(searchScope, new ArrayList<>(searchObjects),
maxSearchResults, intermediateSearchCallback);
}
executor.run(new CoreSearchRequest(intermediateSearchRequest, this,
maxSearchResults, coreSearchCallback), true);
executor.run(new CoreSearchRequest(intermediateSearchRequest, searchScope,
maxSearchResults, coreSearchCallback, internalCallback), true);
}
public void cancelSearch() {

View file

@ -2,117 +2,190 @@ package net.osmand.core.samples.android.sample1.search;
import net.osmand.core.jni.AddressesByNameSearch;
import net.osmand.core.jni.AmenitiesByNameSearch;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.QStringList;
import net.osmand.core.jni.QStringStringListHash;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.ObfAddressStreetGroupSubtype;
import net.osmand.core.jni.ObfAddressStreetGroupType;
import net.osmand.core.jni.ObfsCollection;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.search.items.AddressSearchItem;
import net.osmand.core.samples.android.sample1.search.items.AmenitySearchItem;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.tokens.CitySearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.PoiTypeSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.PostcodeSearchToken;
import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetGroupSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
import net.osmand.core.samples.android.sample1.search.tokens.ObjectSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken.TokenType;
import net.osmand.util.Algorithms;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class SearchScope {
private SearchAPI searchAPI;
private Map<TokenType, SearchToken> resolvedTokens;
private double searchLat;
private double searchLon;
private ObfsCollection obfsCollection;
private SearchString searchString;
private String lang;
private Map<SearchObjectType, SearchToken> objectTokens;
private PointI searchLocation31;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private double searchRadius;
public SearchScope(SearchAPI searchAPI) {
this.searchAPI = searchAPI;
}
public void updateScope() {
resolvedTokens = searchAPI.getSearchString().getResolvedTokens();
LatLon latLon = Utilities.convert31ToLatLon(searchAPI.getSearchLocation());
searchLat = latLon.getLatitude();
searchLon = latLon.getLongitude();
obfsCollection = searchAPI.getObfsCollection();
lang = searchAPI.getLang();
searchString = searchAPI.getSearchStringCopy();
objectTokens = searchString.getObjectTokens();
searchLocation31 = searchAPI.getSearchLocation31();
searchableArea = searchAPI.getSearchableArea();
obfAreaFilter = searchAPI.getObfAreaFilter();
searchRadius = searchAPI.getSearchRadius();
}
public ObfsCollection getObfsCollection() {
return obfsCollection;
}
public String getLang() {
return lang;
}
public SearchString getSearchString() {
return searchString;
}
public Map<SearchObjectType, SearchToken> getObjectTokens() {
return objectTokens;
}
public PointI getSearchLocation31() {
return searchLocation31;
}
public AreaI getSearchableArea() {
return searchableArea;
}
public AreaI getObfAreaFilter() {
return obfAreaFilter;
}
public double getSearchRadius() {
return searchRadius;
}
public void setupAmenitySearchCriteria(AmenitiesByNameSearch.Criteria criteria) {
String categoryName = null;
String typeName = null;
if (resolvedTokens.containsKey(TokenType.POI_TYPE)) {
PoiTypeSearchToken token = (PoiTypeSearchToken)resolvedTokens.get(TokenType.POI_TYPE);
categoryName = token.getPoiType().getCategory().getKeyName();
typeName = token.getName();
} else if (resolvedTokens.containsKey(TokenType.POI_FILTER)) {
SearchToken token = resolvedTokens.get(TokenType.POI_FILTER);
categoryName = token.getName();
} else if (resolvedTokens.containsKey(TokenType.POI_CATEGORY)) {
SearchToken token = resolvedTokens.get(TokenType.POI_CATEGORY);
categoryName = token.getName();
}
if (!Algorithms.isEmpty(categoryName) && !Algorithms.isEmpty(typeName)) {
QStringStringListHash list = new QStringStringListHash();
QStringList stringList = new QStringList();
//todo list.set(categoryName, stringList);
criteria.setCategoriesFilter(list);
} else if (!Algorithms.isEmpty(categoryName)) {
QStringStringListHash list = new QStringStringListHash();
//todo list.set(categoryName, new QStringList());
criteria.setCategoriesFilter(list);
}
//todo criteria.setCategoriesFilter() if needed;
}
public void setupAddressSearchCriteria(AddressesByNameSearch.Criteria criteria) {
//not implemented
}
public boolean processAmenitySearchItem(AmenitySearchItem item) {
boolean res = true;
updateDistance(item);
if (searchRadius > 0) {
res = item.getDistance() < searchRadius;
}
return res;
public boolean processPoiSearchObject(PoiSearchObject poiSearchObject) {
updateDistance(poiSearchObject);
return true;
}
public boolean processAddressSearchItem(AddressSearchItem item) {
boolean res = true;
if (resolvedTokens.containsKey(TokenType.CITY) && item.getParentCityObfId() != null) {
CitySearchToken token = (CitySearchToken)resolvedTokens.get(TokenType.CITY);
res = token.getObfId().equals(item.getParentCityObfId());
} else if (resolvedTokens.containsKey(TokenType.POSTCODE) && item.getParentPostcodeObfId() != null) {
PostcodeSearchToken token = (PostcodeSearchToken)resolvedTokens.get(TokenType.CITY);
res = token.getObfId().equals(item.getParentPostcodeObfId());
}
if (res) {
updateDistance(item);
}
return res;
public boolean processAddressSearchObject(SearchPositionObject addressSearchObject) {
updateDistance(addressSearchObject);
return true;
}
public void processSearchResult(List<SearchItem> searchItems) {
/*
Collections.sort(searchItems, new Comparator<SearchItem>() {
@Override
public int compare(SearchItem lhs, SearchItem rhs) {
int res = Double.compare(lhs.getDistance(), rhs.getDistance());
if (res == 0) {
return lhs.getName().compareToIgnoreCase(rhs.getName());
} else {
return res;
}
public SearchToken processSearchResult(SearchToken token, List<SearchObject> searchObjects) {
SearchToken newToken = null;
boolean cityVillagePostcodeSelected = objectTokens.containsKey(SearchObjectType.CITY)
|| objectTokens.containsKey(SearchObjectType.VILLAGE)
|| objectTokens.containsKey(SearchObjectType.POSTCODE);
for (SearchObject searchObject : searchObjects) {
float priority = 0f;
boolean sortByName = false;
switch (searchObject.getType()) {
case POI:
priority = getPriorityByDistance(10, ((PoiSearchObject) searchObject).getDistance());
break;
case CITY:
case VILLAGE:
case POSTCODE:
float cityType = getCityType((StreetGroupSearchObject) searchObject);
priority = (getPriorityByDistance(cityVillagePostcodeSelected
? 20f : 7f + cityType, ((StreetGroupSearchObject) searchObject).getDistance()));
break;
case STREET:
StreetSearchObject streetSearchObject = (StreetSearchObject) searchObject;
Street street = streetSearchObject.getStreet();
if (!cityVillagePostcodeSelected) {
priority = getPriorityByDistance(9f, streetSearchObject.getDistance());
} else {
boolean streetFromSelectedCity = false;
for (SearchToken st : objectTokens.values()) {
if (st.getSearchObject() instanceof StreetGroupSearchObject) {
StreetGroupSearchObject streetGroupSearchObject = (StreetGroupSearchObject) st.getSearchObject();
if (streetGroupSearchObject.getStreetGroup().getId().getId()
.equals(street.getStreetGroup().getId().getId())) {
streetFromSelectedCity = true;
break;
}
}
}
if (streetFromSelectedCity) {
priority = 3f;
sortByName = true;
} else {
priority = getPriorityByDistance(9f, streetSearchObject.getDistance());
}
}
break;
}
});
*/
searchObject.setPriority(priority);
searchObject.setSortByName(sortByName);
}
//todo
if (searchObjects.size() > 0) {
Collections.sort(searchObjects, new Comparator<SearchObject>() {
@Override
public int compare(SearchObject lhs, SearchObject rhs) {
int res = Double.compare(lhs.getPriority(), rhs.getPriority());
if (res == 0 && lhs.isSortByName() && rhs.isSortByName()) {
return lhs.getName(lang).compareToIgnoreCase(rhs.getName(lang));
} else {
return res;
}
}
});
if (token.getType() == SearchToken.TokenType.NAME_FILTER
&& !Algorithms.isEmpty(token.getQueryText())) {
newToken = new ObjectSearchToken(token, searchObjects.get(0));
}
}
return newToken;
}
private void updateDistance(SearchItem item) {
item.setDistance(Utilities.distance(
searchLon, searchLat, item.getLongitude(), item.getLatitude()));
private float getCityType(StreetGroupSearchObject searchObject) {
if (searchObject.getStreetGroup().getType() == ObfAddressStreetGroupType.CityOrTown) {
if (searchObject.getStreetGroup().getSubtype() == ObfAddressStreetGroupSubtype.City) {
return 1f;
} else if (searchObject.getStreetGroup().getSubtype() == ObfAddressStreetGroupSubtype.Town) {
return 1.5f;
}
}
return 2.5f;
}
private float getPriorityByDistance(float priority, double distance) {
return priority + (float)(1 / (1 + distance));
}
private void updateDistance(SearchPositionObject item) {
item.setDistance(Utilities.distance31(searchLocation31, item.getPosition31()));
}
}

View file

@ -1,8 +1,10 @@
package net.osmand.core.samples.android.sample1.search;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
import net.osmand.core.samples.android.sample1.search.tokens.NameFilterSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken.TokenType;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.HashMap;
@ -17,11 +19,18 @@ public class SearchString {
public SearchString() {
}
public SearchString copy() {
SearchString res = new SearchString();
res.queryText = queryText;
res.tokens = new ArrayList<>(tokens);
return res;
}
public String getQueryText() {
return queryText;
}
public synchronized void setQueryText(String queryText) {
public void setQueryText(String queryText) {
int newTextLength = queryText.length();
int currTextLength = this.queryText.length();
boolean isNewText = currTextLength == 0
@ -73,12 +82,19 @@ public class SearchString {
if (firstWordIndex <= newTextLength - 1) {
SearchToken token = new NameFilterSearchToken(firstWordIndex, queryText.substring(firstWordIndex));
tokens.add(token);
} else if (endWithDelimeter(queryText)) {
SearchToken token = new NameFilterSearchToken(firstWordIndex, "");
tokens.add(token);
}
}
this.queryText = queryText;
}
private boolean endWithDelimeter(String text) {
return !Algorithms.isEmpty(text) && isDelimiterChar(text.charAt(text.length() - 1));
}
private boolean startWithDelimiter(String text) {
char firstChar = text.charAt(0);
return isDelimiterChar(firstChar);
@ -88,7 +104,7 @@ public class SearchString {
return c == ',' || c == ' ';
}
public synchronized SearchToken getNextNameFilterToken() {
public SearchToken getNextNameFilterToken() {
SearchToken res = null;
if (!tokens.isEmpty()) {
for (int i = tokens.size() - 1; i >= 0; i--) {
@ -103,18 +119,18 @@ public class SearchString {
return res;
}
public synchronized SearchToken getLastToken() {
public SearchToken getLastToken() {
if (!tokens.isEmpty()) {
return tokens.get(tokens.size() - 1);
}
return null;
}
public synchronized boolean hasNameFilterTokens() {
public boolean hasNameFilterTokens() {
return getNextNameFilterToken() != null;
}
public synchronized boolean replaceToken(SearchToken oldToken, SearchToken newToken) {
public boolean replaceToken(SearchToken oldToken, SearchToken newToken) {
int index = tokens.indexOf(oldToken);
if (index != -1) {
tokens.set(index, newToken);
@ -123,11 +139,11 @@ public class SearchString {
return false;
}
public synchronized Map<TokenType, SearchToken> getResolvedTokens() {
Map<TokenType, SearchToken> map = new HashMap<>();
public Map<SearchObjectType, SearchToken> getObjectTokens() {
Map<SearchObjectType, SearchToken> map = new HashMap<>();
for (SearchToken token : tokens) {
if (token.getType() != SearchToken.TokenType.NAME_FILTER) {
map.put(token.getType(), token);
if (token.getType() == TokenType.SEARCH_OBJECT) {
map.put(token.getSearchObject().getType(), token);
}
}
return map;

View file

@ -1,111 +0,0 @@
package net.osmand.core.samples.android.sample1.search.items;
import net.osmand.core.jni.Address;
import net.osmand.core.jni.ObfAddressStreetGroupSubtype;
import net.osmand.core.jni.ObfAddressStreetGroupType;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.StreetGroup;
import net.osmand.util.Algorithms;
import java.math.BigInteger;
public class AddressSearchItem extends SearchItem {
private String namePrefix;
private String nameSuffix;
private String typeStr;
private BigInteger parentCityObfId;
private BigInteger parentPostcodeObfId;
public AddressSearchItem(Address address) {
super();
switch (address.getAddressType()) {
case Street:
StreetInternal street = new StreetInternal(address);
setLocation(street.getPosition31());
setNativeName(street.getNativeName());
addLocalizedNames(street.getLocalizedNames());
if (street.getStreetGroup() != null) {
StreetGroup streetGroup = street.getStreetGroup();
nameSuffix = "st.";
typeStr = streetGroup.getNativeName() + "" + getTypeStr(streetGroup);
if (streetGroup.getType() == ObfAddressStreetGroupType.Postcode) {
parentPostcodeObfId = streetGroup.getId().getId();
} else {
parentCityObfId = streetGroup.getId().getId();
}
} else {
typeStr = "Street";
}
break;
case StreetGroup:
StreetGroupInternal streetGroup = new StreetGroupInternal(address);
setLocation(streetGroup.getPosition31());
setNativeName(streetGroup.getNativeName());
addLocalizedNames(streetGroup.getLocalizedNames());
typeStr = getTypeStr(streetGroup);
break;
}
}
public String getNamePrefix() {
return namePrefix;
}
public String getNameSuffix() {
return nameSuffix;
}
@Override
public String getName() {
StringBuilder sb = new StringBuilder();
if (!Algorithms.isEmpty(namePrefix)) {
sb.append(namePrefix);
sb.append(" ");
}
sb.append(super.getName());
if (!Algorithms.isEmpty(nameSuffix)) {
sb.append(" ");
sb.append(nameSuffix);
}
return sb.toString();
}
@Override
public String getType() {
return typeStr;
}
private String getTypeStr(StreetGroup streetGroup) {
String typeStr;
if (streetGroup.getSubtype() != ObfAddressStreetGroupSubtype.Unknown) {
typeStr = streetGroup.getSubtype().name();
} else {
typeStr = streetGroup.getType().name();
}
return typeStr;
}
public BigInteger getParentCityObfId() {
return parentCityObfId;
}
public BigInteger getParentPostcodeObfId() {
return parentPostcodeObfId;
}
private class StreetInternal extends Street {
public StreetInternal(Address address) {
super(Address.getCPtr(address), false);
}
}
private class StreetGroupInternal extends StreetGroup {
public StreetGroupInternal(Address address) {
super(Address.getCPtr(address), false);
}
}
}

View file

@ -1,57 +0,0 @@
package net.osmand.core.samples.android.sample1.search.items;
import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.DecodedCategoryList;
import net.osmand.core.jni.DecodedValueList;
import net.osmand.util.Algorithms;
import java.util.HashMap;
import java.util.Map;
public class AmenitySearchItem extends SearchItem {
private String category;
private String subcategory;
private Map<String, String> values = new HashMap<>();
public AmenitySearchItem(Amenity amenity) {
super(amenity.getPosition31());
setNativeName(amenity.getNativeName());
addLocalizedNames(amenity.getLocalizedNames());
DecodedCategoryList catList = amenity.getDecodedCategories();
if (catList.size() > 0) {
Amenity.DecodedCategory decodedCategory = catList.get(0);
category = decodedCategory.getCategory();
subcategory = decodedCategory.getSubcategory();
}
DecodedValueList decodedValueList = amenity.getDecodedValues();
if (decodedValueList.size() > 0) {
for (int i = 0; i < decodedValueList.size(); i++) {
Amenity.DecodedValue decodedValue = decodedValueList.get(i);
String tag = decodedValue.getDeclaration().getTagName();
String value = decodedValue.getValue();
values.put(tag, value);
}
}
}
public String getCategory() {
return category;
}
public String getSubcategory() {
return subcategory;
}
public Map<String, String> getValues() {
return values;
}
@Override
public String getType() {
return Algorithms.capitalizeFirstLetterAndLowercase(subcategory);
}
}

View file

@ -1,97 +0,0 @@
package net.osmand.core.samples.android.sample1.search.items;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringList;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.Utilities;
import java.util.HashMap;
import java.util.Map;
public abstract class SearchItem {
protected double latitude;
protected double longitude;
protected String nativeName;
protected Map<String, String> localizedNames = new HashMap<>();
private double distance;
private float priority;
protected SearchItem() {
}
protected SearchItem(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
protected SearchItem(PointI location31) {
LatLon latLon = Utilities.convert31ToLatLon(location31);
latitude = latLon.getLatitude();
longitude = latLon.getLongitude();
}
public String getName() {
return nativeName;
}
public abstract String getType();
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public String getNativeName() {
return nativeName;
}
public Map<String, String> getLocalizedNames() {
return localizedNames;
}
protected void setLocation(PointI location31) {
LatLon latLon = Utilities.convert31ToLatLon(location31);
latitude = latLon.getLatitude();
longitude = latLon.getLongitude();
}
protected void setNativeName(String nativeName) {
this.nativeName = nativeName;
}
protected void addLocalizedNames(QStringStringHash localizedNames) {
QStringList locNamesKeys = localizedNames.keys();
for (int i = 0; i < locNamesKeys.size(); i++) {
String key = locNamesKeys.get(i);
String val = localizedNames.get(key);
this.localizedNames.put(key, val);
}
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
public float getPriority() {
return priority;
}
public void setPriority(float priority) {
this.priority = priority;
}
@Override
public String toString() {
return getName() + " (" + getType() + ") {lat:" + getLatitude() + " lon: " + getLongitude() + "}";
}
}

View file

@ -0,0 +1,10 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.StreetGroup;
public class CitySearchObject extends StreetGroupSearchObject {
public CitySearchObject(StreetGroup streetGroup) {
super(SearchObjectType.CITY, streetGroup);
}
}

View file

@ -0,0 +1,26 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
public class CoordinatesSearchObject extends SearchPositionObject {
public CoordinatesSearchObject(PointI position31) {
super(SearchObjectType.COORDINATES, position31);
}
@Override
public PointI getPosition31() {
return (PointI) getInternalObject();
}
@Override
public String getNativeName() {
return null;
}
@Override
protected QStringStringHash getLocalizedNames() {
return null;
}
}

View file

@ -0,0 +1,31 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
public class PoiSearchObject extends SearchPositionObject {
public PoiSearchObject(Amenity amenity) {
super(SearchObjectType.POI, amenity);
}
public Amenity getAmenity() {
return (Amenity) getInternalObject();
}
@Override
public PointI getPosition31() {
return getAmenity().getPosition31();
}
@Override
public String getNativeName() {
return getAmenity().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getAmenity().getLocalizedNames();
}
}

View file

@ -0,0 +1,12 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.StreetGroup;
public class PostcodeSearchObject extends StreetGroupSearchObject {
public PostcodeSearchObject(StreetGroup streetGroup) {
super(SearchObjectType.POSTCODE, streetGroup);
}
}

View file

@ -0,0 +1,84 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.QStringStringHash;
public abstract class SearchObject {
public enum SearchObjectType {
CITY,
VILLAGE,
POSTCODE,
STREET,
BUILDING,
POI_TYPE,
POI_FILTER,
POI,
COORDINATES
}
private SearchObjectType type;
private Object internalObject;
private float priority;
private boolean sortByName;
protected SearchObject(SearchObjectType type, Object internalObject) {
this.type = type;
this.internalObject = internalObject;
}
public SearchObjectType getType() {
return type;
}
protected Object getInternalObject() {
return internalObject;
}
public abstract String getNativeName();
public String getName(String lang) {
QStringStringHash locNames = getLocalizedNames();
if (locNames != null && lang != null) {
String locName = null;
if (locNames.has_key(lang)) {
locName = locNames.get(lang);
}
return locName == null ? getNativeName() : locName;
} else {
return getNativeName();
}
}
public String getNameEn() {
QStringStringHash locNames = getLocalizedNames();
if (locNames != null && locNames.has_key("en")) {
return locNames.get("en");
} else {
return null;
}
}
public float getPriority() {
return priority;
}
public void setPriority(float priority) {
this.priority = priority;
}
public boolean isSortByName() {
return sortByName;
}
public void setSortByName(boolean sortByName) {
this.sortByName = sortByName;
}
protected abstract QStringStringHash getLocalizedNames();
@Override
public String toString() {
return "SearchObject: " + getNativeName();
}
}

View file

@ -0,0 +1,42 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.Address;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.StreetGroup;
public class SearchObjectsHelper {
public static SearchPositionObject getAddressObject(Address address) {
switch (address.getAddressType()) {
case Street:
StreetInternal street = new StreetInternal(address);
return new StreetSearchObject(street);
case StreetGroup:
StreetGroupInternal streetGroup = new StreetGroupInternal(address);
switch (streetGroup.getType()) {
case CityOrTown:
return new CitySearchObject(streetGroup);
case Village:
return new VillageSearchObject(streetGroup);
case Postcode:
return new PostcodeSearchObject(streetGroup);
}
break;
}
return null;
}
private static class StreetInternal extends Street {
public StreetInternal(Address address) {
super(Address.getCPtr(address), false);
}
}
private static class StreetGroupInternal extends StreetGroup {
public StreetGroupInternal(Address address) {
super(Address.getCPtr(address), false);
}
}
}

View file

@ -0,0 +1,29 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
public abstract class SearchPositionObject extends SearchObject {
private double distance;
public SearchPositionObject(SearchObjectType type, Object internalObject) {
super(type, internalObject);
}
public abstract PointI getPosition31();
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
@Override
public String toString() {
return "SearchPositionObject: " + getNativeName()
+ " {x31:" + getPosition31().getX() + " y31: " + getPosition31().getY() + "}";
}
}

View file

@ -0,0 +1,31 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.StreetGroup;
public abstract class StreetGroupSearchObject extends SearchPositionObject {
public StreetGroupSearchObject(SearchObjectType type, StreetGroup streetGroup) {
super(type, streetGroup);
}
public StreetGroup getStreetGroup() {
return (StreetGroup) getInternalObject();
}
@Override
public PointI getPosition31() {
return getStreetGroup().getPosition31();
}
@Override
public String getNativeName() {
return getStreetGroup().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getStreetGroup().getLocalizedNames();
}
}

View file

@ -0,0 +1,31 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.Street;
public class StreetSearchObject extends SearchPositionObject {
public StreetSearchObject(Street street) {
super(SearchObjectType.STREET, street);
}
public Street getStreet() {
return (Street) getInternalObject();
}
@Override
public PointI getPosition31() {
return getStreet().getPosition31();
}
@Override
public String getNativeName() {
return getStreet().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getStreet().getLocalizedNames();
}
}

View file

@ -0,0 +1,12 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.StreetGroup;
public class VillageSearchObject extends StreetGroupSearchObject {
public VillageSearchObject(StreetGroup streetGroup) {
super(SearchObjectType.VILLAGE, streetGroup);
}
}

View file

@ -10,12 +10,16 @@ import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.IQueryController;
import net.osmand.core.jni.ISearch;
import net.osmand.core.jni.NullableAreaI;
import net.osmand.core.samples.android.sample1.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallback;
import net.osmand.core.samples.android.sample1.search.items.AddressSearchItem;
import net.osmand.core.samples.android.sample1.search.items.AmenitySearchItem;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallbackInternal;
import net.osmand.core.samples.android.sample1.search.SearchScope;
import net.osmand.core.samples.android.sample1.search.SearchString;
import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObjectsHelper;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
@ -24,14 +28,18 @@ public class CoreSearchRequest extends SearchRequest {
private IntermediateSearchRequest intermediateSearchRequest;
private boolean intermediateSearchDone;
private SearchCallbackInternal internalCallback;
private int amenityResultsCounter;
private int addressResultsCounter;
public CoreSearchRequest(@Nullable IntermediateSearchRequest intermediateSearchRequest,
@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
super(searchAPI, maxSearchResults, searchCallback);
@NonNull SearchScope searchScope, int maxSearchResults,
@Nullable SearchApiCallback searchCallback,
@Nullable SearchCallbackInternal internalCallback) {
super(searchScope, maxSearchResults, searchCallback);
this.intermediateSearchRequest = intermediateSearchRequest;
this.internalCallback = internalCallback;
}
@Override
@ -51,11 +59,13 @@ public class CoreSearchRequest extends SearchRequest {
}
@Override
protected void onSearchRequestPostExecute(List<SearchItem> searchItems) {
protected void onSearchRequestPostExecute(List<SearchObject> searchObjects) {
if (intermediateSearchRequest != null && !intermediateSearchDone) {
intermediateSearchRequest.cancel();
}
searchAPI.setSearchItems(searchItems);
if (internalCallback != null) {
internalCallback.onSearchObjectsFound(searchObjects);
}
}
@Override
@ -67,37 +77,42 @@ public class CoreSearchRequest extends SearchRequest {
}
@Override
protected List<SearchItem> doSearch() {
protected List<SearchObject> doSearch() {
List<SearchItem> res = new ArrayList<>();
List<SearchObject> res = new ArrayList<>();
SearchString searchString = searchScope.getSearchString();
SearchToken lastToken = searchString.getLastToken();
SearchToken token = searchString.getNextNameFilterToken();
while (token != null && !cancelled) {
if (token.getType() == SearchToken.TokenType.NAME_FILTER) {
List<SearchItem> searchItems = doCoreSearch(token);
res.clear();
res.addAll(searchItems);
if (token.getType() == SearchToken.TokenType.NAME_FILTER
&& !Algorithms.isEmpty(token.getQueryText())) {
res = doCoreSearch(token);
}
if (token != lastToken) {
token = searchString.getNextNameFilterToken();
} else {
break;
}
token = searchString.getNextNameFilterToken();
}
return res;
}
private List<SearchItem> doCoreSearch(@NonNull SearchToken token) {
private List<SearchObject> doCoreSearch(@NonNull SearchToken token) {
System.out.println("=== Start search");
amenityResultsCounter = 0;
addressResultsCounter = 0;
String keyword = token.getQueryText();
final List<SearchItem> searchItems = new ArrayList<>();
final List<SearchObject> searchObjects = new ArrayList<>();
// Setup Amenities by name search
AmenitiesByNameSearch amByNameSearch = new AmenitiesByNameSearch(searchAPI.getObfsCollection());
AmenitiesByNameSearch amByNameSearch = new AmenitiesByNameSearch(searchScope.getObfsCollection());
AmenitiesByNameSearch.Criteria amenityByNameCriteria = new AmenitiesByNameSearch.Criteria();
amenityByNameCriteria.setName(keyword);
if (searchAPI.getObfAreaFilter() != null) {
amenityByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchAPI.getObfAreaFilter()));
if (searchScope.getObfAreaFilter() != null) {
amenityByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchScope.getObfAreaFilter()));
}
searchScope.setupAmenitySearchCriteria(amenityByNameCriteria);
@ -105,9 +120,9 @@ public class CoreSearchRequest extends SearchRequest {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Amenity amenity = new AmenityResultEntry(resultEntry).getAmenity();
AmenitySearchItem amenitySearchItem = new AmenitySearchItem(amenity);
if (searchScope.processAmenitySearchItem(amenitySearchItem)) {
searchItems.add(amenitySearchItem);
PoiSearchObject amenitySearchItem = new PoiSearchObject(amenity);
if (searchScope.processPoiSearchObject(amenitySearchItem)) {
searchObjects.add(amenitySearchItem);
}
System.out.println("Poi found === " + amenitySearchItem.toString());
amenityResultsCounter++;
@ -115,11 +130,11 @@ public class CoreSearchRequest extends SearchRequest {
};
// Setup Addresses by name search
AddressesByNameSearch addrByNameSearch = new AddressesByNameSearch(searchAPI.getObfsCollection());
AddressesByNameSearch.Criteria addrByNameCriteria = new AddressesByNameSearch.Criteria();
AddressesByNameSearch addrByNameSearch = new AddressesByNameSearch(searchScope.getObfsCollection());
final AddressesByNameSearch.Criteria addrByNameCriteria = new AddressesByNameSearch.Criteria();
addrByNameCriteria.setName(keyword);
if (searchAPI.getObfAreaFilter() != null) {
addrByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchAPI.getObfAreaFilter()));
if (searchScope.getObfAreaFilter() != null) {
addrByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchScope.getObfAreaFilter()));
}
searchScope.setupAddressSearchCriteria(addrByNameCriteria);
@ -127,12 +142,14 @@ public class CoreSearchRequest extends SearchRequest {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Address address = new AddressResultEntry(resultEntry).getAddress();
AddressSearchItem addrSearchItem = new AddressSearchItem(address);
if (searchScope.processAddressSearchItem(addrSearchItem)) {
searchItems.add(addrSearchItem);
SearchPositionObject addressSearchObject = SearchObjectsHelper.getAddressObject(address);
if (addressSearchObject != null) {
if (searchScope.processAddressSearchObject(addressSearchObject)) {
searchObjects.add(addressSearchObject);
}
System.out.println("Address found === " + addressSearchObject.toString());
addressResultsCounter++;
}
System.out.println("Address found === " + addrSearchItem.toString());
addressResultsCounter++;
}
};
@ -153,12 +170,15 @@ public class CoreSearchRequest extends SearchRequest {
}
if (!cancelled) {
searchScope.processSearchResult(searchItems);
SearchToken newToken = searchScope.processSearchResult(token, searchObjects);
if (newToken != null && internalCallback != null) {
internalCallback.onNewTokenFound(token, newToken);
}
}
System.out.println("=== Finish search");
return searchItems;
return searchObjects;
}
private class AmenityResultEntry extends AmenitiesByNameSearch.ResultEntry {

View file

@ -3,10 +3,9 @@ package net.osmand.core.samples.android.sample1.search.requests;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import net.osmand.core.samples.android.sample1.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallback;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.requests.SearchRequest;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.SearchScope;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import java.util.ArrayList;
@ -14,27 +13,29 @@ import java.util.List;
public class IntermediateSearchRequest extends SearchRequest {
private List<SearchItem> searchItems;
private List<SearchObject> searchObjects;
protected String keyword = "";
public IntermediateSearchRequest(@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
super(searchAPI, maxSearchResults, searchCallback);
this.searchItems = new ArrayList<>(searchAPI.getSearchItems());
public IntermediateSearchRequest(@NonNull SearchScope searchScope, List<SearchObject> searchObjects,
int maxSearchResults, @Nullable SearchApiCallback searchCallback) {
super(searchScope, maxSearchResults, searchCallback);
this.searchObjects = searchObjects;
SearchToken token = searchString.getLastToken();
SearchToken token = searchScope.getSearchString().getLastToken();
if (token != null && token.getType() == SearchToken.TokenType.NAME_FILTER) {
keyword = token.getQueryText();
keyword = token.getQueryText().toLowerCase();
}
}
@Override
protected List<SearchItem> doSearch() {
List<SearchItem> res = new ArrayList<>();
for (SearchItem item : searchItems) {
protected List<SearchObject> doSearch() {
List<SearchObject> res = new ArrayList<>();
for (SearchObject item : searchObjects) {
if (cancelled) {
break;
}
if (keyword.isEmpty() || item.getName().contains(keyword)) {
if (keyword.isEmpty() || item.getName(searchScope.getLang()).toLowerCase().contains(keyword)
|| item.getNativeName().toLowerCase().contains(keyword)) {
res.add(item);
}
}

View file

@ -4,62 +4,57 @@ import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import net.osmand.core.samples.android.sample1.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallback;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.SearchScope;
import net.osmand.core.samples.android.sample1.search.SearchString;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import java.util.List;
public abstract class SearchRequest {
protected SearchAPI searchAPI;
protected SearchString searchString;
protected SearchScope searchScope;
protected int maxSearchResults;
protected Runnable onFinished;
protected SearchCallback searchCallback;
protected SearchApiCallback searchCallback;
protected boolean cancelled;
public SearchRequest(@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
this.searchAPI = searchAPI;
this.searchString = searchAPI.getSearchString();
this.searchScope= searchAPI.getSearchScope();
public SearchRequest(@NonNull SearchScope searchScope, int maxSearchResults,
@Nullable SearchApiCallback searchCallback) {
this.searchScope = searchScope;
this.maxSearchResults = maxSearchResults;
this.searchCallback = searchCallback;
}
public void run() {
new AsyncTask<Void, Void, List<SearchItem>>() {
new AsyncTask<Void, Void, List<SearchObject>>() {
@Override
protected List<SearchItem> doInBackground(Void... params) {
protected List<SearchObject> doInBackground(Void... params) {
return doSearch();
}
@Override
protected void onPostExecute(List<SearchItem> searchItems) {
protected void onPostExecute(List<SearchObject> searchObjects) {
onSearchRequestPostExecute(searchItems);
onSearchRequestPostExecute(searchObjects);
if (onFinished != null) {
onFinished.run();
}
if (searchCallback != null && !cancelled) {
searchCallback.onSearchFinished(searchItems);
searchCallback.onSearchFinished(searchObjects);
}
}
}.execute();
}
protected void onSearchRequestPostExecute(List<SearchItem> searchItems) {
protected void onSearchRequestPostExecute(List<SearchObject> searchObjects) {
}
protected abstract List<SearchItem> doSearch();
protected abstract List<SearchObject> doSearch();
public void cancel() {
cancelled = true;

View file

@ -1,17 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import java.math.BigInteger;
public class CitySearchToken extends SearchToken {
private BigInteger obfId;
public CitySearchToken(BigInteger obfId, int startIndex, String queryText, String name) {
super(TokenType.CITY, startIndex, queryText, name);
this.obfId = obfId;
}
public BigInteger getObfId() {
return obfId;
}
}

View file

@ -3,6 +3,6 @@ package net.osmand.core.samples.android.sample1.search.tokens;
public class NameFilterSearchToken extends SearchToken {
public NameFilterSearchToken(int startIndex, String queryText) {
super(TokenType.NAME_FILTER, startIndex, queryText, queryText);
super(TokenType.NAME_FILTER, startIndex, queryText, null);
}
}

View file

@ -0,0 +1,14 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
public class ObjectSearchToken extends SearchToken {
public ObjectSearchToken(SearchToken searchToken, SearchObject searchObject) {
super(TokenType.SEARCH_OBJECT, searchToken.getStartIndex(), searchToken.getQueryText(), searchObject);
}
public ObjectSearchToken(int startIndex, String queryText, SearchObject searchObject) {
super(TokenType.SEARCH_OBJECT, startIndex, queryText, searchObject);
}
}

View file

@ -1,18 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import android.support.annotation.NonNull;
import net.osmand.osm.PoiCategory;
public class PoiCategorySearchToken extends SearchToken {
private PoiCategory poiCategory;
public PoiCategorySearchToken(@NonNull PoiCategory poiCategory, int startIndex, String queryText) {
super(TokenType.POI_CATEGORY, startIndex, queryText, poiCategory.getKeyName());
this.poiCategory = poiCategory;
}
public PoiCategory getPoiCategory() {
return poiCategory;
}
}

View file

@ -1,19 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import android.support.annotation.NonNull;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
public class PoiFilterSearchToken extends SearchToken {
private PoiFilter poiFilter;
public PoiFilterSearchToken(@NonNull PoiFilter poiFilter, int startIndex, String queryText) {
super(TokenType.POI_FILTER, startIndex, queryText, poiFilter.getKeyName());
this.poiFilter = poiFilter;
}
public PoiFilter getPoiFilter() {
return poiFilter;
}
}

View file

@ -1,19 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import android.support.annotation.NonNull;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
public class PoiTypeSearchToken extends SearchToken {
private PoiType poiType;
public PoiTypeSearchToken(@NonNull PoiType poiType, int startIndex, String queryText) {
super(TokenType.POI_TYPE, startIndex, queryText, poiType.getKeyName());
this.poiType = poiType;
}
public PoiType getPoiType() {
return poiType;
}
}

View file

@ -1,16 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import java.math.BigInteger;
public class PostcodeSearchToken extends SearchToken {
private BigInteger obfId;
public PostcodeSearchToken(BigInteger obfId, int startIndex, String queryText, String name) {
super(TokenType.POSTCODE, startIndex, queryText, name);
this.obfId = obfId;
}
public BigInteger getObfId() {
return obfId;
}
}

View file

@ -1,29 +1,24 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
public abstract class SearchToken {
public enum TokenType {
CITY,
POSTCODE,
STREET,
BUILDING,
POI_CATEGORY,
POI_FILTER,
POI_TYPE,
LOCATION,
SEARCH_OBJECT,
NAME_FILTER
}
private TokenType type;
private SearchObject searchObject;
private int startIndex;
protected String queryText;
protected String name;
public SearchToken(TokenType type, int startIndex, String queryText, String name) {
public SearchToken(TokenType type, int startIndex, String queryText, SearchObject searchObject) {
this.type = type;
this.startIndex = startIndex;
this.queryText = queryText;
this.name = name;
this.searchObject = searchObject;
}
public TokenType getType() {
@ -50,7 +45,7 @@ public abstract class SearchToken {
return queryText.length();
}
public String getName() {
return name;
public SearchObject getSearchObject() {
return searchObject;
}
}