diff options
| author | Torsten Keil <github@torsten-keil.net> | 2012-01-16 23:39:44 +0100 |
|---|---|---|
| committer | Torsten Keil <github@torsten-keil.net> | 2012-01-16 23:39:44 +0100 |
| commit | e7ae5bf5173cf9eaeb6346ac365262514e44dedf (patch) | |
| tree | 82442f961e07e77d7839aa327df945932c3a5e15 | |
| parent | caff1b35567de0e4f2a0719e831c63a74252d901 (diff) | |
| download | cgeo-e7ae5bf5173cf9eaeb6346ac365262514e44dedf.zip cgeo-e7ae5bf5173cf9eaeb6346ac365262514e44dedf.tar.gz cgeo-e7ae5bf5173cf9eaeb6346ac365262514e44dedf.tar.bz2 | |
Implementation for #977: Import renamed waypoint GPX files
The new Method is based on the gpx file (not only the file name) and
checks all files in the directory for a matching filename.
Note: I updated (just implemented) a test method but couldn't already
test it. I'm working to get the tests running ... currently something
isn't configured right and i don't get it running.
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXImporter.java | 851 | ||||
| -rw-r--r-- | tests/src/cgeo/geocaching/files/GPXImporterTest.java | 19 |
2 files changed, 461 insertions, 409 deletions
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 7ee05ff..6e11679 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -1,409 +1,442 @@ -package cgeo.geocaching.files; - -import cgeo.geocaching.R; -import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.activity.IAbstractActivity; -import cgeo.geocaching.activity.Progress; -import cgeo.geocaching.utils.CancellableHandler; - -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 android.util.Log; - -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_CACHES = 3; - static final int IMPORT_STEP_FINISHED = 4; - static final int IMPORT_STEP_FINISHED_WITH_ERROR = 5; - static final int IMPORT_STEP_CANCEL = 6; - static final int IMPORT_STEP_CANCELED = 7; - - public static final String GPX_FILE_EXTENSION = ".gpx"; - public static final String ZIP_FILE_EXTENSION = ".zip"; - public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = "-wpts.gpx"; - - private static final List<String> GPX_MIME_TYPES = Arrays.asList(new String[] { "text/xml", "application/xml" }); - private static final List<String> ZIP_MIME_TYPES = Arrays.asList(new String[] { "application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream" }); - - private Progress progress = new Progress(); - - 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(Settings.tag, "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; - - public ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) { - this.listId = listId; - this.importStepHandler = importStepHandler; - this.progressHandler = progressHandler; - } - - @Override - public void run() { - final Collection<cgCache> caches; - try { - importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START)); - caches = doImport(); - - importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_CACHES, R.string.gpx_import_storing, caches.size())); - SearchResult search = storeParsedCaches(caches); - Log.i(Settings.tag, "Imported successfully " + caches.size() + " caches."); - - importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, SearchResult.getCount(search), 0, search)); - } catch (IOException e) { - Log.i(Settings.tag, "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(Settings.tag, "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(Settings.tag, "Importing caches canceled"); - importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED)); - } catch (Exception e) { - Log.e(Settings.tag, "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<cgCache> doImport() throws IOException, ParserException; - - private SearchResult storeParsedCaches(Collection<cgCache> caches) { - final SearchResult search = new SearchResult(); - final cgeoapplication app = cgeoapplication.getInstance(); - int storedCaches = 0; - for (cgCache cache : caches) { - // remove from cache because a cache might be re-imported - cgeoapplication.removeCacheFromCache(cache.getGeocode()); - app.addCacheToSearch(search, cache); - - // save memory, imported caches are typically not used immediately - cgeoapplication.removeCacheFromCache(cache.getGeocode()); - - if (progressHandler.isCancelled()) { - throw new CancellationException(); - } - progressHandler.sendMessage(progressHandler.obtainMessage(0, ++storedCaches, 0)); - } - return search; - } - } - - 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<cgCache> doImport() throws IOException, ParserException { - Log.i(Settings.tag, "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 { - - public ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) { - super(listId, importStepHandler, progressHandler); - } - - @Override - protected Collection<cgCache> 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<cgCache> 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<cgCache> doImport(GPXParser parser) throws IOException, ParserException { - Log.i(Settings.tag, "Import GPX file: " + cacheFile.getAbsolutePath()); - importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length())); - Collection<cgCache> caches = parser.parse(cacheFile, progressHandler); - - final File wptsFile = new File(cacheFile.getParentFile(), getWaypointsFileNameForGpxFileName(cacheFile.getName())); - if (wptsFile.canRead()) { - Log.i(Settings.tag, "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<cgCache> doImport(GPXParser parser) throws IOException, ParserException { - Log.i(Settings.tag, "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 { - - public ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) { - super(listId, importStepHandler, progressHandler); - } - - @Override - protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException { - Collection<cgCache> 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(Settings.tag, "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(Settings.tag, "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: - 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: - case IMPORT_STEP_STORE_CACHES: - progress.setMessage(res.getString(msg.arg1)); - progress.setMaxProgressAndReset(msg.arg2); - 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: - fromActivity.showShortToast(res.getString(R.string.gpx_import_canceled)); - importFinished(); - break; - - default: - break; - } - } - }; - - // 1234567.gpx -> 1234567-wpts.gpx - static String getWaypointsFileNameForGpxFileName(String name) { - if (StringUtils.endsWithIgnoreCase(name, GPX_FILE_EXTENSION) && (StringUtils.length(name) > GPX_FILE_EXTENSION.length())) { - return StringUtils.substringBeforeLast(name, ".") + WAYPOINTS_FILE_SUFFIX_AND_EXTENSION; - } else { - return null; - } - } - - protected void importFinished() { - if (importFinishedHandler != null) { - importFinishedHandler.sendEmptyMessage(0); - } - } -} +package cgeo.geocaching.files;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.activity.IAbstractActivity;
+import cgeo.geocaching.activity.Progress;
+import cgeo.geocaching.utils.CancellableHandler;
+
+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 android.util.Log;
+
+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_CACHES = 3;
+ static final int IMPORT_STEP_FINISHED = 4;
+ static final int IMPORT_STEP_FINISHED_WITH_ERROR = 5;
+ static final int IMPORT_STEP_CANCEL = 6;
+ static final int IMPORT_STEP_CANCELED = 7;
+
+ 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(new String[] { "text/xml", "application/xml" });
+ private static final List<String> ZIP_MIME_TYPES = Arrays.asList(new String[] { "application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream" });
+
+ private Progress progress = new Progress();
+
+ 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(Settings.tag, "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;
+
+ public ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ this.listId = listId;
+ this.importStepHandler = importStepHandler;
+ this.progressHandler = progressHandler;
+ }
+
+ @Override
+ public void run() {
+ final Collection<cgCache> caches;
+ try {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
+ caches = doImport();
+
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_CACHES, R.string.gpx_import_storing, caches.size()));
+ SearchResult search = storeParsedCaches(caches);
+ Log.i(Settings.tag, "Imported successfully " + caches.size() + " caches.");
+
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, SearchResult.getCount(search), 0, search));
+ } catch (IOException e) {
+ Log.i(Settings.tag, "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(Settings.tag, "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(Settings.tag, "Importing caches canceled");
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
+ } catch (Exception e) {
+ Log.e(Settings.tag, "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<cgCache> doImport() throws IOException, ParserException;
+
+ private SearchResult storeParsedCaches(Collection<cgCache> caches) {
+ final SearchResult search = new SearchResult();
+ final cgeoapplication app = cgeoapplication.getInstance();
+ int storedCaches = 0;
+ for (cgCache cache : caches) {
+ // remove from cache because a cache might be re-imported
+ cgeoapplication.removeCacheFromCache(cache.getGeocode());
+ app.addCacheToSearch(search, cache);
+
+ // save memory, imported caches are typically not used immediately
+ cgeoapplication.removeCacheFromCache(cache.getGeocode());
+
+ if (progressHandler.isCancelled()) {
+ throw new CancellationException();
+ }
+ progressHandler.sendMessage(progressHandler.obtainMessage(0, ++storedCaches, 0));
+ }
+ return search;
+ }
+ }
+
+ 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<cgCache> doImport() throws IOException, ParserException {
+ Log.i(Settings.tag, "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 {
+
+ public ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<cgCache> 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<cgCache> 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<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i(Settings.tag, "Import GPX file: " + cacheFile.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
+ Collection<cgCache> caches = parser.parse(cacheFile, progressHandler);
+
+ final File wptsFile = new File(cacheFile.getParentFile(), getWaypointsFileNameForGpxFile(cacheFile));
+ if (wptsFile.canRead()) {
+ Log.i(Settings.tag, "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<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i(Settings.tag, "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 {
+
+ public ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
+ Collection<cgCache> 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(Settings.tag, "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(Settings.tag, "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:
+ 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:
+ case IMPORT_STEP_STORE_CACHES:
+ progress.setMessage(res.getString(msg.arg1));
+ progress.setMaxProgressAndReset(msg.arg2);
+ 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:
+ fromActivity.showShortToast(res.getString(R.string.gpx_import_canceled));
+ importFinished();
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * @param name
+ * the gpx file name
+ * @return the expected file name of the waypoints file
+ *
+ * @deprecated use {@link #getWaypointsFileNameForGpxFile(File)} instead
+ */
+ @Deprecated
+ static String getWaypointsFileNameForGpxFileName(String name) {
+ if (StringUtils.endsWithIgnoreCase(name, GPX_FILE_EXTENSION) && (StringUtils.length(name) > GPX_FILE_EXTENSION.length())) {
+ return StringUtils.substringBeforeLast(name, ".") + WAYPOINTS_FILE_SUFFIX_AND_EXTENSION;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @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.lastIndexOfIgnoreCase(filename, WAYPOINTS_FILE_SUFFIX) == -1) {
+ 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);
+ }
+ }
+}
diff --git a/tests/src/cgeo/geocaching/files/GPXImporterTest.java b/tests/src/cgeo/geocaching/files/GPXImporterTest.java index 1bc3e25..681db0f 100644 --- a/tests/src/cgeo/geocaching/files/GPXImporterTest.java +++ b/tests/src/cgeo/geocaching/files/GPXImporterTest.java @@ -25,6 +25,7 @@ public class GPXImporterTest extends AbstractResourceInstrumentationTestCase { private int listId; private File tempDir; + @SuppressWarnings("deprecation") public static void testGetWaypointsFileNameForGpxFileName() { assertEquals("1234567-wpts.gpx", GPXImporter.getWaypointsFileNameForGpxFileName("1234567.gpx")); assertEquals("/mnt/sdcard/1234567-wpts.gpx", GPXImporter.getWaypointsFileNameForGpxFileName("/mnt/sdcard/1234567.gpx")); @@ -40,6 +41,24 @@ public class GPXImporterTest extends AbstractResourceInstrumentationTestCase { assertNull(GPXImporter.getWaypointsFileNameForGpxFileName(".gpx")); } + public void testGetWaypointsFileNameForGpxFile() { + String[] gpxFiles = new String[] { "1234567.gpx", "1.gpx", "1234567.9.gpx", + "1234567.GPX", "gpx.gpx.gpx", ".gpx", + "1234567_query.gpx", "123-4.gpx", "123(5).gpx" }; + String[] wptsFiles = new String[] { "1234567-wpts.gpx", "1-wpts.gpx", "1234567.9-wpts.gpx", + "1234567-wpts.GPX", "gpx.gpx-wpts.gpx", "-wpts.gpx", + "1234567_query-wpts.gpx", "123-wpts-4.gpx", "123-wpts(5).gpx" }; + for (int i = 0; i < gpxFiles.length; i++) { + String gpxFileName = gpxFiles[i]; + String wptsFileName = wptsFiles[i]; + File gpx = new File(tempDir, gpxFileName); + File wpts = new File(tempDir, wptsFileName); + assertEquals(wptsFileName, GPXImporter.getWaypointsFileNameForGpxFile(gpx)); + } + File gpx1 = new File(tempDir, "abc.gpx"); + assertNull(GPXImporter.getWaypointsFileNameForGpxFile(gpx1)); + } + public void testImportGpx() throws IOException { File gc31j2h = new File(tempDir, "gc31j2h.gpx"); copyResourceToFile(R.raw.gc31j2h, gc31j2h); |
