[Core sample] added new search engine

This commit is contained in:
Alexey Kulish 2016-07-11 17:43:24 +03:00
parent a967f56e05
commit ec7c26ece9
40 changed files with 215 additions and 2424 deletions

View file

@ -8,7 +8,6 @@ import android.graphics.PointF;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.text.Editable;
@ -28,14 +27,12 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import net.osmand.CollatorStringMatcher;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.core.android.AtlasMapRendererView;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.IMapLayerProvider;
import net.osmand.core.jni.IMapStylesCollection;
import net.osmand.core.jni.IQueryController;
import net.osmand.core.jni.ISearch;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.Logger;
import net.osmand.core.jni.MapObjectsSymbolsProvider;
import net.osmand.core.jni.MapPresentationEnvironment;
@ -56,26 +53,19 @@ 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.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.objects.PoiTypeObject;
import net.osmand.core.samples.android.sample1.search.objects.PoiTypeSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PoiTypeSearchObject.ObjectType;
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.tokens.ObjectSearchToken;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
import net.osmand.data.LatLon;
import net.osmand.search.example.SearchUICore;
import net.osmand.search.example.SearchUICore.SearchResultCollection;
import net.osmand.search.example.core.ObjectType;
import net.osmand.search.example.core.SearchResult;
import net.osmand.search.example.core.SearchSettings;
import net.osmand.util.MapUtils;
import java.text.Collator;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Locale;
public class MainActivity extends Activity {
private static final String TAG = "OsmAndCoreSample";
@ -93,7 +83,6 @@ public class MainActivity extends Activity {
private MapPrimitivesProvider mapPrimitivesProvider;
private MapObjectsSymbolsProvider mapObjectsSymbolsProvider;
private IMapLayerProvider mapLayerProvider0;
private IMapLayerProvider mapLayerProvider1;
private QIODeviceLogSink fileLogSink;
private AtlasMapRendererView mapView;
@ -107,7 +96,7 @@ public class MainActivity extends Activity {
private float elevationAngle;
private MultiTouchSupport multiTouchSupport;
private SearchAPI searchAPI;
private SearchUICore searchUICore;
private EditText searchEditText;
private TextView searchDetailsText;
@ -138,135 +127,15 @@ public class MainActivity extends Activity {
private static final String PREF_MAP_ZOOM = "MAP_ZOOM";
private static final String PREF_MAP_ELEVATION_ANGLE = "MAP_ELEVATION_ANGLE";
private SearchApiCallback intermediateSearchCallback = new SearchApiCallback() {
public static final String LANGUAGE;
@Override
@Nullable
public List<SearchObject> fetchExternalObjects(String keyword, @Nullable List<SearchObject> completeObjects) {
return null;
static {
String langCode = Locale.getDefault().getLanguage();
if (langCode.isEmpty()) {
langCode = "en";
}
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
LANGUAGE = langCode;
}
};
private SearchApiCallback coreSearchCallback = new SearchApiCallback() {
@Override
@Nullable
public List<SearchObject> fetchExternalObjects(String keyword, @Nullable List<SearchObject> completeObjects) {
List<SearchObject> result = new ArrayList<>();
boolean poiTypeSelected = false;
PoiCategory selectedPoiCategory = null;
PoiFilter selectedPoiFilter = null;
if (completeObjects != null) {
for (SearchObject searchObject : completeObjects) {
if (searchObject.getType() == SearchObjectType.POI_TYPE) {
PoiTypeSearchObject ptObj = (PoiTypeSearchObject) searchObject;
switch (ptObj.getObjectType()) {
case CATEGORY:
selectedPoiCategory = getSampleApplication().getPoiTypes().getPoiCategoryByName(ptObj.getKeyName());
break;
case FILTER:
PoiCategory category = getSampleApplication().getPoiTypes().getPoiCategoryByName(ptObj.getCategoryKeyName());
for (PoiFilter filter : category.getPoiFilters()) {
if (filter.getKeyName().equalsIgnoreCase(ptObj.getKeyName())) {
selectedPoiFilter = filter;
break;
}
}
break;
case TYPE:
poiTypeSelected = true;
break;
}
if (poiTypeSelected || selectedPoiCategory != null || selectedPoiFilter != null) {
break;
}
}
}
if (poiTypeSelected) {
return null;
}
}
PoiTypesHelper poiTypesHelper = getSampleApplication().getPoiTypesHelper();
List<AbstractPoiType> res;
if (selectedPoiCategory != null) {
res = poiTypesHelper.getPoiCategoryTypesTranslatedNames(selectedPoiCategory,
new CollatorStringMatcher(keyword, CollatorStringMatcher.StringMatcherMode.CHECK_STARTS_FROM_SPACE));
final Collator inst = Collator.getInstance();
Collections.sort(res, new Comparator<AbstractPoiType>() {
@Override
public int compare(AbstractPoiType lhs, AbstractPoiType rhs) {
return inst.compare(lhs.getTranslation(), rhs.getTranslation());
}
});
} else if (selectedPoiFilter != null) {
res = poiTypesHelper.getPoiFilterTypesTranslatedNames(selectedPoiFilter,
new CollatorStringMatcher(keyword, CollatorStringMatcher.StringMatcherMode.CHECK_STARTS_FROM_SPACE));
final Collator inst = Collator.getInstance();
Collections.sort(res, new Comparator<AbstractPoiType>() {
@Override
public int compare(AbstractPoiType lhs, AbstractPoiType rhs) {
return inst.compare(lhs.getTranslation(), rhs.getTranslation());
}
});
} else {
res = poiTypesHelper.findPoiTypes(keyword);
}
for (AbstractPoiType pt : res) {
if (pt instanceof PoiCategory) {
result.add(new PoiTypeSearchObject(ObjectType.CATEGORY,
new PoiTypeObject(pt.getTranslation(), pt.getKeyName(), null)));
} else if (pt instanceof PoiFilter) {
PoiFilter poiFilter = (PoiFilter) pt;
result.add(new PoiTypeSearchObject(ObjectType.FILTER,
new PoiTypeObject(poiFilter.getTranslation(), poiFilter.getKeyName(), poiFilter.getPoiCategory().getKeyName())));
} else if (pt instanceof PoiType) {
PoiType poiType = (PoiType) pt;
result.add(new PoiTypeSearchObject(ObjectType.TYPE,
new PoiTypeObject(poiType.getTranslation(), poiType.getKeyName(), poiType.getCategory().getKeyName())));
}
}
return result;
}
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
StringBuilder sb = new StringBuilder();
Map<SearchObjectType, ObjectSearchToken> objectTokensMap = searchAPI.getObjectTokens();
ObjectSearchToken lastObjectToken = searchAPI.getLastObjectToken();
for (ObjectSearchToken token : objectTokensMap.values()) {
if (sb.length() > 0) {
sb.append("");
}
sb.append(token.getSearchObject().getName(MapUtils.LANGUAGE));
}
if (lastObjectToken != null && lastObjectToken.isSuggestion()) {
if (sb.length() > 0) {
sb.append("");
}
sb.append(lastObjectToken.getSearchObject().getName(MapUtils.LANGUAGE));
}
if (sb.length() == 0) {
searchDetailsText.setVisibility(View.GONE);
} else {
searchDetailsText.setText(sb.toString());
searchDetailsText.setVisibility(View.VISIBLE);
}
hideProgressBar();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -342,7 +211,7 @@ public class MainActivity extends Activity {
displayDensityFactor,
1.0f,
1.0f,
MapUtils.LANGUAGE);
LANGUAGE);
//mapPresentationEnvironment->setSettings(configuration.styleSettings);
mapPrimitiviser = new MapPrimitiviser(
mapPresentationEnvironment);
@ -366,8 +235,7 @@ public class MainActivity extends Activity {
app.getIconsCache().setDisplayDensityFactor(displayDensityFactor);
//Setup search
searchAPI = new SearchAPI(obfsCollection, MapUtils.LANGUAGE);
setupSearch();
searchEditText = (EditText) findViewById(R.id.searchEditText);
searchEditText.addTextChangedListener(new TextWatcher() {
@ -392,10 +260,18 @@ public class MainActivity extends Activity {
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus && isSearchListHidden()) {
if (hasFocus) {
net.osmand.core.jni.LatLon latLon = Utilities.convert31ToLatLon(target31);
SearchSettings settings = searchUICore.getPhrase().getSettings().setOriginalLocation(
new LatLon(latLon.getLatitude(), latLon.getLongitude()));
settings = settings.setLang(LANGUAGE);
searchUICore.updateSettings(settings);
adapter.setLocation(new LatLon(latLon.getLatitude(), latLon.getLongitude()));
if (isSearchListHidden()) {
showSearchList();
if (adapter.getCount() > 0) {
LatLon latLon = Utilities.convert31ToLatLon(target31);
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
adapter.notifyDataSetChanged();
} else {
@ -403,6 +279,7 @@ public class MainActivity extends Activity {
}
}
}
}
});
searchDetailsText = (TextView) findViewById(R.id.searchDetailsText);
@ -427,24 +304,58 @@ public class MainActivity extends Activity {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SearchListItem item = adapter.getItem(position);
SearchObject searchObject = item.getSearchObject();
SearchResult sr = item.getSearchResult();
if (sr.objectType == ObjectType.POI
|| sr.objectType == ObjectType.LOCATION
|| sr.objectType == ObjectType.HOUSE
|| sr.objectType == ObjectType.FAVORITE
|| sr.objectType == ObjectType.RECENT_OBJ
|| sr.objectType == ObjectType.WPT
|| sr.objectType == ObjectType.STREET_INTERSECTION) {
if (searchObject.getType() == SearchObjectType.POI
|| searchObject.getType() == SearchObjectType.BUILDING
|| searchObject.getType() == SearchObjectType.COORDINATES) {
// show on map
hideSearchList();
mapView.requestFocus();
showOnMap((SearchListPositionItem) item);
} else {
// complete search query with selected object
completeQueryWithObject(item.getSearchObject());
}
completeQueryWithObject(item.getSearchResult());
}
});
}
private void setupSearch() {
final SampleApplication app = getSampleApplication();
List<BinaryMapIndexReader> files = new ArrayList<>();
File file = new File(app.getAbsoluteAppPath());
if (file.exists() && file.listFiles() != null) {
for (File obf : file.listFiles()) {
if (!obf.isDirectory() && obf.getName().endsWith(".obf")) {
try {
BinaryMapIndexReader bmir = new BinaryMapIndexReader(new RandomAccessFile(obf, "r"), obf);
files.add(bmir);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
searchUICore = new SearchUICore(app.getPoiTypes(), LANGUAGE, files.toArray(new BinaryMapIndexReader[files.size()]));
searchUICore.setOnResultsComplete(new Runnable() {
@Override
public void run() {
app.runInUIThread(new Runnable() {
@Override
public void run() {
hideProgressBar();
updateSearchResult(searchUICore.getCurrentSearchResult(), true);
}
});
}
});
}
@Override
protected void onResume() {
super.onResume();
@ -471,11 +382,13 @@ public class MainActivity extends Activity {
return (SampleApplication) getApplication();
}
private void showOnMap(SearchListPositionItem positionItem) {
private void showOnMap(LatLon latLon, int zoom) {
if (latLon != null) {
PointI target = Utilities.convertLatLonTo31(
new LatLon(positionItem.getLatitude(), positionItem.getLongitude()));
new net.osmand.core.jni.LatLon(latLon.getLatitude(), latLon.getLongitude()));
setTarget(target);
setZoom(17f);
setZoom(zoom);
}
}
private PointI getScreenCenter31() {
@ -484,14 +397,6 @@ public class MainActivity extends Activity {
return point;
}
private AreaI getScreenBounds31() {
PointI topLeftPoint = new PointI();
PointI bottomRightPoint = new PointI();
mapView.getLocationFromScreenPoint(new PointI(0, 0), topLeftPoint);
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth(), mapView.getHeight()), bottomRightPoint);
return new AreaI(topLeftPoint, bottomRightPoint);
}
private void showProgressBar() {
searchIcon.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
@ -536,7 +441,7 @@ public class MainActivity extends Activity {
public void saveMapState() {
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
Editor edit = prefs.edit();
LatLon latLon = Utilities.convert31ToLatLon(target31);
net.osmand.core.jni.LatLon latLon = Utilities.convert31ToLatLon(target31);
edit.putFloat(PREF_MAP_CENTER_LAT, (float) latLon.getLatitude());
edit.putFloat(PREF_MAP_CENTER_LON, (float) latLon.getLongitude());
edit.putFloat(PREF_MAP_AZIMUTH, azimuth);
@ -555,7 +460,7 @@ public class MainActivity extends Activity {
setAzimuth(prefAzimuth);
setElevationAngle(prefElevationAngle);
setTarget(Utilities.convertLatLonTo31(new LatLon(prefLat, prefLon)));
setTarget(Utilities.convertLatLonTo31(new net.osmand.core.jni.LatLon(prefLat, prefLon)));
setZoom(prefZoom);
}
@ -604,37 +509,80 @@ public class MainActivity extends Activity {
}
private void runSearch() {
runSearch(getScreenCenter31(), getScreenBounds31(), queryText);
runSearch(queryText);
}
private void runSearch(PointI position31, AreaI bounds31, String keyword) {
private void runSearch(String text) {
searchAPI.setSearchLocation31(position31);
searchAPI.setObfAreaFilter(bounds31);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS_CORE,
intermediateSearchCallback, coreSearchCallback);
SearchSettings settings = searchUICore.getPhrase().getSettings();
if(settings.getRadiusLevel() != 1){
searchUICore.updateSettings(settings.setRadiusLevel(1));
}
searchUICore.search(text, null);
SearchResultCollection c = searchUICore.search(text, null);
updateSearchResult(c, false);
}
private void completeQueryWithObject(SearchObject searchObject) {
queryText = searchAPI.completeSearch(searchObject, MAX_SEARCH_RESULTS_CORE,
intermediateSearchCallback, coreSearchCallback);
searchEditText.setText(queryText);
searchEditText.setSelection(queryText.length());
private void completeQueryWithObject(SearchResult sr) {
if (sr.location != null) {
showOnMap(sr.location, sr.preferredZoom);
}
searchUICore.selectSearchResult(sr);
String txt = searchUICore.getPhrase().getText(true);
queryText = txt;
searchEditText.setText(txt);
searchEditText.setSelection(txt.length());
searchUICore.search(txt, null);
}
private void processSearchResult(List<SearchObject> searchObjects) {
if (searchObjects != null) {
private void updateSearchResult(SearchResultCollection res, boolean addMore) {
SampleApplication app = getSampleApplication();
if (res.getCurrentSearchResults().size() > 0) {
List<SearchListItem> rows = new ArrayList<>();
for (SearchObject item : searchObjects) {
SearchListItem listItem =
SearchListItem.buildListItem(getSampleApplication(), item);
if (listItem != null) {
for (final SearchResult sr : res.getCurrentSearchResults()) {
int count = 30;
/*
if(addMore) {
JMenuItem mi = new JMenuItem();
mi.setText("Results " + res.getCurrentSearchResults().size() + ", radius " + res.getPhrase().getRadiusLevel()+
" (show more...)");
mi.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SearchSettings settings = searchUICore.getPhrase().getSettings();
searchUICore.updateSettings(settings.setRadiusLevel(settings.getRadiusLevel() + 1));
searchUICore.search(statusField.getText(), null);
updateSearchResult(statusField, new SearchResultCollection(), false);
}
});
popup.add(mi);
}
*/
count--;
if (count == 0) {
// break;
}
//LatLon location = res.getPhrase().getLastTokenLocation();
//String locationString = "";
//if (sr.location != null) {
// locationString = ((int) MapUtils.getDistance(location, sr.location)) + " m";
//}
//mi.setText(sr.localeName + " [" + sr.objectType + "] " + locationString);
SearchListItem listItem = new SearchListItem(app, sr);
if (sr.location != null) {
LatLon location = res.getPhrase().getLastTokenLocation();
listItem.setDistance(MapUtils.getDistance(location, sr.location));
}
rows.add(listItem);
}
}
if (rows.size() > MAX_SEARCH_RESULTS_IU) {
rows = rows.subList(0, MAX_SEARCH_RESULTS_IU);
}
updateListAdapter(rows);
showSearchList();
}

View file

@ -1,30 +0,0 @@
package net.osmand.core.samples.android.sample1;
import java.util.Locale;
public class MapUtils {
public static final String LANGUAGE;
static {
LANGUAGE = getLanguage();
}
public static float unifyRotationTo360(float rotate) {
while (rotate < -180) {
rotate += 360;
}
while (rotate > +180) {
rotate -= 360;
}
return rotate;
}
private static String getLanguage() {
String langCode = Locale.getDefault().getLanguage();
if (langCode.isEmpty()) {
langCode = "en";
}
return langCode;
}
}

View file

@ -5,6 +5,8 @@ import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
import net.osmand.util.MapUtils;
import java.lang.reflect.Method;
public class MultiTouchSupport {

View file

@ -1,108 +0,0 @@
package net.osmand.core.samples.android.sample1;
import net.osmand.CollatorStringMatcher;
import net.osmand.StringMatcher;
import net.osmand.core.samples.android.sample1.search.objects.PoiTypeSearchObject;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
import net.osmand.util.Algorithms;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class PoiTypesHelper {
private SampleApplication app;
public PoiTypesHelper(SampleApplication app) {
this.app = app;
}
public List<AbstractPoiType> findPoiTypes(String s) {
List<AbstractPoiType> poiTypes = new ArrayList<>();
if (Algorithms.isEmpty(s)) {
poiTypes.addAll(app.getPoiTypes().getTopVisibleFilters());
} else {
List<AbstractPoiType> res = app.getPoiTypes().getAllTypesTranslatedNames(
new CollatorStringMatcher(s, CollatorStringMatcher.StringMatcherMode.CHECK_STARTS_FROM_SPACE));
final Collator inst = Collator.getInstance();
Collections.sort(res, new Comparator<AbstractPoiType>() {
@Override
public int compare(AbstractPoiType lhs, AbstractPoiType rhs) {
return inst.compare(lhs.getTranslation(), rhs.getTranslation());
}
});
for (AbstractPoiType p : res) {
poiTypes.add(p);
}
}
return poiTypes;
}
public AbstractPoiType fetchPoiType(PoiTypeSearchObject poiTypeObject) {
switch (poiTypeObject.getObjectType()) {
case CATEGORY:
return app.getPoiTypes().getPoiCategoryByName(poiTypeObject.getKeyName());
case FILTER:
PoiCategory category = app.getPoiTypes().getPoiCategoryByName(poiTypeObject.getCategoryKeyName());
for (PoiFilter filter : category.getPoiFilters()) {
if (filter.getKeyName().equalsIgnoreCase(poiTypeObject.getKeyName())) {
return filter;
}
}
break;
case TYPE:
AbstractPoiType p = app.getPoiTypes().getPoiTypeByKey(poiTypeObject.getKeyName());
if(p == null) {
return app.getPoiTypes().getAnyPoiAdditionalTypeByKey(poiTypeObject.getKeyName());
}
return p;
}
return null;
}
public List<AbstractPoiType> getPoiCategoryTypesTranslatedNames(PoiCategory pc, StringMatcher matcher) {
List<AbstractPoiType> tm = new ArrayList<AbstractPoiType>();
for (PoiFilter pt : pc.getPoiFilters()) {
addIf(tm, pt, matcher);
}
for (PoiType pt : pc.getPoiTypes()) {
if (pt.isReference()) {
continue;
}
addIf(tm, pt, matcher);
}
return tm;
}
public List<AbstractPoiType> getPoiFilterTypesTranslatedNames(PoiFilter pf, StringMatcher matcher) {
List<AbstractPoiType> tm = new ArrayList<AbstractPoiType>();
for (PoiType pt : pf.getPoiTypes()) {
if (pt.isReference()) {
continue;
}
addIf(tm, pt, matcher);
}
return tm;
}
private void addIf(List<AbstractPoiType> tm, AbstractPoiType pc, StringMatcher matcher) {
if (matcher.matches(pc.getTranslation()) || matcher.matches(pc.getKeyName().replace('_', ' '))) {
tm.add(pc);
}
List<PoiType> additionals = pc.getPoiAdditionals();
if (additionals != null) {
for (PoiType a : additionals) {
addIf(tm, a, matcher);
}
}
}
}

View file

@ -2,6 +2,8 @@ package net.osmand.core.samples.android.sample1;
import android.app.Application;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import net.osmand.core.android.CoreResourcesFromAndroidAssets;
import net.osmand.core.android.NativeCore;
@ -17,16 +19,16 @@ public class SampleApplication extends Application
{
private CoreResourcesFromAndroidAssets assetsCustom;
private MapPoiTypes poiTypes;
private PoiTypesHelper poiTypesHelper;
private IconsCache iconsCache;
Handler uiHandler;
@Override
public void onCreate()
{
super.onCreate();
uiHandler = new Handler();
initPoiTypes();
poiTypesHelper = new PoiTypesHelper(this);
// Initialize native core
if (NativeCore.isAvailable() && !NativeCore.isLoaded()) {
@ -42,10 +44,6 @@ public class SampleApplication extends Application
return poiTypes;
}
public PoiTypesHelper getPoiTypesHelper() {
return poiTypesHelper;
}
public IconsCache getIconsCache() {
return iconsCache;
}
@ -97,4 +95,12 @@ public class SampleApplication extends Application
}
return l;
}
public void runInUIThread(Runnable run) {
uiHandler.post(run);
}
public void runInUIThread(Runnable run, long delay) {
uiHandler.postDelayed(run, delay);
}
}

View file

@ -1,21 +0,0 @@
package net.osmand.core.samples.android.sample1;
import java.text.MessageFormat;
public class Utils {
public static String getFormattedDistance(double meters) {
double mainUnitInMeters = 1000;
String mainUnitStr = "km";
if (meters >= 100 * mainUnitInMeters) {
return (int) (meters / mainUnitInMeters + 0.5) + " " + mainUnitStr;
} else if (meters > 9.99f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.#} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else if (meters > 0.999f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.##} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else {
return ((int) (meters + 0.5)) + " m";
}
}
}

View file

@ -1,43 +0,0 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.jni.Building;
import net.osmand.core.jni.Street;
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.BuildingSearchObject;
public class BuildingSearchListItem extends SearchListPositionItem {
private String nameStr;
private String typeStr;
public BuildingSearchListItem(SampleApplication app, BuildingSearchObject buildingObject) {
super(app, buildingObject);
nameStr = buildingObject.getName(MapUtils.LANGUAGE);
Building building = buildingObject.getBaseObject();
Street street = building.getStreet();
if (street != null) {
StreetGroup streetGroup = street.getStreetGroup();
if (streetGroup != null) {
typeStr = streetGroup.getNativeName() + ", " + street.getNativeName();
} else {
typeStr = street.getNativeName();
}
} else {
typeStr = "Building";
}
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -1,28 +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.objects.CitySearchObject;
public class CitySearchListItem extends SearchListPositionItem{
private String nameStr;
private String typeStr;
public CitySearchListItem(SampleApplication app, CitySearchObject cityObject) {
super(app, cityObject);
nameStr = cityObject.getName(MapUtils.LANGUAGE);
typeStr = "City";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -1,119 +0,0 @@
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 poiObject) {
super(app, poiObject);
amenity = parseAmenity(poiObject);
nameStr = amenity.getName(MapUtils.LANGUAGE);
typeStr = getTypeStr();
}
private Amenity parseAmenity(PoiSearchObject poiObject) {
String categoryName = "";
String subcategoryName = "";
Map<String, String> values = new HashMap<>();
net.osmand.core.jni.Amenity coreAmenity = poiObject.getBaseObject();
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(poiObject.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().getMapIcon(st.getOsmTag() + "_" + st.getOsmValue());
}
return drawable;
}
}

View file

@ -1,60 +0,0 @@
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.objects.PoiTypeSearchObject;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
public class PoiTypeSearchListItem extends SearchListItem {
private AbstractPoiType poiType;
private String typeName;
public PoiTypeSearchListItem(SampleApplication app, PoiTypeSearchObject poiTypeObject) {
super(app, poiTypeObject);
poiType = app.getPoiTypesHelper().fetchPoiType(poiTypeObject);
if (poiType != null) {
if (poiType instanceof PoiCategory) {
typeName = "Category";
} else if (poiType instanceof PoiFilter) {
PoiFilter filter = (PoiFilter) poiType;
if (filter.getPoiCategory() != null) {
typeName = ((PoiFilter) poiType).getPoiCategory().getTranslation();
} else {
typeName = "Filter";
}
} else if (poiType instanceof PoiType) {
PoiType type = (PoiType) poiType;
if (type.getCategory() != null) {
typeName = type.getCategory().getTranslation();
} else if (type.getParentType() != null) {
typeName = type.getTranslation();
}
} else {
typeName = "Poi type";
}
} else {
typeName = poiTypeObject.getObjectType().name();
}
}
@Override
public String getName() {
return poiType != null ? poiType.getTranslation() : "Unresolved";
}
@Override
public String getTypeName() {
return typeName;
}
@Override
public Drawable getIcon() {
return null;
}
}

View file

@ -1,29 +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.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 postcodeObject) {
super(app, postcodeObject);
nameStr = postcodeObject.getNativeName();
typeStr = "Postcode";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -9,15 +9,17 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.R;
import net.osmand.core.samples.android.sample1.Utils;
import net.osmand.data.LatLon;
import net.osmand.search.example.core.SearchResult;
import java.text.MessageFormat;
import java.util.List;
public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
private Context ctx;
private LatLon location;
public SearchListAdapter(Context ctx) {
super(ctx, R.layout.search_list_item);
@ -32,12 +34,21 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
notifyDataSetInvalidated();
}
public LatLon getLocation() {
return location;
}
public void setLocation(LatLon location) {
this.location = location;
}
@Override
public SearchListItem getItem(int position) {
return super.getItem(position);
}
public void updateDistance(double latitude, double longitude) {
/*
for (int i = 0; i < getCount(); i++) {
SearchListItem item = getItem(i);
if (item instanceof SearchListPositionItem) {
@ -46,6 +57,7 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
longitude, latitude, positionItem.getLongitude(), positionItem.getLatitude()));
}
}
*/
}
@Override
@ -70,12 +82,12 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
imageView.setImageDrawable(listItem.getIcon());
title.setText(listItem.getName());
subtitle.setText(listItem.getTypeName());
if (listItem instanceof SearchListPositionItem) {
SearchListPositionItem positionItem = (SearchListPositionItem) listItem;
if (positionItem.getDistance() == 0) {
if (location != null && listItem.getSearchResult().location != null) {
double dist = listItem.getDistance();
if (dist == 0) {
distance.setText("");
} else {
distance.setText(Utils.getFormattedDistance(positionItem.getDistance()));
distance.setText(getFormattedDistance(dist));
}
distance.setVisibility(View.VISIBLE);
} else {
@ -84,4 +96,17 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
return view;
}
public static String getFormattedDistance(double meters) {
double mainUnitInMeters = 1000;
String mainUnitStr = "km";
if (meters >= 100 * mainUnitInMeters) {
return (int) (meters / mainUnitInMeters + 0.5) + " " + mainUnitStr;
} else if (meters > 9.99f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.#} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else if (meters > 0.999f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.##} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else {
return ((int) (meters + 0.5)) + " m";
}
}
}

View file

@ -3,62 +3,40 @@ 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.objects.BuildingSearchObject;
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.PoiTypeSearchObject;
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.StreetIntersectionSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.VillageSearchObject;
import net.osmand.search.example.core.SearchResult;
public class SearchListItem {
protected SampleApplication app;
private SearchObject searchObject;
private SearchResult searchResult;
private double distance;
public SearchListItem(SampleApplication app, SearchObject searchObject) {
public SearchListItem(SampleApplication app, SearchResult searchResult) {
this.app = app;
this.searchObject = searchObject;
this.searchResult = searchResult;
}
public static SearchListItem buildListItem(SampleApplication app, SearchObject searchObject) {
switch (searchObject.getType()) {
case POI_TYPE:
return new PoiTypeSearchListItem(app, (PoiTypeSearchObject) searchObject);
case POI:
return new PoiSearchListItem(app, (PoiSearchObject) searchObject);
case BUILDING:
return new BuildingSearchListItem(app, (BuildingSearchObject) searchObject);
case STREET_INTERSECTION:
return new StreetIntersectionSearchListItem(app, (StreetIntersectionSearchObject) searchObject);
case STREET:
return new StreetSearchListItem(app, (StreetSearchObject) searchObject);
case CITY:
return new CitySearchListItem(app, (CitySearchObject) searchObject);
case VILLAGE:
return new VillageSearchListItem(app, (VillageSearchObject) searchObject);
case POSTCODE:
return new PostcodeSearchListItem(app, (PostcodeSearchObject) searchObject);
}
return null;
}
public SearchObject getSearchObject() {
return searchObject;
public SearchResult getSearchResult() {
return searchResult;
}
public String getName() {
return searchObject.getNativeName();
return searchResult.localeName;
}
public String getTypeName() {
return searchObject.getType().name();
return searchResult.objectType.name();
}
public Drawable getIcon() {
return null;
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
}

View file

@ -1,42 +0,0 @@
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.SearchPositionObject;
public class SearchListPositionItem extends SearchListItem {
private double latitude;
private double longitude;
public SearchListPositionItem(SampleApplication app, SearchPositionObject positionObject) {
super(app, positionObject);
PointI position31 = positionObject.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

@ -1,43 +0,0 @@
package net.osmand.core.samples.android.sample1.adapters;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.StreetGroup;
import net.osmand.core.jni.StreetIntersection;
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.StreetIntersectionSearchObject;
public class StreetIntersectionSearchListItem extends SearchListPositionItem {
private String nameStr;
private String typeStr;
public StreetIntersectionSearchListItem(SampleApplication app, StreetIntersectionSearchObject intersectionObject) {
super(app, intersectionObject);
nameStr = intersectionObject.getName(MapUtils.LANGUAGE);
StreetIntersection streetIntersection = intersectionObject.getBaseObject();
Street street = streetIntersection.getStreet();
if (street != null) {
StreetGroup streetGroup = street.getStreetGroup();
if (streetGroup != null) {
typeStr = streetGroup.getNativeName() + ", " + street.getNativeName();
} else {
typeStr = street.getNativeName();
}
} else {
typeStr = "Street intersection";
}
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -1,45 +0,0 @@
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 SearchListPositionItem {
private String nameStr;
private String typeStr;
public StreetSearchListItem(SampleApplication app, StreetSearchObject streetObject) {
super(app, streetObject);
nameStr = streetObject.getName(MapUtils.LANGUAGE);
StreetGroup streetGroup = streetObject.getBaseObject().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

@ -1,28 +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.objects.VillageSearchObject;
public class VillageSearchListItem extends SearchListPositionItem{
private String nameStr;
private String typeStr;
public VillageSearchListItem(SampleApplication app, VillageSearchObject villageObject) {
super(app, villageObject);
nameStr = villageObject.getName(MapUtils.LANGUAGE);
typeStr = "Village";
}
@Override
public String getName() {
return nameStr;
}
@Override
public String getTypeName() {
return typeStr;
}
}

View file

@ -1,203 +0,0 @@
package net.osmand.core.samples.android.sample1.search;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
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.ObjectSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class SearchAPI {
private ObfsCollection obfsCollection;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private PointI searchLocation31;
private double searchRadius;
private String lang;
private SearchRequestExecutor executor;
private SearchString searchString;
private List<SearchObject> searchObjects;
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 {
@Nullable
List<SearchObject> fetchExternalObjects(String keyword, @Nullable List<SearchObject> completeObjects);
void onSearchFinished(List<SearchObject> searchObjects);
}
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(lang);
this.lang = lang;
}
public String getLang() {
return lang;
}
public AreaI getSearchableArea() {
return searchableArea;
}
public void setSearchableArea(AreaI searchableArea) {
this.searchableArea = searchableArea;
}
public AreaI getObfAreaFilter() {
return obfAreaFilter;
}
public void setObfAreaFilter(AreaI obfAreaFilter) {
this.obfAreaFilter = obfAreaFilter;
}
public PointI getSearchLocation31() {
return searchLocation31;
}
public void setSearchLocation31(PointI position31) {
this.searchLocation31 = position31;
}
public double getSearchRadius() {
return searchRadius;
}
public void setSearchRadius(double searchRadius) {
this.searchRadius = searchRadius;
}
public ObfsCollection getObfsCollection() {
return obfsCollection;
}
public SearchString getSearchStringCopy() {
return searchString.copy();
}
public List<SearchObject> getSearchObjects() {
return searchObjects;
}
public void setSearchObjects(List<SearchObject> searchObjects) {
this.searchObjects = searchObjects;
}
public Map<SearchObjectType, ObjectSearchToken> getObjectTokens() {
return searchString.getCompleteObjectTokens();
}
public ObjectSearchToken getLastObjectToken() {
return searchString.getLastObjectToken();
}
public void startSearch(String query, int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
searchString.setPlainText(query);
startSearchInternal(maxSearchResults, intermediateSearchCallback, coreSearchCallback);
}
public String completeSearch(SearchObject searchObject, int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
searchString.completeQuery(searchObject);
startSearchInternal(maxSearchResults, intermediateSearchCallback, coreSearchCallback);
return searchString.getPlainText();
}
private void startSearchInternal(int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
SearchScope searchScope = new SearchScope(this);
IntermediateSearchRequest intermediateSearchRequest = null;
if (searchObjects != null && !searchObjects.isEmpty()) {
intermediateSearchRequest =
new IntermediateSearchRequest(searchScope, new ArrayList<>(searchObjects),
maxSearchResults, intermediateSearchCallback);
}
executor.run(new CoreSearchRequest(intermediateSearchRequest, searchScope,
maxSearchResults, coreSearchCallback, internalCallback), true);
}
public void cancelSearch() {
executor.cancel();
}
public class SearchRequestExecutor {
private SearchRequest ongoingSearchRequest;
private SearchRequest nextSearchRequest;
public void run(SearchRequest searchRequest, boolean cancelCurrentRequest) {
if (ongoingSearchRequest != null) {
nextSearchRequest = searchRequest;
if (cancelCurrentRequest) {
ongoingSearchRequest.cancel();
}
} else {
ongoingSearchRequest = searchRequest;
nextSearchRequest = null;
searchRequest.setOnFinishedCallback(new Runnable() {
@Override
public void run() {
operationFinished();
}
});
searchRequest.run();
}
}
public void cancel() {
if (nextSearchRequest != null) {
nextSearchRequest = null;
}
if (ongoingSearchRequest != null) {
ongoingSearchRequest.cancel();
}
}
private void operationFinished() {
ongoingSearchRequest = null;
if (nextSearchRequest != null) {
run(nextSearchRequest, false);
}
}
}
}

View file

@ -1,72 +0,0 @@
package net.osmand.core.samples.android.sample1.search;
import net.osmand.core.jni.Address;
import net.osmand.core.jni.Building;
import net.osmand.core.jni.OsmAndCoreJNI;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.StreetGroup;
import net.osmand.core.jni.StreetIntersection;
import net.osmand.core.samples.android.sample1.search.objects.BuildingSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.CitySearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PostcodeSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetIntersectionSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.VillageSearchObject;
public class SearchObjectsHelper {
public static SearchPositionObject getAddressObject(Address address) {
switch (address.getAddressType()) {
case Building:
BuildingInternal building = new BuildingInternal(address);
return new BuildingSearchObject(building);
case StreetIntersection:
StreetIntercestionInternal streetIntersection = new StreetIntercestionInternal(address);
return new StreetIntersectionSearchObject(streetIntersection);
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 BuildingInternal extends Building {
public BuildingInternal(Address address) {
super(OsmAndCoreJNI.Street_SWIGSmartPtrUpcast(Address.getCPtr(address)), false);
}
}
private static class StreetIntercestionInternal extends StreetIntersection {
public StreetIntercestionInternal(Address address) {
super(OsmAndCoreJNI.Street_SWIGSmartPtrUpcast(Address.getCPtr(address)), false);
}
}
private static class StreetInternal extends Street {
public StreetInternal(Address address) {
super(OsmAndCoreJNI.Street_SWIGSmartPtrUpcast(Address.getCPtr(address)), false);
}
}
private static class StreetGroupInternal extends StreetGroup {
public StreetGroupInternal(Address address) {
super(OsmAndCoreJNI.StreetGroup_SWIGSmartPtrUpcast(Address.getCPtr(address)), false);
}
}
}

View file

@ -1,276 +0,0 @@
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.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.QStringStringListHash;
import net.osmand.core.jni.Street;
import net.osmand.core.jni.StreetGroup;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.PoiTypeSearchObject;
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.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 java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class SearchScope {
private ObfsCollection obfsCollection;
private SearchString searchString;
private String lang;
private Map<SearchObjectType, ObjectSearchToken> objectTokens;
private PointI searchLocation31;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private double searchRadius;
boolean citySelected;
boolean poiTypeSelected;
private int resultLimitPoiByName = 25;
private int poiByNameCounter = 0;
private int resultLimitCityByName = 25;
private int cityByNameCounter = 0;
private int resultLimitStreetByName = 50;
private int streetByNameCounter = 0;
public SearchScope(SearchAPI searchAPI) {
obfsCollection = searchAPI.getObfsCollection();
lang = searchAPI.getLang();
searchString = searchAPI.getSearchStringCopy();
searchLocation31 = searchAPI.getSearchLocation31();
searchableArea = searchAPI.getSearchableArea();
obfAreaFilter = searchAPI.getObfAreaFilter();
searchRadius = searchAPI.getSearchRadius();
updateScope();
}
public void updateScope() {
objectTokens = searchString.getCompleteObjectTokens();
citySelected = objectTokens.containsKey(SearchObjectType.CITY)
|| objectTokens.containsKey(SearchObjectType.VILLAGE)
|| objectTokens.containsKey(SearchObjectType.POSTCODE)
|| objectTokens.containsKey(SearchObjectType.STREET);
poiTypeSelected = objectTokens.containsKey(SearchObjectType.POI_TYPE);
}
public ObfsCollection getObfsCollection() {
return obfsCollection;
}
public String getLang() {
return lang;
}
public SearchString getSearchString() {
return searchString;
}
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) {
if (objectTokens.containsKey(SearchObjectType.POI_TYPE)) {
PoiTypeSearchObject searchObject =
(PoiTypeSearchObject) objectTokens.get(SearchObjectType.POI_TYPE).getSearchObject();
QStringStringListHash filter = new QStringStringListHash();
// todo SWIG!!! filter.set(searchObject.getCategoryKeyName(), new QStringList(searchObject.getKeyName()));
criteria.setCategoriesFilter(filter);
}
}
public void setupAddressSearchCriteria(AddressesByNameSearch.Criteria criteria) {
if (objectTokens.containsKey(SearchObjectType.STREET)) {
StreetSearchObject streetSearchObject =
(StreetSearchObject) objectTokens.get(SearchObjectType.STREET).getSearchObject();
criteria.setAddressFilter(streetSearchObject.getBaseObject());
if (objectTokens.containsKey(SearchObjectType.POSTCODE)) {
PostcodeSearchObject postcodeSearchObject =
(PostcodeSearchObject) objectTokens.get(SearchObjectType.POSTCODE).getSearchObject();
criteria.setPostcode(postcodeSearchObject.getNativeName());
}
} else if (objectTokens.containsKey(SearchObjectType.CITY)) {
criteria.setAddressFilter(((StreetGroupSearchObject) objectTokens.get(SearchObjectType.CITY)
.getSearchObject()).getBaseObject());
} else if (objectTokens.containsKey(SearchObjectType.VILLAGE)) {
criteria.setAddressFilter(((StreetGroupSearchObject) objectTokens.get(SearchObjectType.VILLAGE)
.getSearchObject()).getBaseObject());
} else if (objectTokens.containsKey(SearchObjectType.POSTCODE)) {
criteria.setAddressFilter(((StreetGroupSearchObject) objectTokens.get(SearchObjectType.POSTCODE)
.getSearchObject()).getBaseObject());
}
}
public boolean processPoiSearchObject(PoiSearchObject poiSearchObject) {
updateDistance(poiSearchObject);
return processSearchObject(poiSearchObject);
}
public boolean processAddressSearchObject(SearchPositionObject addressSearchObject) {
updateDistance(addressSearchObject);
return processSearchObject(addressSearchObject);
}
public SearchToken processSearchResult(SearchToken token, List<SearchObject> searchObjects) {
SearchToken newToken = null;
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) {
return lhs.getName(lang).compareToIgnoreCase(rhs.getName(lang));
} else {
return res;
}
}
});
Iterator<SearchObject> it = searchObjects.iterator();
while (it.hasNext()) {
SearchObject searchObject = it.next();
boolean accept;
switch (searchObject.getType()) {
case POI:
accept = poiByNameCounter < resultLimitPoiByName;
if (accept) {
poiByNameCounter++;
}
break;
case CITY:
case VILLAGE:
case POSTCODE:
accept = cityByNameCounter < resultLimitCityByName;
if (accept) {
cityByNameCounter++;
}
break;
case STREET:
accept = streetByNameCounter < resultLimitStreetByName;
if (accept) {
streetByNameCounter++;
}
default:
accept = true;
break;
}
if (!accept) {
it.remove();
}
}
if (token.getType() == SearchToken.TokenType.NAME_FILTER
&& !token.hasEmptyQuery()) {
boolean suggeston = token == searchString.getLastToken();
newToken = new ObjectSearchToken(token, searchObjects.get(0), suggeston);
searchString.replaceToken(token, newToken);
}
}
return newToken;
}
private boolean processSearchObject(SearchObject searchObject) {
double priority = 0.0;
switch (searchObject.getType()) {
case BUILDING:
priority = 3.0;
break;
case POI_TYPE:
priority = poiTypeSelected ? 10.0 : 9.0;
break;
case POI:
priority = getPriorityByDistance(10.0, ((PoiSearchObject) searchObject).getDistance());
break;
case CITY:
case VILLAGE:
case POSTCODE:
double cityType = getCityType((StreetGroupSearchObject) searchObject);
priority = (getPriorityByDistance(citySelected
? 20.0 : 7.0 + cityType, ((StreetGroupSearchObject) searchObject).getDistance()));
break;
case STREET:
StreetSearchObject streetSearchObject = (StreetSearchObject) searchObject;
Street street = streetSearchObject.getBaseObject();
if (!citySelected) {
priority = getPriorityByDistance(9.0, streetSearchObject.getDistance());
} else {
boolean streetFromSelectedCity = false;
for (ObjectSearchToken st : objectTokens.values()) {
if (st.getSearchObject() instanceof StreetGroupSearchObject) {
StreetGroup streetGroup =
((StreetGroupSearchObject) st.getSearchObject()).getBaseObject();
if (streetGroup.getId().getId().equals(street.getStreetGroup().getId().getId())) {
streetFromSelectedCity = true;
break;
}
} else if (st.getSearchObject() instanceof StreetSearchObject) {
StreetGroup streetGroup =
((StreetSearchObject) st.getSearchObject()).getBaseObject().getStreetGroup();
if (streetGroup.getId().getId().equals(street.getStreetGroup().getId().getId())) {
streetFromSelectedCity = true;
break;
}
}
}
if (streetFromSelectedCity) {
priority = 3.0;
} else {
priority = getPriorityByDistance(9.0, streetSearchObject.getDistance());
}
}
break;
}
searchObject.setPriority(priority);
return true;
}
private double getCityType(StreetGroupSearchObject searchObject) {
if (searchObject.getBaseObject().getType() == ObfAddressStreetGroupType.CityOrTown) {
if (searchObject.getBaseObject().getSubtype() == ObfAddressStreetGroupSubtype.City) {
return 1.0;
} else if (searchObject.getBaseObject().getSubtype() == ObfAddressStreetGroupSubtype.Town) {
return 1.5;
}
}
return 2.5;
}
private double getPriorityByDistance(double priority, double distance) {
return priority + 1.0 - (1.0 / (1.0 + distance));
}
private void updateDistance(SearchPositionObject item) {
item.setDistance(Utilities.distance31(searchLocation31, item.getPosition31()));
}
}

View file

@ -1,218 +0,0 @@
package net.osmand.core.samples.android.sample1.search;
import android.support.annotation.NonNull;
import net.osmand.core.samples.android.sample1.MapUtils;
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.tokens.NameFilterSearchToken;
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.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SearchString {
private String plainText = "";
private List<SearchToken> tokens = new ArrayList<>();
private String lang;
public SearchString(String lang) {
this.lang = lang;
}
public SearchString copy() {
SearchString res = new SearchString(lang);
res.plainText = plainText;
res.tokens = new ArrayList<>(tokens);
return res;
}
public String getPlainText() {
return plainText;
}
public void setPlainText(String plainText) {
int newTextLength = plainText.length();
int currTextLength = this.plainText.length();
boolean isNewText = currTextLength == 0
|| newTextLength == 0
|| !this.plainText.regionMatches(0, plainText, 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
|| token.hasEmptyQuery()
|| (lastTokenIndex < newTextLength - 1 && !startWithDelimiter(plainText.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 = plainText.charAt(i);
if (isDelimiterChar(c)) {
if (i == firstWordIndex) {
firstWordIndex++;
} else {
SearchToken token = new NameFilterSearchToken(firstWordIndex, plainText.substring(firstWordIndex, i));
tokens.add(token);
firstWordIndex = i + 1;
}
}
}
if (firstWordIndex <= newTextLength - 1) {
SearchToken token = new NameFilterSearchToken(firstWordIndex, plainText.substring(firstWordIndex));
tokens.add(token);
} else if (endWithDelimeter(plainText)) {
SearchToken lastToken = getLastToken();
if (lastToken.getType() == TokenType.OBJECT) {
((ObjectSearchToken) lastToken).applySuggestion();
}
SearchToken token = new NameFilterSearchToken(firstWordIndex, "");
tokens.add(token);
}
}
this.plainText = plainText;
}
public void completeQuery(@NonNull SearchObject searchObject) {
String text;
String objectName = searchObject.getName(lang);
int startIndex;
SearchToken lastToken = getLastToken();
if (lastToken == null || lastToken.hasEmptyQuery()) {
startIndex = plainText.length();
text = plainText + objectName + " ";
} else {
startIndex = lastToken.getStartIndex();
text = plainText.substring(0, startIndex) + objectName + " ";
}
ObjectSearchToken token = new ObjectSearchToken(startIndex, objectName, searchObject, false);
if (lastToken == null) {
tokens.add(token);
} else {
tokens.set(tokens.size() - 1, token);
}
tokens.add(new NameFilterSearchToken(text.length(), ""));
plainText = text;
}
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);
}
private boolean isDelimiterChar(char c) {
return c == ',' || c == ' ';
}
public NameFilterSearchToken getNextNameFilterToken() {
NameFilterSearchToken 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 = (NameFilterSearchToken) token;
} else {
break;
}
}
}
return res;
}
public SearchToken getLastToken() {
if (!tokens.isEmpty()) {
return tokens.get(tokens.size() - 1);
}
return null;
}
public ObjectSearchToken getLastObjectToken() {
ObjectSearchToken res = null;
if (!tokens.isEmpty()) {
for (int i = tokens.size() - 1; i >= 0; i--) {
SearchToken token = tokens.get(i);
if (token.getType() == TokenType.OBJECT) {
res = (ObjectSearchToken) token;
break;
}
}
}
return res;
}
public boolean replaceToken(SearchToken oldToken, SearchToken newToken) {
int index = tokens.indexOf(oldToken);
if (index != -1) {
tokens.set(index, newToken);
return true;
}
return false;
}
public Map<SearchObjectType, ObjectSearchToken> getCompleteObjectTokens() {
Map<SearchObjectType, ObjectSearchToken> map = new LinkedHashMap<>();
for (SearchToken token : tokens) {
if (token.getType() == TokenType.OBJECT && !((ObjectSearchToken)token).isSuggestion()) {
map.put(((ObjectSearchToken)token).getSearchObject().getType(), (ObjectSearchToken)token);
}
}
return map;
}
public List<SearchObject> getCompleteObjects() {
List<SearchObject> list = new ArrayList<>();
for (SearchToken token : tokens) {
if (token.getType() == TokenType.OBJECT && !((ObjectSearchToken)token).isSuggestion()) {
list.add(((ObjectSearchToken)token).getSearchObject());
}
}
return list;
}
public static void main(String[] args){
//test
SearchString searchString = new SearchString(MapUtils.LANGUAGE);
searchString.setPlainText("cit");
searchString.setPlainText("city");
searchString.setPlainText("city ");
searchString.setPlainText("city s");
searchString.setPlainText("city st");
searchString.setPlainText("city street ");
searchString.setPlainText("city street 8");
searchString.setPlainText("new");
}
}

View file

@ -1,27 +0,0 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.Building;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
public class BuildingSearchObject extends SearchPositionObject<Building> {
public BuildingSearchObject(Building building) {
super(SearchObjectType.BUILDING, building);
}
@Override
public PointI getPosition31() {
return getBaseObject().getPosition31();
}
@Override
public String getNativeName() {
return getBaseObject().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getBaseObject().getLocalizedNames();
}
}

View file

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

@ -1,26 +0,0 @@
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<PointI> {
public CoordinatesSearchObject(PointI position31) {
super(SearchObjectType.COORDINATES, position31);
}
@Override
public PointI getPosition31() {
return getBaseObject();
}
@Override
public String getNativeName() {
return null;
}
@Override
protected QStringStringHash getLocalizedNames() {
return null;
}
}

View file

@ -1,27 +0,0 @@
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<Amenity> {
public PoiSearchObject(Amenity amenity) {
super(SearchObjectType.POI, amenity);
}
@Override
public PointI getPosition31() {
return getBaseObject().getPosition31();
}
@Override
public String getNativeName() {
return getBaseObject().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getBaseObject().getLocalizedNames();
}
}

View file

@ -1,26 +0,0 @@
package net.osmand.core.samples.android.sample1.search.objects;
public class PoiTypeObject {
private String name;
private String keyName;
private String categoryKeyName;
public PoiTypeObject(String name, String keyName, String categoryKeyName) {
this.name = name;
this.keyName = keyName;
this.categoryKeyName = categoryKeyName;
}
public String getName() {
return name;
}
public String getKeyName() {
return keyName;
}
public String getCategoryKeyName() {
return categoryKeyName;
}
}

View file

@ -1,41 +0,0 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.QStringStringHash;
public class PoiTypeSearchObject extends SearchObject<PoiTypeObject> {
private ObjectType objectType;
public enum ObjectType {
CATEGORY,
FILTER,
TYPE
}
public PoiTypeSearchObject(ObjectType objectType, PoiTypeObject poiTypeObject) {
super(SearchObjectType.POI_TYPE, poiTypeObject);
this.objectType = objectType;
}
public ObjectType getObjectType() {
return objectType;
}
public String getKeyName() {
return getBaseObject().getKeyName();
}
public String getCategoryKeyName() {
return getBaseObject().getCategoryKeyName();
}
@Override
public String getNativeName() {
return getBaseObject().getName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return null;
}
}

View file

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

@ -1,75 +0,0 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.QStringStringHash;
public abstract class SearchObject<T> {
public enum SearchObjectType {
CITY,
VILLAGE,
POSTCODE,
STREET,
STREET_INTERSECTION,
BUILDING,
POI_TYPE,
POI,
COORDINATES
}
private SearchObjectType type;
private T baseObject;
private double priority;
protected SearchObject(SearchObjectType type, T baseObject) {
this.type = type;
this.baseObject = baseObject;
}
public SearchObjectType getType() {
return type;
}
public T getBaseObject() {
return baseObject;
}
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 double getPriority() {
return priority;
}
public void setPriority(double priority) {
this.priority = priority;
}
protected abstract QStringStringHash getLocalizedNames();
@Override
public String toString() {
return "SearchObject: " + getNativeName();
}
}

View file

@ -1,29 +0,0 @@
package net.osmand.core.samples.android.sample1.search.objects;
import net.osmand.core.jni.PointI;
public abstract class SearchPositionObject<T> extends SearchObject<T> {
private double distance;
public SearchPositionObject(SearchObjectType type, T object) {
super(type, object);
}
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

@ -1,27 +0,0 @@
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<StreetGroup> {
public StreetGroupSearchObject(SearchObjectType type, StreetGroup streetGroup) {
super(type, streetGroup);
}
@Override
public PointI getPosition31() {
return getBaseObject().getPosition31();
}
@Override
public String getNativeName() {
return getBaseObject().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getBaseObject().getLocalizedNames();
}
}

View file

@ -1,27 +0,0 @@
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.StreetIntersection;
public class StreetIntersectionSearchObject extends SearchPositionObject<StreetIntersection> {
public StreetIntersectionSearchObject(StreetIntersection streetIntersection) {
super(SearchObjectType.STREET_INTERSECTION, streetIntersection);
}
@Override
public PointI getPosition31() {
return getBaseObject().getPosition31();
}
@Override
public String getNativeName() {
return getBaseObject().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getBaseObject().getLocalizedNames();
}
}

View file

@ -1,27 +0,0 @@
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<Street> {
public StreetSearchObject(Street street) {
super(SearchObjectType.STREET, street);
}
@Override
public PointI getPosition31() {
return getBaseObject().getPosition31();
}
@Override
public String getNativeName() {
return getBaseObject().getNativeName();
}
@Override
protected QStringStringHash getLocalizedNames() {
return getBaseObject().getLocalizedNames();
}
}

View file

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

@ -1,245 +0,0 @@
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.jni.OsmAndCoreJNI;
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.SearchObjectsHelper;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
import net.osmand.core.samples.android.sample1.search.tokens.NameFilterSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.ObjectSearchToken;
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 SearchCallbackInternal internalCallback;
private int amenityResultsCounter;
private int addressResultsCounter;
public CoreSearchRequest(@Nullable IntermediateSearchRequest intermediateSearchRequest,
@NonNull SearchScope searchScope, int maxSearchResults,
@Nullable SearchApiCallback searchCallback,
@Nullable SearchCallbackInternal internalCallback) {
super(searchScope, maxSearchResults, searchCallback);
this.intermediateSearchRequest = intermediateSearchRequest;
this.internalCallback = internalCallback;
}
@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<SearchObject> searchObjects) {
if (intermediateSearchRequest != null && !intermediateSearchDone) {
intermediateSearchRequest.cancel();
}
if (internalCallback != null) {
internalCallback.onSearchObjectsFound(searchObjects);
}
}
@Override
public void cancel() {
if (intermediateSearchRequest != null) {
intermediateSearchRequest.cancel();
}
super.cancel();
}
@Override
protected List<SearchObject> doSearch() {
List<SearchObject> res = new ArrayList<>();
SearchString searchString = searchScope.getSearchString();
SearchToken lastToken = searchString.getLastToken();
NameFilterSearchToken token = searchString.getNextNameFilterToken();
while (token != null && !cancelled) {
if (!token.hasEmptyQuery()) {
res = doCoreSearch(token);
List<SearchObject> externalObjects = searchCallback.fetchExternalObjects(token.getPlainText(), searchString.getCompleteObjects());
if (externalObjects != null) {
res.addAll(externalObjects);
}
}
if (token != lastToken) {
searchScope.updateScope();
token = searchString.getNextNameFilterToken();
} else {
break;
}
}
if (lastToken == null || lastToken.hasEmptyQuery()) {
// 2.4 Search considered to be complete if there no NF in the end (not finished or not regonized objects)
ObjectSearchToken lastObjectToken = searchString.getLastObjectToken();
if (lastObjectToken == null) {
// Last object = [] - none. We display list of poi categories (recents separate tab)
List<SearchObject> externalObjects = searchCallback.fetchExternalObjects("", null);
if (externalObjects != null) {
res = externalObjects;
}
} else {
SearchObject searchObject = lastObjectToken.getSearchObject();
switch (searchObject.getType()) {
case POI_TYPE:
// Last object - poi category/poi filter/poi type. Display: poi filters (if it is poi category & pois around location (if it is specified in query by any previous object) + Search more radius
// For example: Leiden ice hockey, we display all ice hockey around Leiden
List<SearchObject> externalObjects = searchCallback.fetchExternalObjects("", searchString.getCompleteObjects());
if (externalObjects != null) {
res = externalObjects;
}
break;
case CITY:
// Last object - City. Display (list of streets could be quite long)
res = doCoreSearch(new NameFilterSearchToken(0, ""));
break;
case STREET:
// Last object - Street. Display building and intersetcting street
res = doCoreSearch(new NameFilterSearchToken(0, ""));
break;
case POSTCODE:
// Last object - Postcode. Display building and streets
res = doCoreSearch(new NameFilterSearchToken(0, ""));
break;
case BUILDING:
// Last object - Building - object is found
break;
case POI:
// Last object - POI - object is found
break;
}
}
}
return res;
}
private List<SearchObject> doCoreSearch(@NonNull SearchToken token) {
amenityResultsCounter = 0;
addressResultsCounter = 0;
String keyword = token.getPlainText();
final List<SearchObject> searchObjects = new ArrayList<>();
AmenitiesByNameSearch amByNameSearch = null;
AmenitiesByNameSearch.Criteria amenityByNameCriteria = null;
ISearch.INewResultEntryCallback amenityByNameResultCallback = null;
if (!keyword.isEmpty()) {
// Setup Amenities by name search
amByNameSearch = new AmenitiesByNameSearch(searchScope.getObfsCollection());
amenityByNameCriteria = new AmenitiesByNameSearch.Criteria();
amenityByNameCriteria.setName(keyword);
if (searchScope.getObfAreaFilter() != null) {
amenityByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchScope.getObfAreaFilter()));
}
searchScope.setupAmenitySearchCriteria(amenityByNameCriteria);
amenityByNameResultCallback = new ISearch.INewResultEntryCallback() {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Amenity amenity = new AmenityResultEntry(resultEntry).getAmenity();
PoiSearchObject amenitySearchItem = new PoiSearchObject(amenity);
if (searchScope.processPoiSearchObject(amenitySearchItem)) {
searchObjects.add(amenitySearchItem);
}
amenityResultsCounter++;
}
};
}
// Setup Addresses by name search
AddressesByNameSearch addrByNameSearch = new AddressesByNameSearch(searchScope.getObfsCollection());
final AddressesByNameSearch.Criteria addrByNameCriteria = new AddressesByNameSearch.Criteria();
addrByNameCriteria.setName(keyword);
if (searchScope.getObfAreaFilter() != null) {
addrByNameCriteria.setObfInfoAreaFilter(new NullableAreaI(searchScope.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();
SearchPositionObject addressSearchObject = SearchObjectsHelper.getAddressObject(address);
if (addressSearchObject != null) {
if (searchScope.processAddressSearchObject(addressSearchObject)) {
searchObjects.add(addressSearchObject);
}
addressResultsCounter++;
}
}
};
if (amByNameSearch != null) {
amByNameSearch.performSearch(amenityByNameCriteria, amenityByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return (maxSearchResults > 0 && amenityResultsCounter >= maxSearchResults) || cancelled;
}
});
}
if (!cancelled) {
addrByNameSearch.performSearch(addrByNameCriteria, addrByNameResultCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return (maxSearchResults > 0 && addressResultsCounter >= maxSearchResults) || cancelled;
}
});
}
if (!cancelled) {
SearchToken newToken = searchScope.processSearchResult(token, searchObjects);
if (newToken != null && internalCallback != null) {
internalCallback.onNewTokenFound(token, newToken);
}
}
return searchObjects;
}
private class AmenityResultEntry extends AmenitiesByNameSearch.ResultEntry {
protected AmenityResultEntry(ISearch.IResultEntry resultEntry) {
super(OsmAndCoreJNI.AmenitiesByNameSearch_ResultEntry_SWIGUpcast(ISearch.IResultEntry.getCPtr(resultEntry)), false);
}
}
private class AddressResultEntry extends AddressesByNameSearch.ResultEntry {
protected AddressResultEntry(ISearch.IResultEntry resultEntry) {
super(OsmAndCoreJNI.AddressesByNameSearch_ResultEntry_SWIGUpcast(ISearch.IResultEntry.getCPtr(resultEntry)), false);
}
}
}

View file

@ -1,44 +0,0 @@
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.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;
import java.util.List;
public class IntermediateSearchRequest extends SearchRequest {
private List<SearchObject> searchObjects;
protected String keyword = "";
public IntermediateSearchRequest(@NonNull SearchScope searchScope, List<SearchObject> searchObjects,
int maxSearchResults, @Nullable SearchApiCallback searchCallback) {
super(searchScope, maxSearchResults, searchCallback);
this.searchObjects = searchObjects;
SearchToken token = searchScope.getSearchString().getLastToken();
if (token != null && token.getType() == SearchToken.TokenType.NAME_FILTER) {
keyword = token.getPlainText().toLowerCase();
}
}
@Override
protected List<SearchObject> doSearch() {
List<SearchObject> res = new ArrayList<>();
for (SearchObject item : searchObjects) {
if (cancelled) {
break;
}
if (keyword.isEmpty() || item.getName(searchScope.getLang()).toLowerCase().contains(keyword)
|| item.getNativeName().toLowerCase().contains(keyword)) {
res.add(item);
}
}
return res;
}
}

View file

@ -1,66 +0,0 @@
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.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.SearchScope;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import java.util.List;
public abstract class SearchRequest {
protected SearchScope searchScope;
protected int maxSearchResults;
protected Runnable onFinished;
protected SearchApiCallback searchCallback;
protected boolean cancelled;
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<SearchObject>>() {
@Override
protected List<SearchObject> doInBackground(Void... params) {
return doSearch();
}
@Override
protected void onPostExecute(List<SearchObject> searchObjects) {
onSearchRequestPostExecute(searchObjects);
if (onFinished != null) {
onFinished.run();
}
if (searchCallback != null && !cancelled) {
searchCallback.onSearchFinished(searchObjects);
}
}
}.execute();
}
protected void onSearchRequestPostExecute(List<SearchObject> searchObjects) {
}
protected abstract List<SearchObject> doSearch();
public void cancel() {
cancelled = true;
}
public void setOnFinishedCallback(@Nullable Runnable onFinished) {
this.onFinished = onFinished;
}
}

View file

@ -1,8 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
public class NameFilterSearchToken extends SearchToken {
public NameFilterSearchToken(int startIndex, String plainText) {
super(TokenType.NAME_FILTER, startIndex, plainText);
}
}

View file

@ -1,33 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
public class ObjectSearchToken extends SearchToken {
private SearchObject searchObject;
private boolean suggestion = true;
public ObjectSearchToken(SearchToken searchToken, SearchObject searchObject, boolean suggestion) {
super(TokenType.OBJECT, searchToken.getStartIndex(), searchToken.getPlainText());
this.searchObject = searchObject;
this.suggestion = suggestion;
}
public ObjectSearchToken(int startIndex, String plainText, SearchObject searchObject, boolean suggestion) {
super(TokenType.OBJECT, startIndex, plainText);
this.searchObject = searchObject;
this.suggestion = suggestion;
}
public SearchObject getSearchObject() {
return searchObject;
}
public boolean isSuggestion() {
return suggestion;
}
public void applySuggestion() {
this.suggestion = false;
}
}

View file

@ -1,41 +0,0 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import net.osmand.util.Algorithms;
public abstract class SearchToken {
public enum TokenType {
OBJECT,
NAME_FILTER
}
private TokenType type;
private int startIndex;
protected String plainText;
public SearchToken(TokenType type, int startIndex, String plainText) {
this.type = type;
this.startIndex = startIndex;
this.plainText = plainText;
}
public TokenType getType() {
return type;
}
public int getStartIndex() {
return startIndex;
}
public String getPlainText() {
return plainText;
}
public int getLastIndex() {
return startIndex + plainText.length() - 1;
}
public boolean hasEmptyQuery() {
return Algorithms.isEmpty(plainText);
}
}