From 35a044a19287c60f371341b3f4ee4ee941d6ceb6 Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Fri, 22 Jul 2016 22:19:36 +0300 Subject: [PATCH] [Quick search] added wpt search --- OsmAnd/src/net/osmand/plus/GPXUtilities.java | 131 ++++++++++++++++++ .../search/QuickSearchDialogFragment.java | 113 ++++++++++++++- .../plus/search/QuickSearchListItem.java | 26 +++- 3 files changed, 262 insertions(+), 8 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/GPXUtilities.java b/OsmAnd/src/net/osmand/plus/GPXUtilities.java index d504c3fb1d..de04ceab16 100644 --- a/OsmAnd/src/net/osmand/plus/GPXUtilities.java +++ b/OsmAnd/src/net/osmand/plus/GPXUtilities.java @@ -1182,6 +1182,137 @@ public class GPXUtilities { return res; } + public static GPXFile loadWptPt(Context ctx, File f) { + FileInputStream fis = null; + try { + fis = new FileInputStream(f); + GPXFile file = loadWptPt(ctx, fis); + file.path = f.getAbsolutePath(); + try { + fis.close(); + } catch (IOException e) { + } + return file; + } catch (FileNotFoundException e) { + GPXFile res = new GPXFile(); + res.path = f.getAbsolutePath(); + log.error("Error reading gpx", e); //$NON-NLS-1$ + res.warning = ctx.getString(R.string.error_reading_gpx); + return res; + } finally { + try { + if (fis != null) + fis.close(); + } catch (IOException ignore) { + // ignore + } + } + } + + public static GPXFile loadWptPt(Context ctx, InputStream f) { + GPXFile res = new GPXFile(); + SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT, Locale.US); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + XmlPullParser parser = PlatformUtil.newXMLPullParser(); + parser.setInput(getUTF8Reader(f)); //$NON-NLS-1$ + Stack parserState = new Stack(); + boolean extensionReadMode = false; + parserState.push(res); + int tok; + while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (tok == XmlPullParser.START_TAG) { + Object parse = parserState.peek(); + String tag = parser.getName(); + if (extensionReadMode && parse instanceof GPXExtensions) { + String value = readText(parser, tag); + if (value != null) { + ((GPXExtensions) parse).getExtensionsToWrite().put(tag, value); + if (tag.equals("speed") && parse instanceof WptPt) { + try { + ((WptPt) parse).speed = Float.parseFloat(value); + } catch (NumberFormatException e) { + } + } + } + + } else if (parse instanceof GPXExtensions && tag.equals("extensions")) { + extensionReadMode = true; + } else { + if (parse instanceof GPXFile) { + if (parser.getName().equals("wpt")) { + WptPt wptPt = parseWptAttributes(parser); + ((GPXFile) parse).points.add(wptPt); + parserState.push(wptPt); + } + } else if (parse instanceof WptPt) { + if (parser.getName().equals("name")) { + ((WptPt) parse).name = readText(parser, "name"); + } else if (parser.getName().equals("desc")) { + ((WptPt) parse).desc = readText(parser, "desc"); + } else if (parser.getName().equals("link")) { + ((WptPt) parse).link = parser.getAttributeValue("", "href"); + } else if (tag.equals("category")) { + ((WptPt) parse).category = readText(parser, "category"); + } else if (tag.equals("type")) { + if (((WptPt) parse).category == null) { + ((WptPt) parse).category = readText(parser, "type"); + } + } else if (parser.getName().equals("ele")) { + String text = readText(parser, "ele"); + if (text != null) { + try { + ((WptPt) parse).ele = Float.parseFloat(text); + } catch (NumberFormatException e) { + } + } + } else if (parser.getName().equals("hdop")) { + String text = readText(parser, "hdop"); + if (text != null) { + try { + ((WptPt) parse).hdop = Float.parseFloat(text); + } catch (NumberFormatException e) { + } + } + } else if (parser.getName().equals("time")) { + String text = readText(parser, "time"); + if (text != null) { + try { + ((WptPt) parse).time = format.parse(text).getTime(); + } catch (ParseException e) { + } + } + } + } + } + + } else if (tok == XmlPullParser.END_TAG) { + Object parse = parserState.peek(); + String tag = parser.getName(); + if (parse instanceof GPXExtensions && tag.equals("extensions")) { + extensionReadMode = false; + } + + if (tag.equals("wpt")) { + Object pop = parserState.pop(); + assert pop instanceof WptPt; + } + } + } + } catch (RuntimeException e) { + log.error("Error reading gpx", e); //$NON-NLS-1$ + res.warning = ctx.getString(R.string.error_reading_gpx) + " " + e.getMessage(); + } catch (XmlPullParserException e) { + log.error("Error reading gpx", e); //$NON-NLS-1$ + res.warning = ctx.getString(R.string.error_reading_gpx) + " " + e.getMessage(); + } catch (IOException e) { + log.error("Error reading gpx", e); //$NON-NLS-1$ + res.warning = ctx.getString(R.string.error_reading_gpx) + " " + e.getMessage(); + } + + return res; + } + private static Reader getUTF8Reader(InputStream f) throws IOException { BufferedInputStream bis = new BufferedInputStream(f); assert bis.markSupported(); diff --git a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java index d57570e180..d43c93a973 100644 --- a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java @@ -29,6 +29,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import net.osmand.AndroidUtils; +import net.osmand.IndexConstants; import net.osmand.Location; import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; @@ -36,6 +37,7 @@ import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.plus.GPXUtilities; import net.osmand.plus.GPXUtilities.GPXFile; +import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.LockableViewPager; import net.osmand.plus.OsmAndLocationProvider.OsmAndCompassListener; import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener; @@ -45,6 +47,7 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.SearchHistoryHelper; import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; +import net.osmand.plus.myplaces.AvailableGPXFragment.GpxInfo; import net.osmand.plus.resources.RegionAddressRepository; import net.osmand.search.SearchUICore; import net.osmand.search.SearchUICore.SearchResultCollection; @@ -62,6 +65,7 @@ import net.osmand.util.MapUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -97,6 +101,8 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC public static final int SEARCH_FAVORITE_API_PRIORITY = 2; public static final int SEARCH_FAVORITE_OBJECT_PRIORITY = 10; + public static final int SEARCH_WPT_API_PRIORITY = 2; + public static final int SEARCH_WPT_OBJECT_PRIORITY = 10; public static final int SEARCH_HISTORY_API_PRIORITY = 3; public static final int SEARCH_HISTORY_OBJECT_PRIORITY = 10; @@ -299,7 +305,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC } }); - // Setup favorites search api + // Register favorites search api searchUICore.registerAPI(new SearchBaseAPI() { @Override @@ -330,6 +336,9 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC return SEARCH_FAVORITE_API_PRIORITY; } }); + + // Register WptPt search api + searchUICore.registerAPI(new SearchWptAPI(app)); } @Override @@ -774,7 +783,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC protected GPXFile doInBackground(Void... params) { GPXFile gpx = new GPXFile(); for (HistoryEntry h : historyEntries) { - GPXUtilities.WptPt pt = new GPXUtilities.WptPt(); + WptPt pt = new WptPt(); pt.lat = h.getLat(); pt.lon = h.getLon(); pt.name = h.getName().getName(); @@ -959,4 +968,104 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC return SEARCH_HISTORY_API_PRIORITY; } } + + public static class SearchWptAPI extends SearchBaseAPI { + + private OsmandApplication app; + private LoadGpxTask asyncLoader = new LoadGpxTask(); + + public SearchWptAPI(OsmandApplication app) { + this.app = app; + asyncLoader.execute(); + } + + @Override + public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) { + if (asyncLoader.getResult() == null) { + return false; + } + + List infos = asyncLoader.getResult(); + for (GpxInfo info : infos) { + for (WptPt point : info.gpx.points) { + SearchResult sr = new SearchResult(phrase); + sr.localeName = point.getPointDescription(app).getName(); + sr.object = point; + sr.priority = SEARCH_WPT_OBJECT_PRIORITY; + sr.objectType = ObjectType.WPT; + sr.location = new LatLon(point.getLatitude(), point.getLongitude()); + sr.localeRelatedObjectName = info.getFileName(); + sr.preferredZoom = 17; + if (phrase.getLastWord().length() <= 1 && phrase.isNoSelectedType()) { + resultMatcher.publish(sr); + } else if (phrase.getNameStringMatcher().matches(sr.localeName)) { + resultMatcher.publish(sr); + } + } + } + return true; + } + + @Override + public int getSearchPriority(SearchPhrase p) { + if(!p.isNoSelectedType()) { + return -1; + } + return SEARCH_WPT_API_PRIORITY; + } + + + public class LoadGpxTask extends AsyncTask> { + + private List result; + + @Override + protected List doInBackground(Void... params) { + List result = new ArrayList<>(); + loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, this); + return result; + } + + @Override + protected void onPostExecute(List result) { + this.result = result; + } + + private File[] listFilesSorted(File dir) { + File[] listFiles = dir.listFiles(); + if (listFiles == null) { + return new File[0]; + } + Arrays.sort(listFiles); + return listFiles; + } + + private void loadGPXData(File mapPath, List result, LoadGpxTask loadTask) { + if (mapPath.canRead()) { + loadGPXFolder(mapPath, result, loadTask, ""); + } + } + + private void loadGPXFolder(File mapPath, List result, LoadGpxTask loadTask, + String gpxSubfolder) { + for (File gpxFile : listFilesSorted(mapPath)) { + if (gpxFile.isDirectory()) { + String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/" + + gpxFile.getName(); + loadGPXFolder(gpxFile, result, loadTask, sub); + } else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(".gpx")) { + GpxInfo info = new GpxInfo(); + info.subfolder = gpxSubfolder; + info.file = gpxFile; + info.gpx = GPXUtilities.loadWptPt(app, gpxFile); + result.add(info); + } + } + } + + public List getResult() { + return result; + } + } + } } diff --git a/OsmAnd/src/net/osmand/plus/search/QuickSearchListItem.java b/OsmAnd/src/net/osmand/plus/search/QuickSearchListItem.java index e007738e35..8afa1cfa06 100644 --- a/OsmAnd/src/net/osmand/plus/search/QuickSearchListItem.java +++ b/OsmAnd/src/net/osmand/plus/search/QuickSearchListItem.java @@ -15,6 +15,8 @@ import net.osmand.osm.AbstractPoiType; import net.osmand.osm.PoiCategory; import net.osmand.osm.PoiFilter; import net.osmand.osm.PoiType; +import net.osmand.plus.GPXUtilities; +import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -182,9 +184,9 @@ public class QuickSearchListItem { return typeStr; case LOCATION: LatLon latLon = (LatLon) searchResult.object; - String country = app.getRegions().getCountryName(latLon); - if (!Algorithms.isEmpty(country)) { - return country; + String locationCountry = app.getRegions().getCountryName(latLon); + if (!Algorithms.isEmpty(locationCountry)) { + return locationCountry; } else { return ""; } @@ -205,7 +207,19 @@ public class QuickSearchListItem { return app.getString(R.string.shared_string_history); } case WPT: - break; + StringBuilder sb = new StringBuilder(); + WptPt wpt = (WptPt) searchResult.object; + String wptCountry = app.getRegions().getCountryName(new LatLon(wpt.getLatitude(), wpt.getLongitude())); + if (!Algorithms.isEmpty(wptCountry)) { + sb.append(wptCountry); + } + if (!Algorithms.isEmpty(searchResult.localeRelatedObjectName)) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(searchResult.localeRelatedObjectName); + } + return sb.toString(); case UNKNOWN_NAME_FILTER: break; } @@ -295,8 +309,8 @@ public class QuickSearchListItem { return app.getIconsCache().getIcon(SearchHistoryFragment.getItemIcon(entry.getName()), app.getSettings().isLightContent() ? R.color.osmand_orange : R.color.osmand_orange_dark); case WPT: - return app.getIconsCache().getIcon(R.drawable.map_action_flag_dark, - app.getSettings().isLightContent() ? R.color.osmand_orange : R.color.osmand_orange_dark); + WptPt wpt = (WptPt) searchResult.object; + return FavoriteImageDrawable.getOrCreate(app, wpt.getColor(), false); case UNKNOWN_NAME_FILTER: break; }