diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2014-01-03 14:50:10 +0100 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2014-01-03 14:50:10 +0100 |
| commit | db0a4fb12caf8744bbb5f7f6fbf9763368af8335 (patch) | |
| tree | ee234a16e55311e109e01a1034cef5bb02c0397d /main/src | |
| parent | ccc7e82afed6c4ae6f8334a2ab05ff8acf543483 (diff) | |
| download | cgeo-db0a4fb12caf8744bbb5f7f6fbf9763368af8335.zip cgeo-db0a4fb12caf8744bbb5f7f6fbf9763368af8335.tar.gz cgeo-db0a4fb12caf8744bbb5f7f6fbf9763368af8335.tar.bz2 | |
new: GPX import from Android storage access framework
Only works on Kitkat. Now you can import directly from dropbox and
related services.
Diffstat (limited to 'main/src')
6 files changed, 125 insertions, 30 deletions
diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java index 3d2ad0c..b5ed949 100644 --- a/main/src/cgeo/geocaching/CacheListActivity.java +++ b/main/src/cgeo/geocaching/CacheListActivity.java @@ -6,6 +6,7 @@ import cgeo.geocaching.activity.FilteredActivity; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cachelist.CacheListAppFactory; +import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.gc.SearchHandler; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheType; @@ -53,16 +54,19 @@ import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; +import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.provider.OpenableColumns; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.view.ContextMenu; @@ -91,6 +95,8 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA private static final int MSG_RESTART_GEO_AND_DIR = -2; private static final int MSG_CANCEL = -99; + private static final int REQUEST_CODE_IMPORT_GPX = 1; + private CacheListType type = null; private Geopoint coords = null; private SearchResult search = null; @@ -531,7 +537,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA } menu.findItem(R.id.menu_invert_selection).setVisible(adapter.isSelectMode()); - setVisible(menu, R.id.menu_switch_select_mode, !isEmpty); setVisible(menu, R.id.submenu_manage, (isHistory && !isEmpty) || isOffline); setVisible(menu, R.id.submenu_manage_lists, isOffline); @@ -576,6 +581,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA setMenuItemLabel(menu, R.id.menu_remove_from_history, R.string.cache_remove_from_history, R.string.cache_clear_history); setMenuItemLabel(menu, R.id.menu_export, R.string.export, R.string.export); + menu.findItem(R.id.menu_import_android).setVisible(Compatibility.isStorageAccessFrameworkAvailable()); } catch (final RuntimeException e) { Log.e("CacheListActivity.onPrepareOptionsMenu", e); } @@ -637,6 +643,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA case R.id.menu_import_gpx: importGpx(); invalidateOptionsMenuCompatible(); + return true; + case R.id.menu_import_android: + importGpxFromAndroid(); + invalidateOptionsMenuCompatible(); return false; case R.id.menu_create_list: new StoredList.UserInterface(this).promptForListCreation(getListSwitchingRunnable(), newListName); @@ -975,12 +985,42 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA GpxFileListActivity.startSubActivity(this, listId); } + private void importGpxFromAndroid() { + Compatibility.importGpxFromStorageAccessFramework(this, REQUEST_CODE_IMPORT_GPX); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_IMPORT_GPX && resultCode == Activity.RESULT_OK) { + // The document selected by the user won't be returned in the intent. + // Instead, a URI to that document will be contained in the return intent + // provided to this method as a parameter. Pull that uri using "resultData.getData()" + if (data != null) { + final Uri uri = data.getData(); + new GPXImporter(CacheListActivity.this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri)); + } + } + refreshCurrentList(); } + private String getDisplayName(Uri uri) { + Cursor cursor = null; + try { + cursor = getContentResolver().query(uri, new String[] { OpenableColumns.DISPLAY_NAME }, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return null; + } + public void refreshStored(final List<Geocache> caches) { detailTotal = caches.size(); if (detailTotal == 0) { @@ -1675,4 +1715,3 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA //Not interesting } } - diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java new file mode 100644 index 0000000..ed4849f --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java @@ -0,0 +1,25 @@ +package cgeo.geocaching.compatibility; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; + +@TargetApi(19) +public class AndroidLevel19 implements AndroidLevel19Interface { + + @Override + public void importGpxFromStorageAccessFramework(final Activity activity, final int requestCode) { + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a file (as opposed to a list + // of contacts or timezones) + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Mime type based filter, we use "*/*" as GPX does not have a good mime type anyway + intent.setType("*/*"); + + activity.startActivityForResult(intent, requestCode); + } + +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java new file mode 100644 index 0000000..99f140f --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java @@ -0,0 +1,12 @@ +package cgeo.geocaching.compatibility; + +import android.app.Activity; + +public class AndroidLevel19Emulation implements AndroidLevel19Interface { + + @Override + public void importGpxFromStorageAccessFramework(Activity activity, int requestCode) { + // do nothing + } + +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java new file mode 100644 index 0000000..9a27cd8 --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java @@ -0,0 +1,7 @@ +package cgeo.geocaching.compatibility; + +import android.app.Activity; + +public interface AndroidLevel19Interface { + void importGpxFromStorageAccessFramework(Activity activity, final int requestCode); +} diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java index 48454ef..31c9e31 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -5,6 +5,7 @@ import cgeo.geocaching.utils.AngleUtils; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.reflect.MethodUtils; +import org.eclipse.jdt.annotation.NonNull; import android.app.Activity; import android.content.Intent; @@ -24,33 +25,22 @@ public final class Compatibility { private final static AndroidLevel8Interface level8; private final static AndroidLevel11Interface level11; private final static AndroidLevel13Interface level13; + private final static AndroidLevel19Interface level19; static { - if (isLevel8) { - level8 = new AndroidLevel8(); - } - else { - level8 = new AndroidLevel8Emulation(); - } - if (sdkVersion >= 11) { - level11 = new AndroidLevel11(); - } - else { - level11 = new AndroidLevel11Emulation(); - } - if (sdkVersion >= 13) { - level13 = new AndroidLevel13(); - } - else { - level13 = new AndroidLevel13Emulation(); - } + level8 = isLevel8 ? new AndroidLevel8() : new AndroidLevel8Emulation(); + level11 = sdkVersion >= 11 ? new AndroidLevel11() : new AndroidLevel11Emulation(); + level13 = sdkVersion >= 13 ? new AndroidLevel13() : new AndroidLevel13Emulation(); + level19 = sdkVersion >= 19 ? new AndroidLevel19() : new AndroidLevel19Emulation(); } /** * Add 90, 180 or 270 degrees to the given rotation. * - * @param directionNowPre the direction in degrees before adjustment - * @param activity the activity whose rotation is used to adjust the direction + * @param directionNowPre + * the direction in degrees before adjustment + * @param activity + * the activity whose rotation is used to adjust the direction * @return the adjusted direction, in the [0, 360[ range */ public static float getDirectionNow(final float directionNowPre, final Activity activity) { @@ -110,4 +100,11 @@ public final class Compatibility { return level8.getExternalPictureDir(); } + public static void importGpxFromStorageAccessFramework(final @NonNull Activity activity, int requestCodeImportGpx) { + level19.importGpxFromStorageAccessFramework(activity, requestCodeImportGpx); + } + + public static boolean isStorageAccessFrameworkAvailable() { + return sdkVersion >= 19; + } } diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 07ef285..cd2f445 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -14,6 +14,7 @@ import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.Nullable; import android.app.Activity; import android.app.ProgressDialog; @@ -88,21 +89,25 @@ public class GPXImporter { } /** - * Import GPX provided via intent of activity that instantiated this GPXImporter. + * Import GPX file from URI. + * + * @param uri + * URI of the file to import + * @param knownMimeType + * @param knownPathName */ - public void importGPX() { + public void importGPX(final Uri uri, final @Nullable String knownMimeType, final @Nullable String knownPathName) { final ContentResolver contentResolver = fromActivity.getContentResolver(); - final Intent intent = fromActivity.getIntent(); - final Uri uri = intent.getData(); + String mimeType = knownMimeType; + final String pathName = knownPathName != null ? knownPathName : uri.getPath(); - 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)) { + if (StringUtils.endsWithIgnoreCase(pathName, GPX_FILE_EXTENSION) || StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) { mimeType = "application/xml"; } else { // if we can't determine a better type, default to zip import @@ -113,7 +118,7 @@ public class GPXImporter { Log.i("importGPX: " + uri + ", mimetype=" + mimeType); if (GPX_MIME_TYPES.contains(mimeType)) { - if (StringUtils.endsWithIgnoreCase(uri.getPath(), LOC_FILE_EXTENSION)) { + if (StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) { new ImportLocAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start(); } else { new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start(); @@ -125,6 +130,16 @@ public class GPXImporter { } } + /** + * Import GPX provided via intent of activity that instantiated this GPXImporter. + */ + public void importGPX() { + final Intent intent = fromActivity.getIntent(); + final Uri uri = intent.getData(); + final String mimeType = intent.getType(); + importGPX(uri, mimeType, null); + } + static abstract class ImportThread extends Thread { final int listId; final Handler importStepHandler; @@ -281,7 +296,7 @@ public class GPXImporter { } } - static class ImportGpxAttachmentThread extends ImportGpxThread { + public static class ImportGpxAttachmentThread extends ImportGpxThread { private final Uri uri; private final ContentResolver contentResolver; |
