diff options
Diffstat (limited to 'src/cgeo/geocaching/mapcommon')
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java | 57 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/MapBase.java | 64 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java | 198 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/cgMapOverlay.java | 322 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/cgOverlayScale.java | 140 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/cgUsersOverlay.java | 185 | ||||
| -rw-r--r-- | src/cgeo/geocaching/mapcommon/cgeomap.java | 1686 |
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 + } + } +} |
