diff options
Diffstat (limited to 'main/src/cgeo/geocaching/files/GPXImporter.java')
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXImporter.java | 920 |
1 files changed, 462 insertions, 458 deletions
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index b8dcbb3..ff81fe1 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -1,458 +1,462 @@ -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; +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 (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())); + 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); + } + } +} |
