aboutsummaryrefslogtreecommitdiffstats
path: root/src/cgeo/geocaching/mapcommon
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgeo/geocaching/mapcommon')
-rw-r--r--src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java57
-rw-r--r--src/cgeo/geocaching/mapcommon/MapBase.java64
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java198
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapOverlay.java322
-rw-r--r--src/cgeo/geocaching/mapcommon/cgOverlayScale.java140
-rw-r--r--src/cgeo/geocaching/mapcommon/cgUsersOverlay.java185
-rw-r--r--src/cgeo/geocaching/mapcommon/cgeomap.java1686
7 files changed, 2652 insertions, 0 deletions
diff --git a/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
new file mode 100644
index 0000000..41739e2
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayItemImpl;
+
+/**
+ * Base class for itemized overlays. Delegates calls from deriving classes to the contained
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public abstract class ItemizedOverlayBase {
+
+ private ItemizedOverlayImpl ovlImpl;
+
+ public ItemizedOverlayBase(ItemizedOverlayImpl ovlImplIn) {
+ ovlImpl = ovlImplIn;
+ }
+
+ void populate() {
+ ovlImpl.superPopulate();
+ }
+
+ public boolean onTap(int index) {
+ return ovlImpl.superOnTap(index);
+ }
+
+ Drawable boundCenter(Drawable markerIn) {
+ return ovlImpl.superBoundCenter(markerIn);
+ }
+
+ Drawable boundCenterBottom(Drawable markerIn) {
+ return ovlImpl.superBoundCenterBottom(markerIn);
+ }
+
+ void setLastFocusedItemIndex(int index){
+ ovlImpl.superSetLastFocusedItemIndex(index);
+ }
+
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ ovlImpl.superDraw(canvas, mapView, shadow);
+ }
+
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ ovlImpl.superDrawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ public abstract OverlayItemImpl createItem(int index);
+
+ public abstract int size();
+}
diff --git a/src/cgeo/geocaching/mapcommon/MapBase.java b/src/cgeo/geocaching/mapcommon/MapBase.java
new file mode 100644
index 0000000..2340998
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/MapBase.java
@@ -0,0 +1,64 @@
+package cgeo.geocaching.mapcommon;
+
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Base class for the map activity. Delegates base class calls to the
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public class MapBase {
+
+ ActivityImpl mapActivity;
+
+ public MapBase(ActivityImpl activity) {
+ mapActivity = activity;
+ }
+
+ public Resources getResources() {
+ return mapActivity.getResources();
+ }
+
+ public Activity getActivity() {
+ return mapActivity.getActivity();
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ mapActivity.superOnCreate(savedInstanceState);
+ }
+
+ public void onResume() {
+ mapActivity.superOnResume();
+ }
+
+ public void onStop() {
+ mapActivity.superOnResume();
+ }
+
+ public void onPause() {
+ mapActivity.superOnResume();
+ }
+
+ public void onDestroy() {
+ mapActivity.superOnDestroy();
+ }
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapActivity.superOnCreateOptionsMenu(menu);
+ }
+
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapActivity.superOnPrepareOptionsMenu(menu);
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapActivity.superOnOptionsItemSelected(item);
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
new file mode 100644
index 0000000..3951c14
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
@@ -0,0 +1,198 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.location.Location;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import java.util.ArrayList;
+
+public class cgMapMyOverlay implements OverlayBase {
+ private cgSettings settings = null;
+ private Location coordinates = null;
+ private GeoPointImpl location = null;
+ private Double heading = new Double(0);
+ private Paint accuracyCircle = null;
+ private Paint historyLine = null;
+ private Paint historyLineShadow = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Bitmap arrow = null;
+ private int widthArrow = 0;
+ private int heightArrow = 0;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private Location historyRecent = null;
+ private ArrayList<Location> history = new ArrayList<Location>();
+ private Point historyPointN = new Point();
+ private Point historyPointP = new Point();
+
+ public cgMapMyOverlay(cgSettings settingsIn) {
+ settings = settingsIn;
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ coordinates = coordinatesIn;
+ location = settings.getMapFactory().getGeoPointBase((int)(coordinatesIn.getLatitude() * 1e6), (int)(coordinatesIn.getLongitude() * 1e6));
+ }
+
+ public void setHeading(Double headingIn) {
+ heading = headingIn;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ if (coordinates == null || location == null) return;
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (accuracyCircle == null) {
+ accuracyCircle = new Paint();
+ accuracyCircle.setAntiAlias(true);
+ accuracyCircle.setStrokeWidth(1.0f);
+ }
+
+ if (historyLine == null) {
+ historyLine = new Paint();
+ historyLine.setAntiAlias(true);
+ historyLine.setStrokeWidth(3.0f);
+ historyLine.setColor(0xFFFFFFFF);
+ }
+
+ if (historyLineShadow == null) {
+ historyLineShadow = new Paint();
+ historyLineShadow.setAntiAlias(true);
+ historyLineShadow.setStrokeWidth(7.0f);
+ historyLineShadow.setColor(0x66000000);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ double latitude = coordinates.getLatitude();
+ double longitude = coordinates.getLongitude();
+ float accuracy = coordinates.getAccuracy();
+
+ float[] result = new float[1];
+
+ Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result);
+ float longitudeLineDistance = result[0];
+
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(latitude * 1e6), (int)((longitude - accuracy / longitudeLineDistance) * 1e6));
+ projection.toPixels(leftGeo, left);
+ projection.toPixels(location, center);
+ int radius = center.x - left.x;
+
+ accuracyCircle.setColor(0x66000000);
+ accuracyCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ accuracyCircle.setColor(0x08000000);
+ accuracyCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ if (coordinates.getAccuracy() < 50f && ((historyRecent != null && cgBase.getDistance(historyRecent.getLatitude(), historyRecent.getLongitude(), coordinates.getLatitude(), coordinates.getLongitude()) > 0.005) || historyRecent == null)) {
+ if (historyRecent != null) history.add(historyRecent);
+ historyRecent = coordinates;
+
+ int toRemove = history.size() - 700;
+
+ if (toRemove > 0) {
+ for (int cnt = 0; cnt < toRemove; cnt ++) {
+ history.remove(cnt);
+ }
+ }
+ }
+
+ if (settings.maptrail == 1) {
+ int size = history.size();
+ if (size > 1) {
+ int alpha = 0;
+ int alphaCnt = size - 201;
+ if (alphaCnt < 1) alphaCnt = 1;
+
+ for (int cnt = 1; cnt < size; cnt ++) {
+ Location prev = history.get(cnt - 1);
+ Location now = history.get(cnt);
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ if ((alphaCnt - cnt) > 0) alpha = Math.round(255 / (alphaCnt - cnt));
+ else alpha = 255;
+
+ historyLineShadow.setAlpha(alpha);
+ historyLine.setAlpha(alpha);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (size > 0) {
+ Location prev = history.get(size - 1);
+ Location now = coordinates;
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ historyLineShadow.setAlpha(255);
+ historyLine.setAlpha(255);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (arrow == null) {
+ arrow = BitmapFactory.decodeResource(settings.getContext().getResources(), R.drawable.my_location_chevron);
+ widthArrow = arrow.getWidth();
+ heightArrow = arrow.getHeight();
+ }
+
+ int marginLeft;
+ int marginTop;
+
+ marginLeft = center.x - (widthArrow / 2);
+ marginTop = center.y - (heightArrow / 2);
+
+ canvas.rotate(new Float(heading), center.x, center.y);
+ canvas.drawBitmap(arrow, marginLeft, marginTop, null);
+ canvas.rotate(-(new Float(heading)), center.x, center.y);
+
+ canvas.setDrawFilter(remfil);
+
+ //super.draw(canvas, mapView, shadow);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgMapOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
new file mode 100644
index 0000000..7433ccb
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
@@ -0,0 +1,322 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Point;
+import android.location.Location;
+import android.text.Html;
+import android.util.Log;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.cgeonavigate;
+import cgeo.geocaching.cgeopopup;
+import cgeo.geocaching.cgeowaypoint;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+import java.util.ArrayList;
+
+import org.mapsforge.android.maps.Projection;
+
+public class cgMapOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+ private Context context = null;
+ private Boolean fromDetail = false;
+ private boolean displayCircles = false;
+ private ProgressDialog waitDialog = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Paint blockedCircle = null;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private cgSettings settings;
+
+ public cgMapOverlay(cgSettings settingsIn, ItemizedOverlayImpl ovlImpl, Context contextIn, Boolean fromDetailIn) {
+ super(ovlImpl);
+
+ populate();
+ settings = settingsIn;
+
+ context = contextIn;
+ fromDetail = fromDetailIn;
+ }
+
+ public void updateItems(CacheOverlayItemImpl item) {
+ ArrayList<CacheOverlayItemImpl> itemsPre = new ArrayList<CacheOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<CacheOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (CacheOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenterBottom(item.getMarker(0)));
+ }
+
+// items.clear();
+
+// if (itemsPre.size() > 0) {
+ items = (ArrayList<CacheOverlayItemImpl>) itemsPre.clone();
+// }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ public boolean getCircles() {
+ return displayCircles;
+ }
+
+ public void switchCircles() {
+ displayCircles = !displayCircles;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (displayCircles) {
+ if (blockedCircle == null) {
+ blockedCircle = new Paint();
+ blockedCircle.setAntiAlias(true);
+ blockedCircle.setStrokeWidth(1.0f);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ for (CacheOverlayItemImpl item : items) {
+ final cgCoord itemCoord = item.getCoord();
+ float[] result = new float[1];
+
+ Location.distanceBetween(itemCoord.latitude, itemCoord.longitude, itemCoord.latitude, itemCoord.longitude + 1, result);
+ final float longitudeLineDistance = result[0];
+
+ GeoPointImpl itemGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)(itemCoord.longitude * 1e6));
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)((itemCoord.longitude - 161 / longitudeLineDistance) * 1e6));
+
+ projection.toPixels(itemGeo, center);
+ projection.toPixels(leftGeo, left);
+ int radius = center.x - left.x;
+
+ final String type = item.getType();
+ if (type == null || "multi".equals(type) || "mystery".equals(type) || "virtual".equals(type)) {
+ blockedCircle.setColor(0x66000000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ } else {
+ blockedCircle.setColor(0x66BB0000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+
+ blockedCircle.setColor(0x44BB0000);
+ blockedCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ }
+ }
+
+ canvas.setDrawFilter(remfil);
+ }
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ if (waitDialog == null) {
+ waitDialog = new ProgressDialog(context);
+ waitDialog.setMessage("loading details...");
+ waitDialog.setCancelable(false);
+ }
+ waitDialog.show();
+
+ CacheOverlayItemImpl item = items.get(index);
+ cgCoord coordinate = item.getCoord();
+
+ if (coordinate.type != null && coordinate.type.equalsIgnoreCase("cache") == true && coordinate.geocode != null && coordinate.geocode.length() > 0) {
+ Intent popupIntent = new Intent(context, cgeopopup.class);
+
+ popupIntent.putExtra("fromdetail", fromDetail);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else if (coordinate.type != null && coordinate.type.equalsIgnoreCase("waypoint") == true && coordinate.id != null && coordinate.id > 0) {
+ Intent popupIntent = new Intent(context, cgeowaypoint.class);
+
+ popupIntent.putExtra("waypoint", coordinate.id);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else {
+ waitDialog.dismiss();
+ return false;
+ }
+
+ waitDialog.dismiss();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public CacheOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ public void infoDialog(int index) {
+ final CacheOverlayItemImpl item = items.get(index);
+ final cgCoord coordinate = item.getCoord();
+
+ if (coordinate == null) {
+ Log.e(cgSettings.tag, "cgMapOverlay:infoDialog: No coordinates given");
+ return;
+ }
+
+ try {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setCancelable(true);
+
+ if (coordinate.type.equalsIgnoreCase("cache")) {
+ dialog.setTitle("cache");
+
+ String cacheType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ cacheType = cgBase.cacheTypesInv.get(coordinate.typeSpec);
+ } else {
+ cacheType = cgBase.cacheTypesInv.get("mystery");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ngeocode: " + coordinate.geocode.toUpperCase() + "\ntype: " + cacheType);
+ if (fromDetail == false) {
+ dialog.setPositiveButton("detail", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ Intent cachesIntent = new Intent(context, cgeodetail.class);
+ cachesIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(cachesIntent);
+
+ dialog.cancel();
+ }
+ });
+ } else {
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+ } else {
+ dialog.setTitle("waypoint");
+
+ String waypointType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ waypointType = cgBase.waypointTypes.get(coordinate.typeSpec);
+ } else {
+ waypointType = cgBase.waypointTypes.get("waypoint");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ntype: " + waypointType);
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.name);
+
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+
+ dialog.setNegativeButton("dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.infoDialog: " + e.toString());
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgOverlayScale.java b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
new file mode 100644
index 0000000..1e4a6e6
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
@@ -0,0 +1,140 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.Activity;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+public class cgOverlayScale implements OverlayBase {
+ private cgSettings settings = null;
+ private Paint scale = null;
+ private Paint scaleShadow = null;
+ private BlurMaskFilter blur = null;
+ private float pixelDensity = 0l;
+ private double pixels = 0d;
+ private int bottom = 0;
+ private double distance = 0d;
+ private double distanceRound = 0d;
+ private String units = null;
+
+ public cgOverlayScale(Activity activity, cgSettings settingsIn) {
+ settings = settingsIn;
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ //super.draw(canvas, mapView, shadow);
+
+ final double span = mapView.getLongitudeSpan() / 1e6;
+ final GeoPointImpl center = mapView.getMapViewCenter();
+
+ pixels = mapView.getWidth() / 2; // pixels related to following latitude span
+ bottom = mapView.getHeight() - 14; // pixels from bottom side of screen
+ distance = cgBase.getDistance((center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) - (span /2)), (center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) + (span /2)));
+ distance = distance / 2;
+ distanceRound = 0d;
+
+ if(settings.units == cgSettings.unitsImperial) {
+ distance *= cgBase.kmInMiles;
+
+ if (distance > 100) { // 100+ mi > 1xx mi
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "mi";
+ } else if (distance > 10) { // 10 - 100 mi > 1x mi
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "mi";
+ } else if (distance > 1) { // 1 - 10 mi > 1.x mi
+ distanceRound = Math.floor(distance);
+ units = "mi";
+ } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft
+ distance *= 5280;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "ft";
+ } else { // 1 - 100 ft > 1x ft
+ distance *= 5280;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "ft";
+ }
+ } else {
+ if (distance > 100) { // 100+ km > 1xx km
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "km";
+ } else if (distance > 10) { // 10 - 100 km > 1x km
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "km";
+ } else if (distance > 1) { // 1 - 10 km > 1.x km
+ distanceRound = Math.floor(distance);
+ units = "km";
+ } else if (distance > 0.1) { // 100 m - 1 km > 1xx m
+ distance *= 1000;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "m";
+ } else { // 1 - 100 m > 1x m
+ distance *= 1000;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "m";
+ }
+ }
+
+ pixels = Math.round((pixels / distance) * distanceRound);
+
+ if (blur == null) {
+ blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL);
+ }
+
+ if (scaleShadow == null) {
+ scaleShadow = new Paint();
+ scaleShadow.setAntiAlias(true);
+ scaleShadow.setStrokeWidth(4 * pixelDensity);
+ scaleShadow.setMaskFilter(blur);
+ scaleShadow.setTextSize(14 * pixelDensity);
+ scaleShadow.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (scale == null) {
+ scale = new Paint();
+ scale.setAntiAlias(true);
+ scale.setStrokeWidth(2 * pixelDensity);
+ scale.setTextSize(14 * pixelDensity);
+ scale.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (mapView.isSatellite()) {
+ scaleShadow.setColor(0xFF000000);
+ scale.setColor(0xFFFFFFFF);
+ } else {
+ scaleShadow.setColor(0xFFFFFFFF);
+ scale.setColor(0xFF000000);
+ }
+
+ canvas.drawLine(10, bottom, 10, (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine((int)(pixels + 10), bottom, (int)(pixels + 10), (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine(8, bottom, (int)(pixels + 12), bottom, scaleShadow);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow);
+
+ canvas.drawLine(11, bottom, 11, (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine((int)(pixels + 9), bottom, (int)(pixels + 9), (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine(10, bottom, (int)(pixels + 10), bottom, scale);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
new file mode 100644
index 0000000..8eb76cd
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
@@ -0,0 +1,185 @@
+package cgeo.geocaching.mapcommon;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.util.Log;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class cgUsersOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+ private Context context = null;
+ private final Pattern patternGeocode = Pattern.compile("^(GC[A-Z0-9]+)(\\: ?(.+))?$", Pattern.CASE_INSENSITIVE);
+
+ public cgUsersOverlay(ItemizedOverlayImpl ovlImplIn, Context contextIn) {
+ super(ovlImplIn);
+ populate();
+
+ context = contextIn;
+ }
+
+ protected void updateItems(UserOverlayItemImpl item) {
+ ArrayList<UserOverlayItemImpl> itemsPre = new ArrayList<UserOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<UserOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (UserOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenter(item.getMarker(0)));
+ }
+
+ items.clear();
+
+ if (itemsPre.size() > 0) {
+ items = (ArrayList<UserOverlayItemImpl>) itemsPre.clone();
+ }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ final UserOverlayItemImpl item = items.get(index);
+ final cgUser user = item.getUser();
+
+ // set action
+ String action = null;
+ String geocode = null;
+ final Matcher matcherGeocode = patternGeocode.matcher(user.action.trim());
+
+ if (user.action.length() == 0 || user.action.equalsIgnoreCase("pending")) {
+ action = "Looking around";
+ } else if (user.action.equalsIgnoreCase("tweeting")) {
+ action = "Tweeting";
+ } else if (matcherGeocode.find() == true) {
+ if (matcherGeocode.group(1) != null) {
+ geocode = matcherGeocode.group(1).trim().toUpperCase();
+ }
+ if (matcherGeocode.group(3) != null) {
+ action = "Heading to " + geocode + " (" + matcherGeocode.group(3).trim() + ")";
+ } else {
+ action = "Heading to " + geocode;
+ }
+ } else {
+ action = user.action;
+ }
+
+ // set icon
+ int icon = -1;
+ if (user.client.equalsIgnoreCase("c:geo") == true) {
+ icon = R.drawable.client_cgeo;
+ } else if (user.client.equalsIgnoreCase("preCaching") == true) {
+ icon = R.drawable.client_precaching;
+ } else if (user.client.equalsIgnoreCase("Handy Geocaching") == true) {
+ icon = R.drawable.client_handygeocaching;
+ }
+
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ if (icon > -1) {
+ dialog.setIcon(icon);
+ }
+ dialog.setTitle(user.username);
+ dialog.setMessage(action);
+ dialog.setCancelable(true);
+ if (geocode != null && geocode.length() > 0) {
+ dialog.setPositiveButton(geocode + "?", new cacheDetails(geocode));
+ }
+ dialog.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+
+ return true;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ @Override
+ public UserOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ private class cacheDetails implements DialogInterface.OnClickListener {
+
+ private String geocode = null;
+
+ public cacheDetails(String geocodeIn) {
+ geocode = geocodeIn;
+ }
+
+ public void onClick(DialogInterface dialog, int id) {
+ if (geocode != null) {
+ Intent detailIntent = new Intent(context, cgeodetail.class);
+ detailIntent.putExtra("geocode", geocode);
+ context.startActivity(detailIntent);
+ }
+
+ dialog.cancel();
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgeomap.java b/src/cgeo/geocaching/mapcommon/cgeomap.java
new file mode 100644
index 0000000..7ba7532
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgeomap.java
@@ -0,0 +1,1686 @@
+package cgeo.geocaching.mapcommon;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgDirection;
+import cgeo.geocaching.cgGeo;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUpdateDir;
+import cgeo.geocaching.cgUpdateLoc;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgWarning;
+import cgeo.geocaching.cgWaypoint;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import cgeo.geocaching.cgSearch;
+
+import java.util.HashMap;
+import java.util.Locale;
+
+public class cgeomap extends MapBase {
+
+ private Resources res = null;
+ private Activity activity = null;
+ private MapViewImpl mapView = null;
+ private MapControllerImpl mapController = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgeoapplication app = null;
+ private SharedPreferences.Editor prefsEdit = null;
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new UpdateLoc();
+ private cgUpdateDir dirUpdate = new UpdateDir();
+ // from intent
+ private boolean fromDetailIntent = false;
+ private Long searchIdIntent = null;
+ private String geocodeIntent = null;
+ private Double latitudeIntent = null;
+ private Double longitudeIntent = null;
+ private String waypointTypeIntent = null;
+ // status data
+ private Long searchId = null;
+ private String token = null;
+ private boolean noMapTokenShowed = false;
+ // map status data
+ private boolean followMyLocation = false;
+ private Integer centerLatitude = null;
+ private Integer centerLongitude = null;
+ private Integer spanLatitude = null;
+ private Integer spanLongitude = null;
+ private Integer centerLatitudeUsers = null;
+ private Integer centerLongitudeUsers = null;
+ private Integer spanLatitudeUsers = null;
+ private Integer spanLongitudeUsers = null;
+ // thread
+ private LoadTimer loadTimer = null;
+ private UsersTimer usersTimer = null;
+ private LoadThread loadThread = null;
+ private DownloadThread downloadThread = null;
+ private DisplayThread displayThread = null;
+ private UsersThread usersThread = null;
+ private DisplayUsersThread displayUsersThread = null;
+ private LoadDetails loadDetailsThread = null;
+ private volatile long loadThreadRun = 0l;
+ private volatile long downloadThreadRun = 0l;
+ private volatile long usersThreadRun = 0l;
+ private volatile boolean downloaded = false;
+ // overlays
+ private cgMapOverlay overlayCaches = null;
+ private cgUsersOverlay overlayUsers = null;
+ private cgOverlayScale overlayScale = null;
+ private cgMapMyOverlay overlayMyLoc = null;
+ // data for overlays
+ private int cachesCnt = 0;
+ private HashMap<Integer, Drawable> iconsCache = new HashMap<Integer, Drawable>();
+ private ArrayList<cgCache> caches = new ArrayList<cgCache>();
+ private ArrayList<cgUser> users = new ArrayList<cgUser>();
+ private ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+ // storing for offline
+ private ProgressDialog waitDialog = null;
+ private int detailTotal = 0;
+ private int detailProgress = 0;
+ private Long detailProgressTime = 0l;
+ // views
+ private ImageView myLocSwitch = null;
+ // other things
+ private boolean live = true; // live map (live, dead) or rest (displaying caches on map)
+ private boolean liveChanged = false; // previous state for loadTimer
+ private boolean centered = false; // if map is already centered
+ private boolean alreadyCentered = false; // -""- for setting my location
+ // handlers
+ final private Handler displayHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ // set title
+ final StringBuilder title = new StringBuilder();
+
+ if (live == true) {
+ title.append(res.getString(R.string.map_live));
+ } else {
+ title.append(res.getString(R.string.map_map));
+ }
+
+ if (caches != null && cachesCnt > 0) {
+ title.append(" ");
+ title.append("[");
+ title.append(caches.size());
+ title.append("]");
+ }
+
+ base.setTitle(activity, title.toString());
+ } else if (what == 1 && mapView != null) {
+ mapView.invalidate();
+ }
+ }
+ };
+ final private Handler showProgressHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ base.showProgress(activity, false);
+ } else if (what == 1) {
+ base.showProgress(activity, true);
+ }
+ }
+ };
+ final private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ if (waitDialog != null) {
+ Float diffTime = new Float((System.currentTimeMillis() - detailProgressTime) / 1000); // seconds left
+ Float oneCache = diffTime / detailProgress; // left time per cache
+ Float etaTime = (detailTotal - detailProgress) * oneCache; // seconds remaining
+
+ waitDialog.setProgress(detailProgress);
+ if (etaTime < 40) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 90) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ }
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ }
+ }
+ };
+ final private Handler noMapTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (!noMapTokenShowed) {
+ warning.showToast(res.getString(R.string.map_token_err));
+
+ noMapTokenShowed = true;
+ }
+ }
+ };
+
+ public cgeomap(ActivityImpl activity) {
+ super(activity);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // class init
+ res = this.getResources();
+ activity = this.getActivity();
+ app = (cgeoapplication) activity.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ MapFactory mapFactory = settings.getMapFactory();
+
+ // reset status
+ noMapTokenShowed = false;
+
+ // set layout
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // set layout
+ if (settings.skin == 1) {
+ activity.setTheme(R.style.light);
+ } else {
+ activity.setTheme(R.style.dark);
+ }
+ activity.setContentView(settings.getMapFactory().getMapLayoutId());
+ base.setTitle(activity, res.getString(R.string.map_map));
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ mapView = (MapViewImpl) activity.findViewById(mapFactory.getMapViewId());
+ mapView.setMapSource(settings);
+ if (!mapView.needsScaleOverlay()) {
+ mapView.setBuiltinScale(true);
+ }
+
+ // initialize map
+ if (settings.maptype == cgSettings.mapSatellite) {
+ mapView.setSatellite(true);
+ } else {
+ mapView.setSatellite(false);
+ }
+ mapView.setBuiltInZoomControls(true);
+ mapView.displayZoomControls(true);
+ mapView.preLoad();
+
+ // initialize overlays
+ mapView.clearOverlays();
+
+ if (overlayMyLoc == null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (settings.publicLoc > 0 && overlayUsers == null) {
+ overlayUsers = mapView.createAddUsersOverlay(activity, getResources().getDrawable(R.drawable.user_location));
+ }
+
+ if (overlayCaches == null) {
+ overlayCaches = mapView.createAddMapOverlay(settings, mapView.getContext(), getResources().getDrawable(R.drawable.marker), fromDetailIntent);
+ }
+
+ if (overlayScale == null && mapView.needsScaleOverlay()) {
+ overlayScale = new cgOverlayScale(activity, settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayScale));
+ }
+
+ mapView.invalidate();
+
+ mapController = mapView.getMapController();
+ mapController.setZoom(settings.mapzoom);
+
+ // start location and directory services
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ // get parameters
+ Bundle extras = activity.getIntent().getExtras();
+ if (extras != null) {
+ fromDetailIntent = extras.getBoolean("detail");
+ searchIdIntent = extras.getLong("searchid");
+ geocodeIntent = extras.getString("geocode");
+ latitudeIntent = extras.getDouble("latitude");
+ longitudeIntent = extras.getDouble("longitude");
+ waypointTypeIntent = extras.getString("wpttype");
+
+ if (searchIdIntent == 0l) {
+ searchIdIntent = null;
+ }
+ if (latitudeIntent == 0.0) {
+ latitudeIntent = null;
+ }
+ if (longitudeIntent == 0.0) {
+ longitudeIntent = null;
+ }
+ }
+
+ // live or death
+ if (searchIdIntent == null && geocodeIntent == null && (latitudeIntent == null || longitudeIntent == null)) {
+ live = true;
+ } else {
+ live = false;
+ }
+
+ // google analytics
+ if (live) {
+ base.sendAnal(activity, "/map/live");
+
+ followMyLocation = true;
+ } else {
+ base.sendAnal(activity, "/map/normal");
+
+ followMyLocation = false;
+
+ if (geocodeIntent != null || searchIdIntent != null || (latitudeIntent != null && longitudeIntent != null)) {
+ centerMap(geocodeIntent, searchIdIntent, latitudeIntent, longitudeIntent);
+ }
+ }
+ setMyLoc(null);
+ startTimer();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ app.setAction(null);
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ startTimer();
+ }
+
+ @Override
+ public void onStop() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 1, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ menu.add(0, 3, 0, res.getString(R.string.map_live_disable)).setIcon(android.R.drawable.ic_menu_close_clear_cancel);
+ menu.add(0, 4, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as).setEnabled(false);
+ menu.add(0, 2, 0, res.getString(R.string.map_trail_hide)).setIcon(android.R.drawable.ic_menu_recent_history);
+ menu.add(0, 5, 0, res.getString(R.string.map_circles_hide)).setIcon(android.R.drawable.ic_menu_view);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ try {
+ item = menu.findItem(1); // view
+ if (mapView != null && mapView.isSatellite() == false) {
+ item.setTitle(res.getString(R.string.map_view_satellite));
+ } else {
+ item.setTitle(res.getString(R.string.map_view_map));
+ }
+
+ item = menu.findItem(2); // show trail
+ if (settings.maptrail == 1) {
+ item.setTitle(res.getString(R.string.map_trail_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_trail_show));
+ }
+
+ item = menu.findItem(3); // live map
+ if (live == false) {
+ item.setEnabled(false);
+ item.setTitle(res.getString(R.string.map_live_enable));
+ } else {
+ if (settings.maplive == 1) {
+ item.setTitle(res.getString(R.string.map_live_disable));
+ } else {
+ item.setTitle(res.getString(R.string.map_live_enable));
+ }
+ }
+
+ item = menu.findItem(4); // store loaded
+ if (live && !isLoading() && app.getNotOfflineCount(searchId) > 0 && caches != null && caches.size() > 0) {
+ item.setEnabled(true);
+ } else {
+ item.setEnabled(false);
+ }
+
+ item = menu.findItem(5); // show circles
+ if (overlayCaches != null && overlayCaches.getCircles()) {
+ item.setTitle(res.getString(R.string.map_circles_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_circles_show));
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString());
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ if (mapView != null && mapView.isSatellite() == false) {
+ mapView.setSatellite(true);
+
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ prefsEdit.commit();
+ } else {
+ mapView.setSatellite(false);
+
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ prefsEdit.commit();
+ }
+
+ return true;
+ } else if (id == 2) {
+ if (settings.maptrail == 1) {
+ prefsEdit.putInt("maptrail", 0);
+ prefsEdit.commit();
+
+ settings.maptrail = 0;
+ } else {
+ prefsEdit.putInt("maptrail", 1);
+ prefsEdit.commit();
+
+ settings.maptrail = 1;
+ }
+ } else if (id == 3) {
+ if (settings.maplive == 1) {
+ settings.liveMapDisable();
+ } else {
+ settings.liveMapEnable();
+ }
+ liveChanged = true;
+ searchId = null;
+ searchIdIntent = null;
+ } else if (id == 4) {
+ if (live && !isLoading() && caches != null && !caches.isEmpty()) {
+ final ArrayList<String> geocodes = new ArrayList<String>();
+
+ ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ try {
+ if (cachesProtected != null && cachesProtected.size() > 0) {
+ final GeoPointImpl mapCenter = mapView.getMapViewCenter();
+ final int mapCenterLat = mapCenter.getLatitudeE6();
+ final int mapCenterLon = mapCenter.getLongitudeE6();
+ final int mapSpanLat = mapView.getLatitudeSpan();
+ final int mapSpanLon = mapView.getLongitudeSpan();
+
+ for (cgCache oneCache : cachesProtected) {
+ if (oneCache != null && oneCache.latitude != null && oneCache.longitude != null) {
+ if (base.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, oneCache.latitude, oneCache.longitude) && app.isOffline(oneCache.geocode, null) == false) {
+ geocodes.add(oneCache.geocode);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onOptionsItemSelected.#4: " + e.toString());
+ }
+
+ detailTotal = geocodes.size();
+
+ if (detailTotal == 0) {
+ warning.showToast(res.getString(R.string.warn_save_nothing));
+
+ return true;
+ }
+
+ waitDialog = new ProgressDialog(activity);
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ waitDialog.setCancelable(true);
+ waitDialog.setMax(detailTotal);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (loadDetailsThread != null) {
+ loadDetailsThread.stopIt();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ Float etaTime = new Float((detailTotal * (float) 7) / 60);
+ if (etaTime < 0.4) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 1.5) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ waitDialog.show();
+
+ detailProgressTime = System.currentTimeMillis();
+
+ loadDetailsThread = new LoadDetails(loadDetailsHandler, geocodes);
+ loadDetailsThread.start();
+
+ return true;
+ }
+ } else if (id == 5) {
+ if (overlayCaches == null) {
+ return false;
+ }
+
+ overlayCaches.switchCircles();
+ }
+
+ return false;
+ }
+
+ private void savePrefs() {
+ if (mapView == null) {
+ return;
+ }
+
+ if (mapView.isSatellite()) {
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ settings.maptype = cgSettings.mapSatellite;
+ } else {
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ settings.maptype = cgSettings.mapClassic;
+ }
+
+ if (prefsEdit == null) {
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ }
+ prefsEdit.putInt("mapzoom", mapView.getMapZoomLevel());
+ prefsEdit.commit();
+ }
+
+ // set center of map to my location
+ private void myLocationInMiddle() {
+ if (geo == null) {
+ return;
+ }
+ if (!followMyLocation) {
+ return;
+ }
+
+ centerMap(geo.latitudeNow, geo.longitudeNow);
+ }
+
+ // class: update location
+ private class UpdateLoc extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (overlayMyLoc == null && mapView != null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(settings.getMapFactory().getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (overlayMyLoc != null && geo.location != null) {
+ overlayMyLoc.setCoordinates(geo.location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ if (followMyLocation == true) {
+ myLocationInMiddle();
+ }
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo.bearingNow != null) {
+ overlayMyLoc.setHeading(geo.bearingNow);
+ } else {
+ overlayMyLoc.setHeading(new Double(0));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ // class: update direction
+ private class UpdateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ if (overlayMyLoc != null && mapView != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h
+ overlayMyLoc.setHeading(dir.directionNow);
+ mapView.invalidate();
+ }
+ }
+ }
+
+ public void startTimer() {
+ if (latitudeIntent != null && longitudeIntent != null) {
+ // display just one point
+ (new DisplayPointThread()).start();
+ } else {
+ // start timer
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+ loadTimer = new LoadTimer();
+ loadTimer.start();
+ }
+
+ if (settings.publicLoc > 0) {
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+ usersTimer = new UsersTimer();
+ usersTimer.start();
+ }
+ }
+
+ // loading timer
+ private class LoadTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (loadThread != null) {
+ loadThread.stopIt();
+ loadThread = null;
+ }
+
+ if (downloadThread != null) {
+ downloadThread.stopIt();
+ downloadThread = null;
+ }
+
+ if (displayThread != null) {
+ displayThread.stopIt();
+ displayThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ boolean force = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+ force = false;
+
+ if (liveChanged) {
+ moved = true;
+ force = true;
+ } else if (live && settings.maplive == 1 && downloaded == false) {
+ moved = true;
+ } else if (centerLatitude == null || centerLongitude == null) {
+ moved = true;
+ } else if (spanLatitude == null || spanLongitude == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitude) > 50) || (Math.abs(spanLongitudeNow - spanLongitude) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow / 4)) // map moved
+ ) && (cachesCnt <= 0 || caches == null || caches.isEmpty()
+ || !base.isInViewPort(centerLatitude, centerLongitude, centerLatitudeNow, centerLongitudeNow, spanLatitude, spanLongitude, spanLatitudeNow, spanLongitudeNow))) {
+ moved = true;
+ }
+
+ if (moved && caches != null && centerLatitude != null && centerLongitude != null && ((Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow * 1.2)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow * 1.2)))) {
+ force = true;
+ }
+
+ //LeeB
+ // save new values
+ if (moved) {
+ liveChanged = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (1000 < (currentTime - loadThreadRun)) {
+ // from web
+ if (20000 < (currentTime - loadThreadRun)) {
+ force = true; // probably stucked thread
+ }
+
+ if (force && loadThread != null && loadThread.isWorking()) {
+ loadThread.stopIt();
+
+ try {
+ sleep(100);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (loadThread != null && loadThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitude = centerLatitudeNow;
+ centerLongitude = centerLongitudeNow;
+ spanLatitude = spanLatitudeNow;
+ spanLongitude = spanLongitudeNow;
+
+ showProgressHandler.sendEmptyMessage(1); // show progress
+
+ loadThread = new LoadThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ loadThread.setName("loadThread");
+ loadThread.start(); //loadThread will kick off downloadThread once it's done
+ }
+ }
+ }
+
+ if (!isLoading()) {
+ showProgressHandler.sendEmptyMessage(0); // hide progress
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // loading timer
+ private class UsersTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (usersThread != null) {
+ usersThread.stopIt();
+ usersThread = null;
+ }
+
+ if (displayUsersThread != null) {
+ displayUsersThread.stopIt();
+ displayUsersThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (60000 < (currentTime - usersThreadRun)) {
+ moved = true;
+ } else if (centerLatitudeUsers == null || centerLongitudeUsers == null) {
+ moved = true;
+ } else if (spanLatitudeUsers == null || spanLongitudeUsers == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitudeUsers) > 50) || (Math.abs(spanLongitudeNow - spanLongitudeUsers) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitudeUsers) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitudeUsers) > (spanLongitudeNow / 4)) // map moved
+ ) && !base.isInViewPort(centerLatitudeUsers, centerLongitudeUsers, centerLatitudeNow, centerLongitudeNow, spanLatitudeUsers, spanLongitudeUsers, spanLatitudeNow, spanLongitudeNow)) {
+ moved = true;
+ }
+
+ // save new values
+ if (moved && (1000 < (currentTime - usersThreadRun))) {
+ if (usersThread != null && usersThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitudeUsers = centerLatitudeNow;
+ centerLongitudeUsers = centerLongitudeNow;
+ spanLatitudeUsers = spanLatitudeNow;
+ spanLongitudeUsers = spanLongitudeNow;
+
+ usersThread = new UsersThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ usersThread.start();
+ }
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadUsersTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // load caches from database
+ private class LoadThread extends DoThread {
+
+ public LoadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ loadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //LeeB - I think this can be done better:
+ //1. fetch and draw(in another thread) caches from the db (fast? db read will be the slow bit)
+ //2. fetch and draw(in another thread) and then insert into the db caches from geocaching.com - dont draw/insert if exist in memory?
+
+ // stage 1 - pull and render from the DB only
+ if (settings.maplive == 0) {
+ searchId = app.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ } else {
+ searchId = app.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ }
+
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ if (stop) {
+ displayThread.stopIt();
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (settings.maplive >= 1) {
+ if (downloadThread != null && downloadThread.isWorking()) {
+ downloadThread.stopIt();
+ }
+ downloadThread = new DownloadThread(centerLat, centerLon, spanLat, spanLon);
+ downloadThread.setName("downloadThread");
+ downloadThread.start();
+ }
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load caches from internet
+ private class DownloadThread extends DoThread {
+
+ public DownloadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() { //first time we enter we have crappy long/lat....
+ try {
+ stop = false;
+ working = true;
+ downloadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (token == null) {
+ token = base.getMapUserToken(noMapTokenHandler);
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("usertoken", token);
+ params.put("latitude-min", String.format((Locale) null, "%.6f", latMin));
+ params.put("latitude-max", String.format((Locale) null, "%.6f", latMax));
+ params.put("longitude-min", String.format((Locale) null, "%.6f", lonMin));
+ params.put("longitude-max", String.format((Locale) null, "%.6f", lonMax));
+
+ searchId = base.searchByViewport(params, 0);
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId, centerLat, centerLon, spanLat, spanLon);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display (down)loaded caches
+ private class DisplayThread extends DoThread {
+
+ public DisplayThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || caches == null) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display caches
+ final ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ final ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+
+ if (cachesProtected != null && !cachesProtected.isEmpty()) {
+ int counter = 0;
+ int icon = 0;
+ Drawable pin = null;
+ CacheOverlayItemImpl item = null;
+
+ for (cgCache cacheOne : cachesProtected) {
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ if (cacheOne.latitude == null && cacheOne.longitude == null) {
+ continue;
+ }
+
+ final cgCoord coord = new cgCoord(cacheOne);
+ coordinates.add(coord);
+
+ item = settings.getMapFactory().getCacheOverlayItem(coord, cacheOne.type);
+ icon = base.getIcon(true, cacheOne.type, cacheOne.own, cacheOne.found, cacheOne.disabled || cacheOne.archived);
+ pin = null;
+
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+
+ /*
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ */
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = cachesProtected.size();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display cache waypoints
+ if (cachesCnt == 1 && (geocodeIntent != null || searchIdIntent != null) && !live) {
+ if (cachesCnt == 1 && live == false) {
+ cgCache oneCache = cachesProtected.get(0);
+
+ if (oneCache != null && oneCache.waypoints != null && !oneCache.waypoints.isEmpty()) {
+ for (cgWaypoint oneWaypoint : oneCache.waypoints) {
+ if (oneWaypoint.latitude == null && oneWaypoint.longitude == null) {
+ continue;
+ }
+
+ cgCoord coord = new cgCoord(oneWaypoint);
+
+ coordinates.add(coord);
+ item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ icon = base.getIcon(false, oneWaypoint.type, false, false, false);
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+ }
+ } else {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+
+ cachesProtected.clear();
+
+ displayHandler.sendEmptyMessage(0);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load users from Go 4 Cache
+ private class UsersThread extends DoThread {
+
+ public UsersThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ usersThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ users = base.getGeocachersInViewport(settings.getUsername(), latMin, latMax, lonMin, lonMax);
+
+ if (stop) {
+ return;
+ }
+
+ if (displayUsersThread != null && displayUsersThread.isWorking()) {
+ displayUsersThread.stopIt();
+ }
+ displayUsersThread = new DisplayUsersThread(users, centerLat, centerLon, spanLat, spanLon);
+ displayUsersThread.start();
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display users of Go 4 Cache
+ private class DisplayUsersThread extends DoThread {
+
+ private ArrayList<cgUser> users = null;
+
+ public DisplayUsersThread(ArrayList<cgUser> usersIn, long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+
+ users = usersIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || users == null || users.isEmpty()) {
+ return;
+ }
+
+ // display users
+ ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+
+ int counter = 0;
+ UserOverlayItemImpl item = null;
+
+ for (cgUser userOne : users) {
+ if (stop) {
+ return;
+ }
+
+ if (userOne.latitude == null && userOne.longitude == null) {
+ continue;
+ }
+
+ item = settings.getMapFactory().getUserOverlayItemBase(activity, userOne);
+ items.add(item);
+
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayUsers.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+
+ overlayUsers.updateItems(items);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display one point
+ private class DisplayPointThread extends Thread {
+
+ @Override
+ public void run() {
+ if (mapView == null || caches == null) {
+ return;
+ }
+
+ if (latitudeIntent != null && longitudeIntent != null) {
+ cgCoord coord = new cgCoord();
+ coord.type = "waypoint";
+ coord.latitude = latitudeIntent;
+ coord.longitude = longitudeIntent;
+ coord.name = "some place";
+
+ coordinates.add(coord);
+ CacheOverlayItemImpl item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ final int icon = base.getIcon(false, waypointTypeIntent, false, false, false);
+ Drawable pin = null;
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ overlayCaches.updateItems(item);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = 1;
+ } else {
+ cachesCnt = 0;
+ }
+
+ displayHandler.sendEmptyMessage(0);
+ }
+ }
+
+ // parent for those above :)
+ private class DoThread extends Thread {
+
+ protected boolean working = true;
+ protected boolean stop = false;
+ protected long centerLat = 0l;
+ protected long centerLon = 0l;
+ protected long spanLat = 0l;
+ protected long spanLon = 0l;
+
+ public DoThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ centerLat = centerLatIn;
+ centerLon = centerLonIn;
+ spanLat = spanLatIn;
+ spanLon = spanLonIn;
+ }
+
+ public synchronized boolean isWorking() {
+ return working;
+ }
+
+ public synchronized void stopIt() {
+ stop = true;
+ }
+ }
+
+ // get if map is loading something
+ private synchronized boolean isLoading() {
+ boolean loading = false;
+
+ if (loadThread != null && loadThread.isWorking()) {
+ loading = true;
+ } else if (downloadThread != null && downloadThread.isWorking()) {
+ loading = true;
+ } else if (displayThread != null && displayThread.isWorking()) {
+ loading = true;
+ }
+
+ return loading;
+ }
+
+ // store caches
+ private class LoadDetails extends Thread {
+
+ private Handler handler = null;
+ private ArrayList<String> geocodes = null;
+ private volatile boolean stop = false;
+ private long last = 0l;
+
+ public LoadDetails(Handler handlerIn, ArrayList<String> geocodesIn) {
+ handler = handlerIn;
+ geocodes = geocodesIn;
+ }
+
+ public void stopIt() {
+ stop = true;
+ }
+
+ @Override
+ public void run() {
+ if (geocodes == null || geocodes.isEmpty()) {
+ return;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ for (String geocode : geocodes) {
+ try {
+ if (stop == true) {
+ break;
+ }
+
+ if (!app.isOffline(geocode, null)) {
+ if ((System.currentTimeMillis() - last) < 1500) {
+ try {
+ int delay = 1000 + ((Double) (Math.random() * 1000)).intValue() - (int) (System.currentTimeMillis() - last);
+ if (delay < 0) {
+ delay = 500;
+ }
+
+ sleep(delay);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (stop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+
+ break;
+ }
+
+ base.storeCache(app, activity, null, geocode, 1, handler);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.LoadDetails.run: " + e.toString());
+ } finally {
+ // one more cache over
+ detailProgress++;
+ handler.sendEmptyMessage(0);
+ }
+
+ yield();
+
+ last = System.currentTimeMillis();
+ }
+
+ // we're done
+ handler.sendEmptyMessage(1);
+ }
+ }
+
+ // center map to desired location
+ private void centerMap(Double latitude, Double longitude) {
+ if (latitude == null || longitude == null) {
+ return;
+ }
+ if (mapView == null) {
+ return;
+ }
+
+ if (!alreadyCentered) {
+ alreadyCentered = true;
+
+ mapController.setCenter(makeGeoPoint(latitude, longitude));
+ } else {
+ mapController.animateTo(makeGeoPoint(latitude, longitude));
+ }
+ }
+
+ // move map to view results of searchIdIntent
+ private void centerMap(String geocodeCenter, Long searchIdCenter, Double latitudeCenter, Double longitudeCenter) {
+ if (!centered && (geocodeCenter != null || searchIdIntent != null)) {
+ try {
+ ArrayList<Object> viewport;
+
+ if (geocodeCenter != null) {
+ viewport = app.getBounds(geocodeCenter);
+ } else {
+ viewport = app.getBounds(searchIdCenter);
+ }
+
+ Integer cnt = (Integer) viewport.get(0);
+ Integer minLat = null;
+ Integer maxLat = null;
+ Integer minLon = null;
+ Integer maxLon = null;
+
+ if (viewport.get(1) != null) {
+ minLat = new Double((Double) viewport.get(1) * 1e6).intValue();
+ }
+ if (viewport.get(2) != null) {
+ maxLat = new Double((Double) viewport.get(2) * 1e6).intValue();
+ }
+ if (viewport.get(3) != null) {
+ maxLon = new Double((Double) viewport.get(3) * 1e6).intValue();
+ }
+ if (viewport.get(4) != null) {
+ minLon = new Double((Double) viewport.get(4) * 1e6).intValue();
+ }
+
+ if (cnt == null || cnt <= 0 || minLat == null || maxLat == null || minLon == null || maxLon == null) {
+ return;
+ }
+
+ int centerLat = 0;
+ int centerLon = 0;
+
+ if ((Math.abs(maxLat) - Math.abs(minLat)) != 0) {
+ centerLat = minLat + ((maxLat - minLat) / 2);
+ } else {
+ centerLat = maxLat;
+ }
+ if ((Math.abs(maxLon) - Math.abs(minLon)) != 0) {
+ centerLon = minLon + ((maxLon - minLon) / 2);
+ } else {
+ centerLon = maxLon;
+ }
+
+ if (cnt != null && cnt > 0) {
+ mapController.setCenter(settings.getMapFactory().getGeoPointBase(centerLat, centerLon));
+ if (Math.abs(maxLat - minLat) != 0 && Math.abs(maxLon - minLon) != 0) {
+ mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon));
+ }
+ }
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ } else if (!centered && latitudeCenter != null && longitudeCenter != null) {
+ try {
+ mapController.setCenter(makeGeoPoint(latitudeCenter, longitudeCenter));
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ }
+ }
+
+ // switch My Location button image
+ private void setMyLoc(Boolean status) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (status == null) {
+ if (followMyLocation == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ } else {
+ if (status == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ }
+
+ myLocSwitch.setOnClickListener(new MyLocationListener());
+ }
+
+ // set my location listener
+ private class MyLocationListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (followMyLocation == true) {
+ followMyLocation = false;
+
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ } else {
+ followMyLocation = true;
+ myLocationInMiddle();
+
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ }
+ }
+ }
+
+ // make geopoint
+ private GeoPointImpl makeGeoPoint(Double latitude, Double longitude) {
+ return settings.getMapFactory().getGeoPointBase((int) (latitude * 1e6), (int) (longitude * 1e6));
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-live-map",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}