From b7c38b27a9a906bbce7c295dc6d79b7c0262695b Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 21 Aug 2011 15:15:57 +0200 Subject: [PATCH] Implement GPX explorer. Issue 514 --- .../src/net/osmand/osm/MapUtils.java | 22 ---- OsmAnd/res/values-ru/strings.xml | 6 +- OsmAnd/res/values/strings.xml | 6 +- OsmAnd/src/net/osmand/GPXUtilities.java | 38 +++++- .../plus/activities/LocalIndexHelper.java | 110 +++++++++++++++--- .../plus/activities/LocalIndexesActivity.java | 25 ++++ 6 files changed, 166 insertions(+), 41 deletions(-) diff --git a/DataExtractionOSM/src/net/osmand/osm/MapUtils.java b/DataExtractionOSM/src/net/osmand/osm/MapUtils.java index ee02dd3cc3..efcdf3deb6 100644 --- a/DataExtractionOSM/src/net/osmand/osm/MapUtils.java +++ b/DataExtractionOSM/src/net/osmand/osm/MapUtils.java @@ -413,28 +413,6 @@ public class MapUtils { return rotate; } - /** - * Serializes entity without id - */ - public static String serializeEntityPlainString(Entity e){ - for(Entry es : e.getTags().entrySet()) { - // TODO - } - return null; - - } - - /** - * Serializes entity without id - */ - public static Entity derializeEntityPlainString(String value, long id, EntityType t, boolean skipIfEmptyTags){ - if(t == EntityType.NODE){ - - } else { - // TODO - } - return null; - } } diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index 398f6b398e..aa80b8100f 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -1,6 +1,10 @@ - Путей : %1$d\nВсего точек : %2$d\nОтмечено точек : %3$d + \n\nДлинное нажатие для просмотра на карте + \nСредняя скорость : %1$s \nМаксимальная скорость : %2$s + Средняя высота : %1$.0f метров\nПодъем вверх : %2$.0f метров\nПодъем вниз : %2$.0f метров + Путей : %1$d\nВсего точек : %2$d\nОтмечено точек : %3$d\nВсего расстояние : %4$s + \nНачало : %5$tD %5$tR\nОкончание : %6$tD %6$tR\n Установлено %1$d из %2$d объектов успешно архивированы. %1$d из %2$d объектов успешно удалены. diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index ec5858d336..469c8d8667 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -3,7 +3,11 @@ Not needed Base world map is missing. Please consider to download it in order to have proper environment. On board data is missing on SD card. Please consider to download it in order to use maps offline. - Subtracks : %1$d\nTotal Points : %2$d\nWay points : %3$d + \n\nLong click to show on map + \nAverage speed : %1$s \nMaximum speed : %2$s + \nAverage altitude : %1$.0f meters\nElevation up : %2$.0f meters\nElevation down : %3$.0f meters + Subtracks : %1$d\nTotal Points : %2$d\nWay points : %3$d\nTotal Distance : %4$s + \nStart Time : %5$tD %5$tR\nEnd Time : %6$tD %6$tR Installed %1$d items of %2$d succesfully backed up. %1$d items of %2$d succesfully deleted. diff --git a/OsmAnd/src/net/osmand/GPXUtilities.java b/OsmAnd/src/net/osmand/GPXUtilities.java index 29510cc119..081505ee07 100644 --- a/OsmAnd/src/net/osmand/GPXUtilities.java +++ b/OsmAnd/src/net/osmand/GPXUtilities.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -146,10 +147,23 @@ public class GPXUtilities { // such as wpt. However they provide additional information into gpx. public boolean cloudMadeFile; public String error; + + public Location findFistLocation(){ + for(List l : locations){ + for(Location ls : l){ + if(ls != null){ + return ls; + } + } + } + return null; + } } public static GPXFileResult loadGPXFile(Context ctx, File f){ GPXFileResult res = new GPXFileResult(); + SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT); + format.setTimeZone(TimeZone.getTimeZone("UTC")); try { boolean cloudMade = false; XmlPullParser parser = Xml.newPullParser(); @@ -175,13 +189,35 @@ public class GPXUtilities { current.setLongitude(Double.parseDouble(parser.getAttributeValue("", "lon"))); //$NON-NLS-1$ //$NON-NLS-2$ } catch (NumberFormatException e) { current = null; - } } else if (current != null && parser.getName().equals("name")) { //$NON-NLS-1$ if (parser.next() == XmlPullParser.TEXT) { currentName = parser.getText(); } + } else if (current != null && parser.getName().equals("time")) { //$NON-NLS-1$ + if (parser.next() == XmlPullParser.TEXT) { + try { + current.setTime(format.parse(parser.getText()).getTime()); + } catch (ParseException e) { + } + } + } else if (current != null && parser.getName().equals("ele")) { //$NON-NLS-1$ + if (parser.next() == XmlPullParser.TEXT) { + try { + current.setAltitude(Double.parseDouble(parser.getText())); + } catch (NumberFormatException e) { + } + } + } else if (current != null && parser.getName().equals("speed")) { //$NON-NLS-1$ + if (parser.next() == XmlPullParser.TEXT) { + try { + current.setSpeed(Float.parseFloat(parser.getText())); + } catch (NumberFormatException e) { + } + } } + + } else if (tok == XmlPullParser.END_TAG) { if (parser.getName().equals("wpt") || //$NON-NLS-1$ parser.getName().equals("trkpt") || (!cloudMade && parser.getName().equals("rtept"))) { //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index 110cca2dac..e14bfc4ad6 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; @@ -14,6 +13,7 @@ import java.util.Set; import java.util.TreeSet; import net.osmand.GPXUtilities; +import net.osmand.OsmAndFormatter; import net.osmand.GPXUtilities.GPXFileResult; import net.osmand.binary.BinaryIndexPart; import net.osmand.binary.BinaryMapIndexReader; @@ -34,6 +34,7 @@ import net.osmand.plus.voice.MediaCommandPlayerImpl; import net.osmand.plus.voice.TTSCommandPlayerImpl; import android.content.Context; import android.database.sqlite.SQLiteDatabase; +import android.location.Location; import android.os.Build; public class LocalIndexHelper { @@ -54,7 +55,6 @@ public class LocalIndexHelper { return app.getString(R.string.local_index_installed) + " : " + dateformat.format(new Object[]{new Date(f.lastModified())}); } - @SuppressWarnings("unchecked") public void updateDescription(LocalIndexInfo info){ File f = new File(info.getPathToData()); if(info.getType() == LocalIndexType.MAP_DATA){ @@ -63,18 +63,7 @@ public class LocalIndexHelper { } else if(info.getType() == LocalIndexType.POI_DATA){ info.setDescription(getInstalledDate(f)); } else if(info.getType() == LocalIndexType.GPX_DATA){ - GPXFileResult result = GPXUtilities.loadGPXFile(app, f); - if(result.error != null){ - info.setCorrupted(true); - info.setDescription(result.error); - } else { - int points = 0; - for(int i =0; i< result.locations.size() ; i++){ - points += result.locations.get(i).size(); - } - info.setDescription(app.getString(R.string.local_index_gpx_info, result.locations.size(), points, - result.wayPoints.size())); - } + updateGpxInfo(info, f); } else if(info.getType() == LocalIndexType.VOICE_DATA){ info.setDescription(getInstalledDate(f)); } else if(info.getType() == LocalIndexType.TTS_VOICE_DATA){ @@ -109,6 +98,87 @@ public class LocalIndexHelper { } } } + + private void updateGpxInfo(LocalIndexInfo info, File f) { + if(info.getGpxFile() == null){ + info.setGpxFile(GPXUtilities.loadGPXFile(app, f)); + } + GPXFileResult result = info.getGpxFile(); + if(result.error != null){ + info.setCorrupted(true); + info.setDescription(result.error); + } else { + int totalDistance = 0; + long startTime = Long.MAX_VALUE; + long endTime = Long.MIN_VALUE; + + double diffElevationUp = 0; + double diffElevationDown = 0; + double totalElevation = 0; + + float maxSpeed = 0; + int speedCount = 0; + double totalSpeedSum = 0; + + int points = 0; + for(int i = 0; i< result.locations.size() ; i++){ + List subtrack = result.locations.get(i); + points += subtrack.size(); + int distance = 0; + for (int j = 0; j < subtrack.size(); j++) { + long time = subtrack.get(j).getTime(); + if(time != 0){ + startTime = Math.min(startTime, time); + endTime = Math.max(startTime, time); + } + float speed = subtrack.get(j).getSpeed(); + if(speed > 0){ + totalSpeedSum += speed; + maxSpeed = Math.max(speed, maxSpeed); + speedCount ++; + } + + totalElevation += subtrack.get(j).getAltitude(); + if (j > 0) { + double diff = subtrack.get(j).getAltitude() - subtrack.get(j - 1).getAltitude(); + if(diff > 0){ + diffElevationUp += diff; + } else { + diffElevationDown -= diff; + } + distance += MapUtils.getDistance(subtrack.get(j - 1).getLatitude(), subtrack.get(j - 1).getLongitude(), subtrack + .get(j).getLatitude(), subtrack.get(j).getLongitude()); + } + } + totalDistance += distance; + } + if(startTime == Long.MAX_VALUE){ + startTime = f.lastModified(); + } + if(endTime == Long.MIN_VALUE){ + endTime = f.lastModified(); + } + + info.setDescription(app.getString(R.string.local_index_gpx_info, result.locations.size(), points, + result.wayPoints.size(), OsmAndFormatter.getFormattedDistance(totalDistance, app), + startTime, endTime)); + if(totalElevation != 0 || diffElevationUp != 0 || diffElevationDown != 0){ + info.setDescription(info.getDescription() + + app.getString(R.string.local_index_gpx_info_elevation, + totalElevation / points, diffElevationUp, diffElevationDown)); + } + if(speedCount > 0){ + info.setDescription(info.getDescription() + + app.getString(R.string.local_index_gpx_info_speed, + OsmAndFormatter.getFormattedSpeed((float) (totalSpeedSum / speedCount), app), + OsmAndFormatter.getFormattedSpeed(maxSpeed, app))); + + } + + info.setDescription(info.getDescription() + + app.getString(R.string.local_index_gpx_info_show)); + } + } public List getLocalIndexData(LocalIndexType type, LoadLocalIndexTask loadTask){ OsmandSettings settings = OsmandSettings.getOsmandSettings(app.getApplicationContext()); @@ -165,8 +235,6 @@ public class LocalIndexHelper { if(!TileSourceManager.isTileSourceMetaInfoExist(tileFile)){ info.setCorrupted(true); - } else { - // updateTileSourceInfo(tileFile, info); } result.add(info); loadTask.loadFile(info); @@ -321,6 +389,8 @@ public class LocalIndexHelper { // UI state expanded private boolean expanded; + private GPXFileResult gpxFile; + public LocalIndexInfo(LocalIndexType type, File f, boolean backuped){ pathToData = f.getAbsolutePath(); fileName = f.getName(); @@ -362,6 +432,14 @@ public class LocalIndexHelper { this.kbSize = size; } + public void setGpxFile(GPXFileResult gpxFile) { + this.gpxFile = gpxFile; + } + + public GPXFileResult getGpxFile() { + return gpxFile; + } + public boolean isExpanded() { return expanded; } diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java index ca3690c43f..e04b6c3e49 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Set; import net.osmand.Algoritms; +import net.osmand.FavouritePoint; import net.osmand.IProgress; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; @@ -24,15 +25,18 @@ import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; +import android.location.Location; import android.os.AsyncTask; import android.os.Bundle; import android.os.AsyncTask.Status; +import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; import android.widget.BaseExpandableListAdapter; import android.widget.Button; @@ -40,6 +44,8 @@ import android.widget.CheckBox; import android.widget.ExpandableListView; import android.widget.TextView; import android.widget.Toast; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.ExpandableListView.ExpandableListContextMenuInfo; public class LocalIndexesActivity extends ExpandableListActivity { @@ -74,6 +80,24 @@ public class LocalIndexesActivity extends ExpandableListActivity { } }); + getExpandableListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + long packedPos = ((ExpandableListContextMenuInfo)menuInfo).packedPosition; + + final LocalIndexInfo point = (LocalIndexInfo) listAdapter.getChild(ExpandableListView.getPackedPositionGroup(packedPos), + ExpandableListView.getPackedPositionChild(packedPos)); + if(point.getGpxFile() != null){ + Location loc = point.getGpxFile().findFistLocation(); + if(loc != null){ + OsmandSettings.getOsmandSettings(LocalIndexesActivity.this).setMapLocationToShow(loc.getLatitude(),loc.getLongitude()); + } + ((OsmandApplication) getApplication()).setGpxFileToDisplay(point.getGpxFile()); + MapActivity.launchMapActivityMoveToTop(LocalIndexesActivity.this); + } + } + }); + setListAdapter(listAdapter); } @@ -263,6 +287,7 @@ public class LocalIndexesActivity extends ExpandableListActivity { return true; } + @Override protected void onPause() { super.onPause();