diff options
Diffstat (limited to 'main/src/cgeo/geocaching/export/GpxExport.java')
| -rw-r--r-- | main/src/cgeo/geocaching/export/GpxExport.java | 238 |
1 files changed, 13 insertions, 225 deletions
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java index 0ba1a3c..e6b52bc 100644 --- a/main/src/cgeo/geocaching/export/GpxExport.java +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -1,24 +1,12 @@ package cgeo.geocaching.export; import cgeo.geocaching.Geocache; -import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.Waypoint; -import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.enumerations.CacheAttribute; -import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.AsyncTaskWithProgress; -import cgeo.geocaching.utils.TextUtils; import cgeo.geocaching.utils.Log; -import cgeo.geocaching.utils.XmlUtils; -import cgeo.org.kxml2.io.KXmlSerializer; - -import org.apache.commons.lang3.StringUtils; -import org.xmlpull.v1.XmlSerializer; import android.app.Activity; import android.app.AlertDialog; @@ -39,22 +27,11 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.Set; class GpxExport extends AbstractExport { - private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance"; - public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0"; - public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0"; - - /** - * During the export, only this number of geocaches is fully loaded into memory. - */ - public static final int CACHES_PER_BATCH = 100; protected GpxExport() { super(getString(R.string.export_gpx)); @@ -62,7 +39,7 @@ class GpxExport extends AbstractExport { @Override public void export(final List<Geocache> caches, final Activity activity) { - String[] geocodes = getGeocodes(caches); + final String[] geocodes = getGeocodes(caches); if (null == activity) { // No activity given, so no user interaction possible. // Start export with default parameters. @@ -75,10 +52,10 @@ class GpxExport extends AbstractExport { } private Dialog getExportDialog(final String[] geocodes, final Activity activity) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); // AlertDialog has always dark style, so we have to apply it as well always - View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null); + final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null); builder.setView(layout); final TextView text = (TextView) layout.findViewById(R.id.info); @@ -108,7 +85,7 @@ class GpxExport extends AbstractExport { } private static String[] getGeocodes(final List<Geocache> caches) { - ArrayList<String> allGeocodes = new ArrayList<String>(caches.size()); + final ArrayList<String> allGeocodes = new ArrayList<String>(caches.size()); for (final Geocache geocache : caches) { allGeocodes.add(geocache.getGeocode()); } @@ -117,7 +94,6 @@ class GpxExport extends AbstractExport { protected class ExportTask extends AsyncTaskWithProgress<String, File> { private final Activity activity; - private int countExported = 0; /** * Instantiates and configures the task for exporting field notes. @@ -137,7 +113,7 @@ class GpxExport extends AbstractExport { return null; } - List<String> allGeocodes = new ArrayList<String>(Arrays.asList(geocodes)); + final List<String> allGeocodes = new ArrayList<String>(Arrays.asList(geocodes)); setMessage(cgeoapplication.getInstance().getResources().getQuantityString(R.plurals.cache_counts, allGeocodes.size(), allGeocodes.size())); @@ -148,38 +124,21 @@ class GpxExport extends AbstractExport { final File exportLocation = new File(Settings.getGpxExportDir()); exportLocation.mkdirs(); - final XmlSerializer gpx = new KXmlSerializer(); writer = new BufferedWriter(new FileWriter(exportFile)); - gpx.setOutput(writer); + new GpxSerializer().writeGPX(allGeocodes, writer, new GpxSerializer.ProgressListener() { - gpx.startDocument("UTF-8", true); - gpx.setPrefix("", PREFIX_GPX); - gpx.setPrefix("xsi", PREFIX_XSI); - gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK); - gpx.startTag(PREFIX_GPX, "gpx"); - gpx.attribute("", "version", "1.0"); - gpx.attribute("", "creator", "c:geo - http://www.cgeo.org/"); - gpx.attribute(PREFIX_XSI, "schemaLocation", - PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " + - PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd"); - - // Split the overall set of geocodes into small chunks. That is a compromise between memory efficiency (because - // we don't load all caches fully into memory) and speed (because we don't query each cache separately). - while (!allGeocodes.isEmpty()) { - final List<String> batch = allGeocodes.subList(0, Math.min(CACHES_PER_BATCH, allGeocodes.size())); - exportBatch(gpx, batch); - batch.clear(); - } - - gpx.endTag(PREFIX_GPX, "gpx"); - gpx.endDocument(); + @Override + public void publishProgress(int countExported) { + this.publishProgress(countExported); + } + }); } catch (final Exception e) { Log.e("GpxExport.ExportTask export", e); if (writer != null) { try { writer.close(); - } catch (IOException e1) { + } catch (final IOException e1) { // Ignore double error } } @@ -194,184 +153,13 @@ class GpxExport extends AbstractExport { return exportFile; } - private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException { - Set<Geocache> caches = cgData.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY); - for (Geocache cache : caches) { - gpx.startTag(PREFIX_GPX, "wpt"); - gpx.attribute("", "lat", Double.toString(cache.getCoords().getLatitude())); - gpx.attribute("", "lon", Double.toString(cache.getCoords().getLongitude())); - - final Date hiddenDate = cache.getHiddenDate(); - if (hiddenDate != null) { - XmlUtils.simpleText(gpx, PREFIX_GPX, "time", dateFormatZ.format(hiddenDate)); - } - - XmlUtils.multipleTexts(gpx, PREFIX_GPX, - "name", cache.getGeocode(), - "desc", cache.getName(), - "url", cache.getUrl(), - "urlname", cache.getName(), - "sym", cache.isFound() ? "Geocache Found" : "Geocache", - "type", "Geocache|" + cache.getType().pattern); - - gpx.startTag(PREFIX_GROUNDSPEAK, "cache"); - gpx.attribute("", "id", cache.getCacheId()); - gpx.attribute("", "available", !cache.isDisabled() ? "True" : "False"); - gpx.attribute("", "archives", cache.isArchived() ? "True" : "False"); - - XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, - "name", cache.getName(), - "placed_by", cache.getOwnerDisplayName(), - "owner", cache.getOwnerUserId(), - "type", cache.getType().pattern, - "container", cache.getSize().id, - "difficulty", Float.toString(cache.getDifficulty()), - "terrain", Float.toString(cache.getTerrain()), - "country", cache.getLocation(), - "state", "", - "encoded_hints", cache.getHint()); - - writeAttributes(gpx, cache); - - gpx.startTag(PREFIX_GROUNDSPEAK, "short_description"); - gpx.attribute("", "html", TextUtils.containsHtml(cache.getShortDescription()) ? "True" : "False"); - gpx.text(cache.getShortDescription()); - gpx.endTag(PREFIX_GROUNDSPEAK, "short_description"); - - gpx.startTag(PREFIX_GROUNDSPEAK, "long_description"); - gpx.attribute("", "html", TextUtils.containsHtml(cache.getDescription()) ? "True" : "False"); - gpx.text(cache.getDescription()); - gpx.endTag(PREFIX_GROUNDSPEAK, "long_description"); - - writeLogs(gpx, cache); - - gpx.endTag(PREFIX_GROUNDSPEAK, "cache"); - gpx.endTag(PREFIX_GPX, "wpt"); - - writeWaypoints(gpx, cache); - - countExported++; - publishProgress(countExported); - } - } - - private void writeWaypoints(final XmlSerializer gpx, final Geocache cache) throws IOException { - List<Waypoint> waypoints = cache.getWaypoints(); - List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size()); - List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size()); - for (Waypoint wp : cache.getWaypoints()) { - if (wp.isUserDefined()) { - ownWaypoints.add(wp); - } else { - originWaypoints.add(wp); - } - } - int maxPrefix = 0; - for (Waypoint wp : originWaypoints) { - String prefix = wp.getPrefix(); - try { - final int numericPrefix = Integer.parseInt(prefix); - maxPrefix = Math.max(numericPrefix, maxPrefix); - } catch (NumberFormatException ex) { - // ignore non numeric prefix, as it should be unique in the list of non-own waypoints already - } - writeCacheWaypoint(gpx, wp, prefix); - } - // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints - for (Waypoint wp : ownWaypoints) { - maxPrefix++; - String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0'); - writeCacheWaypoint(gpx, wp, prefix); - } - } - - /** - * Writes one waypoint entry for cache waypoint. - * - * @param cache - * The - * @param wp - * @param prefix - * @throws IOException - */ - private void writeCacheWaypoint(final XmlSerializer gpx, final Waypoint wp, final String prefix) throws IOException { - final Geopoint coords = wp.getCoords(); - // TODO: create some extension to GPX to include waypoint without coords - if (coords != null) { - gpx.startTag(PREFIX_GPX, "wpt"); - gpx.attribute("", "lat", Double.toString(coords.getLatitude())); - gpx.attribute("", "lon", Double.toString(coords.getLongitude())); - XmlUtils.multipleTexts(gpx, PREFIX_GPX, - "name", prefix + wp.getGeocode().substring(2), - "cmt", wp.getNote(), - "desc", wp.getName(), - "sym", wp.getWaypointType().toString(), //TODO: Correct identifier string - "type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string - gpx.endTag(PREFIX_GPX, "wpt"); - } - } - - private void writeLogs(final XmlSerializer gpx, final Geocache cache) throws IOException { - if (cache.getLogs().isEmpty()) { - return; - } - gpx.startTag(PREFIX_GROUNDSPEAK, "logs"); - - for (LogEntry log : cache.getLogs()) { - gpx.startTag(PREFIX_GROUNDSPEAK, "log"); - gpx.attribute("", "id", Integer.toString(log.id)); - - XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, - "date", dateFormatZ.format(new Date(log.date)), - "type", log.type.type); - - gpx.startTag(PREFIX_GROUNDSPEAK, "finder"); - gpx.attribute("", "id", ""); - gpx.text(log.author); - gpx.endTag(PREFIX_GROUNDSPEAK, "finder"); - - gpx.startTag(PREFIX_GROUNDSPEAK, "text"); - gpx.attribute("", "encoded", "False"); - gpx.text(log.log); - gpx.endTag(PREFIX_GROUNDSPEAK, "text"); - - gpx.endTag(PREFIX_GROUNDSPEAK, "log"); - } - - gpx.endTag(PREFIX_GROUNDSPEAK, "logs"); - } - - private void writeAttributes(final XmlSerializer gpx, final Geocache cache) throws IOException { - if (cache.getAttributes().isEmpty()) { - return; - } - //TODO: Attribute conversion required: English verbose name, gpx-id - gpx.startTag(PREFIX_GROUNDSPEAK, "attributes"); - - for (String attribute : cache.getAttributes()) { - final CacheAttribute attr = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attribute)); - if (attr == null) { - continue; - } - final boolean enabled = CacheAttribute.isEnabled(attribute); - - gpx.startTag(PREFIX_GROUNDSPEAK, "attribute"); - gpx.attribute("", "id", Integer.toString(attr.gcid)); - gpx.attribute("", "inc", enabled ? "1" : "0"); - gpx.text(attr.getL10n(enabled)); - gpx.endTag(PREFIX_GROUNDSPEAK, "attribute"); - } - - gpx.endTag(PREFIX_GROUNDSPEAK, "attributes"); - } - @Override protected void onPostExecuteInternal(final File exportFile) { if (null != activity) { if (exportFile != null) { ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); if (Settings.getShareAfterExport()) { - Intent shareIntent = new Intent(); + final Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportFile)); shareIntent.setType("application/xml"); |
