aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBananeweizen <bananeweizen@gmx.de>2014-01-03 14:50:10 +0100
committerBananeweizen <bananeweizen@gmx.de>2014-01-03 14:50:10 +0100
commitdb0a4fb12caf8744bbb5f7f6fbf9763368af8335 (patch)
treeee234a16e55311e109e01a1034cef5bb02c0397d
parentccc7e82afed6c4ae6f8334a2ab05ff8acf543483 (diff)
downloadcgeo-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.
-rw-r--r--main/project.properties2
-rw-r--r--main/res/menu/cache_list_options.xml4
-rw-r--r--main/res/values/strings.xml1
-rw-r--r--main/src/cgeo/geocaching/CacheListActivity.java43
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19.java25
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java12
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java7
-rw-r--r--main/src/cgeo/geocaching/compatibility/Compatibility.java37
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java31
9 files changed, 131 insertions, 31 deletions
diff --git a/main/project.properties b/main/project.properties
index 894c810..6d3329d 100644
--- a/main/project.properties
+++ b/main/project.properties
@@ -11,4 +11,4 @@
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
-target=Google Inc.:Google APIs:17
+target=Google Inc.:Google APIs:19
diff --git a/main/res/menu/cache_list_options.xml b/main/res/menu/cache_list_options.xml
index af9135f..418d2de 100644
--- a/main/res/menu/cache_list_options.xml
+++ b/main/res/menu/cache_list_options.xml
@@ -59,6 +59,10 @@
android:title="@string/web_import_title">
</item>
<item
+ android:id="@+id/menu_import_android"
+ android:title="@string/gpx_import_android">
+ </item>
+ <item
android:id="@+id/menu_export"
android:title="@string/export">
</item>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index 247988c..74c92f2 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -763,6 +763,7 @@
<string name="gpx_import_delete_title">Delete file</string>
<string name="gpx_import_delete_message">Do you want to delete %s?</string>
<string name="gpx_import_select_list_title">Import GPX to list</string>
+ <string name="gpx_import_android">Import from Android</string>
<!-- map file select -->
<string name="map_file_select_title">Select map file</string>
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;