package cgeo.geocaching.export; import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringEscapeUtils; import android.app.Activity; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Environment; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; class GpxExport extends AbstractExport { private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/gpx-export"); private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); protected GpxExport() { super(getString(R.string.export_gpx)); } @Override public void export(final List caches, final Activity activity) { new ExportTask(caches, activity).execute((Void) null); } private class ExportTask extends AsyncTask { private final List caches; private final Activity activity; private final Progress progress = new Progress(); private File exportFile; /** * Instantiates and configures the task for exporting field notes. * * @param caches * The {@link List} of {@link cgCache} to be exported * @param activity * optional: Show a progress bar and toasts */ public ExportTask(final List caches, final Activity activity) { this.caches = caches; this.activity = activity; } @Override protected void onPreExecute() { if (null != activity) { progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); progress.setMaxProgressAndReset(caches.size()); } } @Override protected Boolean doInBackground(Void... params) { // quick check for being able to write the GPX file if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return false; } // FIXME: complete export is created in memory. That should be some file stream instead. final StringBuilder gpx = new StringBuilder(); gpx.append(""); gpx.append(""); try { for (int i = 0; i < caches.size(); i++) { cgCache cache = caches.get(i); if (!cache.isDetailed()) { cache = cgeoapplication.getInstance().loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); } gpx.append(""); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getGeocode())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getName())); gpx.append(""); gpx.append(""); gpx.append(cache.isFound() ? "Geocache Found" : "Geocache"); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml("Geocache|" + cache.getType().toString())); //TODO: Correct (english) string gpx.append(""); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getName())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getOwner())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getOwnerReal())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getType().toString())); //TODO: Correct (english) string gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getSize().toString())); //TODO: Correct (english) string gpx.append(""); if (cache.hasAttributes()) { //TODO: Attribute conversion required: English verbose name, gpx-id gpx.append(""); for (String attribute : cache.getAttributes()) { final CacheAttribute attr = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attribute)); final boolean enabled = CacheAttribute.isEnabled(attribute); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(attr.getL10n(enabled))); gpx.append(""); } gpx.append(""); } gpx.append(""); gpx.append(Float.toString(cache.getDifficulty())); gpx.append(""); gpx.append(""); gpx.append(Float.toString(cache.getTerrain())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getShortDescription())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getDescription())); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(cache.getHint())); gpx.append(""); gpx.append(""); //TODO: Waypoints if (cache.getLogs().size() > 0) { gpx.append(""); for (LogEntry log : cache.getLogs()) { gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(dateFormatZ.format(new Date(log.date)))); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(log.type.type)); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(log.author)); gpx.append(""); gpx.append(""); gpx.append(StringEscapeUtils.escapeXml(log.log)); gpx.append(""); gpx.append(""); } gpx.append(""); } gpx.append(""); publishProgress(i + 1); } } catch (Exception e) { Log.e("GpxExport.ExportTask generation", e); return false; } gpx.append(""); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { exportLocation.mkdirs(); SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".gpx"); OutputStream os = null; Writer fw = null; try { os = new FileOutputStream(exportFile); fw = new OutputStreamWriter(os, "UTF-8"); fw.write(gpx.toString()); } catch (IOException e) { Log.e("GpxExport.ExportTask export", e); return false; } finally { if (fw != null) { try { fw.close(); } catch (IOException e) { Log.e("GpxExport.ExportTask export", e); return false; } } } } else { return false; } return true; } @Override protected void onPostExecute(Boolean result) { if (null != activity) { progress.dismiss(); if (result) { ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); } else { ActivityMixin.showToast(activity, getString(R.string.export_failed)); } } } @Override protected void onProgressUpdate(Integer... status) { if (null != activity) { progress.setProgress(status[0]); } } } }