aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/.project8
-rw-r--r--main/res/values/changelog_master.xml5
-rw-r--r--main/res/values/preference_keys.xml3
-rw-r--r--main/res/values/strings.xml3
-rw-r--r--main/res/xml/preferences.xml5
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java13
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java2
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java9
-rw-r--r--main/src/cgeo/geocaching/files/FileType.java8
-rw-r--r--main/src/cgeo/geocaching/files/FileTypeDetector.java77
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java100
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java5
-rw-r--r--main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java7
-rw-r--r--main/src/cgeo/geocaching/maps/PositionDrawer.java8
-rw-r--r--main/src/cgeo/geocaching/maps/ScaleDrawer.java9
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapView.java5
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java3
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java10
-rw-r--r--main/src/cgeo/geocaching/ui/CompassView.java45
-rw-r--r--main/src/cgeo/geocaching/utils/DebugUtils.java37
-rw-r--r--main/src/cgeo/geocaching/utils/ShareUtils.java27
-rw-r--r--tests/src/cgeo/geocaching/files/FileTypeDetectorTest.java52
-rw-r--r--tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java7
29 files changed, 376 insertions, 101 deletions
diff --git a/main/.project b/main/.project
index 80a267b..5f0d599 100644
--- a/main/.project
+++ b/main/.project
@@ -27,7 +27,15 @@
</buildCommand>
</buildSpec>
<natures>
+ <nature>org.sonar.ide.eclipse.core.sonarNature</nature>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
+ <linkedResources>
+ <link>
+ <name>testlink</name>
+ <type>2</type>
+ <location>/home/bananeweizen/workspaces/egit</location>
+ </link>
+ </linkedResources>
</projectDescription>
diff --git a/main/res/values/changelog_master.xml b/main/res/values/changelog_master.xml
index 501cf21..1083326 100644
--- a/main/res/values/changelog_master.xml
+++ b/main/res/values/changelog_master.xml
@@ -5,10 +5,15 @@
<b>Next feature release:</b>\n
· New: Show also own logs on friend log page\n
· New: Filter for caches which are not found\n
+ · New: Show \"Import from web\" also if not yet registered\n
+ · New: Debugging option to save memory dumps on user demand\n
· Fix: Hiding own caches on opencaching\n
· Fix: Webcam caches not marked as found after posting log\n
· Fix: Archived caches now also hidden if hiding disabled caches is active\n
· Fix: Filter invalid characters in GPX files\n
+ · Fix: All caches shown as owned if no username stored\n
+ · Fix: GPX import from mail failing on some devices\n
+ · Fix: Updating cache history should not ask for list to save caches\n
\n
\n
</string>
diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml
index 94a6d2a..2e3de84 100644
--- a/main/res/values/preference_keys.xml
+++ b/main/res/values/preference_keys.xml
@@ -169,5 +169,6 @@
<string name="pref_twitter_cache_message">twitter_cache_message</string>
<string name="pref_twitter_trackable_message">twitter_trackable_message</string>
<string name="pref_ec_icons">ec_icons</string>
+ <string name="pref_memory_dump">memory_dump</string>
<string name="pref_appearance">pref_appearence</string>
-</resources> \ No newline at end of file
+</resources>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index b164070..7a9194e 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -545,6 +545,9 @@
<string name="init_maintenance">Maintenance</string>
<string name="init_maintenance_directories_note">c:geo stores images, log images and other files related to a cache in a separate directory. In some cases (like importing/exporting the database) this directory may contain outdated files, which can be deleted here.</string>
<string name="init_maintenance_directories">Delete orphaned files</string>
+ <string name="init_create_memory_dump">Create memory dump</string>
+ <string name="init_memory_dump">Memory dump</string>
+ <string name="init_memory_dumped">Memory dumped to %s</string>
<string name="settings_open_website">Open website</string>
<string name="settings_settings">Settings</string>
<string name="settings_information">Information</string>
diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml
index 0bb419e..124bd0d 100644
--- a/main/res/xml/preferences.xml
+++ b/main/res/xml/preferences.xml
@@ -740,7 +740,10 @@
android:defaultValue="false"
android:key="@string/pref_debug"
android:title="@string/init_debug" />
+ <Preference
+ android:key="@string/pref_memory_dump"
+ android:title="@string/init_create_memory_dump" />
</PreferenceCategory>
</PreferenceScreen>
-</PreferenceScreen> \ No newline at end of file
+</PreferenceScreen>
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index 1456b0e..c3125ab 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -11,12 +11,12 @@ import rx.functions.Action1;
import rx.observables.ConnectableObservable;
import android.app.Application;
+import android.os.Environment;
import android.view.ViewConfiguration;
-import java.lang.reflect.Field;
-
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.reflect.Field;
public class CgeoApplication extends Application {
@@ -29,10 +29,8 @@ public class CgeoApplication extends Application {
private volatile IGeoData currentGeo = null;
private volatile float currentDirection = 0.0f;
- private static final UncaughtExceptionHandler defaultHandler;
-
static {
- defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+ final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@@ -43,11 +41,10 @@ public class CgeoApplication extends Application {
while (exx.getCause() != null) {
exx = exx.getCause();
}
- if (exx.getClass().equals(OutOfMemoryError.class))
- {
+ if (exx.getClass().equals(OutOfMemoryError.class)) {
try {
Log.e("OutOfMemory");
- android.os.Debug.dumpHprofData("/sdcard/dump.hprof");
+ android.os.Debug.dumpHprofData(Environment.getExternalStorageDirectory().getPath() + "/dump.hprof");
} catch (IOException e) {
Log.e("Error writing dump", e);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index 925f6f0..a38bad0 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -192,8 +192,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public boolean isOwner(final ICache cache) {
- return StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), Settings.getUsername());
-
+ final String user = Settings.getUsername();
+ return StringUtils.isNotEmpty(user) && StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), user);
}
@Override
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
index bdcd78e..3771443 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
@@ -151,7 +151,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
@Override
public boolean isOwner(ICache cache) {
- return StringUtils.equals(cache.getOwnerDisplayName(), getUserName());
+ return StringUtils.isNotEmpty(getUserName()) && StringUtils.equals(cache.getOwnerDisplayName(), getUserName());
}
@Override
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index 08fca0b..39f4bcf 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.ShareUtils;
import org.apache.commons.lang3.CharEncoding;
@@ -15,8 +16,6 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
import android.os.Environment;
import android.view.ContextThemeWrapper;
import android.view.View;
@@ -168,11 +167,7 @@ class GpxExport extends AbstractExport {
if (exportFile != null) {
ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString());
if (Settings.getShareAfterExport()) {
- final Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportFile));
- shareIntent.setType("application/xml");
- activity.startActivity(Intent.createChooser(shareIntent, getString(R.string.export_gpx_to)));
+ ShareUtils.share(activity, exportFile, "application/xml", R.string.export_gpx_to);
}
} else {
ActivityMixin.showToast(activity, getString(R.string.export_failed));
diff --git a/main/src/cgeo/geocaching/files/FileType.java b/main/src/cgeo/geocaching/files/FileType.java
new file mode 100644
index 0000000..ef62351
--- /dev/null
+++ b/main/src/cgeo/geocaching/files/FileType.java
@@ -0,0 +1,8 @@
+package cgeo.geocaching.files;
+
+public enum FileType {
+ UNKNOWN,
+ LOC,
+ GPX,
+ ZIP
+}
diff --git a/main/src/cgeo/geocaching/files/FileTypeDetector.java b/main/src/cgeo/geocaching/files/FileTypeDetector.java
new file mode 100644
index 0000000..389b83a
--- /dev/null
+++ b/main/src/cgeo/geocaching/files/FileTypeDetector.java
@@ -0,0 +1,77 @@
+package cgeo.geocaching.files;
+
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class FileTypeDetector {
+
+ private final ContentResolver contentResolver;
+ private final Uri uri;
+
+ public FileTypeDetector(Uri uri, ContentResolver contentResolver) {
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ public @NonNull FileType getFileType() {
+ InputStream is = null;
+ BufferedReader reader = null;
+ FileType type = FileType.UNKNOWN;
+ try {
+ is = contentResolver.openInputStream(uri);
+ if (is == null) {
+ return FileType.UNKNOWN;
+ }
+ reader = new BufferedReader(new InputStreamReader(is));
+ type = detectHeader(reader);
+ reader.close();
+ } catch (FileNotFoundException e) {
+ Log.e("FileTypeDetector", e);
+ } catch (IOException e) {
+ Log.e("FileTypeDetector", e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ IOUtils.closeQuietly(is);
+ }
+ return type;
+ }
+
+ private static FileType detectHeader(BufferedReader reader)
+ throws IOException {
+ String line = reader.readLine();
+ if (isZip(line)) {
+ return FileType.ZIP;
+ }
+ // scan at most 5 lines of a GPX file
+ for (int i = 0; i < 5; i++) {
+ line = StringUtils.trim(line);
+ if (StringUtils.contains(line, "<loc")) {
+ return FileType.LOC;
+ }
+ if (StringUtils.contains(line, "<gpx")) {
+ return FileType.GPX;
+ }
+ line = reader.readLine();
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private static boolean isZip(String line) {
+ return StringUtils.length(line) >= 4
+ && StringUtils.startsWith(line, "PK") && line.charAt(2) == 3
+ && line.charAt(3) == 4;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index cd2f445..f87e6b9 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.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import android.app.Activity;
@@ -93,46 +94,77 @@ public class GPXImporter {
*
* @param uri
* URI of the file to import
- * @param knownMimeType
- * @param knownPathName
+ * @param mimeType
+ * @param pathName
*/
- public void importGPX(final Uri uri, final @Nullable String knownMimeType, final @Nullable String knownPathName) {
+ public void importGPX(final Uri uri, final @Nullable String mimeType, final @Nullable String pathName) {
final ContentResolver contentResolver = fromActivity.getContentResolver();
- String mimeType = knownMimeType;
- final String pathName = knownPathName != null ? knownPathName : uri.getPath();
-
- // 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(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
- // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
- mimeType = "application/zip";
- }
- }
Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
- if (GPX_MIME_TYPES.contains(mimeType)) {
- if (StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) {
- new ImportLocAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- }
- } else if (ZIP_MIME_TYPES.contains(mimeType)) {
- new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- importFinished();
+ @NonNull
+ FileType fileType = new FileTypeDetector(uri, contentResolver)
+ .getFileType();
+
+ if (fileType == FileType.UNKNOWN) {
+ fileType = getFileTypeFromPathName(pathName);
+ }
+ if (fileType == FileType.UNKNOWN) {
+ fileType = getFileTypeFromMimeType(mimeType);
+ }
+
+ ImportThread importer = getImporterFromFileType(uri, contentResolver,
+ fileType);
+
+ if (importer != null) {
+ importer.start();
+ } else {
+ importFinished();
+ }
+ }
+
+ private static @NonNull FileType getFileTypeFromPathName(
+ final String pathName) {
+ if (StringUtils.endsWithIgnoreCase(pathName, GPX_FILE_EXTENSION)) {
+ return FileType.GPX;
}
- }
- /**
- * Import GPX provided via intent of activity that instantiated this GPXImporter.
- */
+ if (StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) {
+ return FileType.LOC;
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private static @NonNull FileType getFileTypeFromMimeType(
+ final String mimeType) {
+ if (GPX_MIME_TYPES.contains(mimeType)) {
+ return FileType.GPX;
+ } else if (ZIP_MIME_TYPES.contains(mimeType)) {
+ return FileType.ZIP;
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private ImportThread getImporterFromFileType(Uri uri,
+ ContentResolver contentResolver, FileType fileType) {
+ switch (fileType) {
+ case ZIP:
+ return new ImportGpxZipAttachmentThread(uri, contentResolver,
+ listId, importStepHandler, progressHandler);
+ case GPX:
+ return new ImportGpxAttachmentThread(uri, contentResolver, listId,
+ importStepHandler, progressHandler);
+ case LOC:
+ return new ImportLocAttachmentThread(uri, contentResolver, listId,
+ importStepHandler, progressHandler);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Import GPX provided via intent of activity that instantiated this
+ * GPXImporter.
+ */
public void importGPX() {
final Intent intent = fromActivity.getIntent();
final Uri uri = intent.getData();
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 004081f..b4cb4b8 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -43,6 +43,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.eclipse.jdt.annotation.NonNull;
+
import rx.Subscription;
import rx.functions.Action0;
import rx.functions.Action1;
@@ -484,7 +485,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
if (overlayPositionAndScale == null) {
- overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(activity);
+ overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay();
if (trailHistory != null) {
overlayPositionAndScale.setHistory(trailHistory);
}
@@ -995,7 +996,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
if (cgeoMapRef != null) {
if (cgeoMapRef.mapView != null) {
if (cgeoMapRef.overlayPositionAndScale == null) {
- cgeoMapRef.overlayPositionAndScale = cgeoMapRef.mapView.createAddPositionAndScaleOverlay(cgeoMapRef.activity);
+ cgeoMapRef.overlayPositionAndScale = cgeoMapRef.mapView.createAddPositionAndScaleOverlay();
}
boolean needsRepaintForDistance = needsRepaintForDistance();
diff --git a/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
index 6b34b75..63fcd73 100644
--- a/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
+++ b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
@@ -5,7 +5,6 @@ import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OverlayImpl;
-import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Point;
import android.location.Location;
@@ -18,10 +17,10 @@ public class PositionAndScaleOverlay implements GeneralOverlay {
PositionDrawer positionDrawer = null;
ScaleDrawer scaleDrawer = null;
- public PositionAndScaleOverlay(Activity activity, OverlayImpl ovlImpl) {
+ public PositionAndScaleOverlay(OverlayImpl ovlImpl) {
this.ovlImpl = ovlImpl;
- positionDrawer = new PositionDrawer(activity);
- scaleDrawer = new ScaleDrawer(activity);
+ positionDrawer = new PositionDrawer();
+ scaleDrawer = new ScaleDrawer();
}
public void setCoordinates(Location coordinatesIn) {
diff --git a/main/src/cgeo/geocaching/maps/PositionDrawer.java b/main/src/cgeo/geocaching/maps/PositionDrawer.java
index 1a5dcaf..0e20e7c 100644
--- a/main/src/cgeo/geocaching/maps/PositionDrawer.java
+++ b/main/src/cgeo/geocaching/maps/PositionDrawer.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -7,7 +8,6 @@ import cgeo.geocaching.maps.interfaces.MapItemFactory;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.settings.Settings;
-import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -36,11 +36,9 @@ public class PositionDrawer {
private PaintFlagsDrawFilter setfil = null;
private PaintFlagsDrawFilter remfil = null;
private PositionHistory positionHistory = new PositionHistory();
- private Activity activity;
private MapItemFactory mapItemFactory;
- public PositionDrawer(Activity activity) {
- this.activity = activity;
+ public PositionDrawer() {
this.mapItemFactory = Settings.getMapProvider().getMapItemFactory();
}
@@ -144,7 +142,7 @@ public class PositionDrawer {
}
if (arrow == null) {
- arrow = BitmapFactory.decodeResource(activity.getResources(), R.drawable.my_location_chevron);
+ arrow = BitmapFactory.decodeResource(CgeoApplication.getInstance().getResources(), R.drawable.my_location_chevron);
widthArrowHalf = arrow.getWidth() / 2;
heightArrowHalf = arrow.getHeight() / 2;
}
diff --git a/main/src/cgeo/geocaching/maps/ScaleDrawer.java b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
index fb46408..95c987d 100644
--- a/main/src/cgeo/geocaching/maps/ScaleDrawer.java
+++ b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -7,12 +8,13 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl;
import org.apache.commons.lang3.tuple.ImmutablePair;
-import android.app.Activity;
+import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.DisplayMetrics;
+import android.view.WindowManager;
public class ScaleDrawer {
private static final double SCALE_WIDTH_FACTOR = 1.0 / 2.5;
@@ -22,9 +24,10 @@ public class ScaleDrawer {
private BlurMaskFilter blur = null;
private float pixelDensity = 0;
- public ScaleDrawer(Activity activity) {
+ public ScaleDrawer() {
DisplayMetrics metrics = new DisplayMetrics();
- activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ WindowManager windowManager = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
+ windowManager.getDefaultDisplay().getMetrics(metrics);
pixelDensity = metrics.density;
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
index 610dbe1..094c456 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
@@ -20,7 +20,6 @@ import com.google.android.maps.MapView;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.eclipse.jdt.annotation.NonNull;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -120,9 +119,9 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay() {
- GoogleOverlay ovl = new GoogleOverlay(activity);
+ GoogleOverlay ovl = new GoogleOverlay();
getOverlays().add(ovl);
return (PositionAndScaleOverlay) ovl.getBase();
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
index 0a5cf69..c684b9a 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
@@ -8,7 +8,6 @@ import cgeo.geocaching.maps.interfaces.OverlayImpl;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
-import android.app.Activity;
import android.graphics.Canvas;
import java.util.concurrent.locks.Lock;
@@ -19,8 +18,8 @@ public class GoogleOverlay extends Overlay implements OverlayImpl {
private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public GoogleOverlay(Activity activityIn) {
- overlayBase = new PositionAndScaleOverlay(activityIn, this);
+ public GoogleOverlay() {
+ overlayBase = new PositionAndScaleOverlay(this);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
index 5ae8e15..4a6d733 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -6,7 +6,6 @@ import cgeo.geocaching.maps.PositionAndScaleOverlay;
import org.eclipse.jdt.annotation.NonNull;
-import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -47,7 +46,7 @@ public interface MapViewImpl {
CachesOverlay createAddMapOverlay(Context context, Drawable drawable);
- PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity);
+ PositionAndScaleOverlay createAddPositionAndScaleOverlay();
void setMapSource();
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index 7a5aab2..fb057a4 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -24,7 +24,6 @@ import org.mapsforge.android.maps.mapgenerator.MapGeneratorInternal;
import org.mapsforge.android.maps.overlay.Overlay;
import org.mapsforge.core.GeoPoint;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -105,8 +104,8 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity);
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay() {
+ MapsforgeOverlay ovl = new MapsforgeOverlay();
getOverlays().add(ovl);
return (PositionAndScaleOverlay) ovl.getBase();
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
index 74a8601..3df4ab0 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
@@ -8,7 +8,6 @@ import cgeo.geocaching.maps.interfaces.OverlayImpl;
import org.mapsforge.android.maps.Projection;
import org.mapsforge.android.maps.overlay.Overlay;
-import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -20,8 +19,8 @@ public class MapsforgeOverlay extends Overlay implements OverlayImpl {
private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public MapsforgeOverlay(Activity activityIn) {
- overlayBase = new PositionAndScaleOverlay(activityIn, this);
+ public MapsforgeOverlay() {
+ overlayBase = new PositionAndScaleOverlay(this);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
index 4fa4e02..68a03b7 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
@@ -21,7 +21,6 @@ import org.mapsforge.android.mapsold.MapViewMode;
import org.mapsforge.android.mapsold.Overlay;
import org.mapsforge.android.mapsold.Projection;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -96,8 +95,8 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
}
@Override
- public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity);
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay() {
+ MapsforgeOverlay ovl = new MapsforgeOverlay();
getOverlays().add(ovl);
return (PositionAndScaleOverlay) ovl.getBase();
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
index 655e0b9..bfb3548 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
@@ -8,7 +8,6 @@ import cgeo.geocaching.maps.interfaces.OverlayImpl;
import org.mapsforge.android.mapsold.Overlay;
import org.mapsforge.android.mapsold.Projection;
-import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -20,8 +19,8 @@ public class MapsforgeOverlay extends Overlay implements OverlayImpl {
private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public MapsforgeOverlay(Activity activityIn) {
- overlayBase = new PositionAndScaleOverlay(activityIn, this);
+ public MapsforgeOverlay() {
+ overlayBase = new PositionAndScaleOverlay(this);
}
@Override
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index c7933bd..315c73a 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -14,6 +14,7 @@ import cgeo.geocaching.files.SimpleDirChooser;
import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.utils.DatabaseBackupUtils;
+import cgeo.geocaching.utils.DebugUtils;
import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -391,6 +392,15 @@ public class SettingsActivity extends PreferenceActivity {
return true;
}
});
+ Preference memoryDumpPref = getPreference(R.string.pref_memory_dump);
+ memoryDumpPref
+ .setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override public boolean onPreferenceClick(
+ Preference preference) {
+ DebugUtils.createMemoryDump(SettingsActivity.this);
+ return true;
+ }
+ });
}
private void initDbLocationPreference() {
diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java
index 915303b..60982a9 100644
--- a/main/src/cgeo/geocaching/ui/CompassView.java
+++ b/main/src/cgeo/geocaching/ui/CompassView.java
@@ -17,6 +17,7 @@ import android.graphics.PaintFlagsDrawFilter;
import android.util.AttributeSet;
import android.view.View;
+import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
public class CompassView extends View {
@@ -55,11 +56,40 @@ public class CompassView extends View {
private boolean initialDisplay;
private Subscription periodicUpdate;
+ private static final class UpdateAction implements Action0 {
+
+ private final WeakReference<CompassView> compassViewRef;
+
+ private UpdateAction(CompassView view) {
+ this.compassViewRef = new WeakReference<CompassView>(view);
+ }
+
+ @Override
+ public void call() {
+ final CompassView compassView = compassViewRef.get();
+ if (compassView == null) {
+ return;
+ }
+ compassView.updateGraphics();
+ }
+ }
+
public CompassView(Context contextIn) {
super(contextIn);
context = contextIn;
}
+ public void updateGraphics() {
+ final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
+ final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
+ if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
+ Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) {
+ azimuthShown = newAzimuthShown;
+ cacheHeadingShown = newCacheHeadingShown;
+ invalidate();
+ }
+ }
+
public CompassView(Context contextIn, AttributeSet attrs) {
super(contextIn, attrs);
context = contextIn;
@@ -87,24 +117,13 @@ public class CompassView extends View {
initialDisplay = true;
- periodicUpdate = AndroidSchedulers.mainThread().createWorker().schedulePeriodically(new Action0() {
- @Override
- public void call() {
- final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
- final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
- if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
- Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) {
- azimuthShown = newAzimuthShown;
- cacheHeadingShown = newCacheHeadingShown;
- invalidate();
- }
- }
- }, 0, 40, TimeUnit.MILLISECONDS);
+ periodicUpdate = AndroidSchedulers.mainThread().createWorker().schedulePeriodically(new UpdateAction(this), 0, 40, TimeUnit.MILLISECONDS);
}
@Override
public void onDetachedFromWindow() {
periodicUpdate.unsubscribe();
+
super.onDetachedFromWindow();
if (compassUnderlay != null) {
diff --git a/main/src/cgeo/geocaching/utils/DebugUtils.java b/main/src/cgeo/geocaching/utils/DebugUtils.java
new file mode 100644
index 0000000..07aac64
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/DebugUtils.java
@@ -0,0 +1,37 @@
+package cgeo.geocaching.utils;
+
+import cgeo.geocaching.R;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.Context;
+import android.os.Environment;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class DebugUtils {
+
+ private DebugUtils() {
+ // utility class
+ }
+
+ public static void createMemoryDump(final @NonNull Context context) {
+ try {
+ final Date now = new Date();
+ final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyy-MM-dd_hh-mm", Locale.US);
+ File file = FileUtils.getUniqueNamedFile(Environment.getExternalStorageDirectory().getPath()
+ + File.separatorChar + "cgeo_dump_" + fileNameDateFormat.format(now) + ".hprof");
+ android.os.Debug.dumpHprofData(file.getPath());
+ Toast.makeText(context, context.getString(R.string.init_memory_dumped, file.getAbsolutePath()),
+ Toast.LENGTH_LONG).show();
+ ShareUtils.share(context, file, R.string.init_memory_dump);
+ } catch (IOException e) {
+ Log.e("createMemoryDump", e);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/utils/ShareUtils.java b/main/src/cgeo/geocaching/utils/ShareUtils.java
new file mode 100644
index 0000000..bfd6838
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/ShareUtils.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching.utils;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import java.io.File;
+
+public class ShareUtils {
+ private ShareUtils() {
+ // utility class
+ }
+
+ public static void share(final Context context, final @NonNull File file, final @NonNull String mimeType, final int titleResourceId) {
+ final Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
+ shareIntent.setType(mimeType);
+ context.startActivity(Intent.createChooser(shareIntent, context.getString(titleResourceId)));
+ }
+
+ public static void share(final Context context, final @NonNull File file, final int titleResourceId) {
+ share(context, file, "*/*", titleResourceId);
+ }
+}
diff --git a/tests/src/cgeo/geocaching/files/FileTypeDetectorTest.java b/tests/src/cgeo/geocaching/files/FileTypeDetectorTest.java
new file mode 100644
index 0000000..5dbf3c2
--- /dev/null
+++ b/tests/src/cgeo/geocaching/files/FileTypeDetectorTest.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching.files;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase;
+import cgeo.geocaching.test.R;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+
+public class FileTypeDetectorTest extends AbstractResourceInstrumentationTestCase {
+
+ private static class FileContentResolver extends ContentResolver {
+
+ public FileContentResolver(Context context) {
+ super(context);
+ }
+ }
+
+ public void testUnknown() throws Exception {
+ assertFileType(R.raw.gc2cjpf_html, FileType.UNKNOWN);
+ assertFileType(R.raw.map1, FileType.UNKNOWN);
+ }
+
+ public void testLoc() throws Exception {
+ assertFileType(R.raw.gc1bkp3_loc, FileType.LOC);
+ assertFileType(R.raw.oc5952_loc, FileType.LOC);
+ assertFileType(R.raw.waymarking_loc, FileType.LOC);
+ }
+
+ public void testGpx() throws Exception {
+ assertFileType(R.raw.gc1bkp3_gpx100, FileType.GPX);
+ assertFileType(R.raw.gc1bkp3_gpx101, FileType.GPX);
+ assertFileType(R.raw.oc5952_gpx, FileType.GPX);
+ assertFileType(R.raw.renamed_waypoints_wpts, FileType.GPX);
+ assertFileType(R.raw.waymarking_gpx, FileType.GPX);
+ }
+
+ public void testZip() throws Exception {
+ assertFileType(R.raw.pq_error, FileType.ZIP);
+ assertFileType(R.raw.pq7545915, FileType.ZIP);
+ }
+
+ private void assertFileType(final int resourceId, final @NonNull FileType fileType) {
+ final Uri resourceURI = getResourceURI(resourceId);
+ final FileContentResolver contentResolver = new FileContentResolver(getInstrumentation().getContext());
+ assertThat(new FileTypeDetector(resourceURI, contentResolver).getFileType()).isEqualTo(fileType);
+ }
+}
diff --git a/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java b/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java
index df8dc1f..cbad794 100644
--- a/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java
+++ b/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java
@@ -12,7 +12,9 @@ import cgeo.geocaching.files.GPX10Parser;
import cgeo.geocaching.files.ParserException;
import cgeo.geocaching.list.StoredList;
+import android.content.ContentResolver;
import android.content.res.Resources;
+import android.net.Uri;
import android.test.InstrumentationTestCase;
import java.io.File;
@@ -102,4 +104,9 @@ public abstract class AbstractResourceInstrumentationTestCase extends Instrument
instream.close();
}
}
+
+ protected Uri getResourceURI(int resId) {
+ Resources resources = getInstrumentation().getContext().getResources();
+ return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + resources.getResourcePackageName(resId) + '/' + resources.getResourceTypeName(resId) + '/' + resources.getResourceEntryName(resId));
+ }
}