aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/files
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/files')
-rw-r--r--main/src/cgeo/geocaching/files/AbstractFileListActivity.java6
-rw-r--r--main/src/cgeo/geocaching/files/FileParser.java12
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java943
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java85
-rw-r--r--main/src/cgeo/geocaching/files/LocParser.java35
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java19
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java20
7 files changed, 581 insertions, 539 deletions
diff --git a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
index 5ff0d91..8b02eeb 100644
--- a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
+++ b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
@@ -89,7 +89,6 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
setTheme();
setContentView(R.layout.gpx);
- setTitle();
Bundle extras = getIntent().getExtras();
if (extras != null) {
@@ -146,11 +145,6 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
*/
protected abstract List<File> getBaseFolders();
- /**
- * Triggers the deriving class to set the title
- */
- protected abstract void setTitle();
-
private class SearchFilesThread extends Thread {
private final FileListSelector selector = new FileListSelector();
diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java
index 50b65a1..f979d74 100644
--- a/main/src/cgeo/geocaching/files/FileParser.java
+++ b/main/src/cgeo/geocaching/files/FileParser.java
@@ -2,7 +2,9 @@ package cgeo.geocaching.files;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.IOUtils;
+import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -16,7 +18,7 @@ import java.util.concurrent.CancellationException;
public abstract class FileParser {
/**
* Parses caches from input stream.
- *
+ *
* @param stream
* @param progressHandler
* for reporting parsing progress (in bytes read from input stream)
@@ -38,11 +40,11 @@ public abstract class FileParser {
* @throws ParserException
*/
public Collection<Geocache> parse(final File file, final CancellableHandler progressHandler) throws IOException, ParserException {
- FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));
try {
- return parse(fis, progressHandler);
+ return parse(stream, progressHandler);
} finally {
- fis.close();
+ IOUtils.closeQuietly(stream);
}
}
@@ -59,7 +61,7 @@ public abstract class FileParser {
}
return buffer;
} finally {
- input.close();
+ IOUtils.closeQuietly(input);
}
}
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index b8dcbb3..a1c04d7 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -1,458 +1,485 @@
-package cgeo.geocaching.files;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.R;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.Settings;
-import cgeo.geocaching.StaticMapsProvider;
-import cgeo.geocaching.cgData;
-import cgeo.geocaching.activity.IAbstractActivity;
-import cgeo.geocaching.activity.Progress;
-import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.utils.CancellableHandler;
-import cgeo.geocaching.utils.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-public class GPXImporter {
- static final int IMPORT_STEP_START = 0;
- static final int IMPORT_STEP_READ_FILE = 1;
- static final int IMPORT_STEP_READ_WPT_FILE = 2;
- static final int IMPORT_STEP_STORE_STATIC_MAPS = 4;
- static final int IMPORT_STEP_FINISHED = 5;
- static final int IMPORT_STEP_FINISHED_WITH_ERROR = 6;
- static final int IMPORT_STEP_CANCEL = 7;
- static final int IMPORT_STEP_CANCELED = 8;
- static final int IMPORT_STEP_STATIC_MAPS_SKIPPED = 9;
-
- public static final String GPX_FILE_EXTENSION = ".gpx";
- public static final String ZIP_FILE_EXTENSION = ".zip";
- public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
- public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
-
- private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
- private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
-
- private Progress progress = new Progress(true);
-
- private Resources res;
- private int listId;
- private IAbstractActivity fromActivity;
- private Handler importFinishedHandler;
-
- public GPXImporter(final IAbstractActivity fromActivity, final int listId, final Handler importFinishedHandler) {
- this.listId = listId;
- this.fromActivity = fromActivity;
- res = ((Activity) fromActivity).getResources();
- this.importFinishedHandler = importFinishedHandler;
- }
-
- /**
- * Import GPX file. Currently supports *.gpx, *.zip (containing gpx files, e.g. PQ queries) or *.loc files.
- *
- * @param file
- * the file to import
- */
- public void importGPX(final File file) {
- if (StringUtils.endsWithIgnoreCase(file.getName(), GPX_FILE_EXTENSION)) {
- new ImportGpxFileThread(file, listId, importStepHandler, progressHandler).start();
- } else if (StringUtils.endsWithIgnoreCase(file.getName(), ZIP_FILE_EXTENSION)) {
- new ImportGpxZipFileThread(file, listId, importStepHandler, progressHandler).start();
- } else {
- new ImportLocFileThread(file, listId, importStepHandler, progressHandler).start();
- }
- }
-
- /**
- * Import GPX provided via intent of activity that instantiated this GPXImporter.
- */
- public void importGPX() {
- final ContentResolver contentResolver = ((Activity) fromActivity).getContentResolver();
- final Intent intent = ((Activity) fromActivity).getIntent();
- final Uri uri = intent.getData();
-
- String mimeType = intent.getType();
- // if mimetype can't be determined (e.g. for emulators email app), derive it from uri file extension
- // contentResolver.getType(uri) doesn't help but throws exception for emulators email app
- // Permission Denial: reading com.android.email.provider.EmailProvider uri
- // Google search says: there is no solution for this problem
- // Gmail doesn't work at all, see #967
- if (mimeType == null) {
- if (StringUtils.endsWithIgnoreCase(uri.getPath(), GPX_FILE_EXTENSION)) {
- mimeType = "application/xml";
- } else {
- // if we can't determine a better type, default to zip import
- // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
- mimeType = "application/zip";
- }
- }
-
- Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
- if (GPX_MIME_TYPES.contains(mimeType)) {
- new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else if (ZIP_MIME_TYPES.contains(mimeType)) {
- new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- importFinished();
- }
- }
-
- static abstract class ImportThread extends Thread {
- final int listId;
- final Handler importStepHandler;
- final CancellableHandler progressHandler;
-
- protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- this.listId = listId;
- this.importStepHandler = importStepHandler;
- this.progressHandler = progressHandler;
- }
-
- @Override
- public void run() {
- try {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
- final Collection<Geocache> caches = doImport();
- Log.i("Imported successfully " + caches.size() + " caches.");
-
- final SearchResult search = new SearchResult();
- for (Geocache cache : caches) {
- search.addCache(cache);
- }
-
- if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
- boolean finishedWithoutCancel = importStaticMaps(search);
- // Skip last message if static maps where canceled
- if (!finishedWithoutCancel) {
- return;
- }
- }
-
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
- } catch (IOException e) {
- Log.i("Importing caches failed - error reading data: " + e.getMessage());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
- } catch (ParserException e) {
- Log.i("Importing caches failed - data format error" + e.getMessage());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
- } catch (CancellationException e) {
- Log.i("Importing caches canceled");
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
- } catch (Exception e) {
- Log.e("Importing caches failed - unknown error: ", e);
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
- }
- }
-
- protected abstract Collection<Geocache> doImport() throws IOException, ParserException;
-
- private boolean importStaticMaps(final SearchResult importedCaches) {
- int storedCacheMaps = 0;
- for (String geocode : importedCaches.getGeocodes()) {
- Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
- Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
- StaticMapsProvider.downloadMaps(cache);
- storedCacheMaps++;
- if (progressHandler.isCancelled()) {
- return false;
- }
- progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
- }
- return true;
- }
- }
-
- static class ImportLocFileThread extends ImportThread {
- private final File file;
-
- public ImportLocFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.file = file;
- }
-
- @Override
- protected Collection<Geocache> doImport() throws IOException, ParserException {
- Log.i("Import LOC file: " + file.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
- LocParser parser = new LocParser(listId);
- return parser.parse(file, progressHandler);
- }
- }
-
- static abstract class ImportGpxThread extends ImportThread {
-
- protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- }
-
- @Override
- protected Collection<Geocache> doImport() throws IOException, ParserException {
- try {
- // try to parse cache file as GPX 10
- return doImport(new GPX10Parser(listId));
- } catch (ParserException pe) {
- // didn't work -> lets try GPX11
- return doImport(new GPX11Parser(listId));
- }
- }
-
- protected abstract Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException;
- }
-
- static class ImportGpxFileThread extends ImportGpxThread {
- private final File cacheFile;
-
- public ImportGpxFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.cacheFile = file;
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
- Collection<Geocache> caches = parser.parse(cacheFile, progressHandler);
-
- final String wptsFilename = getWaypointsFileNameForGpxFile(cacheFile);
- if (wptsFilename != null) {
- final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
- if (wptsFile.canRead()) {
- Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
- caches = parser.parse(wptsFile, progressHandler);
- }
- }
- return caches;
- }
- }
-
- static class ImportGpxAttachmentThread extends ImportGpxThread {
- private final Uri uri;
- private ContentResolver contentResolver;
-
- public ImportGpxAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.uri = uri;
- this.contentResolver = contentResolver;
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i("Import GPX from uri: " + uri);
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
- InputStream is = contentResolver.openInputStream(uri);
- try {
- return parser.parse(is, progressHandler);
- } finally {
- is.close();
- }
- }
- }
-
- static abstract class ImportGpxZipThread extends ImportGpxThread {
-
- protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Collection<Geocache> caches = Collections.emptySet();
- // can't assume that GPX file comes before waypoint file in zip -> so we need two passes
- // 1. parse GPX files
- ZipInputStream zis = new ZipInputStream(getInputStream());
- try {
- for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
- if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), GPX_FILE_EXTENSION)) {
- if (!StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) zipEntry.getSize()));
- caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
- }
- } else {
- throw new ParserException("Imported zip is not a GPX zip file.");
- }
- zis.closeEntry();
- }
- } finally {
- zis.close();
- }
-
- // 2. parse waypoint files
- zis = new ZipInputStream(getInputStream());
- try {
- for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
- if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) zipEntry.getSize()));
- caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
- }
- zis.closeEntry();
- }
- } finally {
- zis.close();
- }
-
- return caches;
- }
-
- protected abstract InputStream getInputStream() throws IOException;
- }
-
- static class ImportGpxZipFileThread extends ImportGpxZipThread {
- private final File cacheFile;
-
- public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.cacheFile = file;
- Log.i("Import zipped GPX: " + file);
- }
-
- @Override
- protected InputStream getInputStream() throws IOException {
- return new FileInputStream(cacheFile);
- }
- }
-
- static class ImportGpxZipAttachmentThread extends ImportGpxZipThread {
- private final Uri uri;
- private ContentResolver contentResolver;
-
- public ImportGpxZipAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.uri = uri;
- this.contentResolver = contentResolver;
- Log.i("Import zipped GPX from uri: " + uri);
- }
-
- @Override
- protected InputStream getInputStream() throws IOException {
- return contentResolver.openInputStream(uri);
- }
- }
-
- final private CancellableHandler progressHandler = new CancellableHandler() {
- @Override
- public void handleRegularMessage(Message msg) {
- progress.setProgress(msg.arg1);
- }
- };
-
- final private Handler importStepHandler = new Handler() {
- private boolean showProgressAfterCancel = false;
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case IMPORT_STEP_START:
- Message cancelMessage = importStepHandler.obtainMessage(IMPORT_STEP_CANCEL);
- progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_reading_file), res.getString(R.string.gpx_import_loading_caches), ProgressDialog.STYLE_HORIZONTAL, cancelMessage);
- break;
-
- case IMPORT_STEP_READ_FILE:
- case IMPORT_STEP_READ_WPT_FILE:
- progress.setMessage(res.getString(msg.arg1));
- progress.setMaxProgressAndReset(msg.arg2);
- break;
-
- case IMPORT_STEP_STORE_STATIC_MAPS:
- progress.dismiss();
- Message skipMessage = importStepHandler.obtainMessage(IMPORT_STEP_STATIC_MAPS_SKIPPED, msg.arg2, 0);
- progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_static_maps), res.getString(R.string.gpx_import_store_static_maps), ProgressDialog.STYLE_HORIZONTAL, skipMessage);
- progress.setMaxProgressAndReset(msg.arg2);
- break;
-
- case IMPORT_STEP_STATIC_MAPS_SKIPPED:
- progress.dismiss();
- progressHandler.cancel();
- StringBuilder bufferSkipped = new StringBuilder(20);
- bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
- importFinished();
- break;
-
- case IMPORT_STEP_FINISHED:
- progress.dismiss();
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
- importFinished();
- break;
-
- case IMPORT_STEP_FINISHED_WITH_ERROR:
- progress.dismiss();
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_import_failed), res.getString(msg.arg1) + "\n\n" + msg.obj);
- importFinished();
- break;
-
- case IMPORT_STEP_CANCEL:
- progress.dismiss();
- progressHandler.cancel();
- break;
-
- case IMPORT_STEP_CANCELED:
- StringBuilder bufferCanceled = new StringBuilder(20);
- bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
- if (showProgressAfterCancel) {
- bufferCanceled.append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
- }
- fromActivity.showShortToast(bufferCanceled.toString());
- importFinished();
- break;
-
- default:
- break;
- }
- }
- };
-
- /**
- * @param gpxfile
- * the gpx file
- * @return the expected file name of the waypoints file
- */
- static String getWaypointsFileNameForGpxFile(final File gpxfile) {
- if (gpxfile == null || !gpxfile.canRead()) {
- return null;
- }
- final String gpxFileName = gpxfile.getName();
- File dir = gpxfile.getParentFile();
- String[] filenameList = dir.list();
- for (String filename : filenameList) {
- if (!StringUtils.containsIgnoreCase(filename, WAYPOINTS_FILE_SUFFIX)) {
- continue;
- }
- String expectedGpxFileName = StringUtils.substringBeforeLast(filename, WAYPOINTS_FILE_SUFFIX)
- + StringUtils.substringAfterLast(filename, WAYPOINTS_FILE_SUFFIX);
- if (gpxFileName.equals(expectedGpxFileName)) {
- return filename;
- }
- }
- return null;
- }
-
- protected void importFinished() {
- if (importFinishedHandler != null) {
- importFinishedHandler.sendEmptyMessage(0);
- }
- }
-}
+package cgeo.geocaching.files;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.StaticMapsProvider;
+import cgeo.geocaching.cgData;
+import cgeo.geocaching.activity.IAbstractActivity;
+import cgeo.geocaching.activity.Progress;
+import cgeo.geocaching.enumerations.LoadFlags;
+import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class GPXImporter {
+ static final int IMPORT_STEP_START = 0;
+ static final int IMPORT_STEP_READ_FILE = 1;
+ static final int IMPORT_STEP_READ_WPT_FILE = 2;
+ static final int IMPORT_STEP_STORE_STATIC_MAPS = 4;
+ static final int IMPORT_STEP_FINISHED = 5;
+ static final int IMPORT_STEP_FINISHED_WITH_ERROR = 6;
+ static final int IMPORT_STEP_CANCEL = 7;
+ static final int IMPORT_STEP_CANCELED = 8;
+ static final int IMPORT_STEP_STATIC_MAPS_SKIPPED = 9;
+
+ public static final String GPX_FILE_EXTENSION = ".gpx";
+ public static final String LOC_FILE_EXTENSION = ".loc";
+ public static final String ZIP_FILE_EXTENSION = ".zip";
+ public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
+ public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
+
+ private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
+ private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
+
+ private final Progress progress = new Progress(true);
+
+ private final Resources res;
+ private final int listId;
+ private final IAbstractActivity fromActivity;
+ private final Handler importFinishedHandler;
+
+ public GPXImporter(final IAbstractActivity fromActivity, final int listId, final Handler importFinishedHandler) {
+ this.listId = listId;
+ this.fromActivity = fromActivity;
+ res = ((Activity) fromActivity).getResources();
+ this.importFinishedHandler = importFinishedHandler;
+ }
+
+ /**
+ * Import GPX file. Currently supports *.gpx, *.zip (containing gpx files, e.g. PQ queries) or *.loc files.
+ *
+ * @param file
+ * the file to import
+ */
+ public void importGPX(final File file) {
+ if (StringUtils.endsWithIgnoreCase(file.getName(), GPX_FILE_EXTENSION)) {
+ new ImportGpxFileThread(file, listId, importStepHandler, progressHandler).start();
+ } else if (StringUtils.endsWithIgnoreCase(file.getName(), ZIP_FILE_EXTENSION)) {
+ new ImportGpxZipFileThread(file, listId, importStepHandler, progressHandler).start();
+ } else {
+ new ImportLocFileThread(file, listId, importStepHandler, progressHandler).start();
+ }
+ }
+
+ /**
+ * Import GPX provided via intent of activity that instantiated this GPXImporter.
+ */
+ public void importGPX() {
+ final ContentResolver contentResolver = ((Activity) fromActivity).getContentResolver();
+ final Intent intent = ((Activity) fromActivity).getIntent();
+ final Uri uri = intent.getData();
+
+ String mimeType = intent.getType();
+ // if mimetype can't be determined (e.g. for emulators email app), derive it from uri file extension
+ // contentResolver.getType(uri) doesn't help but throws exception for emulators email app
+ // Permission Denial: reading com.android.email.provider.EmailProvider uri
+ // Google search says: there is no solution for this problem
+ // Gmail doesn't work at all, see #967
+ if (mimeType == null) {
+ if (StringUtils.endsWithIgnoreCase(uri.getPath(), GPX_FILE_EXTENSION) || StringUtils.endsWithIgnoreCase(uri.getPath(), LOC_FILE_EXTENSION)) {
+ mimeType = "application/xml";
+ } else {
+ // if we can't determine a better type, default to zip import
+ // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
+ mimeType = "application/zip";
+ }
+ }
+
+ Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
+ if (GPX_MIME_TYPES.contains(mimeType)) {
+ if (StringUtils.endsWithIgnoreCase(uri.getPath(), LOC_FILE_EXTENSION)) {
+ new ImportLocAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ } else {
+ new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ }
+ } else if (ZIP_MIME_TYPES.contains(mimeType)) {
+ new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ } else {
+ importFinished();
+ }
+ }
+
+ static abstract class ImportThread extends Thread {
+ final int listId;
+ final Handler importStepHandler;
+ final CancellableHandler progressHandler;
+
+ protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ this.listId = listId;
+ this.importStepHandler = importStepHandler;
+ this.progressHandler = progressHandler;
+ }
+
+ @Override
+ public void run() {
+ try {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
+ final Collection<Geocache> caches = doImport();
+ Log.i("Imported successfully " + caches.size() + " caches.");
+
+ final SearchResult search = new SearchResult(caches);
+ // Do not put imported caches into the cachecache. That would consume lots of memory for no benefit.
+
+ if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
+ final boolean finishedWithoutCancel = importStaticMaps(search);
+ // Skip last message if static maps where canceled
+ if (!finishedWithoutCancel) {
+ return;
+ }
+ }
+
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
+ } catch (final IOException e) {
+ Log.i("Importing caches failed - error reading data: ", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
+ } catch (final ParserException e) {
+ Log.i("Importing caches failed - data format error", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
+ } catch (final CancellationException e) {
+ Log.i("Importing caches canceled");
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
+ } catch (final Exception e) {
+ Log.e("Importing caches failed - unknown error: ", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
+ }
+ }
+
+ protected abstract Collection<Geocache> doImport() throws IOException, ParserException;
+
+ private boolean importStaticMaps(final SearchResult importedCaches) {
+ int storedCacheMaps = 0;
+ for (final String geocode : importedCaches.getGeocodes()) {
+ final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ if (cache != null) {
+ Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
+ StaticMapsProvider.downloadMaps(cache);
+ } else {
+ Log.d("GPXImporter.ImportThread.importStaticMaps: no data found for " + geocode);
+ }
+ storedCacheMaps++;
+ if (progressHandler.isCancelled()) {
+ return false;
+ }
+ progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
+ }
+ return true;
+ }
+ }
+
+ static class ImportLocFileThread extends ImportThread {
+ private final File file;
+
+ public ImportLocFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.file = file;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ Log.i("Import LOC file: " + file.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
+ final LocParser parser = new LocParser(listId);
+ return parser.parse(file, progressHandler);
+ }
+ }
+
+ static class ImportLocAttachmentThread extends ImportThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportLocAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ Log.i("Import LOC from uri: " + uri);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
+ final InputStream is = contentResolver.openInputStream(uri);
+ final LocParser parser = new LocParser(listId);
+ try {
+ return parser.parse(is, progressHandler);
+ } finally {
+ is.close();
+ }
+ }
+ }
+
+ static abstract class ImportGpxThread extends ImportThread {
+
+ protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ try {
+ // try to parse cache file as GPX 10
+ return doImport(new GPX10Parser(listId));
+ } catch (final ParserException pe) {
+ // didn't work -> lets try GPX11
+ return doImport(new GPX11Parser(listId));
+ }
+ }
+
+ protected abstract Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException;
+ }
+
+ static class ImportGpxFileThread extends ImportGpxThread {
+ private final File cacheFile;
+
+ public ImportGpxFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.cacheFile = file;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
+ Collection<Geocache> caches = parser.parse(cacheFile, progressHandler);
+
+ final String wptsFilename = getWaypointsFileNameForGpxFile(cacheFile);
+ if (wptsFilename != null) {
+ final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
+ if (wptsFile.canRead()) {
+ Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
+ caches = parser.parse(wptsFile, progressHandler);
+ }
+ }
+ return caches;
+ }
+ }
+
+ static class ImportGpxAttachmentThread extends ImportGpxThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportGpxAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i("Import GPX from uri: " + uri);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
+ final InputStream is = contentResolver.openInputStream(uri);
+ try {
+ return parser.parse(is, progressHandler);
+ } finally {
+ is.close();
+ }
+ }
+ }
+
+ static abstract class ImportGpxZipThread extends ImportGpxThread {
+
+ protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Collection<Geocache> caches = Collections.emptySet();
+ // can't assume that GPX file comes before waypoint file in zip -> so we need two passes
+ // 1. parse GPX files
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(getInputStream()));
+ try {
+ for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
+ if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), GPX_FILE_EXTENSION)) {
+ if (!StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) zipEntry.getSize()));
+ caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
+ }
+ } else {
+ throw new ParserException("Imported zip is not a GPX zip file.");
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+
+ // 2. parse waypoint files
+ zis = new ZipInputStream(new BufferedInputStream(getInputStream()));
+ try {
+ for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
+ if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) zipEntry.getSize()));
+ caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+
+ return caches;
+ }
+
+ protected abstract InputStream getInputStream() throws IOException;
+ }
+
+ static class ImportGpxZipFileThread extends ImportGpxZipThread {
+ private final File cacheFile;
+
+ public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.cacheFile = file;
+ Log.i("Import zipped GPX: " + file);
+ }
+
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ return new FileInputStream(cacheFile);
+ }
+ }
+
+ static class ImportGpxZipAttachmentThread extends ImportGpxZipThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportGpxZipAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ Log.i("Import zipped GPX from uri: " + uri);
+ }
+
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ return contentResolver.openInputStream(uri);
+ }
+ }
+
+ final private CancellableHandler progressHandler = new CancellableHandler() {
+ @Override
+ public void handleRegularMessage(Message msg) {
+ progress.setProgress(msg.arg1);
+ }
+ };
+
+ final private Handler importStepHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case IMPORT_STEP_START:
+ final Message cancelMessage = importStepHandler.obtainMessage(IMPORT_STEP_CANCEL);
+ progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_reading_file), res.getString(R.string.gpx_import_loading_caches), ProgressDialog.STYLE_HORIZONTAL, cancelMessage);
+ break;
+
+ case IMPORT_STEP_READ_FILE:
+ case IMPORT_STEP_READ_WPT_FILE:
+ progress.setMessage(res.getString(msg.arg1));
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
+ case IMPORT_STEP_STORE_STATIC_MAPS:
+ progress.dismiss();
+ final Message skipMessage = importStepHandler.obtainMessage(IMPORT_STEP_STATIC_MAPS_SKIPPED, msg.arg2, 0);
+ progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_static_maps), res.getString(R.string.gpx_import_store_static_maps), ProgressDialog.STYLE_HORIZONTAL, skipMessage);
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
+ case IMPORT_STEP_STATIC_MAPS_SKIPPED:
+ progress.dismiss();
+ progressHandler.cancel();
+ final StringBuilder bufferSkipped = new StringBuilder(20);
+ bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
+ importFinished();
+ break;
+
+ case IMPORT_STEP_FINISHED:
+ progress.dismiss();
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
+ importFinished();
+ break;
+
+ case IMPORT_STEP_FINISHED_WITH_ERROR:
+ progress.dismiss();
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_import_failed), res.getString(msg.arg1) + "\n\n" + msg.obj);
+ importFinished();
+ break;
+
+ case IMPORT_STEP_CANCEL:
+ progress.dismiss();
+ progressHandler.cancel();
+ break;
+
+ case IMPORT_STEP_CANCELED:
+ final StringBuilder bufferCanceled = new StringBuilder(20);
+ bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
+ fromActivity.showShortToast(bufferCanceled.toString());
+ importFinished();
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * @param gpxfile
+ * the gpx file
+ * @return the expected file name of the waypoints file
+ */
+ static String getWaypointsFileNameForGpxFile(final File gpxfile) {
+ if (gpxfile == null || !gpxfile.canRead()) {
+ return null;
+ }
+ final String gpxFileName = gpxfile.getName();
+ final File dir = gpxfile.getParentFile();
+ final String[] filenameList = dir.list();
+ for (final String filename : filenameList) {
+ if (!StringUtils.containsIgnoreCase(filename, WAYPOINTS_FILE_SUFFIX)) {
+ continue;
+ }
+ final String expectedGpxFileName = StringUtils.substringBeforeLast(filename, WAYPOINTS_FILE_SUFFIX)
+ + StringUtils.substringAfterLast(filename, WAYPOINTS_FILE_SUFFIX);
+ if (gpxFileName.equals(expectedGpxFileName)) {
+ return filename;
+ }
+ }
+ return null;
+ }
+
+ protected void importFinished() {
+ if (importFinishedHandler != null) {
+ importFinishedHandler.sendEmptyMessage(0);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 96c90cc..76e3713 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -54,13 +54,13 @@ public abstract class GPXParser extends FileParser {
/**
* Attention: case sensitive geocode pattern to avoid matching normal words in the name or description of the cache.
*/
- private static final Pattern patternGeocode = Pattern.compile("([A-Z][0-9A-Z]+)");
- private static final Pattern patternGuid = Pattern.compile(".*" + Pattern.quote("guid=") + "([0-9a-z\\-]+)", Pattern.CASE_INSENSITIVE);
- private static final Pattern patternUrlGeocode = Pattern.compile(".*" + Pattern.quote("wp=") + "([A-Z][0-9A-Z]+)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern PATTERN_GEOCODE = Pattern.compile("([A-Z][0-9A-Z]+)");
+ private static final Pattern PATTERN_GUID = Pattern.compile(".*" + Pattern.quote("guid=") + "([0-9a-z\\-]+)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern PATTERN_URL_GEOCODE = Pattern.compile(".*" + Pattern.quote("wp=") + "([A-Z][0-9A-Z]+)", Pattern.CASE_INSENSITIVE);
/**
* supported groundspeak extensions of the GPX format
*/
- private static final String[] nsGCList = new String[] {
+ private static final String[] GROUNDSPEAK_NAMESPACE = new String[] {
"http://www.groundspeak.com/cache/1/1", // PQ 1.1
"http://www.groundspeak.com/cache/1/0/1", // PQ 1.0.1
"http://www.groundspeak.com/cache/1/0", // PQ 1.0
@@ -183,6 +183,7 @@ public abstract class GPXParser extends FileParser {
R.string.attribute_treeclimbing_yes, // 64
R.string.attribute_frontyard_yes, // 65
R.string.attribute_teamwork_yes, // 66
+ R.string.attribute_geotour_yes, // 67
};
private static final String YES = "_yes";
private static final String NO = "_no";
@@ -205,7 +206,7 @@ public abstract class GPXParser extends FileParser {
String stringName;
try {
stringName = cgeoapplication.getInstance().getResources().getResourceName(stringId);
- } catch (NullPointerException e) {
+ } catch (final NullPointerException e) {
return null;
}
if (stringName == null) {
@@ -271,7 +272,7 @@ public abstract class GPXParser extends FileParser {
Double.valueOf(longitude)));
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse waypoint's latitude and/or longitude.");
}
}
@@ -295,11 +296,7 @@ public abstract class GPXParser extends FileParser {
}
}
- if (StringUtils.isNotBlank(cache.getGeocode())
- && cache.getCoords() != null
- && ((type == null && sym == null)
- || StringUtils.contains(type, "geocache")
- || StringUtils.contains(sym, "geocache"))) {
+ if (isValidForImport()) {
fixCache(cache);
cache.setListId(listId);
cache.setDetailed(true);
@@ -316,6 +313,8 @@ public abstract class GPXParser extends FileParser {
// finally store the cache in the database
result.add(geocode);
cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
+
+ // avoid the cachecache using lots of memory for caches which the user did not actually look at
cgData.removeAllFromCache();
showProgressMessage(progressHandler, progressStream.getProgress());
} else if (StringUtils.isNotBlank(cache.getName())
@@ -364,7 +363,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setHidden(parseDate(body));
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse cache date", e);
}
}
@@ -435,27 +434,38 @@ public abstract class GPXParser extends FileParser {
@Override
public void end(String url) {
- final MatcherWrapper matcher = new MatcherWrapper(patternGuid, url);
+ final MatcherWrapper matcher = new MatcherWrapper(PATTERN_GUID, url);
if (matcher.matches()) {
final String guid = matcher.group(1);
if (StringUtils.isNotBlank(guid)) {
cache.setGuid(guid);
}
}
- final MatcherWrapper matcherCode = new MatcherWrapper(patternUrlGeocode, url);
+ final MatcherWrapper matcherCode = new MatcherWrapper(PATTERN_URL_GEOCODE, url);
if (matcherCode.matches()) {
- String geocode = matcherCode.group(1);
+ final String geocode = matcherCode.group(1);
cache.setGeocode(geocode);
}
}
});
+ // waypoint.urlname (name for waymarks)
+ waypoint.getChild(namespace, "urlname").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String urlName) {
+ if (cache.getName().equals(cache.getGeocode()) && StringUtils.startsWith(cache.getGeocode(), "WM")) {
+ cache.setName(StringUtils.trim(urlName));
+ }
+ }
+ });
+
// for GPX 1.0, cache info comes from waypoint node (so called private children,
// for GPX 1.1 from extensions node
final Element cacheParent = getCacheParent(waypoint);
// GSAK extensions
- for (String gsakNamespace : GSAK_NS) {
+ for (final String gsakNamespace : GSAK_NS) {
final Element gsak = cacheParent.getChild(gsakNamespace, "wptExtension");
gsak.getChild(gsakNamespace, "Watch").setEndTextElementListener(new EndTextElementListener() {
@@ -473,7 +483,7 @@ public abstract class GPXParser extends FileParser {
}
// 3 different versions of the GC schema
- for (String nsGC : nsGCList) {
+ for (final String nsGC : GROUNDSPEAK_NAMESPACE) {
// waypoints.cache
final Element gcCache = cacheParent.getChild(nsGC, "cache");
@@ -491,7 +501,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("available") > -1) {
cache.setDisabled(!attrs.getValue("available").equalsIgnoreCase("true"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse cache attributes.");
}
}
@@ -560,14 +570,14 @@ public abstract class GPXParser extends FileParser {
public void start(Attributes attrs) {
try {
if (attrs.getIndex("id") > -1 && attrs.getIndex("inc") > -1) {
- int attributeId = Integer.parseInt(attrs.getValue("id"));
- boolean attributeActive = Integer.parseInt(attrs.getValue("inc")) != 0;
- String internalId = CacheAttributeTranslator.getInternalId(attributeId, attributeActive);
+ final int attributeId = Integer.parseInt(attrs.getValue("id"));
+ final boolean attributeActive = Integer.parseInt(attrs.getValue("inc")) != 0;
+ final String internalId = CacheAttributeTranslator.getInternalId(attributeId, attributeActive);
if (internalId != null) {
cache.getAttributes().add(internalId);
}
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
// nothing
}
}
@@ -580,7 +590,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setDifficulty(Float.parseFloat(body));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.w("Failed to parse difficulty", e);
}
}
@@ -593,7 +603,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setTerrain(Float.parseFloat(body));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.w("Failed to parse terrain", e);
}
}
@@ -617,7 +627,7 @@ public abstract class GPXParser extends FileParser {
@Override
public void end(String state) {
- String trimmedState = state.trim();
+ final String trimmedState = state.trim();
if (StringUtils.isNotEmpty(trimmedState)) { // state can be completely empty
if (StringUtils.isBlank(cache.getLocation())) {
cache.setLocation(validate(state));
@@ -670,7 +680,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("ref") > -1) {
trackable.setGeocode(attrs.getValue("ref"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing
}
}
@@ -714,7 +724,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("id") > -1) {
log.id = Integer.parseInt(attrs.getValue("id"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing
}
}
@@ -737,7 +747,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
log.date = parseDate(body).getTime();
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse log date", e);
}
}
@@ -776,7 +786,7 @@ public abstract class GPXParser extends FileParser {
progressStream = new ProgressInputStream(stream);
Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler());
return cgData.loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL));
- } catch (SAXException e) {
+ } catch (final SAXException e) {
Log.w("Cannot parse .gpx file as GPX " + version + ": could not parse XML - ", e);
throw new ParserException("Cannot parse .gpx file as GPX " + version + ": could not parse XML", e);
}
@@ -823,7 +833,7 @@ public abstract class GPXParser extends FileParser {
return WaypointType.FINAL;
}
// this is not fully correct, but lets also look for localized waypoint types
- for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
+ for (final WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
final String localized = waypointType.getL10n();
if (StringUtils.isNotEmpty(localized)) {
if (localized.equalsIgnoreCase(sym)) {
@@ -839,7 +849,7 @@ public abstract class GPXParser extends FileParser {
return;
}
final String trimmed = input.trim();
- final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, trimmed);
+ final MatcherWrapper matcherGeocode = new MatcherWrapper(PATTERN_GEOCODE, trimmed);
if (matcherGeocode.find()) {
final String geocode = matcherGeocode.group(1);
// a geocode should not be part of a word
@@ -891,4 +901,17 @@ public abstract class GPXParser extends FileParser {
}
}
}
+
+ private boolean isValidForImport() {
+ if (StringUtils.isBlank(cache.getGeocode())) {
+ return false;
+ }
+ if (cache.getCoords() == null) {
+ return false;
+ }
+ return ((type == null && sym == null)
+ || StringUtils.contains(type, "geocache")
+ || StringUtils.contains(sym, "geocache")
+ || StringUtils.containsIgnoreCase(sym, "waymark"));
+ }
}
diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java
index fe290c3..1cfb2a3 100644
--- a/main/src/cgeo/geocaching/files/LocParser.java
+++ b/main/src/cgeo/geocaching/files/LocParser.java
@@ -27,19 +27,13 @@ import java.util.regex.Pattern;
public final class LocParser extends FileParser {
+ private static final String NAME_OWNER_SEPARATOR = " by ";
private static final Pattern patternGeocode = Pattern
.compile("name id=\"([^\"]+)\"");
private static final Pattern patternLat = Pattern
.compile("lat=\"([^\"]+)\"");
private static final Pattern patternLon = Pattern
.compile("lon=\"([^\"]+)\"");
- // premium only >>
- private static final Pattern patternDifficulty = Pattern
- .compile("<difficulty>([^<]+)</difficulty>");
- private static final Pattern patternTerrain = Pattern
- .compile("<terrain>([^<]+)</terrain>");
- private static final Pattern patternContainer = Pattern
- .compile("<container>([^<]+)</container>");
private static final Pattern patternName = Pattern.compile("CDATA\\[([^\\]]+)\\]");
private static final CacheSize[] SIZES = {
@@ -82,6 +76,7 @@ public final class LocParser extends FileParser {
if (StringUtils.isBlank(cache.getName())) {
cache.setName(coord.getName());
}
+ cache.setOwnerUserId(coord.getOwnerUserId());
}
static Map<String, Geocache> parseCoordinates(final String fileContent) {
@@ -110,7 +105,7 @@ public final class LocParser extends FileParser {
try {
return new Geopoint(Double.valueOf(latitude), Double.valueOf(longitude));
} catch (NumberFormatException e) {
- Log.e("LOC format has changed");
+ Log.e("LOC format has changed", e);
}
// fall back to parser, just in case the format changes
return new Geopoint(latitude, longitude);
@@ -156,7 +151,11 @@ public final class LocParser extends FileParser {
final MatcherWrapper matcherName = new MatcherWrapper(patternName, pointString);
if (matcherName.find()) {
final String name = matcherName.group(1).trim();
- cache.setName(StringUtils.substringBeforeLast(name, " by ").trim());
+ String ownerName = StringUtils.trim(StringUtils.substringAfterLast(name, NAME_OWNER_SEPARATOR));
+ if (StringUtils.isEmpty(cache.getOwnerUserId()) && StringUtils.isNotEmpty(ownerName)) {
+ cache.setOwnerUserId(ownerName);
+ }
+ cache.setName(StringUtils.substringBeforeLast(name, NAME_OWNER_SEPARATOR).trim());
} else {
cache.setName(cache.getGeocode());
}
@@ -167,20 +166,20 @@ public final class LocParser extends FileParser {
cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim()));
}
- final MatcherWrapper matcherDifficulty = new MatcherWrapper(patternDifficulty, pointString);
+ final String difficulty = StringUtils.substringBetween(pointString, "<difficulty>", "</difficulty>");
+ final String terrain = StringUtils.substringBetween(pointString, "<terrain>", "</terrain>");
+ final String container = StringUtils.substringBetween(pointString, "<container>", "</container");
try {
- if (matcherDifficulty.find()) {
- cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim()));
+ if (StringUtils.isNotBlank(difficulty)) {
+ cache.setDifficulty(Float.parseFloat(difficulty.trim()));
}
- final MatcherWrapper matcherTerrain = new MatcherWrapper(patternTerrain, pointString);
- if (matcherTerrain.find()) {
- cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim()));
+ if (StringUtils.isNotBlank(terrain)) {
+ cache.setTerrain(Float.parseFloat(terrain.trim()));
}
- final MatcherWrapper matcherContainer = new MatcherWrapper(patternContainer, pointString);
- if (matcherContainer.find()) {
- final int size = Integer.parseInt(matcherContainer.group(1).trim());
+ if (StringUtils.isNotBlank(container)) {
+ final int size = Integer.parseInt(container.trim());
if (size >= 1 && size <= 8) {
cache.setSize(SIZES[size - 1]);
}
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index f59f15c..0f3e0e1 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -2,14 +2,18 @@ package cgeo.geocaching.files;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.utils.CryptUtils;
+import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpResponse;
+
import org.apache.commons.lang3.StringUtils;
import android.os.Environment;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -275,19 +279,14 @@ public class LocalStorage {
destination.getParentFile().mkdirs();
InputStream input = null;
- OutputStream output;
+ OutputStream output = null;
try {
- input = new FileInputStream(source);
- output = new FileOutputStream(destination);
+ input = new BufferedInputStream(new FileInputStream(source));
+ output = new BufferedOutputStream(new FileOutputStream(destination));
} catch (FileNotFoundException e) {
Log.e("LocalStorage.copy: could not open file", e);
- if (input != null) {
- try {
- input.close();
- } catch (IOException e1) {
- // ignore
- }
- }
+ IOUtils.closeQuietly(input);
+ IOUtils.closeQuietly(output);
return false;
}
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 7520e2e..6b2366c 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -2,11 +2,11 @@ package cgeo.geocaching.files;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
+import cgeo.geocaching.activity.AbstractListActivity;
import cgeo.geocaching.activity.ActivityMixin;
import org.apache.commons.lang3.StringUtils;
-import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -31,7 +31,7 @@ import java.util.List;
/**
* Dialog for choosing a file or directory.
*/
-public class SimpleDirChooser extends ListActivity {
+public class SimpleDirChooser extends AbstractListActivity {
private static final String PARENT_DIR = ".. ";
private File currentDir;
private FileArrayAdapter adapter;
@@ -46,7 +46,6 @@ public class SimpleDirChooser extends ListActivity {
ActivityMixin.setTheme(this);
setContentView(R.layout.simple_dir_chooser);
- setTitle(this.getResources().getString(R.string.simple_dir_chooser_title));
fill(currentDir);
@@ -106,13 +105,13 @@ public class SimpleDirChooser extends ListActivity {
public class FileArrayAdapter extends ArrayAdapter<Option> {
- private Context content;
+ private Context context;
private int id;
private List<Option> items;
public FileArrayAdapter(Context context, int simpleDirItemResId, List<Option> objects) {
super(context, simpleDirItemResId, objects);
- this.content = context;
+ this.context = context;
this.id = simpleDirItemResId;
this.items = objects;
}
@@ -126,7 +125,7 @@ public class SimpleDirChooser extends ListActivity {
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
- LayoutInflater vi = (LayoutInflater) content.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
@@ -187,13 +186,12 @@ public class SimpleDirChooser extends ListActivity {
if (currentOption != lastOption) {
currentOption.setChecked(true);
lastPosition = position;
- okButton.setEnabled(true);
- okButton.setVisibility(View.VISIBLE);
} else {
lastPosition = -1;
- okButton.setEnabled(false);
- okButton.setVisibility(View.INVISIBLE);
}
+ final boolean enabled = currentOption.isChecked() && !currentOption.getName().equals(PARENT_DIR);
+ okButton.setEnabled(enabled);
+ okButton.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
adapter.notifyDataSetChanged();
}
}
@@ -238,7 +236,7 @@ public class SimpleDirChooser extends ListActivity {
@Override
public boolean accept(File dir, String filename) {
File file = new File(dir, filename);
- return file.isDirectory();
+ return file.isDirectory() && file.canWrite();
}
}