Core search in progress

This commit is contained in:
Alexey Kulish 2016-06-22 19:07:32 +03:00
parent 44eeb3f7cc
commit 1a455885fa
22 changed files with 875 additions and 190 deletions

View file

@ -4,6 +4,10 @@ android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
dexOptions {
jumboMode true
}
defaultConfig {
minSdkVersion 14
targetSdkVersion 23

View file

@ -23,12 +23,10 @@ import android.widget.ListView;
import android.widget.TextView;
import net.osmand.core.android.AtlasMapRendererView;
import net.osmand.core.android.NativeCore;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.IMapLayerProvider;
import net.osmand.core.jni.IMapStylesCollection;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.LogSeverityLevel;
import net.osmand.core.jni.Logger;
import net.osmand.core.jni.MapObjectsSymbolsProvider;
import net.osmand.core.jni.MapPresentationEnvironment;
@ -45,12 +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.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchAPICallback;
import net.osmand.core.samples.android.sample1.search.SearchItem;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchCallback;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -86,7 +84,8 @@ public class MainActivity extends Activity {
private SearchAPI searchAPI;
private ListView searchListView;
private SearchListAdapter adapter;
private final static int MAX_SEARCH_RESULTS = 50;
private final static int MAX_SEARCH_RESULTS_CORE = 500;
private final static int MAX_SEARCH_RESULTS_IU = 50;
// Germany
private final static float INIT_LAT = 49.353953f;
@ -402,41 +401,50 @@ public class MainActivity extends Activity {
private void runSearch(AreaI bounds31, String keyword) {
searchAPI.setObfAreaFilter(bounds31);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS, new SearchAPICallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems, boolean cancelled) {
if (searchItems != null && !cancelled) {
LatLon latLon = Utilities.convert31ToLatLon(target31);
List<SearchListItem> rows = new ArrayList<>();
for (SearchItem item : searchItems) {
SearchListItem row =
SearchListItem.buildListItem((SampleApplication)getApplication(), item);
rows.add(row);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS_CORE,
// Intermediate search callback
new SearchCallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems) {
processSearchResult(searchItems);
}
adapter.clear();
adapter.addAll(rows);
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
adapter.sort(new Comparator<SearchListItem>() {
@Override
public int compare(SearchListItem lhs, SearchListItem rhs) {
int res = Double.compare(lhs.getDistance(), rhs.getDistance());
if (res == 0) {
return lhs.getName().compareToIgnoreCase(rhs.getName());
} else {
return res;
}
}
});
adapter.notifyDataSetChanged();
if (adapter.getCount() > 0) {
searchListView.setSelection(0);
},
// Core search callback
new SearchCallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems) {
processSearchResult(searchItems);
}
});
}
showSearchList();
private void processSearchResult(List<SearchItem> searchItems) {
if (searchItems != null) {
LatLon latLon = Utilities.convert31ToLatLon(target31);
double latitude = latLon.getLatitude();
double longitude = latLon.getLongitude();
List<SearchListItem> rows = new ArrayList<>();
for (SearchItem item : searchItems) {
SearchListItem listItem =
SearchListItem.buildListItem((SampleApplication)getApplication(), item);
if (listItem != null) {
rows.add(listItem);
}
}
});
if (rows.size() > MAX_SEARCH_RESULTS_IU) {
rows = rows.subList(0, MAX_SEARCH_RESULTS_IU);
}
adapter.clear();
adapter.addAll(rows);
adapter.notifyDataSetChanged();
if (adapter.getCount() > 0) {
searchListView.setSelection(0);
}
showSearchList();
}
}
private class MapViewOnGestureListener extends SimpleOnGestureListener {

View file

@ -2,7 +2,7 @@ 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.AddressSearchItem;
import net.osmand.core.samples.android.sample1.search.items.AddressSearchItem;
import net.osmand.util.Algorithms;
public class AddressSearchListItem extends SearchListItem {

View file

@ -4,7 +4,7 @@ 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.AmenitySearchItem;
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;

View file

@ -26,8 +26,7 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
for (int i = 0; i < getCount(); i++) {
SearchListItem item = getItem(i);
item.setDistance(Utilities.distance(
longitude, latitude,
item.getLongitude(), item.getLatitude()));
longitude, latitude, item.getLongitude(), item.getLatitude()));
}
}

View file

@ -3,15 +3,14 @@ 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.AddressSearchItem;
import net.osmand.core.samples.android.sample1.search.AmenitySearchItem;
import net.osmand.core.samples.android.sample1.search.SearchItem;
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;
public class SearchListItem {
protected SampleApplication app;
private SearchItem searchItem;
private double distance;
public SearchListItem(SampleApplication app, SearchItem searchItem) {
this.app = app;
@ -45,11 +44,11 @@ public class SearchListItem {
}
public double getDistance() {
return distance;
return searchItem.getDistance();
}
public void setDistance(double distance) {
this.distance = distance;
searchItem.setDistance(distance);
}
public Drawable getIcon() {

View file

@ -1,19 +1,15 @@
package net.osmand.core.samples.android.sample1.search;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import net.osmand.core.jni.Address;
import net.osmand.core.jni.AddressesByNameSearch;
import net.osmand.core.jni.AmenitiesByNameSearch;
import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.IQueryController;
import net.osmand.core.jni.ISearch;
import net.osmand.core.jni.ISearch.INewResultEntryCallback;
import net.osmand.core.jni.NullableAreaI;
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.requests.CoreSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.IntermediateSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.SearchRequest;
import java.util.ArrayList;
import java.util.List;
public class SearchAPI {
@ -21,15 +17,23 @@ public class SearchAPI {
private ObfsCollection obfsCollection;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private SearchRequestExecutor executor;
private PointI searchLocation;
private double searchRadius;
public interface SearchAPICallback {
void onSearchFinished(List<SearchItem> searchItems, boolean cancelled);
private SearchRequestExecutor executor;
private SearchString searchString;
private SearchScope searchScope;
private List<SearchItem> searchItems;
public interface SearchCallback {
void onSearchFinished(List<SearchItem> searchItems);
}
public SearchAPI(ObfsCollection obfsCollection) {
public SearchAPI(@NonNull ObfsCollection obfsCollection) {
this.obfsCollection = obfsCollection;
executor = new SearchRequestExecutor();
this.executor = new SearchRequestExecutor();
this.searchString = new SearchString();
this.searchScope = new SearchScope(this);
}
public AreaI getSearchableArea() {
@ -48,8 +52,55 @@ public class SearchAPI {
this.obfAreaFilter = obfAreaFilter;
}
public void startSearch(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
executor.run(new SearchRequest(keyword, maxSearchResults, apiCallback), true);
public PointI getSearchLocation() {
return searchLocation;
}
public void setSearchLocation(PointI searchLocation) {
this.searchLocation = searchLocation;
}
public double getSearchRadius() {
return searchRadius;
}
public void setSearchRadius(double searchRadius) {
this.searchRadius = searchRadius;
}
public ObfsCollection getObfsCollection() {
return obfsCollection;
}
public SearchString getSearchString() {
return searchString;
}
public SearchScope getSearchScope() {
return searchScope;
}
public List<SearchItem> getSearchItems() {
return searchItems;
}
public void setSearchItems(List<SearchItem> searchItems) {
this.searchItems = searchItems;
}
public void startSearch(String query, int maxSearchResults,
SearchCallback intermediateSearchCallback,
SearchCallback coreSearchCallback) {
searchString.setQueryText(query);
searchScope.updateScope();
IntermediateSearchRequest intermediateSearchRequest = null;
if (searchItems != null && !searchItems.isEmpty()) {
intermediateSearchRequest =
new IntermediateSearchRequest(this, maxSearchResults, intermediateSearchCallback);
}
executor.run(new CoreSearchRequest(intermediateSearchRequest, this,
maxSearchResults, coreSearchCallback), true);
}
public void cancelSearch() {
@ -97,127 +148,4 @@ public class SearchAPI {
}
}
}
public class SearchRequest {
private String keyword;
private int maxSearchResults;
private Runnable onFinished;
private SearchAPICallback apiCallback;
private boolean cancelled;
private int amenityResultsCounter;
private int addressResultsCounter;
public SearchRequest(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
this.keyword = keyword;
this.maxSearchResults = maxSearchResults;
this.apiCallback = apiCallback;
}
public void run() {
new AsyncTask<String, Void, List<SearchItem>>() {
@Override
protected List<SearchItem> doInBackground(String... params) {
return doSearch(params[0]);
}
@Override
protected void onPostExecute(List<SearchItem> searchItems) {
if (onFinished != null) {
onFinished.run();
}
if (apiCallback != null) {
apiCallback.onSearchFinished(searchItems, cancelled);
}
}
}.execute(keyword);
}
private List<SearchItem> doSearch(String keyword) {
System.out.println("=== Start search");
amenityResultsCounter = 0;
addressResultsCounter = 0;
final List<SearchItem> searchItems = new ArrayList<>();
// Setup Amenities by name search
AmenitiesByNameSearch amByNameSearch = new AmenitiesByNameSearch(obfsCollection);
AmenitiesByNameSearch.Criteria amByNameCriteria = new AmenitiesByNameSearch.Criteria();
amByNameCriteria.setName(keyword);
if (obfAreaFilter != null) {
amByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(obfAreaFilter));
}
INewResultEntryCallback amByNameResultCallback = new ISearch.INewResultEntryCallback() {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Amenity amenity = new AmenityResultEntry(resultEntry).getAmenity();
AmenitySearchItem amenitySearchItem = new AmenitySearchItem(amenity);
searchItems.add(amenitySearchItem);
System.out.println("Poi found === " + amenitySearchItem.toString());
amenityResultsCounter++;
}
};
// Setup Addresses by name search
AddressesByNameSearch addrByNameSearch = new AddressesByNameSearch(obfsCollection);
AddressesByNameSearch.Criteria addrByNameCriteria = new AddressesByNameSearch.Criteria();
addrByNameCriteria.setName(keyword);
if (obfAreaFilter != null) {
addrByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(obfAreaFilter));
}
INewResultEntryCallback addrByNameResultCallback = new ISearch.INewResultEntryCallback() {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Address address = new AddressResultEntry(resultEntry).getAddress();
AddressSearchItem addrSearchItem = new AddressSearchItem(address);
searchItems.add(addrSearchItem);
System.out.println("Address found === " + addrSearchItem.toString());
addressResultsCounter++;
}
};
amByNameSearch.performSearch(amByNameCriteria, amByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return amenityResultsCounter >= maxSearchResults || cancelled;
}
});
if (!cancelled) {
addrByNameSearch.performSearch(addrByNameCriteria, addrByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return addressResultsCounter >= maxSearchResults || cancelled;
}
});
}
System.out.println("=== Finish search");
return searchItems;
}
public void cancel() {
cancelled = true;
}
public void setOnFinishedCallback(Runnable onFinished) {
this.onFinished = onFinished;
}
}
private static class AmenityResultEntry extends AmenitiesByNameSearch.ResultEntry {
protected AmenityResultEntry(ISearch.IResultEntry resultEntry) {
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
}
}
private static class AddressResultEntry extends AddressesByNameSearch.ResultEntry {
protected AddressResultEntry(ISearch.IResultEntry resultEntry) {
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
}
}
}

View file

@ -0,0 +1,118 @@
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.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.tokens.SearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken.TokenType;
import net.osmand.util.Algorithms;
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 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();
searchRadius = searchAPI.getSearchRadius();
}
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);
}
}
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 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 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;
}
}
});
*/
//todo
}
private void updateDistance(SearchItem item) {
item.setDistance(Utilities.distance(
searchLon, searchLat, item.getLongitude(), item.getLatitude()));
}
}

View file

@ -0,0 +1,148 @@
package net.osmand.core.samples.android.sample1.search;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SearchString {
private String queryText = "";
private List<SearchToken> tokens = new ArrayList<>();
public SearchString() {
}
public String getQueryText() {
return queryText;
}
public synchronized void setQueryText(String queryText) {
int newTextLength = queryText.length();
int currTextLength = this.queryText.length();
boolean isNewText = currTextLength == 0
|| newTextLength == 0
|| !this.queryText.regionMatches(0, queryText, 0,
newTextLength > currTextLength ? currTextLength : newTextLength);
int lastKnownTokenIndex = -1;
if (isNewText) {
tokens.clear();
} else {
int brokenTokenIndex = -1;
for (int i = 0; i < tokens.size(); i++) {
SearchToken token = tokens.get(i);
int lastTokenIndex = token.getLastIndex();
if (lastTokenIndex > newTextLength - 1
|| (lastTokenIndex < newTextLength - 1 && !startWithDelimiter(queryText.substring(lastTokenIndex + 1)))) {
brokenTokenIndex = i;
break;
}
lastKnownTokenIndex = token.getLastIndex();
}
if (brokenTokenIndex != -1) {
if (brokenTokenIndex == 0) {
tokens.clear();
} else {
for (int i = tokens.size() - 1; i >= brokenTokenIndex; i--) {
tokens.remove(i);
}
}
}
}
if (newTextLength - 1 > lastKnownTokenIndex) {
int firstWordIndex = lastKnownTokenIndex + 1;
for (int i = lastKnownTokenIndex + 1; i < newTextLength; i++) {
char c = queryText.charAt(i);
if (isDelimiterChar(c)) {
if (i == firstWordIndex) {
firstWordIndex++;
} else {
SearchToken token = new NameFilterSearchToken(firstWordIndex, queryText.substring(firstWordIndex, i));
tokens.add(token);
firstWordIndex = i + 1;
}
}
}
if (firstWordIndex <= newTextLength - 1) {
SearchToken token = new NameFilterSearchToken(firstWordIndex, queryText.substring(firstWordIndex));
tokens.add(token);
}
}
this.queryText = queryText;
}
private boolean startWithDelimiter(String text) {
char firstChar = text.charAt(0);
return isDelimiterChar(firstChar);
}
private boolean isDelimiterChar(char c) {
return c == ',' || c == ' ';
}
public synchronized SearchToken getNextNameFilterToken() {
SearchToken res = null;
if (!tokens.isEmpty()) {
for (int i = tokens.size() - 1; i >= 0; i--) {
SearchToken token = tokens.get(i);
if (token.getType() == TokenType.NAME_FILTER) {
res = token;
} else {
break;
}
}
}
return res;
}
public synchronized SearchToken getLastToken() {
if (!tokens.isEmpty()) {
return tokens.get(tokens.size() - 1);
}
return null;
}
public synchronized boolean hasNameFilterTokens() {
return getNextNameFilterToken() != null;
}
public synchronized boolean replaceToken(SearchToken oldToken, SearchToken newToken) {
int index = tokens.indexOf(oldToken);
if (index != -1) {
tokens.set(index, newToken);
return true;
}
return false;
}
public synchronized Map<TokenType, SearchToken> getResolvedTokens() {
Map<TokenType, SearchToken> map = new HashMap<>();
for (SearchToken token : tokens) {
if (token.getType() != SearchToken.TokenType.NAME_FILTER) {
map.put(token.getType(), token);
}
}
return map;
}
public static void main(String[] args){
//test
SearchString searchString = new SearchString();
searchString.setQueryText("cit");
searchString.setQueryText("city");
searchString.setQueryText("city ");
searchString.setQueryText("city s");
searchString.setQueryText("city st");
searchString.setQueryText("city street ");
searchString.setQueryText("city street 8");
searchString.setQueryText("new");
}
}

View file

@ -1,17 +1,23 @@
package net.osmand.core.samples.android.sample1.search;
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();
@ -22,8 +28,14 @@ public class AddressSearchItem extends SearchItem {
setNativeName(street.getNativeName());
addLocalizedNames(street.getLocalizedNames());
if (street.getStreetGroup() != null) {
StreetGroup streetGroup = street.getStreetGroup();
nameSuffix = "st.";
typeStr = street.getStreetGroup().getNativeName() + "" + getTypeStr(street.getStreetGroup());
typeStr = streetGroup.getNativeName() + "" + getTypeStr(streetGroup);
if (streetGroup.getType() == ObfAddressStreetGroupType.Postcode) {
parentPostcodeObfId = streetGroup.getId().getId();
} else {
parentCityObfId = streetGroup.getId().getId();
}
} else {
typeStr = "Street";
}
@ -77,6 +89,14 @@ public class AddressSearchItem extends SearchItem {
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);

View file

@ -1,4 +1,4 @@
package net.osmand.core.samples.android.sample1.search;
package net.osmand.core.samples.android.sample1.search.items;
import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.DecodedCategoryList;

View file

@ -1,4 +1,4 @@
package net.osmand.core.samples.android.sample1.search;
package net.osmand.core.samples.android.sample1.search.items;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.PointI;
@ -16,6 +16,9 @@ public abstract class SearchItem {
protected String nativeName;
protected Map<String, String> localizedNames = new HashMap<>();
private double distance;
private float priority;
protected SearchItem() {
}
@ -71,6 +74,22 @@ public abstract class SearchItem {
}
}
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,175 @@
package net.osmand.core.samples.android.sample1.search.requests;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import net.osmand.core.jni.Address;
import net.osmand.core.jni.AddressesByNameSearch;
import net.osmand.core.jni.AmenitiesByNameSearch;
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.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
public class CoreSearchRequest extends SearchRequest {
private IntermediateSearchRequest intermediateSearchRequest;
private boolean intermediateSearchDone;
private int amenityResultsCounter;
private int addressResultsCounter;
public CoreSearchRequest(@Nullable IntermediateSearchRequest intermediateSearchRequest,
@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
super(searchAPI, maxSearchResults, searchCallback);
this.intermediateSearchRequest = intermediateSearchRequest;
}
@Override
public void run() {
if (intermediateSearchRequest != null) {
intermediateSearchRequest.setOnFinishedCallback(new Runnable() {
@Override
public void run() {
intermediateSearchDone = true;
}
});
intermediateSearchRequest.run();
}
super.run();
}
@Override
protected void onSearchRequestPostExecute(List<SearchItem> searchItems) {
if (intermediateSearchRequest != null && !intermediateSearchDone) {
intermediateSearchRequest.cancel();
}
searchAPI.setSearchItems(searchItems);
}
@Override
public void cancel() {
if (intermediateSearchRequest != null) {
intermediateSearchRequest.cancel();
}
super.cancel();
}
@Override
protected List<SearchItem> doSearch() {
List<SearchItem> res = new ArrayList<>();
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);
}
token = searchString.getNextNameFilterToken();
}
return res;
}
private List<SearchItem> doCoreSearch(@NonNull SearchToken token) {
System.out.println("=== Start search");
amenityResultsCounter = 0;
addressResultsCounter = 0;
String keyword = token.getQueryText();
final List<SearchItem> searchItems = new ArrayList<>();
// Setup Amenities by name search
AmenitiesByNameSearch amByNameSearch = new AmenitiesByNameSearch(searchAPI.getObfsCollection());
AmenitiesByNameSearch.Criteria amenityByNameCriteria = new AmenitiesByNameSearch.Criteria();
amenityByNameCriteria.setName(keyword);
if (searchAPI.getObfAreaFilter() != null) {
amenityByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchAPI.getObfAreaFilter()));
}
searchScope.setupAmenitySearchCriteria(amenityByNameCriteria);
ISearch.INewResultEntryCallback amenityByNameResultCallback = new ISearch.INewResultEntryCallback() {
@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);
}
System.out.println("Poi found === " + amenitySearchItem.toString());
amenityResultsCounter++;
}
};
// Setup Addresses by name search
AddressesByNameSearch addrByNameSearch = new AddressesByNameSearch(searchAPI.getObfsCollection());
AddressesByNameSearch.Criteria addrByNameCriteria = new AddressesByNameSearch.Criteria();
addrByNameCriteria.setName(keyword);
if (searchAPI.getObfAreaFilter() != null) {
addrByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchAPI.getObfAreaFilter()));
}
searchScope.setupAddressSearchCriteria(addrByNameCriteria);
ISearch.INewResultEntryCallback addrByNameResultCallback = new ISearch.INewResultEntryCallback() {
@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);
}
System.out.println("Address found === " + addrSearchItem.toString());
addressResultsCounter++;
}
};
amByNameSearch.performSearch(amenityByNameCriteria, amenityByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return amenityResultsCounter >= maxSearchResults || cancelled;
}
});
if (!cancelled) {
addrByNameSearch.performSearch(addrByNameCriteria, addrByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return addressResultsCounter >= maxSearchResults || cancelled;
}
});
}
if (!cancelled) {
searchScope.processSearchResult(searchItems);
}
System.out.println("=== Finish search");
return searchItems;
}
private class AmenityResultEntry extends AmenitiesByNameSearch.ResultEntry {
protected AmenityResultEntry(ISearch.IResultEntry resultEntry) {
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
}
}
private class AddressResultEntry extends AddressesByNameSearch.ResultEntry {
protected AddressResultEntry(ISearch.IResultEntry resultEntry) {
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
}
}
}

View file

@ -0,0 +1,43 @@
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.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
public class IntermediateSearchRequest extends SearchRequest {
private List<SearchItem> searchItems;
protected String keyword = "";
public IntermediateSearchRequest(@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
super(searchAPI, maxSearchResults, searchCallback);
this.searchItems = new ArrayList<>(searchAPI.getSearchItems());
SearchToken token = searchString.getLastToken();
if (token != null && token.getType() == SearchToken.TokenType.NAME_FILTER) {
keyword = token.getQueryText();
}
}
@Override
protected List<SearchItem> doSearch() {
List<SearchItem> res = new ArrayList<>();
for (SearchItem item : searchItems) {
if (cancelled) {
break;
}
if (keyword.isEmpty() || item.getName().contains(keyword)) {
res.add(item);
}
}
return res;
}
}

View file

@ -0,0 +1,71 @@
package net.osmand.core.samples.android.sample1.search.requests;
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.SearchScope;
import net.osmand.core.samples.android.sample1.search.SearchString;
import net.osmand.core.samples.android.sample1.search.items.SearchItem;
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 boolean cancelled;
public SearchRequest(@NonNull SearchAPI searchAPI, int maxSearchResults, @Nullable SearchCallback searchCallback) {
this.searchAPI = searchAPI;
this.searchString = searchAPI.getSearchString();
this.searchScope= searchAPI.getSearchScope();
this.maxSearchResults = maxSearchResults;
this.searchCallback = searchCallback;
}
public void run() {
new AsyncTask<Void, Void, List<SearchItem>>() {
@Override
protected List<SearchItem> doInBackground(Void... params) {
return doSearch();
}
@Override
protected void onPostExecute(List<SearchItem> searchItems) {
onSearchRequestPostExecute(searchItems);
if (onFinished != null) {
onFinished.run();
}
if (searchCallback != null && !cancelled) {
searchCallback.onSearchFinished(searchItems);
}
}
}.execute();
}
protected void onSearchRequestPostExecute(List<SearchItem> searchItems) {
}
protected abstract List<SearchItem> doSearch();
public void cancel() {
cancelled = true;
}
public void setOnFinishedCallback(@Nullable Runnable onFinished) {
this.onFinished = onFinished;
}
}

View file

@ -0,0 +1,17 @@
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

@ -0,0 +1,8 @@
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);
}
}

View file

@ -0,0 +1,18 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,16 @@
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

@ -0,0 +1,56 @@
package net.osmand.core.samples.android.sample1.search.tokens;
public abstract class SearchToken {
public enum TokenType {
CITY,
POSTCODE,
STREET,
BUILDING,
POI_CATEGORY,
POI_FILTER,
POI_TYPE,
LOCATION,
NAME_FILTER
}
private TokenType type;
private int startIndex;
protected String queryText;
protected String name;
public SearchToken(TokenType type, int startIndex, String queryText, String name) {
this.type = type;
this.startIndex = startIndex;
this.queryText = queryText;
this.name = name;
}
public TokenType getType() {
return type;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public String getQueryText() {
return queryText;
}
public int getLastIndex() {
return startIndex + queryText.length() - 1;
}
public int getQueryTextLenght() {
return queryText.length();
}
public String getName() {
return name;
}
}