package cgeo.geocaching.export; import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.R; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.models.Geocache; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.storage.LocalStorage; import cgeo.geocaching.utils.AsyncTaskWithProgress; import cgeo.geocaching.utils.EnvironmentUtils; import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.ShareUtils; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; import butterknife.ButterKnife; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.CharEncoding; public class GpxExport extends AbstractExport { private String fileName = "geocache.gpx"; // used in tests public GpxExport() { super(R.string.export_gpx); } @Override public void export(@NonNull final List<Geocache> caches, @Nullable final Activity activity) { final String[] geocodes = getGeocodes(caches); calculateFileName(geocodes); if (activity == null) { // No activity given, so no user interaction possible. // Start export with default parameters. new ExportTask(null).execute(geocodes); } else { // Show configuration dialog getExportDialog(geocodes, activity).show(); } } private void calculateFileName(final String[] geocodes) { if (geocodes.length == 1) { // geocode as file name fileName = geocodes[0] + ".gpx"; } else { // date and time as file name final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US); fileName = "export_" + fileNameDateFormat.format(new Date()) + ".gpx"; } fileName = FileUtils.getUniqueNamedFile(new File(Settings.getGpxExportDir(), fileName)).getName(); } private Dialog getExportDialog(final String[] geocodes, final Activity activity) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(activity.getString(R.string.export_confirm_title, activity.getString(R.string.export_gpx))); final View layout = View.inflate(activity, R.layout.gpx_export_dialog, null); builder.setView(layout); final TextView text = ButterKnife.findById(layout, R.id.info); text.setText(activity.getString(R.string.export_confirm_message, Settings.getGpxExportDir(), fileName)); final CheckBox shareOption = ButterKnife.findById(layout, R.id.share); shareOption.setChecked(Settings.getShareAfterExport()); final CheckBox includeFoundStatus = ButterKnife.findById(layout, R.id.include_found_status); includeFoundStatus.setChecked(Settings.getIncludeFoundStatus()); builder.setPositiveButton(R.string.export, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { Settings.setShareAfterExport(shareOption.isChecked()); Settings.setIncludeFoundStatus(includeFoundStatus.isChecked()); dialog.dismiss(); new ExportTask(activity).execute(geocodes); } }); return builder.create(); } private static String[] getGeocodes(final List<Geocache> caches) { return Geocache.getGeocodes(caches).toArray(new String[caches.size()]); } protected class ExportTask extends AsyncTaskWithProgress<String, File> { /** * Instantiates and configures the task for exporting field notes. * * @param activity * optional: Show a progress bar and toasts */ public ExportTask(final Activity activity) { super(activity, getProgressTitle()); } private File getExportFile() { return FileUtils.getUniqueNamedFile(new File(LocalStorage.getGpxExportDirectory(), fileName)); } @Override protected File doInBackgroundInternal(final String[] geocodes) { // quick check for being able to write the GPX file if (!EnvironmentUtils.isExternalStorageAvailable()) { return null; } final List<String> allGeocodes = new ArrayList<>(Arrays.asList(geocodes)); setMessage(CgeoApplication.getInstance().getResources().getQuantityString(R.plurals.cache_counts, allGeocodes.size(), allGeocodes.size())); final File exportFile = getExportFile(); BufferedWriter writer = null; try { final File exportLocation = LocalStorage.getGpxExportDirectory(); FileUtils.mkdirs(exportLocation); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exportFile), CharEncoding.UTF_8)); new GpxSerializer().writeGPX(allGeocodes, writer, new GpxSerializer.ProgressListener() { @Override public void publishProgress(final int countExported) { ExportTask.this.publishProgress(countExported); } }); } catch (final IOException e) { Log.e("GpxExport.ExportTask export", e); IOUtils.closeQuietly(writer); // delete partial GPX file on error if (exportFile.exists()) { FileUtils.deleteIgnoringFailure(exportFile); } return null; } return exportFile; } @Override protected void onPostExecuteInternal(final File exportFile) { final Activity activityLocal = activity; if (activityLocal != null) { if (exportFile != null) { ActivityMixin.showToast(activityLocal, getName() + ' ' + activityLocal.getString(R.string.export_exportedto) + ": " + exportFile.toString()); if (Settings.getShareAfterExport()) { ShareUtils.share(activityLocal, exportFile, "application/xml", R.string.export_gpx_to); } } else { ActivityMixin.showToast(activityLocal, activityLocal.getString(R.string.export_failed)); } } } } }